diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index 6149a1f1c..1e51be6c6 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -50,6 +50,8 @@ #define RS_MSG_NEW 0x0010 /* New */ #define RS_MSG_TRASH 0x0020 /* Trash */ #define RS_MSG_UNREAD_BY_USER 0x0040 /* Unread by user */ +#define RS_MSG_REPLIED 0x0080 /* Message is replied */ +#define RS_MSG_FORWARDED 0x0100 /* Message is forwarded */ #define RS_MSGTAGTYPE_IMPORTANT 1 #define RS_MSGTAGTYPE_WORK 2 @@ -152,15 +154,18 @@ virtual ~RsMsgs() { return; } /* Message Items */ virtual bool getMessageSummaries(std::list &msgList) = 0; -virtual bool getMessage(std::string mId, MessageInfo &msg) = 0; +virtual bool getMessage(const std::string &mId, MessageInfo &msg) = 0; virtual void getMessageCount(unsigned int *pnInbox, unsigned int *pnInboxNew, unsigned int *pnOutbox, unsigned int *pnDraftbox, unsigned int *pnSentbox, unsigned int *pnTrashbox) = 0; virtual bool MessageSend(MessageInfo &info) = 0; -virtual bool MessageToDraft(MessageInfo &info) = 0; -virtual bool MessageToTrash(std::string mid, bool bTrash) = 0; +virtual bool MessageToDraft(MessageInfo &info, const std::string &msgParentId) = 0; +virtual bool MessageToTrash(const std::string &mid, bool bTrash) = 0; +virtual bool getMsgParentId(const std::string &msgId, std::string &msgParentId) = 0; -virtual bool MessageDelete(std::string mid) = 0; -virtual bool MessageRead(std::string mid, bool bUnreadByUser) = 0; +virtual bool MessageDelete(const std::string &mid) = 0; +virtual bool MessageRead(const std::string &mid, bool bUnreadByUser) = 0; +virtual bool MessageReplied(const std::string &mid, bool replied) = 0; +virtual bool MessageForwarded(const std::string &mid, bool forwarded) = 0; /* message tagging */ @@ -169,8 +174,8 @@ virtual bool getMessageTagTypes(MsgTagType& tags) = 0; virtual bool setMessageTagType(uint32_t tagId, std::string& text, uint32_t rgb_color) = 0; virtual bool removeMessageTagType(uint32_t tagId) = 0; -virtual bool getMessageTag(std::string msgId, MsgTagInfo& info) = 0; -virtual bool setMessageTag(std::string msgId, uint32_t tagId, bool set) = 0; +virtual bool getMessageTag(const std::string &msgId, MsgTagInfo& info) = 0; +virtual bool setMessageTag(const std::string &msgId, uint32_t tagId, bool set) = 0; virtual bool resetMessageStandardTagTypes(MsgTagType& tags) = 0; diff --git a/libretroshare/src/rsserver/p3msgs.cc b/libretroshare/src/rsserver/p3msgs.cc index d877c7fd6..1566b375f 100644 --- a/libretroshare/src/rsserver/p3msgs.cc +++ b/libretroshare/src/rsserver/p3msgs.cc @@ -57,7 +57,7 @@ bool p3Msgs::getMessageSummaries(std::list &msgList) -bool p3Msgs::getMessage(std::string mid, MessageInfo &msg) +bool p3Msgs::getMessage(const std::string &mid, MessageInfo &msg) { return mMsgSrv->getMessage(mid, msg); } @@ -75,19 +75,24 @@ bool p3Msgs::MessageSend(MessageInfo &info) return mMsgSrv->MessageSend(info); } -bool p3Msgs::MessageToDraft(MessageInfo &info) +bool p3Msgs::MessageToDraft(MessageInfo &info, const std::string &msgParentId) { - return mMsgSrv->MessageToDraft(info); + return mMsgSrv->MessageToDraft(info, msgParentId); } -bool p3Msgs::MessageToTrash(std::string mid, bool bTrash) +bool p3Msgs::MessageToTrash(const std::string &mid, bool bTrash) { - return mMsgSrv->MessageToTrash(mid, bTrash); + return mMsgSrv->MessageToTrash(mid, bTrash); +} + +bool p3Msgs::getMsgParentId(const std::string &msgId, std::string &msgParentId) +{ + return mMsgSrv->getMsgParentId(msgId, msgParentId); } /****************************************/ /****************************************/ -bool p3Msgs::MessageDelete(std::string mid) +bool p3Msgs::MessageDelete(const std::string &mid) { //std::cerr << "p3Msgs::MessageDelete() "; //std::cerr << "mid: " << mid << std::endl; @@ -95,7 +100,7 @@ bool p3Msgs::MessageDelete(std::string mid) return mMsgSrv -> removeMsgId(mid); } -bool p3Msgs::MessageRead(std::string mid, bool bUnreadByUser) +bool p3Msgs::MessageRead(const std::string &mid, bool bUnreadByUser) { //std::cerr << "p3Msgs::MessageRead() "; //std::cerr << "mid: " << mid << std::endl; @@ -103,6 +108,16 @@ bool p3Msgs::MessageRead(std::string mid, bool bUnreadByUser) return mMsgSrv -> markMsgIdRead(mid, bUnreadByUser); } +bool p3Msgs::MessageReplied(const std::string &mid, bool replied) +{ + return mMsgSrv->setMsgFlag(mid, replied ? RS_MSG_FLAGS_REPLIED : 0, RS_MSG_FLAGS_REPLIED); +} + +bool p3Msgs::MessageForwarded(const std::string &mid, bool forwarded) +{ + return mMsgSrv->setMsgFlag(mid, forwarded ? RS_MSG_FLAGS_FORWARDED : 0, RS_MSG_FLAGS_FORWARDED); +} + bool p3Msgs::getMessageTagTypes(MsgTagType& tags) { return mMsgSrv->getMessageTagTypes(tags); @@ -118,12 +133,12 @@ bool p3Msgs::removeMessageTagType(uint32_t tagId) return mMsgSrv->removeMessageTagType(tagId); } -bool p3Msgs::getMessageTag(std::string msgId, MsgTagInfo& info) +bool p3Msgs::getMessageTag(const std::string &msgId, MsgTagInfo& info) { return mMsgSrv->getMessageTag(msgId, info); } -bool p3Msgs::setMessageTag(std::string msgId, uint32_t tagId, bool set) +bool p3Msgs::setMessageTag(const std::string &msgId, uint32_t tagId, bool set) { return mMsgSrv->setMessageTag(msgId, tagId, set); } diff --git a/libretroshare/src/rsserver/p3msgs.h b/libretroshare/src/rsserver/p3msgs.h index b1653cddc..419d6bede 100644 --- a/libretroshare/src/rsserver/p3msgs.h +++ b/libretroshare/src/rsserver/p3msgs.h @@ -54,22 +54,25 @@ class p3Msgs: public RsMsgs * @param msgList ref to list summarising client's msgs */ virtual bool getMessageSummaries(std::list &msgList); - virtual bool getMessage(std::string mId, MessageInfo &msg); + virtual bool getMessage(const std::string &mId, MessageInfo &msg); virtual void getMessageCount(unsigned int *pnInbox, unsigned int *pnInboxNew, unsigned int *pnOutbox, unsigned int *pnDraftbox, unsigned int *pnSentbox, unsigned int *pnTrashbox); virtual bool MessageSend(MessageInfo &info); - virtual bool MessageToDraft(MessageInfo &info); - virtual bool MessageToTrash(std::string mid, bool bTrash); - virtual bool MessageDelete(std::string mid); - virtual bool MessageRead(std::string mid, bool bUnreadByUser); + virtual bool MessageToDraft(MessageInfo &info, const std::string &msgParentId); + virtual bool MessageToTrash(const std::string &mid, bool bTrash); + virtual bool MessageDelete(const std::string &mid); + virtual bool MessageRead(const std::string &mid, bool bUnreadByUser); + virtual bool MessageReplied(const std::string &mid, bool replied); + virtual bool MessageForwarded(const std::string &mid, bool forwarded); + virtual bool getMsgParentId(const std::string &msgId, std::string &msgParentId); virtual bool getMessageTagTypes(MsgTagType& tags); virtual bool setMessageTagType(uint32_t tagId, std::string& text, uint32_t rgb_color); virtual bool removeMessageTagType(uint32_t tagId); - virtual bool getMessageTag(std::string msgId, MsgTagInfo& info); + virtual bool getMessageTag(const std::string &msgId, MsgTagInfo& info); /* set == false && tagId == 0 --> remove all */ - virtual bool setMessageTag(std::string msgId, uint32_t tagId, bool set); + virtual bool setMessageTag(const std::string &msgId, uint32_t tagId, bool set); virtual bool resetMessageStandardTagTypes(MsgTagType& tags); diff --git a/libretroshare/src/serialiser/rsmsgitems.cc b/libretroshare/src/serialiser/rsmsgitems.cc index 825fafb0f..368beb20e 100644 --- a/libretroshare/src/serialiser/rsmsgitems.cc +++ b/libretroshare/src/serialiser/rsmsgitems.cc @@ -1102,12 +1102,146 @@ RsMsgSrcId* RsMsgSerialiser::deserialiseMsgSrcIdItem(void* data, uint32_t* pktsi } /************************* end of definition of msgSrcId serialisation functions ************************/ + +/************************************** Message ParentId **********************/ + +RsMsgParentId::~RsMsgParentId() +{ + return; +} + +std::ostream& RsMsgParentId::print(std::ostream& out, uint16_t indent) +{ + printRsItemBase(out, "RsMsgParentIdItem", indent); + uint16_t int_Indent = indent + 2; + + printIndent(out, int_Indent); + out << "msgId : " << msgId << std::endl; + + printIndent(out, int_Indent); + out << "msgParentId: " << msgParentId << std::endl; + + + printRsItemEnd(out, "RsMsgParentId", indent); + + return out; +} + +void RsMsgParentId::clear() +{ + msgId = 0; + msgParentId = 0; + + return; +} + +uint32_t RsMsgSerialiser::sizeMsgParentIdItem(RsMsgParentId* item) +{ + uint32_t s = 8; /* header */ + + s += 4; // srcId + s += 4; // msgParentId + + return s; +} + +bool RsMsgSerialiser::serialiseMsgParentIdItem(RsMsgParentId *item, void *data, uint32_t* pktsize) +{ + uint32_t tlvsize = sizeMsgParentIdItem(item); + uint32_t offset = 0; + + if (*pktsize < tlvsize) + return false; /* not enough space */ + + *pktsize = tlvsize; + + bool ok = true; + + ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize); + +#ifdef RSSERIAL_DEBUG + std::cerr << "RsMsgSerialiser::serialiseMsgParentIdItem() Header: " << ok << std::endl; + std::cerr << "RsMsgSerialiser::serialiseMsgParentIdItem() Size: " << tlvsize << std::endl; +#endif + + /* skip the header */ + offset += 8; + + ok &= setRawUInt32(data, tlvsize, &offset, item->msgId); + ok &= setRawUInt32(data, tlvsize, &offset, item->msgParentId); + + if (offset != tlvsize) + { + ok = false; +#ifdef RSSERIAL_DEBUG + std::cerr << "RsMsgSerialiser::serialiseMsgParentIdItem() Size Error! " << std::endl; +#endif + } + + return ok; +} + +RsMsgParentId* RsMsgSerialiser::deserialiseMsgParentIdItem(void* data, uint32_t* pktsize) +{ + /* get the type and size */ + uint32_t rstype = getRsItemId(data); + uint32_t rssize = getRsItemSize(data); + + uint32_t offset = 0; + + + if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || + (RS_SERVICE_TYPE_MSG != getRsItemService(rstype)) || + (RS_PKT_SUBTYPE_MSG_PARENT_TAG != getRsItemSubType(rstype))) + { + return NULL; /* wrong type */ + } + + if (*pktsize < rssize) /* check size */ + return NULL; /* not enough data */ + + /* set the packet length */ + *pktsize = rssize; + + bool ok = true; + + /* ready to load */ + RsMsgParentId *item = new RsMsgParentId(); + item->clear(); + + /* skip the header */ + offset += 8; + + + /* get mandatory parts first */ + ok &= getRawUInt32(data, rssize, &offset, &(item->msgId)); + ok &= getRawUInt32(data, rssize, &offset, &(item->msgParentId)); + + if (offset != rssize) + { + /* error */ + delete item; + return NULL; + } + + if (!ok) + { + delete item; + return NULL; + } + + return item; +} + +/************************* end of definition of msgParentId serialisation functions ************************/ + uint32_t RsMsgSerialiser::size(RsItem *i) { RsMsgItem *mi; RsMsgTagType *mtt; RsMsgTags *mts; RsMsgSrcId *msi; + RsMsgParentId *msp; /* in order of frequency */ if (NULL != (mi = dynamic_cast(i))) @@ -1118,6 +1252,10 @@ uint32_t RsMsgSerialiser::size(RsItem *i) { return sizeMsgSrcIdItem(msi); } + else if (NULL != (msp = dynamic_cast(i))) + { + return sizeMsgParentIdItem(msp); + } else if (NULL != (mtt = dynamic_cast(i))) { return sizeTagItem(mtt); @@ -1138,6 +1276,7 @@ bool RsMsgSerialiser::serialise(RsItem *i, void *data, uint32_t *pktsize) RsMsgItem *mi; RsMsgSrcId* msi; + RsMsgParentId* msp; RsMsgTagType *mtt; RsMsgTags *mts; @@ -1150,6 +1289,10 @@ bool RsMsgSerialiser::serialise(RsItem *i, void *data, uint32_t *pktsize) { return serialiseMsgSrcIdItem(msi, data, pktsize); } + else if (NULL != (msp = dynamic_cast(i))) + { + return serialiseMsgParentIdItem(msp, data, pktsize); + } else if (NULL != (mtt = dynamic_cast(i))) { return serialiseTagItem(mtt, data, pktsize); @@ -1185,6 +1328,9 @@ RsItem* RsMsgSerialiser::deserialise(void *data, uint32_t *pktsize) case RS_PKT_SUBTYPE_MSG_SRC_TAG: return deserialiseMsgSrcIdItem(data, pktsize); break; + case RS_PKT_SUBTYPE_MSG_PARENT_TAG: + return deserialiseMsgParentIdItem(data, pktsize); + break; case RS_PKT_SUBTYPE_MSG_TAG_TYPE: return deserialiseTagItem(data, pktsize); break; diff --git a/libretroshare/src/serialiser/rsmsgitems.h b/libretroshare/src/serialiser/rsmsgitems.h index c3aaa7c73..2810da40f 100644 --- a/libretroshare/src/serialiser/rsmsgitems.h +++ b/libretroshare/src/serialiser/rsmsgitems.h @@ -54,6 +54,7 @@ const uint8_t RS_PKT_SUBTYPE_PRIVATECHATMSG_CONFIG = 0x05 ; // default is 0x01 const uint8_t RS_PKT_SUBTYPE_MSG_TAG_TYPE = 0x03; const uint8_t RS_PKT_SUBTYPE_MSG_TAGS = 0x04; const uint8_t RS_PKT_SUBTYPE_MSG_SRC_TAG = 0x05; +const uint8_t RS_PKT_SUBTYPE_MSG_PARENT_TAG = 0x06; class RsChatItem: public RsItem @@ -184,6 +185,8 @@ const uint32_t RS_MSG_FLAGS_DRAFT = 0x0004; const uint32_t RS_MSG_FLAGS_NEW = 0x0010; const uint32_t RS_MSG_FLAGS_TRASH = 0x0020; const uint32_t RS_MSG_FLAGS_UNREAD_BY_USER = 0x0040; +const uint32_t RS_MSG_FLAGS_REPLIED = 0x0080; +const uint32_t RS_MSG_FLAGS_FORWARDED = 0x0100; class RsMsgItem: public RsItem { @@ -275,6 +278,26 @@ public: }; +class RsMsgParentId : public RsItem +{ + +public: + RsMsgParentId() + : RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_MSG, + RS_PKT_SUBTYPE_MSG_PARENT_TAG) + { return;} + + std::ostream &print(std::ostream &out, uint16_t indent = 0); + + virtual ~RsMsgParentId(); + virtual void clear(); + + + uint32_t msgId; + uint32_t msgParentId; + +}; + class RsMsgSerialiser: public RsSerialType { public: @@ -311,6 +334,9 @@ virtual uint32_t sizeMsgSrcIdItem(RsMsgSrcId *); virtual bool serialiseMsgSrcIdItem (RsMsgSrcId *item, void *data, uint32_t *size); virtual RsMsgSrcId *deserialiseMsgSrcIdItem(void *data, uint32_t *size); +virtual uint32_t sizeMsgParentIdItem(RsMsgParentId *); +virtual bool serialiseMsgParentIdItem (RsMsgParentId *item, void *data, uint32_t *size); +virtual RsMsgParentId *deserialiseMsgParentIdItem(void *data, uint32_t *size); bool m_bConfiguration; // is set to true for saving configuration (enables serialising msgId) diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index 7ce780940..a7e85c5a9 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -135,7 +135,6 @@ int p3MsgService::incomingMsgs() changed = true ; ++i; mi -> recvTime = time(NULL); - mi -> msgFlags = RS_MSG_FLAGS_NEW; mi -> msgId = getNewUniqueMsgId(); std::string mesg; @@ -149,6 +148,8 @@ int p3MsgService::incomingMsgs() } else { + mi -> msgFlags = RS_MSG_FLAGS_NEW; + /* from a peer */ MsgInfoSummary mis; initRsMIS(mi, mis); @@ -285,6 +286,7 @@ std::list p3MsgService::saveList(bool& cleanup) std::map::iterator mit2; std::map::iterator mit3; std::list::iterator lit; + std::map::iterator mit4; MsgTagType stdTags; @@ -308,6 +310,9 @@ std::list p3MsgService::saveList(bool& cleanup) for(mit3 = mMsgTags.begin(); mit3 != mMsgTags.end(); mit3++) itemList.push_back(mit3->second); + for(mit4 = mParentId.begin(); mit4 != mParentId.end(); mit4++) + itemList.push_back(mit4->second); + return itemList; } @@ -371,6 +376,7 @@ bool p3MsgService::loadList(std::list load) RsMsgTagType* mtt; RsMsgTags* mti; RsMsgSrcId* msi; + RsMsgParentId* msp; std::list items; std::list::iterator it; @@ -415,6 +421,10 @@ bool p3MsgService::loadList(std::list load) srcIdMsgMap.insert(std::pair(msi->msgId, msi->srcId)); mSrcIdList.push_back(msi); // does not need to be kept } + else if(NULL != (msp = dynamic_cast(*it))) + { + mParentId.insert(std::pair(msp->msgId, msp)); + } } // sort items into lists @@ -453,6 +463,20 @@ bool p3MsgService::loadList(std::list load) } } + /* remove missing msgId in mParentId */ + std::map::iterator mit = mParentId.begin(); + while (mit != mParentId.end()) { + if (imsg.find(mit->first) == imsg.end()) { + if (msgOutgoing.find(mit->first) == msgOutgoing.end()) { + /* not found */ + mParentId.erase(mit++); + continue; + } + } + + mit++; + } + return true; } @@ -523,7 +547,7 @@ bool p3MsgService::getMessageSummaries(std::list &msgList) } -bool p3MsgService::getMessage(std::string &mId, MessageInfo &msg) +bool p3MsgService::getMessage(const std::string &mId, MessageInfo &msg) { std::map::iterator mit; uint32_t msgId = atoi(mId.c_str()); @@ -590,7 +614,7 @@ void p3MsgService::getMessageCount(unsigned int *pnInbox, unsigned int *pnInboxN } /* remove based on the unique mid (stored in sid) */ -bool p3MsgService::removeMsgId(std::string &mid) +bool p3MsgService::removeMsgId(const std::string &mid) { std::map::iterator mit; uint32_t msgId = atoi(mid.c_str()); @@ -627,6 +651,7 @@ bool p3MsgService::removeMsgId(std::string &mid) IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ setMessageTag(mid, 0, false); + setMsgParentId(msgId, 0); rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD); } @@ -634,7 +659,7 @@ bool p3MsgService::removeMsgId(std::string &mid) return changed; } -bool p3MsgService::markMsgIdRead(std::string &mid, bool bUnreadByUser) +bool p3MsgService::markMsgIdRead(const std::string &mid, bool bUnreadByUser) { std::map::iterator mit; uint32_t msgId = atoi(mid.c_str()); @@ -677,6 +702,104 @@ bool p3MsgService::markMsgIdRead(std::string &mid, bool bUnreadByUser) return true; } +bool p3MsgService::setMsgFlag(const std::string &mid, uint32_t flag, uint32_t mask) +{ + std::map::iterator mit; + uint32_t msgId = atoi(mid.c_str()); + + bool changed = false; + + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + + mit = imsg.find(msgId); + if (mit == imsg.end()) + { + mit = msgOutgoing.find(msgId); + if (mit == msgOutgoing.end()) + { + return false; + } + } + + uint32_t oldFlag = mit->second->msgFlags; + + mit->second->msgFlags &= ~mask; + mit->second->msgFlags |= flag; + + if (mit->second->msgFlags != oldFlag) { + changed = true; + IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ + } + } /* UNLOCKED */ + + if (changed) { + rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD); + } + + return true; +} + +bool p3MsgService::getMsgParentId(const std::string &msgId, std::string &msgParentId) +{ + msgParentId.clear(); + + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + + std::map::iterator mit = mParentId.find(atoi(msgId.c_str())); + if (mit == mParentId.end()) { + return false; + } + + std::ostringstream out; + out << mit->second->msgParentId; + msgParentId = out.str(); + + return true; +} + +bool p3MsgService::setMsgParentId(uint32_t msgId, uint32_t msgParentId) +{ + std::map::iterator mit; + + bool changed = false; + + { + RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ + + mit = mParentId.find(msgId); + if (mit == mParentId.end()) + { + if (msgParentId) { + RsMsgParentId* msp = new RsMsgParentId(); + msp->PeerId (mConnMgr->getOwnId()); + msp->msgId = msgId; + msp->msgParentId = msgParentId; + mParentId.insert(std::pair(msgId, msp)); + + changed = true; + } + } else { + if (msgParentId) { + if (mit->second->msgParentId != msgParentId) { + mit->second->msgParentId = msgParentId; + changed = true; + } + } else { + delete mit->second; + mParentId.erase(mit); + changed = true; + } + } + } /* UNLOCKED */ + + if (changed) { + IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ + } + + return true; +} + /****************************************/ /****************************************/ /* Message Items */ @@ -745,7 +868,7 @@ bool p3MsgService::MessageSend(MessageInfo &info) return true; } -bool p3MsgService::MessageToDraft(MessageInfo &info) +bool p3MsgService::MessageToDraft(MessageInfo &info, const std::string &msgParentId) { RsMsgItem *msg = initMIRsMsg(info, mConnMgr->getOwnId()); if (msg) @@ -786,6 +909,8 @@ bool p3MsgService::MessageToDraft(MessageInfo &info) info.msgId = out.str(); } + setMsgParentId(msg->msgId, atoi(msgParentId.c_str())); + IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD); @@ -919,7 +1044,7 @@ bool p3MsgService::removeMessageTagType(uint32_t tagId) return true; } -bool p3MsgService::getMessageTag(std::string &msgId, MsgTagInfo& info) +bool p3MsgService::getMessageTag(const std::string &msgId, MsgTagInfo& info) { RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/ @@ -945,7 +1070,7 @@ bool p3MsgService::getMessageTag(std::string &msgId, MsgTagInfo& info) } /* set == false && tagId == 0 --> remove all */ -bool p3MsgService::setMessageTag(std::string &msgId, uint32_t tagId, bool set) +bool p3MsgService::setMessageTag(const std::string &msgId, uint32_t tagId, bool set) { uint32_t mid = atoi(msgId.c_str()); if (mid == 0) { @@ -1047,7 +1172,7 @@ bool p3MsgService::resetMessageStandardTagTypes(MsgTagType& tags) } /* move message to trash based on the unique mid */ -bool p3MsgService::MessageToTrash(std::string mid, bool bTrash) +bool p3MsgService::MessageToTrash(const std::string &mid, bool bTrash) { std::map::iterator mit; uint32_t msgId = atoi(mid.c_str()); @@ -1141,6 +1266,14 @@ void p3MsgService::initRsMI(RsMsgItem *msg, MessageInfo &mi) { mi.msgflags |= RS_MSG_UNREAD_BY_USER; } + if (msg->msgFlags & RS_MSG_FLAGS_REPLIED) + { + mi.msgflags |= RS_MSG_REPLIED; + } + if (msg->msgFlags & RS_MSG_FLAGS_FORWARDED) + { + mi.msgflags |= RS_MSG_FORWARDED; + } mi.ts = msg->sendTime; mi.srcId = msg->PeerId(); @@ -1228,6 +1361,14 @@ void p3MsgService::initRsMIS(RsMsgItem *msg, MsgInfoSummary &mis) { mis.msgflags |= RS_MSG_UNREAD_BY_USER; } + if (msg->msgFlags & RS_MSG_FLAGS_REPLIED) + { + mis.msgflags |= RS_MSG_REPLIED; + } + if (msg->msgFlags & RS_MSG_FLAGS_FORWARDED) + { + mis.msgflags |= RS_MSG_FORWARDED; + } mis.srcId = msg->PeerId(); { diff --git a/libretroshare/src/services/p3msgservice.h b/libretroshare/src/services/p3msgservice.h index 6518c9881..90d55a72e 100644 --- a/libretroshare/src/services/p3msgservice.h +++ b/libretroshare/src/services/p3msgservice.h @@ -56,23 +56,27 @@ bool MsgNotifications(); /* popup - messages */ bool getMessageNotifications(std::list ¬eList); bool getMessageSummaries(std::list &msgList); -bool getMessage(std::string &mid, MessageInfo &msg); +bool getMessage(const std::string &mid, MessageInfo &msg); void getMessageCount(unsigned int *pnInbox, unsigned int *pnInboxNew, unsigned int *pnOutbox, unsigned int *pnDraftbox, unsigned int *pnSentbox, unsigned int *pnTrashbox); -bool removeMsgId(std::string &mid); -bool markMsgIdRead(std::string &mid, bool bUnreadByUser); +bool removeMsgId(const std::string &mid); +bool markMsgIdRead(const std::string &mid, bool bUnreadByUser); +bool setMsgFlag(const std::string &mid, uint32_t flag, uint32_t mask); +bool getMsgParentId(const std::string &msgId, std::string &msgParentId); +// msgParentId == 0 --> remove +bool setMsgParentId(uint32_t msgId, uint32_t msgParentId); bool MessageSend(MessageInfo &info); -bool MessageToDraft(MessageInfo &info); -bool MessageToTrash(std::string mid, bool bTrash); +bool MessageToDraft(MessageInfo &info, const std::string &msgParentId); +bool MessageToTrash(const std::string &mid, bool bTrash); bool getMessageTagTypes(MsgTagType& tags); bool setMessageTagType(uint32_t tagId, std::string& text, uint32_t rgb_color); bool removeMessageTagType(uint32_t tagId); -bool getMessageTag(std::string &msgId, MsgTagInfo& info); +bool getMessageTag(const std::string &msgId, MsgTagInfo& info); /* set == false && tagId == 0 --> remove all */ -bool setMessageTag(std::string &msgId, uint32_t tagId, bool set); +bool setMessageTag(const std::string &msgId, uint32_t tagId, bool set); bool resetMessageStandardTagTypes(MsgTagType& tags); @@ -134,6 +138,9 @@ void initStandardTagTypes(); // used delete msgSrcIds after config save std::list mSrcIdList; + // save the parent of the messages in draft for replied and forwarded + std::map mParentId; + std::string config_dir; }; diff --git a/libretroshare/src/tests/serialiser/rsmsgitem_test.cc b/libretroshare/src/tests/serialiser/rsmsgitem_test.cc index 976c99184..6d60d25ee 100644 --- a/libretroshare/src/tests/serialiser/rsmsgitem_test.cc +++ b/libretroshare/src/tests/serialiser/rsmsgitem_test.cc @@ -124,6 +124,13 @@ RsSerialType* init_item(RsMsgSrcId& ms) return new RsMsgSerialiser(); } +RsSerialType* init_item(RsMsgParentId& ms) +{ + ms.msgId = rand()%354; + ms.msgParentId = rand()%476; + + return new RsMsgSerialiser(); +} bool operator ==(const RsChatMsgItem& cmiLeft,const RsChatMsgItem& cmiRight) { @@ -223,6 +230,14 @@ bool operator ==(const RsMsgSrcId& msLeft, const RsMsgSrcId& msRight) return true; } +bool operator ==(const RsMsgParentId& msLeft, const RsMsgParentId& msRight) +{ + if(msLeft.msgId != msRight.msgId) return false; + if(msLeft.msgParentId != msRight.msgParentId) return false; + + return true; +} + int main() { test_RsItem(); REPORT("Serialise/Deserialise RsChatMsgItem"); @@ -233,6 +248,7 @@ int main() test_RsItem(); REPORT("Serialise/Deserialise RsMsgTagType"); test_RsItem(); REPORT("Serialise/Deserialise RsMsgTags"); test_RsItem(); REPORT("Serialise/Deserialise RsMsgSrcId"); + test_RsItem(); REPORT("Serialise/Deserialise RsMsgParentId"); std::cerr << std::endl; diff --git a/retroshare-gui/src/gui/ForumsDialog.cpp b/retroshare-gui/src/gui/ForumsDialog.cpp index fca53b1b1..b621c8bae 100644 --- a/retroshare-gui/src/gui/ForumsDialog.cpp +++ b/retroshare-gui/src/gui/ForumsDialog.cpp @@ -1704,16 +1704,13 @@ void ForumsDialog::replytomessage() if (rsPeers->getPeerName(msgInfo.srcId) !="") { - MessageComposer *nMsgDialog = new MessageComposer(); - nMsgDialog->newMsg(); - nMsgDialog->insertTitleText( (QString("Re:") + " " + QString::fromStdWString(msgInfo.title)).toStdString()) ; - nMsgDialog->setWindowTitle(tr("Re:") + " " + QString::fromStdWString(msgInfo.title) ) ; + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + nMsgDialog->insertTitleText(QString::fromStdWString(msgInfo.title), MessageComposer::REPLY); QTextDocument doc ; doc.setHtml(QString::fromStdWString(msgInfo.msg)) ; - std::string cited_text(doc.toPlainText().toStdString()) ; - nMsgDialog->insertPastedText(cited_text) ; + nMsgDialog->insertPastedText(doc.toPlainText()); nMsgDialog->addRecipient(MessageComposer::TO, msgInfo.srcId, false); nMsgDialog->show(); nMsgDialog->activateWindow(); diff --git a/retroshare-gui/src/gui/MessagesDialog.cpp b/retroshare-gui/src/gui/MessagesDialog.cpp index 67f1b4dbe..1025bb296 100644 --- a/retroshare-gui/src/gui/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/MessagesDialog.cpp @@ -66,10 +66,11 @@ #define COLUMN_DATA 0 // column for storing the userdata like msgid and srcid -#define ROLE_SORT Qt::UserRole -#define ROLE_MSGID Qt::UserRole + 1 -#define ROLE_SRCID Qt::UserRole + 2 -#define ROLE_UNREAD Qt::UserRole + 3 +#define ROLE_SORT Qt::UserRole +#define ROLE_MSGID Qt::UserRole + 1 +#define ROLE_SRCID Qt::UserRole + 2 +#define ROLE_UNREAD Qt::UserRole + 3 +#define ROLE_MSGFLAGS Qt::UserRole + 4 #define ROW_INBOX 0 #define ROW_OUTBOX 1 @@ -737,11 +738,13 @@ void MessagesDialog::folderlistWidgetCostumPopupMenu(QPoint point) void MessagesDialog::newmessage() { - MessageComposer *nMsgDialog = new MessageComposer(); + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + if (nMsgDialog == NULL) { + return; + } /* fill it in */ //std::cerr << "MessagesDialog::newmessage()" << std::endl; - nMsgDialog->newMsg(); nMsgDialog->show(); nMsgDialog->activateWindow(); @@ -757,16 +760,11 @@ void MessagesDialog::editmessage() if(!getCurrentMsg(cid, mid)) return ; - MessageInfo msgInfo; - if (!rsMsgs->getMessage(mid, msgInfo)) { - std::cerr << "MessagesDialog::editmessage() Couldn't find Msg" << std::endl; + MessageComposer *pMsgDialog = MessageComposer::newMsg(mid); + if (pMsgDialog == NULL) { return; } - MessageComposer *pMsgDialog = new MessageComposer(); - /* fill it in */ - pMsgDialog->newMsg(msgInfo.msgId); - pMsgDialog->show(); pMsgDialog->activateWindow(); @@ -786,35 +784,11 @@ void MessagesDialog::replytomessage() mCurrCertId = cid; mCurrMsgId = mid; - MessageInfo msgInfo; - if (!rsMsgs -> getMessage(mid, msgInfo)) - return ; - - MessageComposer *nMsgDialog = new MessageComposer(); - /* fill it in */ - //std::cerr << "MessagesDialog::newmessage()" << std::endl; - nMsgDialog->newMsg(); - - QString text = QString::fromStdWString(msgInfo.title); - - if (text.startsWith("Re:", Qt::CaseInsensitive)) - { - nMsgDialog->insertTitleText( QString::fromStdWString(msgInfo.title).toStdString()) ; - } - else - { - nMsgDialog->insertTitleText( (QString("Re:") + " " + QString::fromStdWString(msgInfo.title)).toStdString()) ; + MessageComposer *nMsgDialog = MessageComposer::replyMsg(mid, false); + if (nMsgDialog == NULL) { + return; } - nMsgDialog->setWindowTitle( tr ("Compose: ") + tr("Re:") + " " + QString::fromStdWString(msgInfo.title) ) ; - - - QTextDocument doc ; - doc.setHtml(QString::fromStdWString(msgInfo.msg)) ; - std::string cited_text(doc.toPlainText().toStdString()) ; - - nMsgDialog->insertPastedText(cited_text) ; - nMsgDialog->addRecipient(MessageComposer::TO, msgInfo.srcId, false); nMsgDialog->show(); nMsgDialog->activateWindow(); @@ -834,40 +808,9 @@ void MessagesDialog::replyallmessage() mCurrCertId = cid; mCurrMsgId = mid; - MessageInfo msgInfo; - if (!rsMsgs -> getMessage(mid, msgInfo)) - return ; - - MessageComposer *nMsgDialog = new MessageComposer(); - /* fill it in */ - //std::cerr << "MessagesDialog::newmessage()" << std::endl; - nMsgDialog->newMsg(); - - QString text = QString::fromStdWString(msgInfo.title); - - if (text.startsWith("Re:", Qt::CaseInsensitive)) - { - nMsgDialog->insertTitleText( QString::fromStdWString(msgInfo.title).toStdString()) ; - } - else - { - nMsgDialog->insertTitleText( (QString("Re:") + " " + QString::fromStdWString(msgInfo.title)).toStdString()) ; - } - nMsgDialog->setWindowTitle( tr ("Compose: ") + tr("Re:") + " " + QString::fromStdWString(msgInfo.title) ) ; - - - QTextDocument doc ; - doc.setHtml(QString::fromStdWString(msgInfo.msg)) ; - std::string cited_text(doc.toPlainText().toStdString()) ; - - nMsgDialog->insertPastedText(cited_text) ; - nMsgDialog->addRecipient(MessageComposer::TO, msgInfo.srcId, false); - - std::list tl ( msgInfo.msgto ); - - for ( std::list::iterator tli = tl.begin(); tli!= tl.end(); tli++ ) - { - nMsgDialog->addRecipient(MessageComposer::TO, *tli, false) ; + MessageComposer *nMsgDialog = MessageComposer::replyMsg(mid, true); + if (nMsgDialog == NULL) { + return; } nMsgDialog->show(); @@ -889,46 +832,11 @@ void MessagesDialog::forwardmessage() mCurrCertId = cid; mCurrMsgId = mid; - MessageInfo msgInfo; - if (!rsMsgs -> getMessage(mid, msgInfo)) - return ; - - MessageComposer *nMsgDialog = new MessageComposer(); - /* fill it in */ - //std::cerr << "MessagesDialog::newmessage()" << std::endl; - nMsgDialog->newMsg(); - - QString text = QString::fromStdWString(msgInfo.title); - - if (text.startsWith("Fwd:", Qt::CaseInsensitive)) - { - nMsgDialog->insertTitleText( QString::fromStdWString(msgInfo.title).toStdString()) ; - } - else - { - nMsgDialog->insertTitleText( (QString("Fwd:") + " " + QString::fromStdWString(msgInfo.title)).toStdString()) ; + MessageComposer *nMsgDialog = MessageComposer::forwardMsg(mid); + if (nMsgDialog == NULL) { + return; } - nMsgDialog->setWindowTitle( tr ("Compose:") + " " + tr("Fwd:") + " " + QString::fromStdWString(msgInfo.title) ) ; - - - QTextDocument doc ; - doc.setHtml(QString::fromStdWString(msgInfo.msg)) ; - std::string cited_text(doc.toPlainText().toStdString()) ; - - nMsgDialog->insertForwardPastedText(cited_text) ; - - std::list& files_info = msgInfo.files; - - /* enable all files for sending */ - std::list::iterator it; - for(it = files_info.begin(); it != files_info.end(); it++) - { - it->inRecommend = true; - } - - nMsgDialog->insertFileList(files_info); - //nMsgDialog->addRecipient( msgInfo.srcId ) ; nMsgDialog->show(); nMsgDialog->activateWindow(); @@ -1087,31 +995,37 @@ void MessagesDialog::messagesTagsChanged() insertMessages(); } -static void InitIconAndFont(QStandardItem *pItem [COLUMN_COUNT], int nFlag) +static void InitIconAndFont(QStandardItem *pItem [COLUMN_COUNT]) { QString sText = pItem [COLUMN_SUBJECT]->text(); QString mid = pItem [COLUMN_DATA]->data(ROLE_MSGID).toString(); + int nFlag = pItem [COLUMN_DATA]->data(ROLE_MSGFLAGS).toInt(); // show the real "New" state if (nFlag & RS_MSG_NEW) { - if (sText.startsWith("Re:", Qt::CaseInsensitive)) { - pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-replied.png")); - } else if (sText.startsWith("Fwd:", Qt::CaseInsensitive)) { - pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-forwarded.png")); - } else { - pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail.png")); - } pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-state-new.png")); } else { - // Change Message icon when Subject is Re: or Fwd: - if (sText.startsWith("Re:", Qt::CaseInsensitive)) { - pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-replied-read.png")); - } else if (sText.startsWith("Fwd:", Qt::CaseInsensitive)) { - pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-forwarded-read.png")); + if (nFlag & RS_MSG_UNREAD_BY_USER) { + if ((nFlag & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_REPLIED) { + pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-replied.png")); + } else if ((nFlag & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_FORWARDED) { + pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-forwarded.png")); + } else if ((nFlag & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == (RS_MSG_REPLIED | RS_MSG_FORWARDED)) { + pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-replied-forw.png")); + } else { + pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail.png")); + } } else { - pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-read.png")); + if ((nFlag & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_REPLIED) { + pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-replied-read.png")); + } else if ((nFlag & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_FORWARDED) { + pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-forwarded-read.png")); + } else if ((nFlag & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == (RS_MSG_REPLIED | RS_MSG_FORWARDED)) { + pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-replied-forw-read.png")); + } else { + pItem[COLUMN_SUBJECT]->setIcon(QIcon(":/images/message-mail-read.png")); + } } - pItem[COLUMN_SUBJECT]->setIcon(QIcon()); } bool bNew = nFlag & (RS_MSG_NEW | RS_MSG_UNREAD_BY_USER); @@ -1405,9 +1319,10 @@ void MessagesDialog::insertMessages() QString msgId = QString::fromStdString(it->msgId); item[COLUMN_DATA]->setData(QString::fromStdString(it->srcId), ROLE_SRCID); item[COLUMN_DATA]->setData(msgId, ROLE_MSGID); + item[COLUMN_DATA]->setData(it->msgflags, ROLE_MSGFLAGS); // Init icon and font - InitIconAndFont(item, it->msgflags); + InitIconAndFont(item); // Tags MsgTagInfo tagInfo; @@ -1555,7 +1470,18 @@ void MessagesDialog::setMsgAsReadUnread(const QList &Rows, bool bRead) std::string mid = item[COLUMN_DATA]->data(ROLE_MSGID).toString().toStdString(); if (rsMsgs->MessageRead(mid, !bRead)) { - InitIconAndFont(item, bRead ? 0 : RS_MSG_UNREAD_BY_USER); + int nFlag = item[COLUMN_DATA]->data(ROLE_MSGFLAGS).toInt(); + nFlag &= ~RS_MSG_NEW; + + if (bRead) { + nFlag &= ~RS_MSG_UNREAD_BY_USER; + } else { + nFlag |= RS_MSG_UNREAD_BY_USER; + } + + item[COLUMN_DATA]->setData(nFlag, ROLE_MSGFLAGS); + + InitIconAndFont(item); } } diff --git a/retroshare-gui/src/gui/PeersDialog.cpp b/retroshare-gui/src/gui/PeersDialog.cpp index 641947477..27284db61 100644 --- a/retroshare-gui/src/gui/PeersDialog.cpp +++ b/retroshare-gui/src/gui/PeersDialog.cpp @@ -1433,9 +1433,9 @@ void PeersDialog::insertChat() QString notifyMsg = name + ": " + editor.toPlainText(); if(notifyMsg.length() > 30) - emit notifyGroupChat(QString("New group chat"), notifyMsg.left(30) + QString("...")); + emit notifyGroupChat(tr("New group chat"), notifyMsg.left(30) + QString("...")); else - emit notifyGroupChat(QString("New group chat"), notifyMsg); + emit notifyGroupChat(tr("New group chat"), notifyMsg); } historyKeeper.addMessage(incoming, it->rsid, name, sendTime, recvTime, msg); diff --git a/retroshare-gui/src/gui/PeersDialog.ui b/retroshare-gui/src/gui/PeersDialog.ui index 79267e27a..f03ebb96a 100644 --- a/retroshare-gui/src/gui/PeersDialog.ui +++ b/retroshare-gui/src/gui/PeersDialog.ui @@ -899,7 +899,7 @@ p, li { white-space: pre-wrap; } - Live Chat + Group Chat diff --git a/retroshare-gui/src/gui/SearchDialog.cpp b/retroshare-gui/src/gui/SearchDialog.cpp index 2d9f14ed4..1fad2ef5b 100644 --- a/retroshare-gui/src/gui/SearchDialog.cpp +++ b/retroshare-gui/src/gui/SearchDialog.cpp @@ -1199,12 +1199,14 @@ void SearchDialog::sendLinkTo( ) copysearchLink(); /* create a message */ - MessageComposer *nMsgDialog = new MessageComposer(); + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + if (nMsgDialog == NULL) { + return; + } - nMsgDialog->newMsg(); - nMsgDialog->insertTitleText("New RetroShare Link(s)"); + nMsgDialog->insertTitleText(tr("New RetroShare Link(s)")); - nMsgDialog->insertMsgText(RSLinkClipboard::toHtml().toStdString()) ; + nMsgDialog->insertMsgText(RSLinkClipboard::toHtml()) ; nMsgDialog->show(); /* window will destroy itself! */ diff --git a/retroshare-gui/src/gui/SharedFilesDialog.cpp b/retroshare-gui/src/gui/SharedFilesDialog.cpp index 40b916ff7..6cc3129cc 100644 --- a/retroshare-gui/src/gui/SharedFilesDialog.cpp +++ b/retroshare-gui/src/gui/SharedFilesDialog.cpp @@ -410,16 +410,18 @@ void SharedFilesDialog::sendremoteLinkTo() copyLinkRemote (); /* create a message */ - MessageComposer *nMsgDialog = new MessageComposer(); + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + if (nMsgDialog == NULL) { + return; + } /* fill it in * files are receommended already * just need to set peers */ std::cerr << "SharedFilesDialog::sendremoteLinkTo()" << std::endl; - nMsgDialog->newMsg(); - nMsgDialog->insertTitleText("RetroShare Link"); - nMsgDialog->insertMsgText(RSLinkClipboard::toHtml().toStdString()); + nMsgDialog->insertTitleText(tr("RetroShare Link")); + nMsgDialog->insertMsgText(RSLinkClipboard::toHtml()); nMsgDialog->show(); @@ -431,40 +433,43 @@ void SharedFilesDialog::sendLinkTo() copyLinkLocal (); /* create a message */ - MessageComposer *nMsgDialog = new MessageComposer(); - + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + if (nMsgDialog == NULL) { + return; + } /* fill it in * files are receommended already * just need to set peers */ std::cerr << "SharedFilesDialog::sendLinkTo()" << std::endl; - nMsgDialog->newMsg(); - nMsgDialog->insertTitleText("RetroShare Link"); + nMsgDialog->insertTitleText(tr("RetroShare Link")); - nMsgDialog->insertMsgText(RSLinkClipboard::toHtml().toStdString()); + nMsgDialog->insertMsgText(RSLinkClipboard::toHtml()); nMsgDialog->show(); /* window will destroy itself! */ } -void SharedFilesDialog::sendHtmlLinkTo( ) +void SharedFilesDialog::sendHtmlLinkTo() { copyLinkLocal (); /* create a message */ - MessageComposer *nMsgDialog = new MessageComposer(); + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + if (nMsgDialog == NULL) { + return; + } /* fill it in * files are receommended already * just need to set peers */ std::cerr << "SharedFilesDialog::sendLinkTo()" << std::endl; - nMsgDialog->newMsg(); - nMsgDialog->insertTitleText("RetroShare Link"); + nMsgDialog->insertTitleText(tr("RetroShare Link")); // nMsgDialog->insertHtmlText(QApplication::clipboard()->text().toStdString());// not compatible with multiple links - nMsgDialog->insertMsgText(RSLinkClipboard::toHtml().toStdString()); + nMsgDialog->insertMsgText(RSLinkClipboard::toHtml()); nMsgDialog->show(); @@ -588,7 +593,10 @@ void SharedFilesDialog::recommendFilesTo( std::string rsid ) return ; /* create a message */ - MessageComposer *nMsgDialog = new MessageComposer(); + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + if (nMsgDialog == NULL) { + return; + } /* fill it in * files are receommended already @@ -596,9 +604,14 @@ void SharedFilesDialog::recommendFilesTo( std::string rsid ) */ nMsgDialog->insertFileList(files_info) ; - nMsgDialog->newMsg(); - nMsgDialog->insertTitleText("Recommendation(s)"); - nMsgDialog->insertMsgText(rsPeers->getPeerName(rsPeers->getOwnId())+" recommends " + ( (files_info.size()>1)?"a list of files":"a file")+" to you"); + nMsgDialog->insertTitleText(tr("Recommendation(s)")); + + QString peerName = QString::fromStdString(rsPeers->getPeerName(rsPeers->getOwnId())); + if (files_info.size() > 1) { + nMsgDialog->insertMsgText(tr("%1 recommends a list of files to you").arg(peerName)); + } else { + nMsgDialog->insertMsgText(tr("%1 recommends a file to you").arg(peerName)); + } nMsgDialog->addRecipient(MessageComposer::TO, rsid, false) ; nMsgDialog->sendMessage(); @@ -618,12 +631,14 @@ void SharedFilesDialog::recommendFilesToMsg( std::string rsid ) /* create a message */ - MessageComposer *nMsgDialog = new MessageComposer(); + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + if (nMsgDialog == NULL) { + return; + } nMsgDialog->insertFileList(files_info) ; - nMsgDialog->newMsg(); - nMsgDialog->insertTitleText("Recommendation(s)"); - nMsgDialog->insertMsgText("Recommendation(s)"); + nMsgDialog->insertTitleText(tr("Recommendation(s)")); + nMsgDialog->insertMsgText(tr("Recommendation(s)")); nMsgDialog->show(); std::cout << "recommending to " << rsid << std::endl ; diff --git a/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp b/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp index 9a2a656d4..b166b4c14 100644 --- a/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp +++ b/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp @@ -196,8 +196,10 @@ void ChatMsgItem::sendMsg() if (mParent) { - MessageComposer *nMsgDialog = new MessageComposer(); - nMsgDialog->newMsg(); + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + if (nMsgDialog == NULL) { + return; + } nMsgDialog->addRecipient(MessageComposer::TO, mPeerId, false); nMsgDialog->show(); diff --git a/retroshare-gui/src/gui/feeds/MsgItem.cpp b/retroshare-gui/src/gui/feeds/MsgItem.cpp index 5c9d3d9cd..c78ae4ec0 100644 --- a/retroshare-gui/src/gui/feeds/MsgItem.cpp +++ b/retroshare-gui/src/gui/feeds/MsgItem.cpp @@ -254,26 +254,15 @@ void MsgItem::replyMsg() { //mParent->openMsg(FEEDHOLDER_MSG_MESSAGE, mPeerId, mMsgId); - MessageInfo msgInfo; - if (!rsMsgs -> getMessage(mMsgId, msgInfo)) - return ; + MessageComposer *nMsgDialog = MessageComposer::replyMsg(mMsgId, false); + if (nMsgDialog == NULL) { + return; + } - MessageComposer *nMsgDialog = new MessageComposer(); - nMsgDialog->newMsg(); - nMsgDialog->insertTitleText( (QString("Re: ") + QString::fromStdWString(msgInfo.title)).toStdString()) ; - nMsgDialog->setWindowTitle(tr("Re: ") + QString::fromStdWString(msgInfo.title) ) ; - - QTextDocument doc ; - doc.setHtml(QString::fromStdWString(msgInfo.msg)) ; - std::string cited_text(doc.toPlainText().toStdString()) ; - - nMsgDialog->insertPastedText(cited_text) ; - nMsgDialog->addRecipient(MessageComposer::TO, msgInfo.srcId, false); nMsgDialog->show(); nMsgDialog->activateWindow(); /* window will destroy itself! */ - } } diff --git a/retroshare-gui/src/gui/feeds/PeerItem.cpp b/retroshare-gui/src/gui/feeds/PeerItem.cpp index b5256fecf..46482ce9f 100644 --- a/retroshare-gui/src/gui/feeds/PeerItem.cpp +++ b/retroshare-gui/src/gui/feeds/PeerItem.cpp @@ -302,8 +302,10 @@ void PeerItem::sendMsg() { //mParent->openMsg(FEEDHOLDER_MSG_MESSAGE, mPeerId, ""); - MessageComposer *nMsgDialog = new MessageComposer(); - nMsgDialog->newMsg(); + MessageComposer *nMsgDialog = MessageComposer::newMsg(); + if (nMsgDialog == NULL) { + return; + } nMsgDialog->addRecipient(MessageComposer::TO, mPeerId, false); nMsgDialog->show(); diff --git a/retroshare-gui/src/gui/images.qrc b/retroshare-gui/src/gui/images.qrc index a679d8ad8..c8f8ee230 100644 --- a/retroshare-gui/src/gui/images.qrc +++ b/retroshare-gui/src/gui/images.qrc @@ -282,6 +282,8 @@ images/message-mail-forwarded-read.png images/message-mail-replied.png images/message-mail-forwarded.png + images/message-mail-replied-forw.png + images/message-mail-replied-forw-read.png images/message-state-read.png images/message-state-unread.png images/message-state-header.png diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.cpp b/retroshare-gui/src/gui/msgs/MessageComposer.cpp index 95546115d..31ddfb3a7 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.cpp +++ b/retroshare-gui/src/gui/msgs/MessageComposer.cpp @@ -102,6 +102,8 @@ MessageComposer::MessageComposer(QWidget *parent, Qt::WFlags flags) /* Invoke the Qt Designer generated object setup routine */ ui.setupUi(this); + m_msgType = NORMAL; + setupFileActions(); setupEditActions(); setupViewActions(); @@ -275,6 +277,9 @@ MessageComposer::MessageComposer(QWidget *parent, Qt::WFlags flags) // load settings processSettings(true); + /* worker fns */ + insertSendList(); + /* set focus to subject */ ui.titleEdit->setFocus(); @@ -322,9 +327,10 @@ void MessageComposer::processSettings(bool bLoad) /* create a message */ - MessageComposer *pMsgDialog = new MessageComposer(); - - pMsgDialog->newMsg(); + MessageComposer *pMsgDialog = MessageComposer::newMsg(); + if (pMsgDialog == NULL) { + return; + } if (group) { pMsgDialog->addRecipient(TO, id, true); @@ -383,15 +389,13 @@ void MessageComposer::recommendFriend(std::list &peerids) } /* create a message */ - MessageComposer *pMsgDialog = new MessageComposer(); + MessageComposer *pMsgDialog = MessageComposer::newMsg(); - pMsgDialog->newMsg(); - pMsgDialog->setWindowTitle(tr("Compose") + ": " + tr("Friend Recommendation")) ; - pMsgDialog->insertTitleText(tr("Friend Recommendation(s)").toStdString()); + pMsgDialog->insertTitleText(tr("Friend Recommendation(s)")); - std::string sMsgText = tr("I recommend a good friend of me, you can trust him too when you trust me.
Copy friend link and paste to Friends list").toStdString(); + QString sMsgText = tr("I recommend a good friend of me, you can trust him too when you trust me.
Copy friend link and paste to Friends list"); sMsgText += "

