added unsubscribe protocol, updated GUI

git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-ChatLobby@4738 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2011-12-27 13:47:37 +00:00
parent cc57ab2462
commit 3addb36e4c
12 changed files with 213 additions and 19 deletions

View File

@ -57,7 +57,14 @@ 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);
@ -184,6 +191,7 @@ RsItem *RsChatSerialiser::deserialise(void *data, uint32_t *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 ;
@ -200,6 +208,14 @@ 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 */
@ -347,6 +363,32 @@ bool RsChatLobbyMsgItem::serialise(void *data, uint32_t& pktsize)
return ok ;
}
bool RsChatLobbyUnsubscribeItem::serialise(void *data, uint32_t& pktsize)
{
uint32_t tlvsize = serial_size() ;
if (pktsize < tlvsize)
return false; /* not enough space */
bool ok = true ;
ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize); // correct header!
uint32_t offset = 8 ;
ok &= setRawUInt64(data, tlvsize, &offset, lobby_id);
if (offset != tlvsize)
{
ok = false;
#ifdef CHAT_DEBUG
std::cerr << "RsChatSerialiser::serialiseItem() Size Error! " << std::endl;
#endif
}
#ifdef CHAT_DEBUG
std::cerr << "computed size: " << 256*((unsigned char*)data)[6]+((unsigned char*)data)[7] << std::endl ;
#endif
pktsize = tlvsize ;
return ok ;
}
bool RsChatLobbyConnectChallengeItem::serialise(void *data, uint32_t& pktsize)
{
uint32_t tlvsize = serial_size() ;
@ -574,7 +616,23 @@ RsChatLobbyMsgItem::RsChatLobbyMsgItem(void *data,uint32_t /*size*/)
if (!ok)
std::cerr << "Unknown error while deserializing." << std::endl ;
}
RsChatLobbyUnsubscribeItem::RsChatLobbyUnsubscribeItem(void *data,uint32_t /*size*/)
: RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE)
{
uint32_t rssize = getRsItemSize(data);
bool ok = true ;
std::cerr << "RsChatLobbyUnsubscribeItem: rsitem size is " << rssize << std::endl;
uint32_t offset = 8 ;
/* get mandatory parts first */
ok &= getRawUInt64(data, rssize, &offset, &lobby_id);
if (offset != rssize)
std::cerr << "Size error while deserializing." << std::endl ;
if (!ok)
std::cerr << "Unknown error while deserializing." << std::endl ;
}
RsChatLobbyConnectChallengeItem::RsChatLobbyConnectChallengeItem(void *data,uint32_t /*size*/)
: RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE)
{

View File

@ -55,6 +55,7 @@ const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_MSG = 0x06 ;
const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE = 0x07 ;
const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_ACCEPT = 0x08 ;
const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE = 0x09 ;
const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE= 0x0A ;
// for defining tags themselves and msg tags
const uint8_t RS_PKT_SUBTYPE_MSG_TAG_TYPE = 0x03;
@ -129,6 +130,22 @@ class RsChatLobbyMsgItem: public RsChatMsgItem
ChatLobbyNickName nick ;
};
class RsChatLobbyUnsubscribeItem: public RsChatItem
{
public:
RsChatLobbyUnsubscribeItem() :RsChatItem(RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE) {}
RsChatLobbyUnsubscribeItem(void *data,uint32_t size) ; // deserialization
virtual ~RsChatLobbyUnsubscribeItem() {}
virtual std::ostream& print(std::ostream &out, uint16_t indent = 0);
uint64_t lobby_id ;
virtual bool serialise(void *data,uint32_t& size) ; // Isn't it better that items can serialize themselves ?
virtual uint32_t serial_size() ; // deserialise is handled using a constructor
};
class RsChatLobbyConnectChallengeItem: public RsChatItem
{
public:

View File

@ -644,6 +644,15 @@ void p3ChatService::receiveChatQueue()
continue ;
}
RsChatLobbyUnsubscribeItem *cu = dynamic_cast<RsChatLobbyUnsubscribeItem*>(item) ;
if(cu != NULL)
{
handleFriendUnsubscribeLobby(cu) ;
delete item ;
continue ;
}
std::cerr << "Received ChatItem of unhandled type: " << std::endl;
item->print(std::cerr,0) ;
@ -1711,11 +1720,63 @@ ChatLobbyId p3ChatService::createChatLobby(const std::string& lobby_name,const s
return lobby_id ;
}
void p3ChatService::handleFriendUnsubscribeLobby(RsChatLobbyUnsubscribeItem *item)
{
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
std::map<ChatLobbyId,ChatLobbyEntry>::iterator it = _chat_lobbys.find(item->lobby_id) ;
std::cerr << "Received unsubscribed to lobby " << item->lobby_id << ", from friend " << item->PeerId() << std::endl;
if(it == _chat_lobbys.end())
{
std::cerr << "Chat lobby " << item->lobby_id << " does not exist ! Can't unsubscribe!" << std::endl;
return ;
}
for(std::set<std::string>::iterator it2(it->second.participating_friends.begin());it2!=it->second.participating_friends.end();++it2)
if(*it2 == item->PeerId())
{
std::cerr << " removing peer id " << item->PeerId() << " from participant list of lobby " << item->lobby_id << std::endl;
it->second.participating_friends.erase(it2) ;
break ;
}
}
void p3ChatService::unsubscribeChatLobby(const ChatLobbyId& id)
{
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
// send a lobby leaving packet. To be implemented.
std::map<ChatLobbyId,ChatLobbyEntry>::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<std::string>::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<std::string,ChatLobbyId>::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)
{

View File

@ -219,6 +219,7 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
void checkAndRedirectMsgToLobby(RsChatMsgItem*) ;
void handleConnectionChallenge(RsChatLobbyConnectChallengeItem *item) ;
void sendConnectionChallenge(ChatLobbyId id) ;
void handleFriendUnsubscribeLobby(RsChatLobbyUnsubscribeItem*) ;
void cleanLobbyCaches() ;
static std::string makeVirtualPeerId(ChatLobbyId) ;

View File

@ -62,16 +62,8 @@ ChatLobbyDialog::~ChatLobbyDialog()
{
// announce leaving of lobby
rsMsgs->unsubscribeChatLobby(lobby_id) ;
}
void ChatLobbyDialog::closeEvent(QCloseEvent* e)
{
std::cerr << "In close event!" << std::endl;
if(QMessageBox::Yes == QMessageBox::question(NULL,tr("Unsubsribe to lobby?"),tr("Do you want to unsubscribe to this chat lobby?"),QMessageBox::Yes, QMessageBox::No))
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) ;
PopupChatDialog::closeEvent(e) ;
}
void ChatLobbyDialog::setNickName(const QString& nick)

