diff --git a/libretroshare/src/retroshare/rsiface.h b/libretroshare/src/retroshare/rsiface.h index 863b69ccd..475f90ba0 100644 --- a/libretroshare/src/retroshare/rsiface.h +++ b/libretroshare/src/retroshare/rsiface.h @@ -222,6 +222,7 @@ const int NOTIFY_LIST_PRIVATE_INCOMING_CHAT = 14; const int NOTIFY_LIST_PRIVATE_OUTGOING_CHAT = 15; const int NOTIFY_LIST_GROUPLIST = 16; const int NOTIFY_LIST_CHANNELLIST_LOCKED = 17; // use connect with Qt::QueuedConnection +const int NOTIFY_LIST_CHAT_LOBBY_INVITATION = 18; const int NOTIFY_TYPE_SAME = 0x01; const int NOTIFY_TYPE_MOD = 0x02; /* general purpose, check all */ diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index b8157c500..1d88a4202 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -30,6 +30,7 @@ #include #include #include +#include #include "rstypes.h" @@ -61,6 +62,10 @@ #define RS_MSGTAGTYPE_LATER 5 #define RS_MSGTAGTYPE_USER 100 +typedef uint64_t ChatLobbyId ; +typedef uint64_t ChatLobbyMsgId ; +typedef std::string ChatLobbyNickName ; + class MessageInfo { public: @@ -129,16 +134,33 @@ class ChatInfo { public: std::string rsid; + std::string peer_nickname; unsigned int chatflags; uint32_t sendTime; uint32_t recvTime; std::wstring msg; }; +class ChatLobbyInvite +{ + public: + ChatLobbyId lobby_id ; + std::string peer_id ; + std::string lobby_name ; +}; +class ChatLobbyInfo +{ + public: + ChatLobbyId lobby_id ; // unique id of the lobby + std::string nick_name ; // nickname to use for this lobby + std::string lobby_name ; // name to use for this lobby + + std::set participating_friends ; // list of direct friend who participate. Used to broadcast sent messages. + std::set nick_names ; // list of non direct friend who participate. Used to display only. +}; + std::ostream &operator<<(std::ostream &out, const MessageInfo &info); std::ostream &operator<<(std::ostream &out, const ChatInfo &info); -//std::ostream &operator<<(std::ostream &out, const MsgTagInfo); -//std::ostream &operator<<(std::ostream &out, const MsgTagType); bool operator==(const ChatInfo&, const ChatInfo&); @@ -186,12 +208,13 @@ virtual bool resetMessageStandardTagTypes(MsgTagType& tags) = 0; /* Chat */ virtual bool sendPublicChat(const std::wstring& msg) = 0; virtual bool sendPrivateChat(const std::string& id, const std::wstring& msg) = 0; -virtual int getPublicChatQueueCount() = 0; +virtual int getPublicChatQueueCount() = 0; virtual bool getPublicChatQueue(std::list &chats) = 0; -virtual int getPrivateChatQueueCount(bool incoming) = 0; +virtual int getPrivateChatQueueCount(bool incoming) = 0; virtual bool getPrivateChatQueueIds(bool incoming, std::list &ids) = 0; virtual bool getPrivateChatQueue(bool incoming, const std::string& id, std::list &chats) = 0; virtual bool clearPrivateChatQueue(bool incoming, const std::string& id) = 0; + virtual void sendStatusString(const std::string& id,const std::string& status_string) = 0 ; virtual void sendGroupChatStatusString(const std::string& status_string) = 0 ; @@ -205,9 +228,24 @@ virtual void getAvatarData(const std::string& pid,unsigned char *& data,int& siz virtual void setOwnAvatarData(const unsigned char *data,int size) = 0 ; virtual void getOwnAvatarData(unsigned char *& data,int& size) = 0 ; +virtual bool isLobbyId(const std::string& virtual_peer_id,ChatLobbyId& lobby_id) = 0; +virtual bool getVirtualPeerId(const ChatLobbyId& lobby_id,std::string& vpid) = 0; +virtual void getChatLobbyList(std::list& cl_info) = 0; +virtual void invitePeerToLobby(const ChatLobbyId& lobby_id,const std::string& peer_id) = 0; +virtual bool acceptLobbyInvite(const ChatLobbyId& id) = 0 ; +virtual void denyLobbyInvite(const ChatLobbyId& id) = 0 ; +virtual void getPendingChatLobbyInvites(std::list& invites) = 0; +virtual void unsubscribeChatLobby(const ChatLobbyId& lobby_id) = 0; +virtual bool setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick) = 0; +virtual bool getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick) = 0 ; +virtual bool setDefaultNickNameForChatLobby(const std::string& nick) = 0; +virtual bool getDefaultNickNameForChatLobby(std::string& nick) = 0 ; +virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const std::list& invited_friends) = 0 ; + /****************************************/ }; #endif + diff --git a/libretroshare/src/rsserver/p3msgs.cc b/libretroshare/src/rsserver/p3msgs.cc index 56fb174a7..ac902415f 100644 --- a/libretroshare/src/rsserver/p3msgs.cc +++ b/libretroshare/src/rsserver/p3msgs.cc @@ -260,3 +260,61 @@ void p3Msgs::setCustomStateString(const std::string& state_string) mChatSrv->setOwnCustomStateString(state_string) ; } +bool p3Msgs::getVirtualPeerId(const ChatLobbyId& id,std::string& peer_id) +{ + return mChatSrv->getVirtualPeerId(id,peer_id) ; +} +bool p3Msgs::isLobbyId(const std::string& peer_id,ChatLobbyId& id) +{ + return mChatSrv->isLobbyId(peer_id,id) ; +} + +void p3Msgs::getChatLobbyList(std::list& linfos) +{ + mChatSrv->getChatLobbyList(linfos) ; +} +void p3Msgs::invitePeerToLobby(const ChatLobbyId& lobby_id, const std::string& peer_id) +{ + mChatSrv->invitePeerToLobby(lobby_id,peer_id) ; +} +void p3Msgs::unsubscribeChatLobby(const ChatLobbyId& lobby_id) +{ + mChatSrv->unsubscribeChatLobby(lobby_id) ; +} +bool p3Msgs::setDefaultNickNameForChatLobby(const std::string& nick) +{ + return mChatSrv->setDefaultNickNameForChatLobby(nick) ; +} +bool p3Msgs::getDefaultNickNameForChatLobby(std::string& nick_name) +{ + return mChatSrv->getDefaultNickNameForChatLobby(nick_name) ; +} + +bool p3Msgs::setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick) +{ + return mChatSrv->setNickNameForChatLobby(lobby_id,nick) ; +} +bool p3Msgs::getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick_name) +{ + return mChatSrv->getNickNameForChatLobby(lobby_id,nick_name) ; +} + +ChatLobbyId p3Msgs::createChatLobby(const std::string& lobby_name,const std::list& invited_friends) +{ + return mChatSrv->createChatLobby(lobby_name,invited_friends) ; +} + +bool p3Msgs::acceptLobbyInvite(const ChatLobbyId& id) +{ + return mChatSrv->acceptLobbyInvite(id) ; +} +void p3Msgs::denyLobbyInvite(const ChatLobbyId& id) +{ + mChatSrv->denyLobbyInvite(id) ; +} +void p3Msgs::getPendingChatLobbyInvites(std::list& invites) +{ + mChatSrv->getPendingChatLobbyInvites(invites) ; +} + + diff --git a/libretroshare/src/rsserver/p3msgs.h b/libretroshare/src/rsserver/p3msgs.h index 39b39e903..1e104def0 100644 --- a/libretroshare/src/rsserver/p3msgs.h +++ b/libretroshare/src/rsserver/p3msgs.h @@ -168,6 +168,20 @@ class p3Msgs: public RsMsgs /****************************************/ + virtual bool getVirtualPeerId(const ChatLobbyId& id,std::string& vpid) ; + virtual bool isLobbyId(const std::string& virtual_peer_id,ChatLobbyId& lobby_id) ; + virtual void getChatLobbyList(std::list >&) ; + virtual void invitePeerToLobby(const ChatLobbyId&, const std::string&) ; + virtual bool acceptLobbyInvite(const ChatLobbyId& id) ; + virtual void denyLobbyInvite(const ChatLobbyId& id) ; + virtual void getPendingChatLobbyInvites(std::list& invites) ; + virtual void unsubscribeChatLobby(const ChatLobbyId& lobby_id) ; + virtual bool setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string&) ; + virtual bool getNickNameForChatLobby(const ChatLobbyId&,std::string& nick) ; + virtual bool setDefaultNickNameForChatLobby(const std::string&) ; + virtual bool getDefaultNickNameForChatLobby(std::string& nick) ; + virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const std::list& invited_friends) ; + private: p3MsgService *mMsgSrv; diff --git a/libretroshare/src/serialiser/rsmsgitems.cc b/libretroshare/src/serialiser/rsmsgitems.cc index 4586146dd..c89141d24 100644 --- a/libretroshare/src/serialiser/rsmsgitems.cc +++ b/libretroshare/src/serialiser/rsmsgitems.cc @@ -57,7 +57,54 @@ std::ostream& RsChatMsgItem::print(std::ostream &out, uint16_t indent) printRsItemEnd(out, "RsChatMsgItem", indent); return out; } +std::ostream& RsChatLobbyUnsubscribeItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsChatLobbyUnsubscribeItem", indent); + printIndent(out, indent); + out << "Lobby id: " << std::hex << lobby_id << std::endl; + printRsItemEnd(out, "RsChatLobbyUnsubscribeItem", indent); + return out; +} +std::ostream& RsChatLobbyConnectChallengeItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsChatLobbyConnectChallengeItem", indent); + printIndent(out, indent); + out << "Challenge Code: " << std::hex << challenge_code << std::endl; + printRsItemEnd(out, "RsChatLobbyConnectChallengeItem", indent); + return out; +} +std::ostream& RsChatLobbyMsgItem::print(std::ostream &out, uint16_t indent) +{ + RsChatMsgItem::print(out,indent) ; + printIndent(out, indent); + out << "Lobby ID: " << std::hex << lobby_id << std::endl; + printIndent(out, indent); + out << "Msg ID: " << std::hex << msg_id << std::dec << std::endl; + printIndent(out, indent); + out << "Nick: " << nick << std::dec << std::endl; + + printRsItemEnd(out, "RsChatLobbyMsgItem", indent); + return out; +} + +std::ostream& RsChatLobbyInviteItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsChatLobbyInviteItem", indent); + uint16_t int_Indent = indent + 2; + + printIndent(out, int_Indent); + out << "peerId: " << PeerId() << std::endl; + + printIndent(out, int_Indent); + out << "lobby id: " << std::hex << lobby_id << std::dec << std::endl; + + printIndent(out, int_Indent); + out << "lobby name: " << lobby_name << std::endl; + + printRsItemEnd(out, "RsChatLobbyInviteItem", indent); + return out; +} std::ostream& RsPrivateChatMsgConfigItem::print(std::ostream &out, uint16_t indent) { printRsItemBase(out, "RsPrivateChatMsgConfigItem", indent); @@ -137,10 +184,14 @@ RsItem *RsChatSerialiser::deserialise(void *data, uint32_t *pktsize) switch(getRsItemSubType(rstype)) { - case RS_PKT_SUBTYPE_DEFAULT: return new RsChatMsgItem(data,*pktsize) ; + case RS_PKT_SUBTYPE_DEFAULT: return new RsChatMsgItem(data,*pktsize) ; case RS_PKT_SUBTYPE_PRIVATECHATMSG_CONFIG: return new RsPrivateChatMsgConfigItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_CHAT_STATUS: return new RsChatStatusItem(data,*pktsize) ; - case RS_PKT_SUBTYPE_CHAT_AVATAR: return new RsChatAvatarItem(data,*pktsize) ; + case RS_PKT_SUBTYPE_CHAT_STATUS: return new RsChatStatusItem(data,*pktsize) ; + case RS_PKT_SUBTYPE_CHAT_AVATAR: return new RsChatAvatarItem(data,*pktsize) ; + case RS_PKT_SUBTYPE_CHAT_LOBBY_MSG: return new RsChatLobbyMsgItem(data,*pktsize) ; + case RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE: return new RsChatLobbyInviteItem(data,*pktsize) ; + case RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE: return new RsChatLobbyConnectChallengeItem(data,*pktsize) ; + case RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE: return new RsChatLobbyUnsubscribeItem(data,*pktsize) ; default: std::cerr << "Unknown packet type in chat!" << std::endl ; return NULL ; @@ -157,6 +208,38 @@ uint32_t RsChatMsgItem::serial_size() return s; } +uint32_t RsChatLobbyUnsubscribeItem::serial_size() +{ + uint32_t s = 8; /* header */ + s += 8; // challenge code + return s ; +} + + +uint32_t RsChatLobbyConnectChallengeItem::serial_size() +{ + uint32_t s = 8; /* header */ + s += 8; // challenge code + return s ; +} + +uint32_t RsChatLobbyMsgItem::serial_size() +{ + uint32_t s = RsChatMsgItem::serial_size() ; // parent + s += 8; // lobby_id + s += 8; // msg_id + s += GetTlvStringSize(nick) ; // nick + + return s; +} +uint32_t RsChatLobbyInviteItem::serial_size() +{ + uint32_t s = 8; /* header */ + s += 8; // lobby_id + s += GetTlvStringSize(lobby_name) ; // lobby name + + return s; +} uint32_t RsPrivateChatMsgConfigItem::serial_size() { uint32_t s = 8; /* header */ @@ -201,7 +284,7 @@ RsChatAvatarItem::~RsChatAvatarItem() /* serialise the data to the buffer */ bool RsChatMsgItem::serialise(void *data, uint32_t& pktsize) { - uint32_t tlvsize = serial_size() ; + uint32_t tlvsize = RsChatMsgItem::serial_size() ; uint32_t offset = 0; if (pktsize < tlvsize) @@ -228,7 +311,7 @@ bool RsChatMsgItem::serialise(void *data, uint32_t& pktsize) #ifdef CHAT_DEBUG std::cerr << "Serialized the following message:" << std::endl; std::cerr << "========== BEGIN MESSAGE =========" << std::endl; - for(int i=0;igetPeerName(rsPeers->getOwnId()); } int p3ChatService::tick() @@ -58,6 +61,15 @@ int p3ChatService::tick() receiveChatQueue(); } + static time_t last_clean_time = 0 ; + time_t now = time(NULL) ; + + if(last_clean_time + LOBBY_CACHE_CLEANING_PERIOD < now) + { + cleanLobbyCaches() ; + last_clean_time = now ; + } + return 0; } @@ -207,7 +219,7 @@ void p3ChatService::checkSizeAndSendMessage(RsChatMsgItem *msg) { // chop off the first 15000 wchars - RsChatMsgItem *item = new RsChatMsgItem(*msg) ; + RsChatMsgItem *item = msg->duplicate() ; item->message = item->message.substr(0,MAX_STRING_SIZE) ; msg->message = msg->message.substr(MAX_STRING_SIZE,msg->message.size()-MAX_STRING_SIZE) ; @@ -215,7 +227,7 @@ void p3ChatService::checkSizeAndSendMessage(RsChatMsgItem *msg) // Clear out any one time flags that should not be copied into multiple objects. This is // a precaution, in case the receivign peer does not yet handle split messages transparently. // - item->chatFlags &= (RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_PUBLIC) ; + item->chatFlags &= (RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_PUBLIC | RS_CHAT_FLAG_LOBBY) ; // Indicate that the message is to be continued. // @@ -225,8 +237,88 @@ void p3ChatService::checkSizeAndSendMessage(RsChatMsgItem *msg) sendItem(msg) ; } +bool p3ChatService::getVirtualPeerId(const ChatLobbyId& id,std::string& vpid) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + +#ifdef CHAT_DEBUG + std::cerr << "Was asked for virtual peer name of " << std::hex << id << std::dec<< std::endl; +#endif + std::map::const_iterator it(_chat_lobbys.find(id)) ; + + if(it == _chat_lobbys.end()) + { +#ifdef CHAT_DEBUG + std::cerr << " not found!! " << std::endl; +#endif + return false ; + } + + vpid = it->second.virtual_peer_id ; +#ifdef CHAT_DEBUG + std::cerr << " returning " << vpid << std::endl; +#endif + return true ; +} + +void p3ChatService::locked_printDebugInfo() const +{ + std::cerr << "Recorded lobbies: " << std::endl; + + for( std::map::const_iterator it(_chat_lobbys.begin()) ;it!=_chat_lobbys.end();++it) + { + std::cerr << " Lobby id\t\t: " << std::hex << it->first << std::dec << std::endl; + std::cerr << " Lobby name\t\t: " << it->second.lobby_name << std::endl; + std::cerr << " nick name\t\t: " << it->second.nick_name << std::endl; + std::cerr << " Lobby peer id\t: " << it->second.virtual_peer_id << std::endl; + std::cerr << " Challenge count\t: " << it->second.connexion_challenge_count << std::endl; + std::cerr << " Cached messages\t: " << it->second.msg_cache.size() << std::endl; + + for(std::map::const_iterator it2(it->second.msg_cache.begin());it2!=it->second.msg_cache.end();++it2) + std::cerr << " " << std::hex << it2->first << std::dec << " time=" << it2->second << std::endl; + + std::cerr << " Participating friends: " << std::endl; + + for(std::set::const_iterator it2(it->second.participating_friends.begin());it2!=it->second.participating_friends.end();++it2) + std::cerr << " " << *it2 << std::endl; + + std::cerr << " Participating nick names: " << std::endl; + + for(std::set::const_iterator it2(it->second.nick_names.begin());it2!=it->second.nick_names.end();++it2) + std::cerr << " " << *it2 << std::endl; + + } + + std::cerr << "Recorded lobby names: " << std::endl; + + for( std::map::const_iterator it(_lobby_ids.begin()) ;it!=_lobby_ids.end();++it) + std::cerr << " \"" << it->first << "\" id = " << std::hex << it->second << std::dec << std::endl; +} + +bool p3ChatService::isLobbyId(const std::string& id,ChatLobbyId& lobby_id) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + std::map::const_iterator it(_lobby_ids.find(id)) ; + + if(it != _lobby_ids.end()) + { + lobby_id = it->second ; + return true ; + } + else + return false ; +} + bool p3ChatService::sendPrivateChat(const std::string &id, const std::wstring &msg) { + // look into ID. Is it a peer, or a chat lobby? + + ChatLobbyId lobby_id ; + + if(isLobbyId(id,lobby_id)) + return sendLobbyChat(msg,lobby_id) ; + // make chat item.... #ifdef CHAT_DEBUG std::cerr << "p3ChatService::sendPrivateChat()"; @@ -363,6 +455,49 @@ bool p3ChatService::checkAndRebuildPartialMessage(RsChatMsgItem *ci) } } +void p3ChatService::checkAndRedirectMsgToLobby(RsChatMsgItem *ci) +{ +#ifdef CHAT_DEBUG + std::cerr << "Checking msg..." << std::endl; +#endif + + if(!(ci->chatFlags & RS_CHAT_FLAG_LOBBY)) + { +#ifdef CHAT_DEBUG + std::cerr << " normal chat!" << std::endl; +#endif + return ; + } +#ifdef CHAT_DEBUG + else + std::cerr << " lobby chat!" << std::endl; +#endif + + RsChatLobbyMsgItem *lobbyItem = dynamic_cast(ci) ; + + if(ci == NULL) + std::cerr << "Warning: chat message has lobby flag, but is not a chat lobby item!!" << std::endl; + + std::string vpeer_id ; + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + std::map::const_iterator it = _chat_lobbys.find(lobbyItem->lobby_id) ; + + if(it == _chat_lobbys.end()) + { + std::cerr << "(EE) p3ChatService::checkAndRedirectMsgToLobby(): RsItem is a lobby item, but the id is not known!!" << std::endl; + ci->PeerId(std::string()) ; + return ; + } + vpeer_id = it->second.virtual_peer_id ; + } + + recvLobbyChat(lobbyItem) ; // needs the proper peerId + ci->PeerId(vpeer_id) ; // thenthe peer Id is changed to the lobby id (virtual peer id). +} + + void p3ChatService::receiveChatQueue() { @@ -381,6 +516,10 @@ void p3ChatService::receiveChatQueue() if(ci != NULL) // real chat message { + // check if it's a lobby msg, in which case we replace the peer id by the lobby's virtual peer id. + // + checkAndRedirectMsgToLobby(ci) ; + #ifdef CHAT_DEBUG std::cerr << "p3ChatService::receiveChatQueue() Item:"; std::cerr << std::endl; @@ -433,9 +572,11 @@ void p3ChatService::receiveChatQueue() ci->recvTime = now; if (ci->chatFlags & RS_CHAT_FLAG_PRIVATE) { + std::cerr << "Adding msg 0x" << std::hex << (void*)ci << std::dec << " to private chat incoming list." << std::endl; privateChanged = true; privateIncomingList.push_back(ci); // don't delete the item !! } else { + std::cerr << "Adding msg 0x" << std::hex << (void*)ci << std::dec << " to public chat incoming list." << std::endl; publicChanged = true; publicList.push_back(ci); // don't delete the item !! @@ -446,6 +587,7 @@ void p3ChatService::receiveChatQueue() } } /* UNLOCK */ } + continue ; } RsChatStatusItem *cs = dynamic_cast(item) ; @@ -495,6 +637,37 @@ void p3ChatService::receiveChatQueue() delete item ; continue ; } + + RsChatLobbyInviteItem *cl = dynamic_cast(item) ; + + if(cl != NULL) + { + handleRecvLobbyInvite(cl) ; + delete item ; + continue ; + } + + RsChatLobbyConnectChallengeItem *cn = dynamic_cast(item) ; + + if(cn != NULL) + { + handleConnectionChallenge(cn) ; + delete item ; + continue ; + } + + RsChatLobbyUnsubscribeItem *cu = dynamic_cast(item) ; + + if(cu != NULL) + { + handleFriendUnsubscribeLobby(cu) ; + delete item ; + continue ; + } + + + std::cerr << "Received ChatItem of unhandled type: " << std::endl; + item->print(std::cerr,0) ; } if (publicChanged) { @@ -681,16 +854,15 @@ void p3ChatService::initRsChatInfo(RsChatMsgItem *c, ChatInfo &i) i.recvTime = c->recvTime; i.msg = c->message; + RsChatLobbyMsgItem *lobbyItem = dynamic_cast(c) ; + + if(lobbyItem != NULL) + i.peer_nickname = lobbyItem->nick; + if (c -> chatFlags & RS_CHAT_FLAG_PRIVATE) - { i.chatflags |= RS_CHAT_PRIVATE; - //std::cerr << "RsServer::initRsChatInfo() Chat Private!!!"; - } else - { i.chatflags |= RS_CHAT_PUBLIC; - //std::cerr << "RsServer::initRsChatInfo() Chat Public!!!"; - } } void p3ChatService::setOwnCustomStateString(const std::string& s) @@ -1024,6 +1196,16 @@ bool p3ChatService::loadList(std::list& load) continue; } + RsConfigKeyValueSet *vitem = NULL ; + + if(NULL != (vitem = dynamic_cast(*it))) + for(std::list::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) + if(kit->key == "DEFAULT_NICK_NAME") + { + std::cerr << "Loaded config default nick name for chat: " << kit->value << std::endl ; + _default_nick_name = kit->value ; + } + // delete unknown items delete *it; } @@ -1073,6 +1255,14 @@ bool p3ChatService::saveList(bool& cleanup, std::list& list) list.push_back(ci); } + RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ; + RsTlvKeyValue kv; + kv.key = "DEFAULT_NICK_NAME" ; + kv.value = _default_nick_name ; + vitem->tlvkvs.pairs.push_back(kv) ; + + list.push_back(vitem) ; + return true; } @@ -1086,6 +1276,7 @@ RsSerialiser *p3ChatService::setupSerialiser() { RsSerialiser *rss = new RsSerialiser ; rss->addSerialType(new RsChatSerialiser) ; + rss->addSerialType(new RsGeneralConfigSerialiser()); return rss ; } @@ -1135,3 +1326,582 @@ void p3ChatService::statusChange(const std::list &plist) } } } + +//********************** Chat Lobby Stuff ***********************// + +bool p3ChatService::recvLobbyChat(RsChatLobbyMsgItem *item) +{ + bool send_challenge = false ; + ChatLobbyId send_challenge_lobby ; + + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + locked_printDebugInfo() ; // debug +#ifdef CHAT_DEBUG + std::cerr << "Handling ChatLobbyMsg " << std::hex << item->msg_id << ", lobby id " << item->lobby_id << ", from peer id " << item->PeerId() << std::endl; +#endif + + // send upward for display + + std::map::iterator it(_chat_lobbys.find(item->lobby_id)) ; + + if(it == _chat_lobbys.end()) + { + std::cerr << "Chatlobby for id " << std::hex << item->lobby_id << " has no record. Dropping the msg." << std::dec << std::endl; + return false ; + } + ChatLobbyEntry& lobby(it->second) ; + + // Adds the peer id to the list of friend participants, even if it's not original msg source + + lobby.participating_friends.insert(item->PeerId()) ; + lobby.nick_names.insert(item->nick) ; + + // Checks wether the msg is already recorded or not + + std::map::const_iterator it2(lobby.msg_cache.find(item->msg_id)) ; + + if(it2 != lobby.msg_cache.end()) // found! + { + std::cerr << " Msg already received at time " << it2->second << ". Dropping!" << std::endl ; + return false ; + } +#ifdef CHAT_DEBUG + std::cerr << " Msg already not received already. Adding in cache, and forwarding!" << std::endl ; +#endif + + lobby.msg_cache[item->msg_id] = time(NULL) ; + + // Forward to allparticipating friends, except this peer. + + for(std::set::const_iterator it(lobby.participating_friends.begin());it!=lobby.participating_friends.end();++it) + if((*it)!=item->PeerId() && mLinkMgr->isOnline(*it)) + { + RsChatLobbyMsgItem *item2 = new RsChatLobbyMsgItem(*item) ; // copy almost everything + + item2->PeerId(*it) ; + + sendItem(item2); + } + + if(++lobby.connexion_challenge_count > CONNECTION_CHALLENGE_MAX_COUNT) + { + lobby.connexion_challenge_count = 0 ; + send_challenge_lobby = item->lobby_id ; + send_challenge = true ; + } + } + + if(send_challenge) + sendConnectionChallenge(send_challenge_lobby) ; + + return true ; +} + +bool p3ChatService::sendLobbyChat(const std::wstring& msg, const ChatLobbyId& lobby_id) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + +#ifdef CHAT_DEBUG + std::cerr << "Sending chat lobby message to lobby " << std::hex << lobby_id << std::dec << std::endl; + std::cerr << "msg:" << std::endl; + std::wcerr << msg << std::endl; +#endif + + // get a pointer to the info for that chat lobby. + // + std::map::iterator it(_chat_lobbys.find(lobby_id)) ; + + if(it == _chat_lobbys.end()) + { + std::cerr << "Chatlobby for id " << std::hex << lobby_id << " has no record. This is a serious error!!" << std::dec << std::endl; + return false ; + } + ChatLobbyEntry& lobby(it->second) ; + + RsChatLobbyMsgItem item ; + + // chat lobby stuff + // + do { item.msg_id = RSRandom::random_u64(); } while( lobby.msg_cache.find(item.msg_id) != lobby.msg_cache.end() ) ; + + lobby.msg_cache[item.msg_id] = time(NULL) ; // put the msg in cache! + + item.lobby_id = lobby_id ; + item.nick = lobby.nick_name ; + + // chat msg stuff + // + item.chatFlags = RS_CHAT_FLAG_LOBBY | RS_CHAT_FLAG_PRIVATE; + item.sendTime = time(NULL); + item.recvTime = item.sendTime; + item.message = msg; + + for(std::set::const_iterator it(lobby.participating_friends.begin());it!=lobby.participating_friends.end();++it) + if(mLinkMgr->isOnline(*it)) + { + RsChatLobbyMsgItem *sitem = new RsChatLobbyMsgItem(item) ; // copies almost everything + + sitem->PeerId(*it) ; + + sendItem(sitem); + } + + locked_printDebugInfo() ; // debug + return true ; +} + +void p3ChatService::handleConnectionChallenge(RsChatLobbyConnectChallengeItem *item) +{ + // Look into message cache of all lobbys to handle the challenge. + // +#ifdef CHAT_DEBUG + std::cerr << "p3ChatService::handleConnectionChallenge(): received connexion challenge:" << std::endl; + std::cerr << " Challenge code = 0x" << std::hex << item->challenge_code << std::dec << std::endl; + std::cerr << " Peer Id = " << item->PeerId() << std::endl; +#endif + + ChatLobbyId lobby_id ; + bool found = false ; + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + for(std::map::iterator it(_chat_lobbys.begin());it!=_chat_lobbys.end() && !found;++it) + for(std::map::const_iterator it2(it->second.msg_cache.begin());it2!=it->second.msg_cache.end() && !found;++it2) + { + uint64_t code = makeConnexionChallengeCode(it->first,it2->first) ; +#ifdef CHAT_DEBUG + std::cerr << " Lobby_id = 0x" << std::hex << it->first << ", msg_id = 0x" << it2->first << ": code = 0x" << code << std::dec << std::endl ; +#endif + + if(code == item->challenge_code) + { +#ifdef CHAT_DEBUG + std::cerr << " Challenge accepted for lobby " << std::hex << it->first << ", for chat msg " << it2->first << std::dec << std::endl ; + std::cerr << " Sending connection request to peer " << item->PeerId() << std::endl; +#endif + + lobby_id = it->first ; + found = true ; + + // also add the peer to the list of participating friends + it->second.participating_friends.insert(item->PeerId()) ; + } + } + } + + if(found) // send invitation. As the peer already has the lobby, the invitation will most likely be accepted. + invitePeerToLobby(lobby_id, item->PeerId()) ; + else + std::cerr << " Challenge denied: no existing cached msg has matching Id." << std::endl; +} + +void p3ChatService::sendConnectionChallenge(ChatLobbyId lobby_id) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + +#ifdef CHAT_DEBUG + std::cerr << "Sending connection challenge to friends for lobby 0x" << std::hex << lobby_id << std::dec << std::endl ; +#endif + + // look for a msg in cache. Any recent msg is fine. + + std::map::const_iterator it = _chat_lobbys.find(lobby_id) ; + + if(it == _chat_lobbys.end()) + { + std::cerr << "ERROR: sendConnectionChallenge(): could not find lobby 0x" << std::hex << lobby_id << std::dec << std::endl; + return ; + } + + time_t now = time(NULL) ; + uint64_t code = 0 ; + + for(std::map::const_iterator it2(it->second.msg_cache.begin());it2!=it->second.msg_cache.end();++it2) + if(it2->second + 20 > now) // any msg not older than 20 seconds is fine. + { + code = makeConnexionChallengeCode(lobby_id,it2->first) ; +#ifdef CHAT_DEBUG + std::cerr << " Using msg id 0x" << std::hex << it2->first << ", challenge code = " << code << std::dec << std::endl; +#endif + break ; + } + + if(code == 0) + { + std::cerr << " No suitable message found in cache. Weird !!" << std::endl; + return ; + } + + // Broadcast to all direct friends + + std::list ids ; + mLinkMgr->getOnlineList(ids); + + for(std::list::const_iterator it(ids.begin());it!=ids.end();++it) + { + RsChatLobbyConnectChallengeItem *item = new RsChatLobbyConnectChallengeItem ; + + item->PeerId(*it) ; + item->challenge_code = code ; + + sendItem(item); + } +} + +uint64_t p3ChatService::makeConnexionChallengeCode(ChatLobbyId lobby_id,ChatLobbyMsgId msg_id) +{ + return ((uint64_t)lobby_id) ^ (uint64_t)msg_id ; +} + +void p3ChatService::getChatLobbyList(std::list& linfos) +{ + // fill up a dummy list for now. + + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + linfos.clear() ; + + for(std::map::const_iterator it(_chat_lobbys.begin());it!=_chat_lobbys.end();++it) + linfos.push_back(it->second) ; +} +void p3ChatService::invitePeerToLobby(const ChatLobbyId& lobby_id, const std::string& peer_id) +{ +#ifdef CHAT_DEBUG + std::cerr << "Sending invitation to peer " << peer_id << " to lobby "<< std::hex << lobby_id << std::dec << std::endl; +#endif + + RsChatLobbyInviteItem *item = new RsChatLobbyInviteItem ; + + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _chat_lobbys.find(lobby_id) ; + + if(it == _chat_lobbys.end()) + { + std::cerr << " invitation send: canceled. Lobby " << lobby_id << " not found!" << std::endl; + return ; + } + item->lobby_id = lobby_id ; + item->lobby_name = it->second.lobby_name ; + item->PeerId(peer_id) ; + + sendItem(item) ; +} +void p3ChatService::handleRecvLobbyInvite(RsChatLobbyInviteItem *item) +{ +#ifdef CHAT_DEBUG + std::cerr << "Received invite to lobby from " << item->PeerId() << " to lobby " << item->lobby_id << ", named " << item->lobby_name << std::endl; +#endif + + // 1 - store invite in a cache + // + // 1.1 - if the lobby is already setup, add the peer to the communicating peers. + // + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + std::map::iterator it = _chat_lobbys.find(item->lobby_id) ; + + if(it != _chat_lobbys.end()) + { + std::cerr << " Lobby already exists. Addign new friend " << item->PeerId() << " to it" << std::endl; + + it->second.participating_friends.insert(item->PeerId()) ; + return ; + } + // no, then create a new invitation entry in the cache. + + ChatLobbyInvite invite ; + invite.lobby_id = item->lobby_id ; + invite.peer_id = item->PeerId() ; + invite.lobby_name = item->lobby_name ; + + _lobby_invites_queue[item->lobby_id] = invite ; + } + // 2 - notify the gui to ask the user. + rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_CHAT_LOBBY_INVITATION, NOTIFY_TYPE_ADD); +} + +void p3ChatService::getPendingChatLobbyInvites(std::list& invites) +{ + invites.clear() ; + + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + for(std::map::const_iterator it(_lobby_invites_queue.begin());it!=_lobby_invites_queue.end();++it) + invites.push_back(it->second) ; +} + +bool p3ChatService::acceptLobbyInvite(const ChatLobbyId& lobby_id) +{ + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + +#ifdef CHAT_DEBUG + std::cerr << "Accepting chat lobby "<< lobby_id << std::endl; +#endif + + std::map::iterator it = _lobby_invites_queue.find(lobby_id) ; + + if(it == _lobby_invites_queue.end()) + { + std::cerr << " (EE) lobby invite not in cache!!" << std::endl; + return false; + } + + if(_chat_lobbys.find(lobby_id) != _chat_lobbys.end()) + { + std::cerr << " (II) Lobby already exists. Weird." << std::endl; + return true ; + } + +#ifdef CHAT_DEBUG + std::cerr << " Creating new Lobby entry." << std::endl; +#endif + + ChatLobbyEntry entry ; + entry.participating_friends.insert(it->second.peer_id) ; + entry.nick_name = _default_nick_name ; // to be changed. For debug only!! + entry.lobby_id = lobby_id ; + entry.lobby_name = it->second.lobby_name ; + entry.virtual_peer_id = makeVirtualPeerId(lobby_id) ; + entry.connexion_challenge_count = 0 ; + + _lobby_ids[entry.virtual_peer_id] = lobby_id ; + _chat_lobbys[lobby_id] = entry ; + + _lobby_invites_queue.erase(it) ; // remove the invite from cache. + + // we should also send a message to the lobby to tell we're here. + +#ifdef CHAT_DEBUG + std::cerr << " Pushing new msg item to incoming msgs." << std::endl; +#endif + + RsChatLobbyMsgItem *item = new RsChatLobbyMsgItem; + item->lobby_id = entry.lobby_id ; + item->msg_id = 0 ; + item->nick = "Lobby management" ; + item->message = std::wstring(L"Welcome to chat lobby") ; + item->PeerId(entry.virtual_peer_id) ; + item->chatFlags = RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_LOBBY ; + + privateIncomingList.push_back(item) ; + } +#ifdef CHAT_DEBUG + std::cerr << " Notifying of new recvd msg." << std::endl ; +#endif + + rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); + + // send AKN item + std::wstring wmsg(_default_nick_name.length(), L' '); // Make room for characters + // Copy string to wstring. + std::copy(_default_nick_name.begin(), _default_nick_name.end(), wmsg.begin()); + + sendLobbyChat(wmsg + L" joined the lobby",lobby_id) ; + return true ; +} + +std::string p3ChatService::makeVirtualPeerId(ChatLobbyId lobby_id) +{ + std::ostringstream os ; + os << "Chat Lobby 0x" << std::hex << lobby_id << std::dec ; + + return os.str() ; +} + + +void p3ChatService::denyLobbyInvite(const ChatLobbyId& lobby_id) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + +#ifdef CHAT_DEBUG + std::cerr << "Denying chat lobby invite to "<< lobby_id << std::endl; +#endif + std::map::iterator it = _lobby_invites_queue.find(lobby_id) ; + + if(it == _lobby_invites_queue.end()) + { + std::cerr << " (EE) lobby invite not in cache!!" << std::endl; + return ; + } + + _lobby_invites_queue.erase(it) ; +} + +ChatLobbyId p3ChatService::createChatLobby(const std::string& lobby_name,const std::list& invited_friends) +{ +#ifdef CHAT_DEBUG + std::cerr << "Creating a new Chat lobby !!" << std::endl; +#endif + ChatLobbyId lobby_id ; + { + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + // create a unique id. + // + do { lobby_id = RSRandom::random_u64() ; } while(_chat_lobbys.find(lobby_id) != _chat_lobbys.end()) ; + +#ifdef CHAT_DEBUG + std::cerr << " New (unique) ID: " << std::hex << lobby_id << std::dec << std::endl; +#endif + + ChatLobbyEntry entry ; + entry.participating_friends.clear() ; + entry.nick_name = _default_nick_name ; // to be changed. For debug only!! + entry.lobby_id = lobby_id ; + entry.lobby_name = lobby_name ; + entry.virtual_peer_id = makeVirtualPeerId(lobby_id) ; + entry.connexion_challenge_count = 0 ; + + _lobby_ids[entry.virtual_peer_id] = lobby_id ; + _chat_lobbys[lobby_id] = entry ; + } + + for(std::list::const_iterator it(invited_friends.begin());it!=invited_friends.end();++it) + invitePeerToLobby(lobby_id,*it) ; + + return lobby_id ; +} + +void p3ChatService::handleFriendUnsubscribeLobby(RsChatLobbyUnsubscribeItem *item) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + std::map::iterator it = _chat_lobbys.find(item->lobby_id) ; + +#ifdef CHAT_DEBUG + std::cerr << "Received unsubscribed to lobby " << item->lobby_id << ", from friend " << item->PeerId() << std::endl; +#endif + + if(it == _chat_lobbys.end()) + { + std::cerr << "Chat lobby " << item->lobby_id << " does not exist ! Can't unsubscribe!" << std::endl; + return ; + } + + for(std::set::iterator it2(it->second.participating_friends.begin());it2!=it->second.participating_friends.end();++it2) + if(*it2 == item->PeerId()) + { +#ifdef CHAT_DEBUG + std::cerr << " removing peer id " << item->PeerId() << " from participant list of lobby " << item->lobby_id << std::endl; +#endif + it->second.participating_friends.erase(it2) ; + break ; + } +} + +void p3ChatService::unsubscribeChatLobby(const ChatLobbyId& id) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator it = _chat_lobbys.find(id) ; + + if(it == _chat_lobbys.end()) + { + std::cerr << "Chat lobby " << id << " does not exist ! Can't unsubscribe!" << std::endl; + return ; + } + // send a lobby leaving packet to all friends + + for(std::set::const_iterator it2(it->second.participating_friends.begin());it2!=it->second.participating_friends.end();++it2) + { + RsChatLobbyUnsubscribeItem *item = new RsChatLobbyUnsubscribeItem ; + + item->lobby_id = id ; + item->PeerId(*it2) ; + + sendItem(item) ; + } + + // remove lobby information + + _chat_lobbys.erase(it) ; + + for(std::map::iterator it2(_lobby_ids.begin());it2!=_lobby_ids.end();++it2) + if(it2->second == id) + { + _lobby_ids.erase(it2) ; + break ; + } + + // done! +} +bool p3ChatService::setDefaultNickNameForChatLobby(const std::string& nick) +{ + _default_nick_name = nick; + IndicateConfigChanged() ; + return true ; +} +bool p3ChatService::getDefaultNickNameForChatLobby(std::string& nick) +{ + nick = _default_nick_name ; + return true ; +} +bool p3ChatService::getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + +#ifdef CHAT_DEBUG + std::cerr << "getting nickname for chat lobby "<< std::hex << lobby_id << std::dec << std::endl; +#endif + std::map::iterator it = _chat_lobbys.find(lobby_id) ; + + if(it == _chat_lobbys.end()) + { + std::cerr << " (EE) lobby does not exist!!" << std::endl; + return false ; + } + + nick = it->second.nick_name ; + return true ; +} + +bool p3ChatService::setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick) +{ + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + +#ifdef CHAT_DEBUG + std::cerr << "Changing nickname for chat lobby " << std::hex << lobby_id << std::dec << " to " << nick << std::endl; +#endif + std::map::iterator it = _chat_lobbys.find(lobby_id) ; + + if(it == _chat_lobbys.end()) + { + std::cerr << " (EE) lobby does not exist!!" << std::endl; + return false; + } + + it->second.nick_name = nick ; + return true ; +} + +void p3ChatService::cleanLobbyCaches() +{ +#ifdef CHAT_DEBUG + std::cerr << "Cleaning chat lobby caches." << std::endl; +#endif + + RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ + + time_t now = time(NULL) ; + + for(std::map::iterator it = _chat_lobbys.begin();it!=_chat_lobbys.end();++it) + for(std::map::iterator it2(it->second.msg_cache.begin());it2!=it->second.msg_cache.end();) + if(it2->second + MAX_KEEP_MSG_RECORD < now) + { +#ifdef CHAT_DEBUG + std::cerr << " removing old msg 0x" << std::hex << it2->first << ", time=" << std::dec << it2->second << std::endl; +#endif + + std::map::iterator tmp(it2) ; + ++tmp ; + it->second.msg_cache.erase(it2) ; + it2 = tmp ; + } + else + ++it2 ; +} + + diff --git a/libretroshare/src/services/p3chatservice.h b/libretroshare/src/services/p3chatservice.h index 619e67578..b99d9c1e9 100644 --- a/libretroshare/src/services/p3chatservice.h +++ b/libretroshare/src/services/p3chatservice.h @@ -153,6 +153,20 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor */ bool clearPrivateChatQueue(bool incoming, const std::string &id); + bool getVirtualPeerId(const ChatLobbyId&, std::string& virtual_peer_id) ; + bool isLobbyId(const std::string&, ChatLobbyId&) ; + void getChatLobbyList(std::list >&) ; + bool acceptLobbyInvite(const ChatLobbyId& id) ; + void denyLobbyInvite(const ChatLobbyId& id) ; + void getPendingChatLobbyInvites(std::list& invites) ; + void invitePeerToLobby(const ChatLobbyId&, const std::string&) ; + void unsubscribeChatLobby(const ChatLobbyId& lobby_id) ; + bool setNickNameForChatLobby(const ChatLobbyId& lobby_id,const std::string& nick) ; + bool getNickNameForChatLobby(const ChatLobbyId& lobby_id,std::string& nick) ; + bool setDefaultNickNameForChatLobby(const std::string& nick) ; + bool getDefaultNickNameForChatLobby(std::string& nick) ; + ChatLobbyId createChatLobby(const std::string& lobby_name,const std::list& invited_friends) ; + protected: /************* from p3Config *******************/ virtual RsSerialiser *setupSerialiser() ; @@ -198,6 +212,20 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor /// Called when a RsChatMsgItem is received. The item may be collapsed with any waiting partial chat item from the same peer. bool checkAndRebuildPartialMessage(RsChatMsgItem*) ; + /// receive and handle chat lobby item + bool recvLobbyChat(RsChatLobbyMsgItem*) ; + bool sendLobbyChat(const std::wstring&, const ChatLobbyId&) ; + void handleRecvLobbyInvite(RsChatLobbyInviteItem*) ; + void checkAndRedirectMsgToLobby(RsChatMsgItem*) ; + void handleConnectionChallenge(RsChatLobbyConnectChallengeItem *item) ; + void sendConnectionChallenge(ChatLobbyId id) ; + void handleFriendUnsubscribeLobby(RsChatLobbyUnsubscribeItem*) ; + void cleanLobbyCaches() ; + + static std::string makeVirtualPeerId(ChatLobbyId) ; + static uint64_t makeConnexionChallengeCode(ChatLobbyId lobby_id,ChatLobbyMsgId msg_id) ; + + void locked_printDebugInfo() const ; RsChatAvatarItem *makeOwnAvatarItem() ; RsChatStatusItem *makeOwnCustomStateStringItem() ; @@ -214,6 +242,20 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor std::string _custom_status_string ; std::map _state_strings ; + + class ChatLobbyEntry: public ChatLobbyInfo + { + public: + std::map msg_cache ; + std::string virtual_peer_id ; + int connexion_challenge_count ; + }; + + std::map _chat_lobbys ; + std::map _lobby_invites_queue ; + std::map _lobby_ids ; + std::string _default_nick_name ; + time_t last_lobby_challenge_time ; // prevents bruteforce attack }; class p3ChatService::StateStringInfo diff --git a/libretroshare/src/tests/serialiser/rsmsgitem_test.cc b/libretroshare/src/tests/serialiser/rsmsgitem_test.cc index 6d60d25ee..8497cdbf7 100644 --- a/libretroshare/src/tests/serialiser/rsmsgitem_test.cc +++ b/libretroshare/src/tests/serialiser/rsmsgitem_test.cc @@ -25,6 +25,7 @@ #include +#include "util/rsrandom.h" #include "serialiser/rsmsgitems.h" #include "serialiser/rstlvutil.h" #include "util/utest.h" @@ -41,6 +42,24 @@ RsSerialType* init_item(RsChatMsgItem& cmi) return new RsChatSerialiser(); } +RsSerialType* init_item(RsChatLobbyMsgItem& cmi) +{ + RsSerialType *serial = init_item( *dynamic_cast(&cmi)) ; + + cmi.msg_id = RSRandom::random_u64() ; + cmi.lobby_id = RSRandom::random_u64() ; + cmi.nick = "My nickname" ; + + return serial ; +} + +RsSerialType* init_item(RsChatLobbyInviteItem& cmi) +{ + cmi.lobby_id = RSRandom::random_u64() ; + cmi.lobby_name = "Name of the lobby" ; + + return new RsChatSerialiser(); +} RsSerialType* init_item(RsPrivateChatMsgConfigItem& pcmi) { @@ -162,8 +181,25 @@ bool operator ==(const RsChatStatusItem& csiLeft, const RsChatStatusItem& csiRig return true; } +bool operator ==(const RsChatLobbyMsgItem& csiLeft, const RsChatLobbyMsgItem& csiRight) +{ + if(! ( (RsChatMsgItem&)csiLeft == (RsChatMsgItem&)csiRight)) + return false ; + if(csiLeft.lobby_id != csiRight.lobby_id) return false ; + if(csiLeft.msg_id != csiRight.msg_id) return false ; + if(csiLeft.nick != csiRight.nick) return false ; + return true; +} + +bool operator ==(const RsChatLobbyInviteItem& csiLeft, const RsChatLobbyInviteItem& csiRight) +{ + if(csiLeft.lobby_id != csiRight.lobby_id) return false ; + if(csiLeft.lobby_name != csiRight.lobby_name) return false ; + + return true; +} bool operator ==(const RsChatAvatarItem& caiLeft, const RsChatAvatarItem& caiRight) { @@ -241,7 +277,8 @@ bool operator ==(const RsMsgParentId& msLeft, const RsMsgParentId& msRight) int main() { test_RsItem(); REPORT("Serialise/Deserialise RsChatMsgItem"); - test_RsItem(); REPORT("Serialise/Deserialise RsPrivateChatMsgConfigItem"); + test_RsItem(); REPORT("Serialise/Deserialise RsChatLobbyMsgItem"); + test_RsItem(); REPORT("Serialise/Deserialise RsChatLobbyInviteItem"); test_RsItem(); REPORT("Serialise/Deserialise RsChatStatusItem"); test_RsItem(); REPORT("Serialise/Deserialise RsChatAvatarItem"); test_RsItem(); REPORT("Serialise/Deserialise RsMsgItem"); diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index 946f58e9f..c21cd5e94 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -270,6 +270,8 @@ HEADERS += rshare.h \ gui/profile/StatusMessage.h \ gui/chat/PopupChatWindow.h \ gui/chat/PopupChatDialog.h \ + gui/chat/ChatLobbyDialog.h \ + gui/chat/CreateLobbyDialog.h \ gui/chat/HandleRichText.h \ gui/chat/ChatStyle.h \ gui/channels/CreateChannel.h \ @@ -407,6 +409,7 @@ FORMS += gui/StartDialog.ui \ gui/channels/ShareKey.ui \ gui/chat/PopupChatWindow.ui \ gui/chat/PopupChatDialog.ui \ + gui/chat/CreateLobbyDialog.ui \ gui/connect/ConfCertDialog.ui \ gui/msgs/MessageComposer.ui \ gui/msgs/MessageWindow.ui\ @@ -530,6 +533,8 @@ SOURCES += main.cpp \ gui/channels/ShareKey.cpp \ gui/chat/PopupChatWindow.cpp \ gui/chat/PopupChatDialog.cpp \ + gui/chat/ChatLobbyDialog.cpp \ + gui/chat/CreateLobbyDialog.cpp \ gui/chat/HandleRichText.cpp \ gui/chat/ChatStyle.cpp \ gui/connect/ConfCertDialog.cpp \ diff --git a/retroshare-gui/src/gui/FriendsDialog.cpp b/retroshare-gui/src/gui/FriendsDialog.cpp index c0d3e4f4e..37f120f02 100644 --- a/retroshare-gui/src/gui/FriendsDialog.cpp +++ b/retroshare-gui/src/gui/FriendsDialog.cpp @@ -311,6 +311,28 @@ void FriendsDialog::updateStatusString(const QString& peer_id, const QString& st QTimer::singleShot(5000,this,SLOT(resetStatusBar())) ; } +void FriendsDialog::readChatLobbyInvites() +{ + std::list invites ; + rsMsgs->getPendingChatLobbyInvites(invites) ; + + for(std::list::const_iterator it(invites.begin());it!=invites.end();++it) + if(QMessageBox::Ok == QMessageBox::question(NULL,tr("Invitation to chat lobby"),QString::fromStdString((*it).peer_id)+QString(" invites you to chat lobby named ")+QString::fromUtf8((*it).lobby_name.c_str()),QMessageBox::Ok,QMessageBox::Ignore)) + { + std::cerr << "Accepting invite to lobby " << (*it).lobby_name << std::endl; + + rsMsgs->acceptLobbyInvite( (*it).lobby_id ) ; + + std::string vpid ; + if(rsMsgs->getVirtualPeerId( (*it).lobby_id,vpid ) ) + PopupChatDialog::chatFriend(vpid) ; + else + std::cerr << "No lobby known with id 0x" << std::hex << (*it).lobby_id << std::dec << std::endl; + } + else + rsMsgs->denyLobbyInvite( (*it).lobby_id ) ; +} + void FriendsDialog::updatePeerStatusString(const QString& peer_id,const QString& status_string,bool is_private_chat) { if(is_private_chat) diff --git a/retroshare-gui/src/gui/FriendsDialog.h b/retroshare-gui/src/gui/FriendsDialog.h index d6717a13f..700eaddd5 100644 --- a/retroshare-gui/src/gui/FriendsDialog.h +++ b/retroshare-gui/src/gui/FriendsDialog.h @@ -57,6 +57,7 @@ public slots: void insertChat(); void setChatInfo(QString info, QColor color=QApplication::palette().color(QPalette::WindowText)); void resetStatusBar() ; + void readChatLobbyInvites() ; void fileHashingFinished(QList hashedFiles); diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp new file mode 100644 index 000000000..8fda5a57b --- /dev/null +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -0,0 +1,79 @@ +/**************************************************************** + * + * RetroShare is distributed under the following license: + * + * Copyright (C) 2011, csoler + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util/misc.h" +#include "rshare.h" + +#include +#include +#include + +#include +#include + +#include "ChatLobbyDialog.h" + +/** Default constructor */ +ChatLobbyDialog::ChatLobbyDialog(const std::string& dialog_id,const ChatLobbyId& lid, const QString &name, QWidget *parent, Qt::WFlags flags) + : PopupChatDialog(dialog_id,name,parent,flags),lobby_id(lid) +{ + // remove the avatar widget. Replace it with a friends list. + + ui.avatarWidget->hide() ; + PopupChatDialog::updateStatus(QString::fromStdString(getPeerId()),RS_STATUS_ONLINE) ; + + QObject::connect(this,SIGNAL(close()),this,SLOT(closeAndAsk())) ; +} + +/** Destructor. */ +ChatLobbyDialog::~ChatLobbyDialog() +{ + // announce leaving of lobby + + if(QMessageBox::Yes == QMessageBox::question(NULL,tr("Unsubscribe to lobby?"),tr("Do you want to unsubscribe to this chat lobby?"),QMessageBox::Yes | QMessageBox::No)) + rsMsgs->unsubscribeChatLobby(lobby_id) ; +} + +void ChatLobbyDialog::setNickName(const QString& nick) +{ + rsMsgs->setNickNameForChatLobby(lobby_id,nick.toStdString()) ; +} + +void ChatLobbyDialog::updateStatus(const QString &peer_id, int status) +{ + // For now. We need something more efficient to tell when the lobby is disconnected. + // +} + diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h new file mode 100644 index 000000000..65c220360 --- /dev/null +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h @@ -0,0 +1,66 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2006, crypton + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + + +#ifndef _CHATLOBBYDIALOG_H +#define _CHATLOBBYDIALOG_H + +#include "ui_PopupChatDialog.h" + +class QAction; +class QTextEdit; +class QTextCharFormat; +class AttachFileItem; +class ChatInfo; + +#include +#include "ChatStyle.h" +#include "gui/style/RSStyle.h" +#include "PopupChatDialog.h" + +class ChatLobbyDialog: public PopupChatDialog +{ + Q_OBJECT + + protected: + /** Default constructor */ + ChatLobbyDialog(const std::string& id,const ChatLobbyId& lid, const QString &name, QWidget *parent = 0, Qt::WFlags flags = 0); + + /** Default destructor */ + virtual ~ChatLobbyDialog(); + +// virtual void addChatMsg(bool incoming, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &message, enumChatType chatType); +// virtual void sendChat(); + + friend class PopupChatDialog ; + + // The following methods are differentfrom those of the parent: + // + virtual void updateStatus(const QString &peer_id, int status) ; // needs grouped status. Not yet implemented. + + protected slots: + void setNickName(const QString&) ; + + private: + ChatLobbyId lobby_id ; +}; + +#endif diff --git a/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp b/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp new file mode 100644 index 000000000..546a96fae --- /dev/null +++ b/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp @@ -0,0 +1,204 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2010 Christopher Evi-Parker + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#include "CreateLobbyDialog.h" + +#include +#include + +#include +#include + +#include "gui/common/PeerDefs.h" +#include "gui/chat/PopupChatDialog.h" + +CreateLobbyDialog::CreateLobbyDialog(const std::list& peer_list,QWidget *parent, Qt::WFlags flags, std::string grpId, int grpType) : + QDialog(parent, flags), mGrpId(grpId), mGrpType(grpType) +{ + ui = new Ui::CreateLobbyDialog() ; + ui->setupUi(this); + + std::string default_nick ; + rsMsgs->getDefaultNickNameForChatLobby(default_nick) ; + + ui->lobbyName_LE->setPlaceholderText(tr("Put a sensible lobby name here")) ; + ui->nickName_LE->setPlaceholderText(tr("Your nickname for this lobby (Change default name in options->chat)")) ; + ui->nickName_LE->setText(QString::fromStdString(default_nick)) ; + + connect( ui->shareButton, SIGNAL( clicked ( bool ) ), this, SLOT( createLobby( ) ) ); + connect( ui->cancelButton, SIGNAL( clicked ( bool ) ), this, SLOT( cancel( ) ) ); + connect( ui->lobbyName_LE, SIGNAL( textChanged ( QString ) ), this, SLOT( checkTextFields( ) ) ); + connect( ui->nickName_LE, SIGNAL( textChanged ( QString ) ), this, SLOT( checkTextFields( ) ) ); + + connect(ui->keyShareList, SIGNAL(itemChanged( QTreeWidgetItem *, int ) ), + this, SLOT(togglePersonItem( QTreeWidgetItem *, int ) )); + + setShareList(peer_list); + checkTextFields() ; +} + + +CreateLobbyDialog::~CreateLobbyDialog() +{ + delete ui; +} + +void CreateLobbyDialog::closeEvent (QCloseEvent * event) +{ + QWidget::closeEvent(event); +} + +void CreateLobbyDialog::changeEvent(QEvent *e) +{ + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void CreateLobbyDialog::checkTextFields() +{ + if(ui->lobbyName_LE->text() == "" || ui->nickName_LE->text() == "") + ui->shareButton->setEnabled(false) ; + else + ui->shareButton->setEnabled(true) ; +} +void CreateLobbyDialog::createLobby() +{ + if(mShareList.empty()) + { + QMessageBox::warning(this, tr("RetroShare"),tr("Please select at least one peer"), + QMessageBox::Ok, QMessageBox::Ok); + + return; + } + + // create chat lobby !! + std::string lobby_name = ui->lobbyName_LE->text().toStdString() ; + + // add to group + ChatLobbyId id = rsMsgs->createChatLobby(lobby_name, mShareList); + + std::cerr << "gui: Created chat lobby " << std::hex << id << std::endl ; + + // set nick name ! + + rsMsgs->setNickNameForChatLobby(id,ui->nickName_LE->text().toStdString()) ; + + // open chat window !! + std::string vpid ; + + if(rsMsgs->getVirtualPeerId(id,vpid)) + PopupChatDialog::chatFriend(vpid) ; + + close(); +} + +void CreateLobbyDialog::cancel() +{ + close(); +} + +void CreateLobbyDialog::setShareList(const std::list& friend_list) +{ + if (!rsPeers) + { + /* not ready yet! */ + return; + } + + std::list peers; + std::list::iterator it; + + mShareList.clear() ; + rsPeers->getFriendList(peers); + + /* get a link to the table */ + QTreeWidget *shareWidget = ui->keyShareList; + + QList items; + + for(it = peers.begin(); it != peers.end(); it++) + { + RsPeerDetails detail; + if (!rsPeers->getPeerDetails(*it, detail)) + { + continue; /* BAD */ + } + + /* make a widget per friend */ + QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)0); + + item -> setText(0, PeerDefs::nameWithLocation(detail)); + if (detail.state & RS_PEER_STATE_CONNECTED) { + item -> setTextColor(0,(Qt::darkBlue)); + } + item -> setSizeHint(0, QSize( 17,17 ) ); + item -> setText(1, QString::fromStdString(detail.id)); + item -> setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + + item -> setCheckState(0, Qt::Unchecked); + + for(std::list::const_iterator it2(friend_list.begin());it2!=friend_list.end();++it2) + if(*it == *it2) + { + item -> setCheckState(0, Qt::Checked); + mShareList.push_back(*it) ; + break ; + } + + /* add to the list */ + items.append(item); + } + + /* remove old items */ + shareWidget->clear(); + shareWidget->setColumnCount(1); + + /* add the items in! */ + shareWidget->insertTopLevelItems(0, items); + + shareWidget->update(); /* update display */ +} + +void CreateLobbyDialog::togglePersonItem( QTreeWidgetItem *item, int /*col*/ ) +{ + /* extract id */ + std::string id = (item -> text(1)).toStdString(); + + /* get state */ + bool checked = (Qt::Checked == item -> checkState(0)); /* alway column 0 */ + + /* call control fns */ + std::list::iterator lit = std::find(mShareList.begin(), mShareList.end(), id); + + if(checked && (lit == mShareList.end())) + mShareList.push_back(id); // make sure ids not added already + else if(lit != mShareList.end()) + mShareList.erase(lit); + + return; +} + diff --git a/retroshare-gui/src/gui/chat/CreateLobbyDialog.h b/retroshare-gui/src/gui/chat/CreateLobbyDialog.h new file mode 100644 index 000000000..f2ffaf948 --- /dev/null +++ b/retroshare-gui/src/gui/chat/CreateLobbyDialog.h @@ -0,0 +1,41 @@ +#ifndef SHAREKEY_H +#define SHAREKEY_H + +#include + +#include "ui_CreateLobbyDialog.h" + +class CreateLobbyDialog : public QDialog { + Q_OBJECT +public: + /* + *@param chanId The channel id to send request for + */ + CreateLobbyDialog(const std::list& friends_list,QWidget *parent = 0, Qt::WFlags flags = 0, std::string grpId = "", int grpType = 0); + ~CreateLobbyDialog(); + +protected: + void changeEvent(QEvent *e); + void closeEvent (QCloseEvent * event); + +private: + + void setShareList(const std::list&); + + Ui::CreateLobbyDialog *ui; + + std::string mGrpId; + std::list mShareList; + int mGrpType; + +private slots: + + void createLobby(); + void checkTextFields(); + void cancel(); + void togglePersonItem(QTreeWidgetItem* item, int col); + + +}; + +#endif // SHAREKEY_H diff --git a/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui b/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui new file mode 100644 index 000000000..accb62a4a --- /dev/null +++ b/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui @@ -0,0 +1,300 @@ + + + CreateLobbyDialog + + + + 0 + 0 + 586 + 532 + + + + Create Chat Lobby + + + + 0 + + + 0 + + + + + + + + 239 + 49 + + + + QFrame#frame{background-image: url(:/images/connect/connectFriendBanner.png); +} + + + QFrame::NoFrame + + + QFrame::Raised + + + + 6 + + + + + + 64 + 64 + + + + + + + :/images/user/agt_forum64.png + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:600; color:#ffffff;">Create Chat Lobby</span></p></body></html> + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A chat lobby is a decentralized and anonymous chat group. All participants receive all messages. Once the lobby is created you can invite other friends from the Friends tab.</p></body></html> + + + + + + + + + + + Lobby name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Your nick name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Select the Friends with which you want to group chat.</span></p></body></html> + + + + + + + true + + + + 0 + 0 + + + + + 52487 + 524287 + + + + + 220 + 0 + + + + + 0 + 0 + + + + check peers you would like to share private publish key with + + + false + + + QDockWidget::NoDockWidgetFeatures + + + Invited friends + + + + + 0 + + + 0 + + + + + + 0 + 4 + + + + + 20 + 0 + + + + + 1677215 + 16777215 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16 + 16 + + + + true + + + + Contacts: + + + + + + + + + + + + QLayout::SetDefaultConstraint + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Create + + + + + + + Cancel + + + + + + + + + + + + + + + + + diff --git a/retroshare-gui/src/gui/chat/PopupChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupChatDialog.cpp index f8ed9c1c7..1025571a0 100644 --- a/retroshare-gui/src/gui/chat/PopupChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupChatDialog.cpp @@ -33,6 +33,7 @@ #include #include "PopupChatDialog.h" +#include "ChatLobbyDialog.h" #include "PopupChatWindow.h" #include "gui/RetroShareLink.h" #include "util/misc.h" @@ -125,7 +126,7 @@ PopupChatDialog::PopupChatDialog(const std::string &id, const QString &name, QWi connect(ui.hashBox, SIGNAL(fileHashingFinished(QList)), this, SLOT(fileHashingFinished(QList))); - connect(NotifyQt::getInstance(), SIGNAL(peerStatusChanged(const QString&, int)), this, SLOT(updateStatus(const QString&, int))); + connect(NotifyQt::getInstance(), SIGNAL(peerStatusChanged(const QString&, int)), this, SLOT(updateStatus_slot(const QString&, int))); connect(NotifyQt::getInstance(), SIGNAL(peerHasNewCustomStateString(const QString&, const QString&)), this, SLOT(updatePeersCustomStateString(const QString&, const QString&))); connect(ui.chattextEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint))); @@ -261,16 +262,35 @@ void PopupChatDialog::processSettings(bool bLoad) { /* see if it exists already */ PopupChatDialog *popupchatdialog = getExistingInstance(id); + if (popupchatdialog == NULL) { if (chatflags & RS_CHAT_OPEN) { RsPeerDetails sslDetails; - if (rsPeers->getPeerDetails(id, sslDetails)) { + ChatLobbyId lobby_id ; + + if (rsPeers->getPeerDetails(id, sslDetails)) + { popupchatdialog = new PopupChatDialog(id, PeerDefs::nameWithLocation(sslDetails)); chatDialogs[id] = popupchatdialog; PopupChatWindow *window = PopupChatWindow::getWindow(false); window->addDialog(popupchatdialog); } + else if (rsMsgs->isLobbyId(id, lobby_id)) + { + std::list linfos; + rsMsgs->getChatLobbyList(linfos) ; + + for(std::list::const_iterator it(linfos.begin());it!=linfos.end();++it) + if( (*it).lobby_id == lobby_id) + { + popupchatdialog = new ChatLobbyDialog(id,lobby_id,QString::fromStdString((*it).lobby_name)); + chatDialogs[id] = popupchatdialog; + + PopupChatWindow *window = PopupChatWindow::getWindow(false); + window->addDialog(popupchatdialog); + } + } } } @@ -337,6 +357,14 @@ void PopupChatDialog::processSettings(bool bLoad) } } +void PopupChatDialog::closeChat(const std::string& id) +{ + PopupChatDialog *popupchatdialog = getExistingInstance(id); + + if(popupchatdialog != NULL) + popupchatdialog->hide() ; +} + void PopupChatDialog::chatFriend(const std::string &id) { if (id.empty()){ @@ -344,10 +372,16 @@ void PopupChatDialog::chatFriend(const std::string &id) } std::cerr<<" popup dialog chat friend 1"<isLobbyId(id,lid)) + { + getPrivateChat(id, RS_CHAT_OPEN | RS_CHAT_FOCUS); + return ; + } + RsPeerDetails detail; - if (!rsPeers->getPeerDetails(id, detail)) { + if (!rsPeers->getPeerDetails(id, detail)) return; - } std::string firstId; @@ -682,7 +716,8 @@ void PopupChatDialog::sendChat() std::cout << "PopupChatDialog:sendChat " << std::endl; #endif - if (rsMsgs->sendPrivateChat(dialogId, msg)) { + if (sendPrivateChat(msg)) + { QDateTime currentTime = QDateTime::currentDateTime(); addChatMsg(false, QString::fromUtf8(rsPeers->getPeerName(ownId).c_str()), currentTime, currentTime, QString::fromStdWString(msg), TYPE_NORMAL); } @@ -695,6 +730,11 @@ void PopupChatDialog::sendChat() setFont(); } +bool PopupChatDialog::sendPrivateChat(const std::wstring& msg) +{ + return rsMsgs->sendPrivateChat(dialogId, msg) ; +} + /** Toggles the ToolBox on and off, changes toggle button text */ @@ -905,6 +945,11 @@ void PopupChatDialog::clearOfflineMessages() manualDelete = false; } +void PopupChatDialog::updateStatus_slot(const QString &peer_id, int status) +{ + updateStatus(peer_id,status) ; +} + void PopupChatDialog::updateStatus(const QString &peer_id, int status) { std::string stdPeerId = peer_id.toStdString(); diff --git a/retroshare-gui/src/gui/chat/PopupChatDialog.h b/retroshare-gui/src/gui/chat/PopupChatDialog.h index 437929045..f47c02605 100644 --- a/retroshare-gui/src/gui/chat/PopupChatDialog.h +++ b/retroshare-gui/src/gui/chat/PopupChatDialog.h @@ -46,6 +46,7 @@ public: static PopupChatDialog *getPrivateChat(const std::string &id, uint chatflags); static void cleanupChat(); static void chatFriend(const std::string &id); + static void closeChat(const std::string &id); static void privateChatChanged(int list, int type); void updateStatusString(const QString& peer_id, const QString& statusString); @@ -58,9 +59,10 @@ public: void activate(); bool setStyle(); const RSStyle &getStyle(); + virtual void updateStatus(const QString &peer_id, int status); public slots: - void updateStatus(const QString &peer_id, int status); + void updateStatus_slot(const QString &peer_id, int status); protected: /** Default constructor */ @@ -142,6 +144,9 @@ private: RSStyle style; +protected: + virtual bool sendPrivateChat(const std::wstring& msg) ; // can be derived to send chat to e.g. a chat lobby + /** Qt Designer generated object */ Ui::PopupChatDialog ui; }; diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index 81c0b380d..028e24108 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -31,6 +31,7 @@ #include "GroupDefs.h" #include "gui/chat/PopupChatDialog.h" +#include "gui/chat/CreateLobbyDialog.h" #include "gui/common/AvatarDefs.h" #include "gui/connect/ConfCertDialog.h" #include "gui/connect/ConnectFriendWizard.h" @@ -292,143 +293,177 @@ void FriendList::peerTreeWidgetCostumPopupMenu() contextMnu.addAction(widgetAction); // create menu entries - if (c) { // if a peer is selected - int type = c->type(); + if (c) + { // if a peer is selected + int type = c->type(); - // define header - switch (type) { - case TYPE_GROUP: - //this is a GPG key - textLabel->setText("" + tr("Group") + ""); - break; - case TYPE_GPG: - //this is a GPG key - textLabel->setText("" + tr("Friend") + ""); - break; - case TYPE_SSL: - //this is a SSL key - textLabel->setText("" + tr("Location") + ""); - break; - } + // define header + switch (type) { + case TYPE_GROUP: + //this is a GPG key + textLabel->setText("" + tr("Group") + ""); + break; + case TYPE_GPG: + //this is a GPG key + textLabel->setText("" + tr("Friend") + ""); + break; + case TYPE_SSL: + //this is a SSL key + textLabel->setText("" + tr("Location") + ""); + break; + } - switch (type) { - case TYPE_GROUP: - { - bool standard = c->data(COLUMN_DATA, ROLE_STANDARD).toBool(); + switch (type) { + case TYPE_GROUP: + { + bool standard = c->data(COLUMN_DATA, ROLE_STANDARD).toBool(); - contextMnu.addAction(QIcon(IMAGE_MSG), tr("Message Group"), this, SLOT(msgfriend())); - contextMnu.addAction(QIcon(IMAGE_ADDFRIEND), tr("Add Friend"), this, SLOT(addFriend())); + contextMnu.addAction(QIcon(IMAGE_MSG), tr("Message Group"), this, SLOT(msgfriend())); + contextMnu.addAction(QIcon(IMAGE_ADDFRIEND), tr("Add Friend"), this, SLOT(addFriend())); - contextMnu.addSeparator(); + contextMnu.addSeparator(); - QAction *action = contextMnu.addAction(QIcon(IMAGE_EDIT), tr("Edit Group"), this, SLOT(editGroup())); - action->setDisabled(standard); + QAction *action = contextMnu.addAction(QIcon(IMAGE_EDIT), tr("Edit Group"), this, SLOT(editGroup())); + action->setDisabled(standard); - action = contextMnu.addAction(QIcon(IMAGE_REMOVE), tr("Remove Group"), this, SLOT(removeGroup())); - action->setDisabled(standard); - } - break; - case TYPE_GPG: - case TYPE_SSL: - { - contextMnu.addAction(QIcon(IMAGE_CHAT), tr("Chat"), this, SLOT(chatfriendproxy())); - contextMnu.addAction(QIcon(IMAGE_MSG), tr("Message Friend"), this, SLOT(msgfriend())); + action = contextMnu.addAction(QIcon(IMAGE_REMOVE), tr("Remove Group"), this, SLOT(removeGroup())); + action->setDisabled(standard); - contextMnu.addSeparator(); + contextMnu.addAction(QIcon(IMAGE_CHAT), tr("Create chat lobby"), this, SLOT(createchatlobby())); + } + break; + case TYPE_GPG: + case TYPE_SSL: + { + contextMnu.addAction(QIcon(IMAGE_CHAT), tr("Chat"), this, SLOT(chatfriendproxy())); + QMenu *mnu = contextMnu.addMenu(QIcon(IMAGE_CHAT), tr("Chat lobbies")) ; - contextMnu.addAction(QIcon(IMAGE_FRIENDINFO), tr("Friend Details"), this, SLOT(configurefriend())); -// contextMnu.addAction(QIcon(IMAGE_PEERINFO), tr("Profile View"), this, SLOT(viewprofile())); -// action = contextMnu.addAction(QIcon(IMAGE_EXPORTFRIEND), tr("Export Friend"), this, SLOT(exportfriend())); + mnu->addAction(QIcon(IMAGE_ADDFRIEND),tr("create new"),this,SLOT(createchatlobby())) ; - if (type == TYPE_GPG) { - contextMnu.addAction(QIcon(IMAGE_EXPORTFRIEND), tr("Recommend this Friend to..."), this, SLOT(recommendfriend())); - } + // Get existing lobbies + // + std::list cl_infos ; + rsMsgs->getChatLobbyList(cl_infos) ; - contextMnu.addAction(QIcon(IMAGE_CONNECT), tr("Connect To Friend"), this, SLOT(connectfriend())); + for(std::list::const_iterator it(cl_infos.begin());it!=cl_infos.end();++it) + { + std::cerr << "Adding meny entry with lobby id " << std::hex << (*it).lobby_id << std::dec << std::endl; - if (type == TYPE_GPG) { - contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyLink())); - } + QMenu *mnu2 = mnu->addMenu(QIcon(IMAGE_CHAT), QString::fromUtf8((*it).lobby_name.c_str())) ; - QAction *action = contextMnu.addAction(QIcon(IMAGE_PASTELINK), tr("Paste Friend Link"), this, SLOT(pastePerson())); - if (RSLinkClipboard::empty(RetroShareLink::TYPE_PERSON)) { - action->setDisabled(true); - } + QAction* inviteToLobbyAction = new QAction(tr("Invite this friend"), mnu2); + inviteToLobbyAction->setData(QString::number((*it).lobby_id)); + connect(inviteToLobbyAction, SIGNAL(triggered()), this, SLOT(inviteToLobby())); + mnu2->addAction(inviteToLobbyAction); - if (type == TYPE_GPG) { - contextMnu.addAction(QIcon(IMAGE_DENYFRIEND), tr("Deny Friend"), this, SLOT(removefriend())); - } else { - //this is a SSL key - contextMnu.addAction(QIcon(IMAGE_REMOVEFRIEND), tr("Remove Friend Location"), this, SLOT(removefriend())); - } + QAction* showLobbyAction = new QAction(tr("Show"), mnu2); + showLobbyAction->setData(QString::number((*it).lobby_id)); + connect(showLobbyAction, SIGNAL(triggered()), this, SLOT(showLobby())); + mnu2->addAction(showLobbyAction); - if (mShowGroups && type == TYPE_GPG) { - QMenu* addToGroupMenu = NULL; - QMenu* moveToGroupMenu = NULL; + QAction* unsubscribeToLobbyAction = new QAction(tr("Unsubscribe"), mnu2); + unsubscribeToLobbyAction->setData(QString::number((*it).lobby_id)); + connect(unsubscribeToLobbyAction, SIGNAL(triggered()), this, SLOT(unsubscribeToLobby())); + mnu2->addAction(unsubscribeToLobbyAction); + } - std::list groupInfoList; - rsPeers->getGroupInfoList(groupInfoList); + contextMnu.addAction(QIcon(IMAGE_MSG), tr("Message Friend"), this, SLOT(msgfriend())); - GroupDefs::sortByName(groupInfoList); + contextMnu.addSeparator(); - std::string gpgId = getRsId(c); + contextMnu.addAction(QIcon(IMAGE_FRIENDINFO), tr("Friend Details"), this, SLOT(configurefriend())); + // contextMnu.addAction(QIcon(IMAGE_PEERINFO), tr("Profile View"), this, SLOT(viewprofile())); + // action = contextMnu.addAction(QIcon(IMAGE_EXPORTFRIEND), tr("Export Friend"), this, SLOT(exportfriend())); - QTreeWidgetItem *parent = c->parent(); + if (type == TYPE_GPG) { + contextMnu.addAction(QIcon(IMAGE_EXPORTFRIEND), tr("Recommend this Friend to..."), this, SLOT(recommendfriend())); + } - bool foundGroup = false; - // add action for all groups, except the own group - for (std::list::iterator groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); groupIt++) { - if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpgId) == groupIt->peerIds.end()) { - if (parent) { - if (addToGroupMenu == NULL) { - addToGroupMenu = new QMenu(tr("Add to group"), &contextMnu); - } - QAction* addToGroupAction = new QAction(GroupDefs::name(*groupIt), addToGroupMenu); - addToGroupAction->setData(QString::fromStdString(groupIt->id)); - connect(addToGroupAction, SIGNAL(triggered()), this, SLOT(addToGroup())); - addToGroupMenu->addAction(addToGroupAction); - } + contextMnu.addAction(QIcon(IMAGE_CONNECT), tr("Connect To Friend"), this, SLOT(connectfriend())); - if (moveToGroupMenu == NULL) { - moveToGroupMenu = new QMenu(tr("Move to group"), &contextMnu); - } - QAction* moveToGroupAction = new QAction(GroupDefs::name(*groupIt), moveToGroupMenu); - moveToGroupAction->setData(QString::fromStdString(groupIt->id)); - connect(moveToGroupAction, SIGNAL(triggered()), this, SLOT(moveToGroup())); - moveToGroupMenu->addAction(moveToGroupAction); - } else { - foundGroup = true; - } - } + if (type == TYPE_GPG) { + contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyLink())); + } - if (addToGroupMenu || moveToGroupMenu || foundGroup) { - QMenu *groupsMenu = contextMnu.addMenu(QIcon(IMAGE_GROUP16), tr("Groups")); + QAction *action = contextMnu.addAction(QIcon(IMAGE_PASTELINK), tr("Paste Friend Link"), this, SLOT(pastePerson())); + if (RSLinkClipboard::empty(RetroShareLink::TYPE_PERSON)) { + action->setDisabled(true); + } - if (addToGroupMenu) { - groupsMenu->addMenu(addToGroupMenu); - } + if (type == TYPE_GPG) { + contextMnu.addAction(QIcon(IMAGE_DENYFRIEND), tr("Deny Friend"), this, SLOT(removefriend())); + } else { + //this is a SSL key + contextMnu.addAction(QIcon(IMAGE_REMOVEFRIEND), tr("Remove Friend Location"), this, SLOT(removefriend())); + } - if (moveToGroupMenu) { - groupsMenu->addMenu(moveToGroupMenu); - } + if (mShowGroups && type == TYPE_GPG) { + QMenu* addToGroupMenu = NULL; + QMenu* moveToGroupMenu = NULL; - if (foundGroup) { - // add remove from group - if (parent && parent->type() == TYPE_GROUP) { - QAction *removeFromGroup = groupsMenu->addAction(tr("Remove from group")); - removeFromGroup->setData(parent->data(COLUMN_DATA, ROLE_ID)); - connect(removeFromGroup, SIGNAL(triggered()), this, SLOT(removeFromGroup())); - } + std::list groupInfoList; + rsPeers->getGroupInfoList(groupInfoList); - QAction *removeFromAllGroups = groupsMenu->addAction(tr("Remove from all groups")); - removeFromAllGroups->setData(""); - connect(removeFromAllGroups, SIGNAL(triggered()), this, SLOT(removeFromGroup())); - } - } - } - } - } - } else { + GroupDefs::sortByName(groupInfoList); + + std::string gpgId = getRsId(c); + + QTreeWidgetItem *parent = c->parent(); + + bool foundGroup = false; + // add action for all groups, except the own group + for (std::list::iterator groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); groupIt++) { + if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpgId) == groupIt->peerIds.end()) { + if (parent) { + if (addToGroupMenu == NULL) { + addToGroupMenu = new QMenu(tr("Add to group"), &contextMnu); + } + QAction* addToGroupAction = new QAction(GroupDefs::name(*groupIt), addToGroupMenu); + addToGroupAction->setData(QString::fromStdString(groupIt->id)); + connect(addToGroupAction, SIGNAL(triggered()), this, SLOT(addToGroup())); + addToGroupMenu->addAction(addToGroupAction); + } + + if (moveToGroupMenu == NULL) { + moveToGroupMenu = new QMenu(tr("Move to group"), &contextMnu); + } + QAction* moveToGroupAction = new QAction(GroupDefs::name(*groupIt), moveToGroupMenu); + moveToGroupAction->setData(QString::fromStdString(groupIt->id)); + connect(moveToGroupAction, SIGNAL(triggered()), this, SLOT(moveToGroup())); + moveToGroupMenu->addAction(moveToGroupAction); + } else { + foundGroup = true; + } + } + + if (addToGroupMenu || moveToGroupMenu || foundGroup) { + QMenu *groupsMenu = contextMnu.addMenu(QIcon(IMAGE_GROUP16), tr("Groups")); + + if (addToGroupMenu) { + groupsMenu->addMenu(addToGroupMenu); + } + + if (moveToGroupMenu) { + groupsMenu->addMenu(moveToGroupMenu); + } + + if (foundGroup) { + // add remove from group + if (parent && parent->type() == TYPE_GROUP) { + QAction *removeFromGroup = groupsMenu->addAction(tr("Remove from group")); + removeFromGroup->setData(parent->data(COLUMN_DATA, ROLE_ID)); + connect(removeFromGroup, SIGNAL(triggered()), this, SLOT(removeFromGroup())); + } + + QAction *removeFromAllGroups = groupsMenu->addAction(tr("Remove from all groups")); + removeFromAllGroups->setData(""); + connect(removeFromAllGroups, SIGNAL(triggered()), this, SLOT(removeFromGroup())); + } + } + } + } + } + } else { QAction *action = contextMnu.addAction(QIcon(IMAGE_PASTELINK), tr("Paste Friend Link"), this, SLOT(pastePerson())); if (RSLinkClipboard::empty(RetroShareLink::TYPE_PERSON)) { action->setDisabled(true); @@ -1371,6 +1406,80 @@ void FriendList::configurefriend() ConfCertDialog::showIt(getRsId(getCurrentPeer()), ConfCertDialog::PageDetails); } +void FriendList::showLobby() +{ + std::string lobby_id = qobject_cast(sender())->data().toString().toStdString(); + + if(lobby_id.empty()) + return; + + std::string vpeer_id ; + + if(rsMsgs->getVirtualPeerId( ChatLobbyId(QString::fromStdString(lobby_id).toULongLong() ),vpeer_id)) + PopupChatDialog::chatFriend(vpeer_id) ; +} +void FriendList::unsubscribeToLobby() +{ + std::string lobby_id = qobject_cast(sender())->data().toString().toStdString(); + + if(lobby_id.empty()) + return; + + std::string vpeer_id ; + rsMsgs->getVirtualPeerId( ChatLobbyId(QString::fromStdString(lobby_id).toULongLong() ),vpeer_id) ; + + if(QMessageBox::Ok == QMessageBox::question(this,tr("Unsubscribe to lobby"),tr("You are about to unsubscribe a chat lobby
You can only re-enter if your friends invite you again."),QMessageBox::Ok | QMessageBox::Cancel)) + rsMsgs->unsubscribeChatLobby(ChatLobbyId(QString::fromStdString(lobby_id).toULongLong())) ; + + // we should also close existing windows. + + PopupChatDialog::closeChat(vpeer_id) ; +} + + +void FriendList::inviteToLobby() +{ + QTreeWidgetItem *c = getCurrentPeer(); + + if (c == NULL) { + return; + } + + if (c->type() != TYPE_SSL) { + // wrong type + return; + } + + std::string lobby_id = qobject_cast(sender())->data().toString().toStdString(); + + if(lobby_id.empty()) + return; + + std::string peer_id = getRsId(c) ; + + // add to group + rsMsgs->invitePeerToLobby(ChatLobbyId(QString::fromStdString(lobby_id).toULongLong()), peer_id); + + std::string vpeer_id ; + if(rsMsgs->getVirtualPeerId( ChatLobbyId(QString::fromStdString(lobby_id).toULongLong() ),vpeer_id) ) + PopupChatDialog::chatFriend(vpeer_id) ; +} + +void FriendList::createchatlobby() +{ + QTreeWidgetItem *c = getCurrentPeer(); + + if (c == NULL) + return; + + std::list friend_list ; + + std::string peer_id = getRsId(c) ; + friend_list.push_back(peer_id) ; + + CreateLobbyDialog(friend_list).exec() ; +} + void FriendList::addToGroup() { QTreeWidgetItem *c = getCurrentPeer(); diff --git a/retroshare-gui/src/gui/common/FriendList.h b/retroshare-gui/src/gui/common/FriendList.h index db633cf3c..459751214 100644 --- a/retroshare-gui/src/gui/common/FriendList.h +++ b/retroshare-gui/src/gui/common/FriendList.h @@ -122,6 +122,11 @@ private slots: void editGroup(); void removeGroup(); + + void inviteToLobby(); + void createchatlobby(); + void unsubscribeToLobby(); + void showLobby(); }; #endif // FRIENDLIST_H diff --git a/retroshare-gui/src/gui/notifyqt.cpp b/retroshare-gui/src/gui/notifyqt.cpp index 35bd51ff8..4b46f0ae7 100644 --- a/retroshare-gui/src/gui/notifyqt.cpp +++ b/retroshare-gui/src/gui/notifyqt.cpp @@ -307,6 +307,12 @@ void NotifyQt::notifyListChange(int list, int type) #endif emit filesPostModChanged(true) ; /* Local */ break; + case NOTIFY_LIST_CHAT_LOBBY_INVITATION: +#ifdef NOTIFY_DEBUG + std::cerr << "received files changed" << std::endl ; +#endif + emit chatLobbyInviteReceived() ; /* Local */ + break; case NOTIFY_LIST_DIRLIST_FRIENDS: #ifdef NOTIFY_DEBUG std::cerr << "received files changed" << std::endl ; diff --git a/retroshare-gui/src/gui/notifyqt.h b/retroshare-gui/src/gui/notifyqt.h index 10d35f548..fe094b53f 100644 --- a/retroshare-gui/src/gui/notifyqt.h +++ b/retroshare-gui/src/gui/notifyqt.h @@ -92,6 +92,7 @@ class NotifyQt: public QObject, public NotifyBase void downloadCompleteCountChanged(int /* count */); void channelMsgReadSatusChanged(const QString& channelId, const QString& msgId, int status); void historyChanged(uint msgId, int type); + void chatLobbyInviteReceived() ; /* Notify from GUI */ void chatStyleChanged(int /*ChatStyle::enumStyleType*/ styleType); diff --git a/retroshare-gui/src/gui/settings/ChatPage.cpp b/retroshare-gui/src/gui/settings/ChatPage.cpp index 1365c5ef6..1f7b1be34 100644 --- a/retroshare-gui/src/gui/settings/ChatPage.cpp +++ b/retroshare-gui/src/gui/settings/ChatPage.cpp @@ -28,6 +28,7 @@ #include "rsharesettings.h" #include +#include #define VARIANT_STANDARD "Standard" @@ -115,6 +116,8 @@ ChatPage::save(QString &/*errmsg*/) rsHistory->setSaveCount(true, ui.publicChatSaveCount->value()); rsHistory->setSaveCount(false, ui.privateChatSaveCount->value()); + rsMsgs->setDefaultNickNameForChatLobby(ui.chatLobbyNick_LE->text().toStdString()) ; + ChatStyleInfo info; QListWidgetItem *item = ui.publicList->currentItem(); if (item) { @@ -175,6 +178,10 @@ ChatPage::load() publicStylePath = loadStyleInfo(ChatStyle::TYPE_PUBLIC, ui.publicList, ui.publicComboBoxVariant, publicStyleVariant); privateStylePath = loadStyleInfo(ChatStyle::TYPE_PRIVATE, ui.privateList, ui.privateComboBoxVariant, privateStyleVariant); historyStylePath = loadStyleInfo(ChatStyle::TYPE_HISTORY, ui.historyList, ui.historyComboBoxVariant, historyStyleVariant); + + std::string nick ; + rsMsgs->getDefaultNickNameForChatLobby(nick) ; + ui.chatLobbyNick_LE->setText(QString::fromStdString(nick)) ; } void ChatPage::on_pushButtonChangeChatFont_clicked() diff --git a/retroshare-gui/src/gui/settings/ChatPage.ui b/retroshare-gui/src/gui/settings/ChatPage.ui index a74dc4262..a4f234863 100644 --- a/retroshare-gui/src/gui/settings/ChatPage.ui +++ b/retroshare-gui/src/gui/settings/ChatPage.ui @@ -521,35 +521,89 @@ Chat Settings - - - - - Enable Emoticons Privat Chat - - - true - - + + + + + + + Enable Emoticons Privat Chat + + + true + + + + + + + Enable Emoticons Group Chat + + + true + + + + + + + Send message with Ctrl+Return + + + + + + + Default nickname for chat lobbies: + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + - - - - Enable Emoticons Group Chat - - - true - - - - - - - Send message with Ctrl+Return - - - - + diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 2f1073667..5a8ec44e3 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -281,6 +281,7 @@ int main(int argc, char *argv[]) QObject::connect(notify,SIGNAL(messagesChanged()) ,w->messagesDialog ,SLOT(insertMessages() )) ; QObject::connect(notify,SIGNAL(messagesTagsChanged()) ,w->messagesDialog ,SLOT(messagesTagsChanged() )) ; QObject::connect(notify,SIGNAL(messagesChanged()) ,w ,SLOT(updateMessages() )) ; + QObject::connect(notify,SIGNAL(chatLobbyInviteReceived()) ,w->friendsDialog ,SLOT(readChatLobbyInvites() )) ; QObject::connect(notify,SIGNAL(forumsChanged()) ,w ,SLOT(updateForums() ), Qt::QueuedConnection); QObject::connect(notify,SIGNAL(channelsChanged(int)) ,w ,SLOT(updateChannels(int) ), Qt::QueuedConnection); QObject::connect(notify,SIGNAL(downloadCompleteCountChanged(int)) ,w ,SLOT(updateTransfers(int) ));