"; - sMsgText += BuildRecommendHtml(peerids).toStdString(); + sMsgText += BuildRecommendHtml(peerids); pMsgDialog->insertMsgText(sMsgText); // pMsgDialog->insertFileList(files_info); @@ -704,7 +708,7 @@ void MessageComposer::insertFileList(const std::list& files_info) /* make a widget per person */ QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)0); - item->setText(0, QString::fromStdString(it->fname)); /* (0) Filename */ + item->setText(0, QString::fromUtf8(it->fname.c_str())); /* (0) Filename */ item->setText(1, misc::friendlyUnit(it->size)); /* (1) Size */ item->setText(2, QString::number(0)) ;//it->rank)); item->setText(3, QString::fromStdString(it->hash)); @@ -820,38 +824,38 @@ static void calculateGroupsOfSslIds(std::list &existingGroupInfos, } } -void MessageComposer::newMsg(std::string msgId /*= ""*/) +MessageComposer *MessageComposer::newMsg(const std::string &msgId /*= ""*/) { - /* clear all */ - ui.msgText->setText(""); + MessageComposer *msgComposer = new MessageComposer(); - /* worker fns */ - insertSendList(); + msgComposer->addEmptyRecipient(); - ui.recipientWidget->setRowCount(0); - addEmptyRecipient(); - - m_sMsgId = msgId; - m_sDraftMsgId.clear(); - - if (m_sMsgId.empty() == false) { + if (msgId.empty() == false) { // fill existing message MessageInfo msgInfo; - if (!rsMsgs->getMessage(m_sMsgId, msgInfo)) { + if (!rsMsgs->getMessage(msgId, msgInfo)) { std::cerr << "MessageComposer::newMsg() Couldn't find Msg" << std::endl; - m_sMsgId.clear(); - return; + delete msgComposer; + return NULL; } if (msgInfo.msgflags & RS_MSG_DRAFT) { - m_sDraftMsgId = msgId; + msgComposer->m_sDraftMsgId = msgId; + + rsMsgs->getMsgParentId(msgId, msgComposer->m_msgParentId); + + if (msgInfo.msgflags & RS_MSG_REPLIED) { + msgComposer->m_msgType = REPLY; + } else if (msgInfo.msgflags & RS_MSG_FORWARDED) { + msgComposer->m_msgType = FORWARD; + } } - insertTitleText( QString::fromStdWString(msgInfo.title).toStdString()); + msgComposer->insertTitleText(QString::fromStdWString(msgInfo.title)); - insertMsgText(QString::fromStdWString(msgInfo.msg).toStdString()); + msgComposer->insertMsgText(QString::fromStdWString(msgInfo.msg)); - insertFileList(msgInfo.files); + msgComposer->insertFileList(msgInfo.files); // get existing groups std::list groupInfoList; @@ -863,48 +867,152 @@ void MessageComposer::newMsg(std::string msgId /*= ""*/) calculateGroupsOfSslIds(groupInfoList, msgInfo.msgto, groupIds); for (groupIt = groupIds.begin(); groupIt != groupIds.end(); groupIt++ ) { - addRecipient(MessageComposer::TO, *groupIt, true) ; + msgComposer->addRecipient(MessageComposer::TO, *groupIt, true) ; } for (it = msgInfo.msgto.begin(); it != msgInfo.msgto.end(); it++ ) { - addRecipient(MessageComposer::TO, *it, false) ; + msgComposer->addRecipient(MessageComposer::TO, *it, false) ; } calculateGroupsOfSslIds(groupInfoList, msgInfo.msgcc, groupIds); for (groupIt = groupIds.begin(); groupIt != groupIds.end(); groupIt++ ) { - addRecipient(MessageComposer::CC, *groupIt, true) ; + msgComposer->addRecipient(MessageComposer::CC, *groupIt, true) ; } for (it = msgInfo.msgcc.begin(); it != msgInfo.msgcc.end(); it++ ) { - addRecipient(MessageComposer::CC, *it, false) ; + msgComposer->addRecipient(MessageComposer::CC, *it, false) ; } calculateGroupsOfSslIds(groupInfoList, msgInfo.msgbcc, groupIds); for (groupIt = groupIds.begin(); groupIt != groupIds.end(); groupIt++ ) { - addRecipient(MessageComposer::BCC, *groupIt, true) ; + msgComposer->addRecipient(MessageComposer::BCC, *groupIt, true) ; } for (it = msgInfo.msgbcc.begin(); it != msgInfo.msgbcc.end(); it++ ) { - addRecipient(MessageComposer::BCC, *it, false) ; + msgComposer->addRecipient(MessageComposer::BCC, *it, false) ; } - ui.msgText->document()->setModified(false); + msgComposer->ui.msgText->document()->setModified(false); } else { - insertTitleText(tr("No Title").toStdString()); + msgComposer->insertTitleText(tr("No Title")); } - calculateTitle(); + msgComposer->calculateTitle(); + + return msgComposer; } -void MessageComposer::insertTitleText(std::string title) +MessageComposer *MessageComposer::replyMsg(const std::string &msgId, bool all) { - ui.titleEdit->setText(QString::fromStdString(title)); + MessageInfo msgInfo; + if (!rsMsgs->getMessage(msgId, msgInfo)) { + return NULL; + } + + MessageComposer *msgComposer = MessageComposer::newMsg(); + msgComposer->m_msgParentId = msgId; + msgComposer->m_msgType = REPLY; + + /* fill it in */ + + msgComposer->insertTitleText(QString::fromStdWString(msgInfo.title), REPLY); + + QTextDocument doc ; + doc.setHtml(QString::fromStdWString(msgInfo.msg)); + + msgComposer->insertPastedText(doc.toPlainText()); + msgComposer->addRecipient(MessageComposer::TO, msgInfo.srcId, false); + + if (all) { + std::string ownId = rsPeers->getOwnId(); + + for (std::list::iterator tli = msgInfo.msgto.begin(); tli != msgInfo.msgto.end(); tli++) { + if (ownId != *tli) { + msgComposer->addRecipient(MessageComposer::TO, *tli, false) ; + } + } + + for (std::list::iterator tli = msgInfo.msgcc.begin(); tli != msgInfo.msgcc.end(); tli++) { + if (ownId != *tli) { + msgComposer->addRecipient(MessageComposer::TO, *tli, false) ; + } + } + } + + msgComposer->calculateTitle(); + + /* window will destroy itself! */ + + return msgComposer; } -void MessageComposer::insertPastedText(std::string msg) +MessageComposer *MessageComposer::forwardMsg(const std::string &msgId) { - std::string::size_type i=0 ; - while( (i=msg.find_first_of('\n',i+1)) < msg.size()) - msg.replace(i,1,std::string("\n
> ")) ; + MessageInfo msgInfo; + if (!rsMsgs->getMessage(msgId, msgInfo)) { + return NULL; + } - ui.msgText->setHtml(QString("")+QString::fromStdString(std::string("> ") + msg)+"