View File

@ -55,7 +55,6 @@ class ChatLobbyDialog: public 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.
virtual void closeEvent(QCloseEvent*) ;
protected slots:
void setNickName(const QString&) ;

View File

@ -40,7 +40,7 @@ CreateLobbyDialog::CreateLobbyDialog(const std::list<std::string>& peer_list,QWi
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")) ;
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( ) ) );

View File

@ -88,6 +88,17 @@ p, li { white-space: pre-wrap; }
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QTextEdit" name="textEdit">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>

View File

@ -359,6 +359,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()){

View File

@ -47,6 +47,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);

View File

@ -336,23 +336,36 @@ void FriendList::peerTreeWidgetCostumPopupMenu()
case TYPE_SSL:
{
contextMnu.addAction(QIcon(IMAGE_CHAT), tr("Chat"), this, SLOT(chatfriendproxy()));
QMenu *mnu = contextMnu.addMenu(QIcon(IMAGE_CHAT), tr("Invite to chat lobby")) ;
QMenu *mnu = contextMnu.addMenu(QIcon(IMAGE_CHAT), tr("Chat lobbies")) ;
mnu->addAction(QIcon(IMAGE_ADDFRIEND),tr("create new"),this,SLOT(createchatlobby())) ;
// Get existing lobbies
//
std::list<ChatLobbyInfo> cl_infos ;
rsMsgs->getChatLobbyList(cl_infos) ;
for(std::list<ChatLobbyInfo>::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;
QAction* inviteToLobbyAction = new QAction(QString::fromUtf8((*it).lobby_name.c_str()), mnu);
QMenu *mnu2 = mnu->addMenu(QIcon(IMAGE_CHAT), QString::fromUtf8((*it).lobby_name.c_str())) ;
QAction* inviteToLobbyAction = new QAction(tr("Invite this friend"), mnu2);
inviteToLobbyAction->setData(QString::number((*it).lobby_id));
connect(inviteToLobbyAction, SIGNAL(triggered()), this, SLOT(inviteToLobby()));
mnu->addAction(inviteToLobbyAction);
}
mnu2->addAction(inviteToLobbyAction);
mnu->addAction(QIcon(IMAGE_CHAT),tr("create new"),this,SLOT(createchatlobby())) ;
QAction* showLobbyAction = new QAction(tr("Show"), mnu2);
showLobbyAction->setData(QString::number((*it).lobby_id));
connect(showLobbyAction, SIGNAL(triggered()), this, SLOT(showLobby()));
mnu2->addAction(showLobbyAction);
QAction* unsubscribeToLobbyAction = new QAction(tr("Unsubscribe"), mnu2);
unsubscribeToLobbyAction->setData(QString::number((*it).lobby_id));
connect(unsubscribeToLobbyAction, SIGNAL(triggered()), this, SLOT(unsubscribeToLobby()));
mnu2->addAction(unsubscribeToLobbyAction);
}
contextMnu.addAction(QIcon(IMAGE_MSG), tr("Message Friend"), this, SLOT(msgfriend()));
@ -1393,6 +1406,37 @@ void FriendList::configurefriend()
ConfCertDialog::showIt(getRsId(getCurrentPeer()), ConfCertDialog::PageDetails);
}
void FriendList::showLobby()
{
std::string lobby_id = qobject_cast<QAction*>(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<QAction*>(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<br>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();

View File

@ -125,6 +125,8 @@ private slots:
void inviteToLobby();
void createchatlobby();
void unsubscribeToLobby();
void showLobby();
};
#endif // FRIENDLIST_H