Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2419|回复: 4
打印 上一主题 下一主题

已读未读的原理

[复制链接]

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
跳转到指定楼层
楼主
发表于 2015-11-1 23:11:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 hechengjin 于 2015-11-1 23:38 编辑

  1. 已读:
  2. //////////////界面点选中邮件,自动标志为已读的流程///////////////

  3. messenger.xul
  4. onselect="ThreadPaneSelectionChanged();"
  5. function ThreadPaneSelectionChanged()
  6. {
  7.   GetThreadTree().view.selectionChanged();
  8. }

  9. .\mailnews\base\src\nsMsgDBView.cpp
  10. NS_IMETHODIMP nsMsgDBView::SelectionChanged()
  11. {
  12. ????
  13. }

  14. nsImapMailFolder::MarkMessagesRead(nsIArray *messages, bool markRead)
  15. {
  16.         StoreImapFlags(kImapMsgSeenFlag, markRead, keysToMarkRead.Elements(), keysToMarkRead.Length(), nullptr);
  17. }
  18. nsImapMailFolder::StoreImapFlags(int32_t flags, bool addFlags,
  19. {
  20. imapService->AddMessageFlags(this, aUrlListener ? aUrlListener : this,
  21.                                    nullptr, msgIds, flags, true);
  22. }
  23. nsImapService::AddMessageFlags(nsIMsgFolder *aImapMailFolder,
  24. {
  25.          return DiddleFlags(aImapMailFolder, aUrlListener, aURL, messageIdentifierList,
  26.                      "addmsgflags", flags, messageIdsAreUID);
  27. }

  28. nsImapService::DiddleFlags(nsIMsgFolder *aImapMailFolder,
  29. {
  30.         nsresult rv = CreateStartOfImapUrl(EmptyCString(), getter_AddRefs(imapUrl),
  31.         rv = uri->SetSpec(urlSpec);
  32. }
  33. nsImapUrl::SetSpec(const nsACString &aSpec)
  34. {
  35.         rv = ParseUrl();
  36. }
  37. nsresult nsImapUrl::ParseUrl()
  38. {
  39.         ParseImapPart(unescapedImapPartOfUrl.BeginWriting()+1);
  40. }

  41. ??????????




  42. nsImapProtocol::Run()
  43. nsImapProtocol::ImapThreadMainLoop()
  44. nsImapProtocol::ProcessCurrentURL()
  45. nsImapProtocol::ProcessSelectedStateURL()
  46. nsImapProtocol::ProcessStoreFlags(...)
  47. {
  48.         if (flags & kImapMsgSeenFlag && kImapMsgSeenFlag & settableFlags)
  49.       flagString .Append("\\Seen ");
  50. }
  51. nsImapProtocol::Store(const nsCString &messageList, const char * messageData,
  52. {
  53.         12 uid store 28 +Flags (\Seen)
  54. }
  55. ---------------------------------
  56. >        xul.dll!nsMsgDBView::OnHdrFlagsChanged(nsIMsgDBHdr * aHdrChanged, unsigned int aOldFlags, unsigned int aNewFlags, nsIDBChangeListener * aInstigator) Line 5950        C++
  57.          xul.dll!nsMsgGroupView::OnHdrFlagsChanged(nsIMsgDBHdr * aHdrChanged, unsigned int aOldFlags, unsigned int aNewFlags, nsIDBChangeListener * aInstigator) Line 614        C++
  58.          xul.dll!nsMsgDatabase::NotifyHdrChangeAll(nsIMsgDBHdr * aHdrChanged, unsigned int aOldFlags, unsigned int aNewFlags, nsIDBChangeListener * aInstigator) Line 837        C++
  59.          xul.dll!nsMsgDatabase::MarkHdrReadInDB(nsIMsgDBHdr * msgHdr, bool bRead, nsIDBChangeListener * instigator) Line 2134        C++
  60.          xul.dll!nsMsgDatabase::MarkHdrRead(nsIMsgDBHdr * msgHdr, bool bRead, nsIDBChangeListener * instigator) Line 2574        C++
  61.          xul.dll!nsMsgDatabase::MarkRead(unsigned int key, bool bRead, nsIDBChangeListener * instigator) Line 2148        C++
  62.          xul.dll!nsMsgHdr::MarkRead(bool bRead) Line 228        C++
  63.          xul.dll!nsMsgDBFolder::MarkMessagesRead(nsIArray * messages, bool markRead) Line 4685        C++
  64.          xul.dll!nsImapMailFolder::MarkMessagesRead(nsIArray * messages, bool markRead) Line 1885        C++


  65. /////////////////////未读/////////////////
  66. ///web标志为未读后,客户端的更新流程

  67. nsIDBChangeListener.idl
  68. nsMsgDBView::OnHdrFlagsChanged(nsIMsgDBHdr *aHdrChanged, uint32_t aOldFlags,  //数据库变化通知界面
  69. {

  70. }

  71. nsImapMailFolder::SyncFlags(nsIImapFlagAndUidState *flagState)  //分析网络返回设置邮件标志
  72. {
  73.         flagState->GetNumberOfMessages(&messageIndex); //获取返回的邮件数量
  74.         for (int32_t flagIndex = 0; flagIndex < messageIndex; flagIndex++) //对每一个邮件分别进行设置
  75.   {
  76.                 flagState->GetUidOfMessage(flagIndex, &uidOfMessage); //获取消息的UID
  77.                 flagState->GetMessageFlags(flagIndex, &flags); //获取此消息的标志
  78.                
  79.         }
  80. }

  81. nsImapMailFolder::UpdateImapMailboxInfo(nsIImapProtocol* aProtocol, nsIMailboxSpec* aSpec)
  82. {
  83.         nsCOMPtr <nsIImapFlagAndUidState> flagState;
  84.   aSpec->GetFlagState(getter_AddRefs(flagState));
  85. }

  86. nsImapProtocol.cpp
  87. m_parser.SetFlagState(m_flagState);

  88. nsImapServerResponseParser.cpp
  89. void nsImapServerResponseParser::SetFlagState(nsIImapFlagAndUidState *state)
  90. {
  91.         fFlagState = state;
  92. }


  93. /nsImapFlagAndUidState.cpp
  94. nsImapFlagAndUidState::AddUidFlagPair(uint32_t uid, imapMessageFlagsType flags, uint32_t zeroBasedIndex)
  95. {
  96. }


  97. DONE

  98. 15 OK IDLE completed

  99. 16 uid store 30 +Flags (\Seen)

  100. 16 OK UID STORE completed

  101. 17 IDLE

  102. + Waiting for DONE

  103. DONE

  104. 17 OK IDLE completed

  105. 18 noop

  106. 18 OK NOOP completed

  107. 19 UID fetch 32:* (FLAGS)

  108. * 14 FETCH (UID 31 FLAGS (\Seen))

  109. 19 OK UID FETCH completed

  110. 20 IDLE

  111. + Waiting for DONE
复制代码
回复

使用道具 举报

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
沙发
 楼主| 发表于 2015-11-1 23:38:35 | 只看该作者
  1.   mailnews/imap/src/nsimapProtocol.cpp
  2. AppendUid(fetchStr, 1);
  3.   fetchStr.Append(":*");
复制代码
回复 支持 反对

使用道具 举报

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
板凳
 楼主| 发表于 2015-11-3 00:42:57 | 只看该作者

a unique identifier sequence range of 32:* includes the UID of the last message in the mailbox, even if that value is less than 32.
21 UID fetch 32:* (FLAGS)
* 3 FETCH (UID 31 FLAGS (\Seen))
21 OK UID FETCH completed
回复 支持 反对

使用道具 举报

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
地板
 楼主| 发表于 2015-11-3 15:33:06 | 只看该作者
  1. nsImapCore.h
  2. #define kNoImapMsgFlag                0x0000
  3. #define kImapMsgSeenFlag              0x0001
  4. #define kImapMsgAnsweredFlag          0x0002
  5. #define kImapMsgFlaggedFlag           0x0004
  6. #define kImapMsgDeletedFlag           0x0008
  7. #define kImapMsgDraftFlag             0x0010
  8. #define kImapMsgRecentFlag            0x0020
  9. #define        kImapMsgForwardedFlag         0x0040                /* Not always supported, check mailbox folder */
  10. #define kImapMsgMDNSentFlag           0x0080                /* Not always supported. check mailbox folder */
  11. #define kImapMsgCustomKeywordFlag     0x0100            /* this msg has a custom keyword */
  12. #define kImapMsgLabelFlags            0x0E00            /* supports 5 labels only supported if the folder supports keywords */
  13. #define kImapMsgSupportMDNSentFlag    0x2000
  14. #define kImapMsgSupportForwardedFlag  0x4000
复制代码
回复 支持 反对

使用道具 举报

388

主题

602

帖子

2218

积分

金牌会员

Rank: 6Rank: 6

积分
2218
5#
 楼主| 发表于 2015-11-3 18:06:00 | 只看该作者
两个情况,一个是服务端真的返回状态不正确,另一个是程序没有全量更新到对应的状态
第一种情况:
新收到的邮件的UID:  102846
在客户端设置为已读后,观察web端,也已经转为已读取状态,但发送下列命令却返回的没有已读标志

对应发送的命令:26 UID fetch 102847:* (FLAGS)    ----发送值也不方便简单的进行减1,因为一次新邮件数可能很多
对应返回的内容:* 325 FETCH (UID 102846 FLAGS ())   ---返回的标志中没有已读取标志 正常为 * 325 FETCH (UID 102846 FLAGS (\Seen))   


验证:发送 UID fetch 最大UID+1:* (FLAGS)   ----代表只获取新邮件的状态?   only new messages please



总结:服务端的返回有问题,本来已经标志为已读了,可后来同步后又说没读,造成客户端状态改变。


32 uid store 103097 +Flags (\Seen)

* 341 FETCH (FLAGS (\Seen) UID 103097)


正常未读
15 UID fetch 102888:* (FLAGS)
* 329 FETCH (UID 102923 FLAGS ())   ---------不能简单的根据标志是否有进行判断,这样会一直循环下去。


9 UID fetch 1:* (FLAGS)
* 1 FETCH (UID 100002 FLAGS (\Seen))
...
* 332 FETCH (UID 103024 FLAGS ())

C93 UID FETCH 1445233981 (UID FLAGS)
* 9 FETCH (UID 1445233981 FLAGS ())

针对第2种情况的修改方案:

发送store命令为什么没有更新本地缓存中的已读取标志? 或返回成功状态后,本地状态为什么没有变化?
问题原因:
最初始发送一条指令获取所有邮件状态,1:*,这里有一条未读记录为29,
本地将29标志为已读后 uid store 29 +Flags (\Seen),本地变成已经读取??? ---执行了什么?为什么本地没有更新为已读状态??
下次再获取邮件状态时,则会从32:*获取,里面返回没有29,29却又变成原来的读取状态

跟踪标志变更过程  uid store 29 +Flags (\Seen)
nsImapProtocol::Store(const nsCString &messageList, const char * messageData,
{
  nsresult rv = SendData(protocolString); //protocolString = "9 uid store 31 +Flags (\\Seen)\r\n"
  m_flagChangeCount++;
  ParseIMAPandCheckForNewMail(protocolString);
  if (GetServerStateParser().LastCommandSuccessful() && CheckNeeded())
    Check();
}


nsTArray<nsMsgKey>      fUids;
nsTArray<imapMessageFlagsType> fFlags;
-------------------
修改方案1:
修改标志为已读的变更时,把本地缓存的邮件也保存为未读
但由于原有流程判断是不是进行全量更新的逻辑影响,即如何web又设置了未读,而客户端却只同步最新的一封的状态,造成其它未读状态无法获取到,
因此状又会和远程不一致。所以采用方案2
修改方案2:
修改是否进行全量同步的逻辑(即是否发命令 1:* ),如果本地做过标注,则进行全量同步。(弊端:点一下邮件都会发送标志为已读取的状态变化)



方案1相关代码
mailnews\imap\src\nsImapFlagAndUidState.cpp

void nsImapFlagAndUidState::UpdateUIDandFlagInfo(uint32_t uid, imapMessageFlagsType Flags)
{
        PR_CEnterMonitor(this);
        int32_t ndx = (int32_t)fUids.IndexOfFirstElementGt(uid) - 1;
        bool foundIt = ndx >= 0 && fUids[ndx] == uid;
        if (foundIt)
        {
                fFlags[ndx] |= Flags;
        }
        else if (ndx < fUids.Length())
        {
                fFlags[ndx] = Flags;
        }
        PR_CExitMonitor(this);
}

mailnews\imap\src\nsImapFlagAndUidState.h

void UpdateUIDandFlagInfo(uint32_t uid, imapMessageFlagsType Flags);

mailnews\imap\src\nsImapProtocol.cpp
nsImapProtocol::Store(const nsCString &messageList, const char * messageData,
nsresult rv = SendData(protocolString);
if (NS_SUCCEEDED(rv))
{
  m_flagChangeCount++;
  ParseIMAPandCheckForNewMail(protocolString);
  int32_t msgCount = msgKeys.Length();
  PR_LOG(IMAP, PR_LOG_DEBUG, ("nsImapProtocol::Store m_flagState->UpdateUIDandFlagInfo msgCount:%d \r\n", msgCount));
  if (PL_strstr(messageData, "Seen") && PL_strstr(messageData, "+Flags"))
  {
          for (int32_t i = 0; i < msgCount; i++)
          {
                  PR_LOG(IMAP, PR_LOG_DEBUG, ("nsImapProtocol::Store m_flagState->UpdateUIDandFlagInfo uid:%d \r\n", msgKeys));
                  m_flagState->UpdateUIDandFlagInfo(msgKeys, kImapMsgSeenFlag);
          }
  }
  if (GetServerStateParser().LastCommandSuccessful() && CheckNeeded())
    Check();       
}

--------------
方案2相关代码
mailnews\imap\src\nsImapProtocol.cpp

void nsImapProtocol:rocessMailboxUpdate(bool handlePossibleUndo)
if (m_flagChangeCount > 0 )
  AppendUid(fetchStr, 1);
else
  AppendUid(fetchStr, highestRecordedUID + 1);


回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|firemail ( 粤ICP备15085507号-1 )

GMT+8, 2024-11-26 03:26 , Processed in 0.060776 second(s), 19 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表