") ; + MessageComposer *msgComposer = MessageComposer::newMsg(); + msgComposer->m_msgParentId = msgId; + msgComposer->m_msgType = FORWARD; + + /* fill it in */ + + msgComposer->insertTitleText(QString::fromStdWString(msgInfo.title), FORWARD); + + QTextDocument doc ; + doc.setHtml(QString::fromStdWString(msgInfo.msg)) ; + + msgComposer->insertForwardPastedText(doc.toPlainText()); + + std::list& files_info = msgInfo.files; + + /* enable all files for sending */ + std::list::iterator it; + for(it = files_info.begin(); it != files_info.end(); it++) + { + it->inRecommend = true; + } + + msgComposer->insertFileList(files_info); + + msgComposer->calculateTitle(); + + /* window will destroy itself! */ + + return msgComposer; +} + +void MessageComposer::insertTitleText(const QString &title, enumMessageType type) +{ + QString titleText; + + switch (type) { + case NORMAL: + titleText = title; + break; + case REPLY: + if (title.startsWith("Re:", Qt::CaseInsensitive)) { + titleText = title; + } else { + titleText = tr("Re:") + " " + title; + } + break; + case FORWARD: + if (title.startsWith("Fwd:", Qt::CaseInsensitive)) { + titleText = title; + } else { + titleText = tr("Fwd:") + " " + title; + } + break; + } + + ui.titleEdit->setText(titleText); +} + +void MessageComposer::insertPastedText(QString msg) +{ + msg.replace("\n", "\n
> "); + + ui.msgText->setHtml(" > " + msg + "

"); ui.msgText->setFocus( Qt::OtherFocusReason ); @@ -915,13 +1023,11 @@ void MessageComposer::insertPastedText(std::string msg) ui.msgText->document()->setModified(true); } -void MessageComposer::insertForwardPastedText(std::string msg) +void MessageComposer::insertForwardPastedText(QString msg) { - std::string::size_type i=0 ; - while( (i=msg.find_first_of('\n',i+1)) < msg.size()) - msg.replace(i,1,std::string("\n
> ")) ; + msg.replace("\n", "\n
> "); - ui.msgText->setHtml(QString("
")+QString::fromStdString(std::string("") + msg)+"

") ; + ui.msgText->setHtml("
> " + msg + "

"); ui.msgText->setFocus( Qt::OtherFocusReason ); @@ -932,9 +1038,9 @@ void MessageComposer::insertForwardPastedText(std::string msg) ui.msgText->document()->setModified(true); } -void MessageComposer::insertMsgText(std::string msg) +void MessageComposer::insertMsgText(const QString &msg) { - ui.msgText->setText(QString::fromStdString(msg)); + ui.msgText->setText(msg); ui.msgText->setFocus( Qt::OtherFocusReason ); @@ -945,9 +1051,9 @@ void MessageComposer::insertMsgText(std::string msg) ui.msgText->document()->setModified(true); } -void MessageComposer::insertHtmlText(std::string msg) +void MessageComposer::insertHtmlText(const QString &msg) { - ui.msgText->setHtml(QString(" ") ) + QString::fromStdString(std::string(msg)) + "") ; + ui.msgText->setHtml(" " + msg + ""); ui.msgText->document()->setModified(true); } @@ -1058,17 +1164,47 @@ bool MessageComposer::sendMessage_internal(bool bDraftbox) if (bDraftbox) { mi.msgId = m_sDraftMsgId; - rsMsgs->MessageToDraft(mi); + + rsMsgs->MessageToDraft(mi, m_msgParentId); // use new message id m_sDraftMsgId = mi.msgId; + + switch (m_msgType) { + case NORMAL: + break; + case REPLY: + rsMsgs->MessageReplied(m_sDraftMsgId, true); + break; + case FORWARD: + rsMsgs->MessageForwarded(m_sDraftMsgId, true); + break; + } + + // PROBLEM: message to set reply/forwarded get lost } else { /* check for the recipient */ if (mi.msgto.empty()) { QMessageBox::warning(this, tr("RetroShare"), tr("Please insert at least one recipient."), QMessageBox::Ok); return false; // Don't send with no recipient } - rsMsgs->MessageSend(mi); + + if (rsMsgs->MessageSend(mi) == false) { + return false; + } + + if (m_msgParentId.empty() == false) { + switch (m_msgType) { + case NORMAL: + break; + case REPLY: + rsMsgs->MessageReplied(m_msgParentId, true); + break; + case FORWARD: + rsMsgs->MessageForwarded(m_msgParentId, true); + break; + } + } } ui.msgText->document()->setModified(false); @@ -1748,7 +1884,6 @@ void MessageComposer::saveasDraft() sendMessage_internal(true); } - void MessageComposer::filePrint() { #ifndef QT_NO_PRINTER diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.h b/retroshare-gui/src/gui/msgs/MessageComposer.h index 06abac2a2..fe8510b24 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.h +++ b/retroshare-gui/src/gui/msgs/MessageComposer.h @@ -40,6 +40,7 @@ class MessageComposer : public QMainWindow public: enum enumType { TO, CC, BCC }; + enum enumMessageType { NORMAL, REPLY, FORWARD }; public: /** Default Constructor */ @@ -50,22 +51,23 @@ public: static void msgFriend(std::string id, bool group); static void recommendFriend(std::list &peerids); - void newMsg(std::string msgId = ""); + static MessageComposer *newMsg(const std::string &msgId = ""); + static MessageComposer *replyMsg(const std::string &msgId, bool all); + static MessageComposer *forwardMsg(const std::string &msgId); /* worker fns */ void insertSendList(); void insertFileList(const std::list&); void insertFileList(const std::list&); - void insertTitleText(std::string title); - void insertPastedText(std::string msg) ; - void insertForwardPastedText(std::string msg); - void insertHtmlText(std::string msg); - void insertMsgText(std::string msg); + void insertTitleText(const QString &title, enumMessageType type = NORMAL); + void insertPastedText(QString msg) ; + void insertForwardPastedText(QString msg); + void insertHtmlText(const QString &msg); + void insertMsgText(const QString &msg); void addRecipient(enumType type, const std::string &id, bool group); void Create_New_Image_Tag(const QString urlremoteorlocal); public slots: - /* actions to take.... */ void sendMessage(); void cancelMessage(); @@ -73,7 +75,6 @@ public slots: void changeFormatType(int styleIndex ); - protected: void closeEvent (QCloseEvent * event); bool eventFilter(QObject *obj, QEvent *ev); @@ -155,7 +156,7 @@ private: void colorChanged(const QColor &c); void alignmentChanged(Qt::Alignment a); - bool sendMessage_internal(bool bDraftbox); + bool sendMessage_internal(bool bDraftbox); void FilterItems(); bool FilterItem(QTreeWidgetItem *pItem, QString &sPattern); @@ -191,8 +192,9 @@ private: QHash autoLinkTitleDictionary; QHash autoLinkTargetDictionary; - std::string m_sMsgId; // existing message id + std::string m_msgParentId; // parent message id std::string m_sDraftMsgId; // existing message id + enumMessageType m_msgType; /* maps of files */ std::list mAttachments; diff --git a/retroshare-gui/src/lang/retroshare_de.qm b/retroshare-gui/src/lang/retroshare_de.qm index b7a5e09c7..5f67ea327 100644 Binary files a/retroshare-gui/src/lang/retroshare_de.qm and b/retroshare-gui/src/lang/retroshare_de.qm differ diff --git a/retroshare-gui/src/lang/retroshare_de.ts b/retroshare-gui/src/lang/retroshare_de.ts index 0218907c8..63cc640bc 100644 --- a/retroshare-gui/src/lang/retroshare_de.ts +++ b/retroshare-gui/src/lang/retroshare_de.ts @@ -1183,7 +1183,7 @@ Verfügbar: %3 Abbrechen - + Quick Message Schnelle Nachrricht @@ -3550,27 +3550,22 @@ p, li { white-space: pre-wrap; } - + RetroShare - + No Forum Selected! Kein Forum ausgewählt! - - Re: - - - - + You cant reply a Anonymous Author Du kannst einem anonymen Autor nicht antworten - + Your Forums Deine Foren @@ -5289,8 +5284,7 @@ Bitte gib etwas Speicher frei und drücke OK. MessageComposer - - + Compose Verfassen @@ -5432,7 +5426,7 @@ Bitte gib etwas Speicher frei und drücke OK. Setzt Schriftart auf Codestil - + To An @@ -5522,7 +5516,7 @@ Bitte gib etwas Speicher frei und drücke OK. Blockquote hinzufügen - + &Left &Links @@ -5542,36 +5536,46 @@ Bitte gib etwas Speicher frei und drücke OK. &Blocksatz - - + + Save Message Nachricht speichern - + Message has not been Sent. Do you want to save message to draft box? Nachricht wurde noch nicht gesendet. Möchtest Du die Nachricht in den Entwürfen speichern? - - + + Re: + Re: + + + + Fwd: + Fwd: + + + + RetroShare - + Do you want to send the message without a subject ? Möchtest Du die Nachricht ohne Betreff senden ? - + Please insert at least one recipient. Bitte geben sie mindestens einen Empfänger ein. - + Unknown Unbekannt @@ -5702,7 +5706,7 @@ Möchtest Du die Nachricht in den Entwürfen speichern? Speichern unter... - + Print Document Dokument drucken @@ -5729,12 +5733,7 @@ Willst Du die Nachricht speichern ? Zusätzliche Datei hinzufügen - - Friend Recommendation - Freundempfehlung - - - + Friend Recommendation(s) Freundempfehlung(en) @@ -5834,7 +5833,7 @@ Willst Du die Nachricht speichern ? MessagesDialog - + New Message Neue Nachricht @@ -5857,7 +5856,7 @@ Willst Du die Nachricht speichern ? - + From Von @@ -5942,15 +5941,15 @@ p, li { white-space: pre-wrap; } - + Inbox Posteingang - - + + Outbox Postausgang @@ -5962,7 +5961,7 @@ p, li { white-space: pre-wrap; } - + Sent Gesendet @@ -6024,13 +6023,13 @@ p, li { white-space: pre-wrap; } Speichern unter... - + Print Document Dokument drucken - + Subject Betreff @@ -6090,19 +6089,7 @@ p, li { white-space: pre-wrap; } Herunterladen - - - Compose: - Verfassen: - - - - - Re: - - - - + Hide Empfohlene Dateien ausblenden @@ -6112,7 +6099,7 @@ p, li { white-space: pre-wrap; } Empfohlene Dateien einblenden - + Save as... Speichern unter... @@ -6122,7 +6109,7 @@ p, li { white-space: pre-wrap; } HTML-Dateien (*.htm *.html);;Alle Dateien (*) - + Reply to All Allen antworten @@ -6161,8 +6148,8 @@ p, li { white-space: pre-wrap; } - - + + Trash Papierkorb @@ -6178,7 +6165,7 @@ p, li { white-space: pre-wrap; } Ordner - + Remove All Tags Alle Schlagwörter entfernen @@ -6208,34 +6195,24 @@ p, li { white-space: pre-wrap; } Papierkorb leeren - - Compose: - Verfassen: - - - - Fwd: - - - - - + + Drafts Entwürfe - + To An - + Edit... Editieren... - + @@ -6421,17 +6398,12 @@ p, li { white-space: pre-wrap; } Medium abspielen - - Re: - Re: - - - + Reply Message Auf Nachricht antworten - + Hide Verbergen @@ -7226,7 +7198,7 @@ p, li { white-space: pre-wrap; } Verbergen - + Quick Message Schnelle Nachrricht @@ -7377,7 +7349,13 @@ p, li { white-space: pre-wrap; } Verfügbar - + + + New group chat + Neuer Gruppenchat + + + Add Extra File Zusätzliche Datei hinzufügen @@ -7436,12 +7414,7 @@ p, li { white-space: pre-wrap; } Statusnachricht ändern - - Live Chat - - - - + Bold Fett @@ -7510,7 +7483,12 @@ p, li { white-space: pre-wrap; } Schriftart - + + Group Chat + Gruppenchat + + + <!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; } @@ -9221,6 +9199,11 @@ p, li { white-space: pre-wrap; } Folder Ordner + + + New RetroShare Link(s) + Neu(e) RetroShare Link(s) + Any @@ -9267,7 +9250,7 @@ p, li { white-space: pre-wrap; } Such ID - + Download Notice Download @@ -9964,22 +9947,22 @@ p, li { white-space: pre-wrap; } - + Open File Datei öffnen - + Open Folder Ordner öffnen - + Set command for opening this file Setze eine Regel zum Öffnen dieser Datei - + Copy retroshare Link Kopiere RetroShare Link @@ -9999,7 +9982,17 @@ p, li { white-space: pre-wrap; } Sende RetroShare Link - + + %1 recommends a list of files to you + %1 empfiehlt Dir eine Liste von Dateien + + + + %1 recommends a file to you + %1 empfiehlt Dir eine Datei + + + Recommend (Automated message) To Empfehle (automatisch) in einer Nachricht an @@ -10009,7 +10002,7 @@ p, li { white-space: pre-wrap; } Empfehle in einer Nachricht an - + Copy retroshare Links to Clipboard Kopiere RetroShare Links in die Zwischenablage @@ -10039,7 +10032,21 @@ p, li { white-space: pre-wrap; } Füge die Links zur Verknüpfungs-Wolke hinzu - + + + + RetroShare Link + RetroShare Link + + + + + + Recommendation(s) + Empfehlung(en) + + + <strong>My Shared Files</strong> <strong>Meine Dateien</strong>