hechengjin 发表于 2016-3-27 23:24:23

pop流程跟踪

-----向导窗口 emailWizard.xul检测配置--------

接收方式选择pop3 。 重新测试:
onHalfManualTest

涉及到文件
emailWizard.js
guessConfig成功后设置界面输入输出服务器配置
guessConfig.js
guessConfig
1.创建AccountConfig对象 accountConfig.js   含有收发服务器参数
resultConfig = new AccountConfig();
2.如果离线,自动配置好resultConfig 的收发信服务器参数返回
if (Services.io.offline)

3.其它情况创建收发服务器探测对象
incomingHostDetector = new IncomingHostDetector(progress, incomingSuccess,
                                                incomingError);
outgoingHostDetector = new OutgoingHostDetector(progress, outgoingSuccess,
                                                outgoingError);

根据设置好的服务器可能域名地址及对应端口号进行测试
"imap." +domain"pop3." +domain等
incomingHostDetector.start
start : function(domain, hostIsPrecise, type, port, socketType)
_tryAll : function()
thisTry.abortable = SocketUtil(

var transportService = Cc["@mozilla.org/network/socket-transport-service;1"]
                         .getService(Ci.nsISocketTransportService);
var transport = transportService.createTransport
var outstream = transport.openOutputStream(0, 0, 0);--输出流
var stream = transport.openInputStream(0, 0, 0);
var instream = Cc["@mozilla.org/scriptableinputstream;1"]
      .createInstance(Ci.nsIScriptableInputStream);
instream.init(stream);---输入流
var pump = Cc["@mozilla.org/network/input-stream-pump;1"]
      .createInstance(Ci.nsIInputStreamPump);
    pump.init(stream, -1, -1, 0, 0, false);----输入流
    pump.asyncRead(dataListener, null);   --异步读
    return new SocketAbortable(transport);
} catch (e) { _error(e); }


-----向导窗口 emailWizard.xul完成操作--------
emailWizard.js
onCreate
{
validateAndFinish(configFilledIn) //根据上一步检测出的配置参数进行验证
}
validateAndFinish
{
checkIncomingServerAlreadyExists//检测接收服务器是否已经存在createInBackend.js 这四个条件相同即存在(username\hostname\type\port)
checkOutgoingServerAlreadyExists//检测发送服务器是否已经存在 createInBackend.js 这三个条件相同即存在(username\hostname\port)
verifyConfig //登录验证 verifyConfig.js

}

verifyConfig{
//从账号管理组件入手
var accountManager = Cc["@mozilla.org/messenger/account-manager;1"]
                     .getService(Ci.nsIMsgAccountManager);
1.检测账号中是否有此收信服务器accountManager.findRealServer
2. 不存在则创建nsMsgAccountManager.cpp
var inServer =   accountManager.createIncomingServer(config.incoming.username,
                                        config.incoming.hostname,
                                        sanitize.enum(config.incoming.type,
                                                    ["pop3", "imap", "nntp"]));
并初始化负值其它相关参数
inServer.port = config.incoming.port;
inServer.password = config.incoming.password;
    inServer.socketType = Ci.nsMsgSocketType.plain;
inServer.authMethod = config.incoming.auth;

3.登录验证
verifyLogon(config, inServer, alter, msgWindow,
                  successCallback, errorCallback);
}

verifyLogon
{
// 设置验证用户登录的回调,verifyLogon 将同步创建 transport并利用通知(notification )回调 此侦听器同时侦听此url和证书错误,故实现 nsIUrlListener和nsIBadCertListener2 这两个接口 另外还实现了nsIInterfaceRequestor和nsISupports接口
let listener = new urlListener(config, inServer, alter, msgWindow, successCallback, errorCallback);
let uri = inServer.verifyLogon(listener, msgWindow);

验证成功后调用 emailWizard.js 中的 finish : function()
}

urlListener.prototype =
{
//nsIUrlListener
OnStartRunningUrl: function(aUrl)
OnStopRunningUrl: function(aUrl, aExitCode)
//nsIBadCertListener2.idl
notifyCertProblem: function(socketInfo, status, targetSite)
// nsIInterfaceRequestor
getInterface: function(iid)
// nsISupports
QueryInterface: function(iid)
}

inServer.verifyLogon
imap



[*]line 969, as member of class nsImapIncomingServer -- nsImapIncomingServer::VerifyLogon(nsIUrlListener *aUrlListener,
pop

[*]line 480, as member of class nsPop3IncomingServer -- nsPop3IncomingServer::VerifyLogon(nsIUrlListener *aUrlListener,




hechengjin 发表于 2016-3-27 23:24:39

--------pop3验证底层实现-------
nsPop3IncomingServer.cpp
NS_IMETHODIMP nsPop3IncomingServer::VerifyLogon(nsIUrlListener *aUrlListener,nsIMsgWindow *aMsgWindow, nsIURI **aURL)
{
nsresult rv;
nsCOMPtr<nsIPop3Service> pop3Service = do_GetService(kCPop3ServiceCID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
return pop3Service->VerifyLogon(this, aUrlListener, aMsgWindow, aURL);
}

nsPop3Service.cpp
NS_IMETHODIMP nsPop3Service::VerifyLogon(nsIMsgIncomingServer *aServer,...
{
//根据pop3收信服务器的前端设置(用户名[进行编码防止含有 / % @]、主机名、端口)构造url
char *urlSpec = PR_smprintf("pop3://%s@%s:%d/?verifyLogon", escapedUsername.get(), popHost.get(), popPort);
////pop3://13342978053@pop3.139.com:110/?verifyLogon
//构造url接口智能指针 nsIURI
nsCOMPtr<nsIURI> url;   //参考下面 url构建做了什么
rv = BuildPop3Url(urlSpec, nullptr, popServer, aUrlListener,getter_AddRefs(url), aMsgWindow);
//运行url
rv = RunPopUrl(aServer, url);

}

RunPopUrl
{
1.获取pop收信服务器配置的用户名
nsresult rv = aServer->GetRealUsername(userName);

2.判断收信服务是否在忙
rv = aServer->GetServerBusy(&serverBusy);//参考下面 服务是否在忙做了什么
a.忙,弹出提示
nsCOMPtr<nsIMsgMailNewsUrl> url = do_QueryInterface(aUrlToRun);
    if (url)
      AlertServerBusy(url);
b.不忙进行如下执行
nsRefPtr<nsPop3Protocol> protocol = new nsPop3Protocol(aUrlToRun); //参看下面的关于nsPop3Protocol类
//设置用户名
protocol->SetUsername(userName.get());
//加载url //参看下面的关于nsPop3Protocol类中加载Url
rv = protocol->LoadUrl(aUrlToRun);
//设置收取邮件数
protocol->SetNumForRETR(aNumForRETR);
}


****url构建做了什么*************
url中有一个指向pop3sink的指针m_pop3Sink
nsresult nsPop3Service::BuildPop3Url()
{
nsPop3Sink *pop3Sink = new nsPop3Sink(); //nsIPop3Sink
pop3Sink->SetPopServer(server);
pop3Sink->SetFolder(inbox);
//创建pop3Url
nsCOMPtr<nsIPop3URL> pop3Url = do_CreateInstance(kPop3UrlCID, &rv);
pop3Url->SetPop3Sink(pop3Sink);//m_pop3Sink = aPop3Sink;

nsCOMPtr<nsIMsgMailNewsUrl> mailnewsurl = do_QueryInterface(pop3Url);
//前端传入的侦听器在这里注册
mailnewsurl->RegisterListener(aUrlListener);
{
nsMsgMailNewsUrl::RegisterListener    mUrlListeners.AppendElement(aUrlListener);
nsMsgMailNewsUrl.cpp文件中使用 NOTIFY_URL_LISTENERS(propertyfunc_, params_) 发出侦听通知

}
****************

****服务是否在忙做了什么******
NS_IMETHODIMP nsMsgIncomingServer::GetServerBusy(bool * aServerBusy)
{
NS_ENSURE_ARG_POINTER(aServerBusy);
*aServerBusy = m_serverBusy;
return NS_OK;

//主要看什么时候设置了忙状态
NS_IMETHODIMP nsMsgIncomingServer::SetServerBusy(bool aServerBusy)
{
m_serverBusy = aServerBusy;
return NS_OK;
}


***************************

************关于nsPop3Protocol类******nsPop3Protocol.cpp
class nsPop3Protocol : public nsMsgProtocol,
                     public nsIPop3Protocol,
                     public nsIMsgAsyncPromptListener
{ ...}
nsresult nsPop3Protocol:oadUrl(nsIURI* aURL..)
{
//1.初始化url完成功能
*a.日志初始化b.创建pop3连接数据结构 m_pop3ConDatac.设置关于下载的其它参数初始值d.从url中获取状态信息m_statusFeedback
*e.从url中获取收信服务器,及其相关参数m_socketTypeauthMethod 用于连接设置 f.记录此url于m_url变量g.预留接收弹出窗口方法 ir
*h.初始化代理信息详细参考下面代理信息 usePAC=false    i.过滤器列表应用 可优化点,以提高性能? j.连接类型设置connectionType = "ssl";
*k.打开网络Socket 参考 打开网络Socketl.创建命令输出流 参考 创建命令输出流m.初始化后端访问的语言资源方法 mLocalBundle
nsresult rv = Initialize(aURL);

//2.记录url
m_url = do_QueryInterface(aURL);

//3.参考 检测端口安全
rv = NS_CheckPortSafety(port, "pop");

//4.获取url的Query段mQuery,用来判决进行的查询操作上面url最后传入的字符串参数 参考 获取url的Query段
nsCAutoString queryPart;
rv = url->GetQuery(queryPart);//如: "verifyLogon"

//5.根据上面的返回设置连接结构中对应的标志值
m_pop3ConData->only_check_for_new_mail = (PL_strcasestr(queryPart.get(), "check") != nullptr);
m_pop3ConData->verify_logon = (PL_strcasestr(queryPart.get(), "verifyLogon") != nullptr);
m_pop3ConData->get_url = (PL_strcasestr(queryPart.get(), "gurl") != nullptr);

//6.非登录情况下执行
if (!m_pop3ConData->verify_logon)
{
m_pop3Server->GetLeaveMessagesOnServer(&m_pop3ConData->leave_on_server); // 会根据不同的邮件夹的设置获取
m_pop3Server->GetHeadersOnly(&m_pop3ConData->headers_only);//根据收信服务器的设置获取
//关于消息大小的限制,并设置相关变量的值
server->GetLimitOfflineMessageSize(&limitMessageSize);----"limit_offline_message_size"
m_pop3ConData->size_limit = (max_size) ? max_size * 1024 : 50 * 1024;
//关于在服务器上留取邮件数量的设置
m_pop3Server->GetDeleteByAgeFromServer(&deleteByAgeFromServer);//根据收信服务器的设置获取
deleteByAgeFromServer
;

      if (deleteByAgeFromServer)
      m_pop3Server->GetNumDaysToLeaveOnServer(&numDaysToLeaveOnServer);//根据收信服务器的设置获取
numDaysToLeaveOnServer

}

//7.记录sink// UIDL stuffUIDL的东西???
nsCOMPtr<nsIPop3URL> pop3Url = do_QueryInterface(m_url);
if (pop3Url)
    pop3Url->GetPop3Sink(getter_AddRefs(m_nsIPop3Sink));

//8.关于邮件目录的设置
nsCOMPtr<nsIFile> mailDirectory;
//根据收信服务获取邮件目录 详细参考 收信服务获取本地目录
rv = server->GetLocalPath(getter_AddRefs(mailDirectory));   如创建的子目录名为“pop3.139.com”
9.设置服务器为忙
server->SetServerBusy(true); // the server is now busy

10.非登录状态下设置Pop3UidlHost链表结构维护每个账号的哈希表?
if (!m_pop3ConData->verify_logon)
    m_pop3ConData->uidlinfo = net_pop3_load_state(hostName.get(), userName.get(), mailDirectory);

11. 设置为无新邮件状态
m_pop3ConData->biffstate = nsIMsgFolder::nsMsgBiffState_NoMail;

12.邮件删除逻辑处理_____
if (m_pop3ConData->uidlinfo && numDaysToLeaveOnServer > 0)
....
13.uidl逻辑处理___
const char* uidl = PL_strcasestr(queryPart.get(), "uidl=");
.....
14.连接状态设置
m_pop3ConData->next_state = POP3_START_CONNECT;
m_pop3ConData->next_state_after_response = POP3_FINISH_CONNECT;

15.运行当前url
m_pop3Server->SetRunningProtocol(this);
    return nsMsgProtocol:oadUrl(aURL);







}


******************
***** 收信服务获取本地目录*****
nsMsgIncomingServer.cpp
nsMsgIncomingServer::GetLocalPath(nsIFile **aLocalPath)
{
rv = GetFileValue("directory-rel", "directory", aLocalPath);
//根据当前收信服务器的相关信息创建对应目录
nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
rv = getProtocolInfo(getter_AddRefs(protocolInfo));
nsCOMPtr<nsIFile> localPath;
rv = protocolInfo->GetDefaultLocalPath(getter_AddRefs(localPath));
localPath->Create(nsIFile:IRECTORY_TYPE, 0755);

}

*****************************


***代理信息********
PAC可能是代理访问控制的意思
nsProtocolProxyService.cpp
nsProtocolProxyService::Resolve(nsIURI *uri, uint32_t flags,
pop://pop3.139.com:110----代理url含有的相关信息
DIRECT直接
class nsProxyInfo MOZ_FINAL : public nsIProxyInfo
**********************

*******打开网络Socket *********
rv = OpenNetworkSocketWithInfo(hostName.get(), port, connectionType, proxyInfo, ir);
{
//1. 获取 SocketTransportService
nsCOMPtr<nsISocketTransportService> socketService (do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID));
//2.创建Transport详细参见创建Transport
nsCOMPtr<nsISocketTransport> strans;
rv = socketService->CreateTransport(&connectionType, connectionType != nullptr,
                                    nsDependentCString(aHostName),
                                    aGetPort, aProxyInfo,
                                    getter_AddRefs(strans));
//3.设置安全回调,即指向上面的ir用于后端弹出窗口
strans->SetSecurityCallbacks(callbacks);

//4.创建循环引用,可能用来防止线程阻塞???是在主线程吗?线程ID是哪个?
// creates cyclic reference!
nsCOMPtr<nsIThread> currentThread(do_GetCurrentThread());
strans->SetEventSink(this, currentThread);

//5.记录当前传输连接
m_transport = strans;

//6.获取tcp连接超时设置,并进行相关设置
prefBranch->GetIntPref("mailnews.tcptimeout", &gSocketTimeout);
strans->SetTimeout(nsISocketTransport::TIMEOUT_CONNECT, gSocketTimeout + 60);
strans->SetTimeout(nsISocketTransport::TIMEOUT_READ_WRITE, gSocketTimeout);

//7.设置QoS
(Quality of Service) "服务质量"详细参看下面 关于Qos的获取

uint8_t qos;
rv = GetQoSBits(&qos);
if (NS_SUCCEEDED(rv))
    strans->SetQoSBits(qos);


//8.设置传输状态详见下面设置传输状态
return SetupTransportState();

}
****************************

***创建Transport*************
.\mozilla\netwerk\base\src\nsSocketTransportService2.cpp
nsSocketTransportService::CreateTransport(const char **types,
{
nsSocketTransport *trans = new nsSocketTransport();
nsresult rv = trans->Init(types, typeCount, host, port, proxyInfo);
}
***************************


*******关于Qos的获取*************
nsCAutoString prefName("mail.");
prefName.Append(protocol);
prefName.Append(".qos");
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
int32_t val;
rv = prefBranch->GetIntPref(prefName.get(), &val);
NS_ENSURE_SUCCESS(rv, rv);
*****************************************

************设置传输状态*************
if (!m_socketIsOpen && m_transport)
// open buffered, blocking output stream输出流m_outputStream 用于发送数据 nsMsgProtocol::SendDatam_outputStream->Write(dataBuffer, PL_strlen(dataBuffer), &writeCount);
    rv = m_transport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 0, 0, getter_AddRefs(m_outputStream));
****************************

*********创建命令输出流***************
m_lineStreamBuffer = new nsMsgLineStreamBuffer(OUTPUT_BUFFER_SIZE, true);

************************************

***********检测端口安全*********************
NS_CheckPortSafety(int32_t       port,
                   const char   *scheme,
                   nsIIOService *ioService = nullptr)
{
    nsresult rv;
    nsCOMPtr<nsIIOService> grip;
    rv = net_EnsureIOService(&ioService, grip);
    if (ioService) {
      bool allow;
      rv = ioService->AllowPort(port, scheme, &allow);
      if (NS_SUCCEEDED(rv) && !allow) {
            NS_WARNING("port blocked");
            rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED;
      }
    }
    return rv;
}
*******************************************


*****获取url的Query段*************
const nsDependentCSubstring Query()   { return Segment(mQuery); }
// url parts (relative to mSpec)
    URLSegment mScheme;
    URLSegment mAuthority;
    URLSegment mUsername;
    URLSegment mPassword;
    URLSegment mHost;
    URLSegment mPath;
    URLSegment mFilepath;
    URLSegment mDirectory;
    URLSegment mBasename;
    URLSegment mExtension;
    URLSegment mQuery;
    URLSegment mRef;
********************************

hechengjin 发表于 2016-3-27 23:24:56

15.运行当前协议
m_pop3Server->SetRunningProtocol(this);
{
m_runningProtocol = aProtocol;
}

16.调用父类执行

return nsMsgProtocol:: LoadUrl(aURL);

// Ouput stream for writing commands to the socket
nsCOMPtr<nsIOutputStream>   m_outputStream;   // this will be obtained from the transport interface
nsCOMPtr<nsIInputStream>    m_inputStream;
// Ouput stream for writing commands to the socket
nsCOMPtr<nsITransport>m_transport;
nsCOMPtr<nsIRequest>    m_request;

nsresult nsMsgProtocol:: LoadUrl(nsIURI * aURL, nsISupports * aConsumer)

//从transport获取输入流 nsCOMPtr<nsIInputStream>    m_inputStream;
rv = m_transport->OpenInputStream(0, 0, 0, getter_AddRefs(m_inputStream));
///inputStream关联 pump 提供异步方法
nsCOMPtr<nsIInputStreamPump> pump;
      rv = NS_NewInputStreamPump(getter_AddRefs(pump),
          m_inputStream, -1, m_readCount);
m_request = pump; // keep a reference to the pump so we can cancel it
//注册有数据的通知 // put us in a state where we are always notified of incoming data
      rv = pump->AsyncRead(this, urlSupports);


hechengjin 发表于 2016-3-27 23:27:09

触发的状态机的跟踪nsPop3Protocol:: ProcessProtocolState(nsIURI * url, nsIInputStream * aInputStream, uint32_t sourceOffset, uint32_t aLength)xul.dll!nsPop3Protocol::ProcessProtocolState(nsIURI * url, nsIInputStream * aInputStream, unsigned int sourceOffset, unsigned int aLength) 行 3868 C++
> xul.dll!nsMsgProtocol::OnDataAvailable(nsIRequest * request, nsISupports * ctxt, nsIInputStream * inStr, unsigned int sourceOffset, unsigned int count) 行 357 + 0x14 字节 C++
xul.dll!nsInputStreamPump::OnStateTransfer() 行 490 + 0x16 字节 C++
xul.dll!nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream * stream) 行 372 C++
xul.dll!nsOutputStreamReadyEvent::Run() 行 83 C++
xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) 行 624 + 0x6 字节 C++
xul.dll!NS_ProcessNextEvent_P(nsIThread * thread, bool mayWait) 行 220 + 0xd 字节 C++
xul.dll!nsThread::Shutdown() 行 466 + 0xa 字节 C++
xul.dll!nsRunnableMethodImpl<unsigned int (__stdcall nsIThread::*)(void),1>::Run() 行 350 C++
xul.dll!nsThread::ProcessNextEvent(bool mayWait, bool * result) 行 624 + 0x6 字节 C++
xul.dll!NS_ProcessNextEvent_P(nsIThread * thread, bool mayWait) 行 220 + 0xd 字节 C++
xul.dll!mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate * aDelegate) 行 82 + 0xa 字节 C++
xul.dll!MessageLoop::RunHandler() 行 202 C++
xul.dll!MessageLoop::Run() 行 176 C++
xul.dll!nsBaseAppShell::Run() 行 165 C++
xul.dll!nsAppShell::Run() 行 232 + 0x6 字节 C++
xul.dll!nsAppStartup::Run() 行 274 C++
xul.dll!XREMain::XRE_mainRun() 行 3856 + 0x9 字节 C++
xul.dll!XREMain::XRE_main(int argc, char * * argv, const nsXREAppData * aAppData) 行 3933 + 0x7 字节 C++
xul.dll!XRE_main(int argc, char * * argv, const nsXREAppData * aAppData, unsigned int aFlags) 行 4009 + 0x12 字节 C++
139Mail.exe!do_main(const char * exePath, int argc, char * * argv) 行 112 C++
139Mail.exe!NS_internal_main(int argc, char * * argv) 行 200 + 0x12 字节 C++
139Mail.exe!wmain(int argc, wchar_t * * argv) 行 102 C++
139Mail.exe!__tmainCRTStartup() 行 552 + 0x17 字节 C
即连接的缓存中有可用数据时,会触发OnDataAvailable调用,抓包如下:


创建url后的状态更新过程:
1.POP3_START_CONNECT
2.POP3_FINISH_CONNECT
3.POP3_WAIT_FOR_START_OF_CONNECTION_RESPONSE
根据服务端的返回设置服务器相关信息
然后再根据连接类型发送用户名密码登录。
如:
int32_t nsPop3Protocol::SendAuth()
{
if(!m_pop3ConData->command_succeeded)
    return(Error(POP3_SERVER_ERROR));

nsCAutoString command("AUTH" CRLF);

m_pop3ConData->next_state_after_response = POP3_AUTH_RESPONSE;
return SendData(command.get());
}

hechengjin 发表于 2016-3-27 23:27:25

+OK richmail system v10(32d255323e8d829-c3ed4)
AUTH
-ERR Bad sequence of commands
CAPA
-ERR Bad sequence of commands
USER 13342978053@139.com
+OK
PASS cccccpassword
+OK login success
STAT
+OK 3 140231
QUIT
+OK dewey POP3 server signing off

前端createAccountInBackend
进行上面几个命令后,
前端js文件 createInBackend.js
function createAccountInBackend(config, isPublicEmailAddr, curEmailAddr)
account.incomingServer = inServer; // will create folder调用下面c++代码
会进入邮件夹创建
nsMsgAccount::SetIncomingServer(nsIMsgIncomingServer *aIncomingServer)

hechengjin 发表于 2016-3-27 23:27:41

第一阶段总结:

验证接收成功失败的回调函数
function verifyLogon(config, inServer, alter, msgWindow, successCallback, errorCallback)
回调函数在verifyConfig.js验证函数内部转换成js对象 listener
let listener = new urlListener(config, inServer, alter, msgWindow,
                                  successCallback, errorCallback);
listener对象实现 nsIUrlListener 接口
//nsIUrlListener
OnStartRunningUrl: function(aUrl)
OnStopRunningUrl: function(aUrl, aExitCode)
{
this._log.info("Finished verifyConfig resulted in " + aExitCode);
    if (Components.isSuccessCode(aExitCode))//判断返回的退出码
   {
       this._cleanup();
       this.mSuccessCallback(this.mConfig);//登录成功,完成成功函数的回调
   }
}
--------C++后端关于listener对象的传递与处理机制-------------
js:
let listener = new urlListener(config, inServer, alter, msgWindow,
                                  successCallback, errorCallback);
msgWindow.notificationCallbacks = listener;//注意这里有一个回调通知的保存和恢复
let uri = inServer.verifyLogon(listener, msgWindow);
c++:    //aUrlListener对应js中的listener
nsPop3IncomingServer::VerifyLogon(nsIUrlListener *aUrlListener,nsIMsgWindow *aMsgWindow, nsIURI **aURL)
{
nsCOMPtr<nsIPop3Service> pop3Service = do_GetService(kCPop3ServiceCID, &rv);
return pop3Service->VerifyLogon(this, aUrlListener, aMsgWindow, aURL);
}
nsPop3Service::VerifyLogon(nsIMsgIncomingServer *aServer,nsIUrlListener *aUrlListener,nsIMsgWindow *aMsgWindow,
nsIURI **aURL)
{
//组建url并把listener对象封装进去
char *urlSpec = PR_smprintf("pop3://%s@%s:%d/?verifyLogon",escapedUsername.get(), popHost.get(), popPort);
//构造结果示例:pop3://13342978053@pop3.139.com:110/?verifyLogon
nsCOMPtr<nsIURI> url;

rv = BuildPop3Url(urlSpec, nullptr, popServer, aUrlListener,
getter_AddRefs(url), aMsgWindow);
}
nsPop3Service::BuildPop3Url(const char *urlSpec,
nsIMsgFolder *inbox,
nsIPop3IncomingServer *server,
nsIUrlListener *aUrlListener,nsIURI **aUrl,nsIMsgWindow *aMsgWindow)
{
nsCOMPtr<nsIPop3URL> pop3Url = do_CreateInstance(kPop3UrlCID, &rv);
rv = CallQueryInterface(pop3Url, aUrl);
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsurl = do_QueryInterface(pop3Url);
//上面接口的获取参看nsIPop3URL的继承关系 class nsPop3URL : public nsIPop3URL, public nsMsgMailNewsUrl
mailnewsurl->RegisterListener(aUrlListener);
}
//注册后查看后面是处理的
\mailnews\base\util\nsMsgMailNewsUrl.cpp
nsMsgMailNewsUrl::RegisterListener(nsIUrlListener *aUrlListener)
{
mUrlListeners.AppendElement(aUrlListener);
}
//发送通知的宏
#define NOTIFY_URL_LISTENERS(propertyfunc_, params_)                   \
PR_BEGIN_MACRO                                                       \
nsTObserverArray<nsCOMPtr<nsIUrlListener> >::ForwardIterator iter(mUrlListeners); \
while (iter.HasMore()) {                                             \
    nsCOMPtr<nsIUrlListener> listener = iter.GetNext();                \
    listener->propertyfunc_ params_;                                 \
}                                                                  \
PR_END_MACRO
//跟踪何时调用这个宏
nsresult nsMsgMailNewsUrl::SetUrlState(bool aRunningUrl, nsresult aExitCode)
{
{
if (m_runningUrl)
{
    NOTIFY_URL_LISTENERS(OnStartRunningUrl, (this));
}
else
{
    NOTIFY_URL_LISTENERS(OnStopRunningUrl, (this, aExitCode));
    mUrlListeners.Clear();
}
}
//协议中何时调用
nsPop3Protocol.cpp#4119
case POP3_FREE:
mailnewsurl->SetUrlState(false, m_pop3ConData->urlStatus);

hechengjin 发表于 2016-3-27 23:28:06

emailWizard.js
validateAndFinish
self.finish();
finish : function()
{
curAccount =createAccountInBackend(this.getConcreteConfig(), true, this._email);
let folder = curAccount.incomingServer.rootMsgFolder;
    let server = curAccount.incomingServer;
if ("imap" == server.type) {
else if ("pop3" == server.type) {
this.startPop3FetchMsg(server, folder);{ server.getNewMessages(folder, null, null);}
}
createInBackend.js
createAccountInBackend
{
//创建收信服务
var accountManager = Cc["@mozilla.org/messenger/account-manager;1"]
                     .getService(Ci.nsIMsgAccountManager);
var inServer = accountManager.createIncomingServer
//创建发信服务
outServer = smtpManager.createSmtpServer();
//创建identity
var identity = accountManager.createIdentity();
//创建账号并记录收信服务器不同于验证过程,验证过程没有这步
var account = accountManager.createAccount();
account.incomingServer = inServer; // will create folder
//设置账号的identity
account.addIdentity(identity);

setFolders(identity, inServer);
//保存账号信息
accountManager.saveAccountInfo();

return account;

}

hechengjin 发表于 2016-3-27 23:28:26

var inServer = accountManager.createIncomingServer
nsMsgAccountManager.cpp//创建后台C++中的内存对象与js对应
nsMsgAccountManager::CreateIncomingServer(const nsACString&username,
                                          const nsACString& hostname,
                                          const nsACString& type,
                                          nsIMsgIncomingServer **_retval)
{
nsresult rv = LoadAccounts();
}

nsMsgAccountManager:oadAccounts()
{
//1.mailSession的作用
nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
    mailSession->AddFolderListener(this, nsIFolderListener::added |
                                       nsIFolderListener::removed |
                                       nsIFolderListener::intPropertyChanged);
//2.biff service 的作用
nsCOMPtr<nsIMsgBiffManager> biffService =
         do_GetService(NS_MSGBIFFMANAGER_CONTRACTID, &rv);
biffService->Init();

//3.purge service的作用
nsCOMPtr<nsIMsgPurgeService> purgeService =
         do_GetService(NS_MSGPURGESERVICE_CONTRACTID, &rv);
purgeService->Init();

//4.integration service 的作用
nsCOMPtr<nsIMessengerOSIntegration> integrationService =
         do_GetService(NS_MESSENGEROSINTEGRATION_CONTRACTID, &rv);
//5.通过mail.accountmanager.accounts配置中存储的所有账号信息获取账号进入点
nsCString accountList;
rv = m_prefs->GetCharPref(PREF_MAIL_ACCOUNTMANAGER_ACCOUNTS, getter_Copies(accountList));
//6.关于预加载账号
mailnews.js
pref("mailnews.append_preconfig_accounts.version", 1); //预加载账号的版本号配置
mail.accountmanager.appendaccounts//预加载账号 逗号分隔的帐户列表参考mail.accountmanager.accounts里的配置
判断默认配置mailnews.js和当前配置prefs.js的不同,以确认预加载账号的更新
//7.解析账号列表(字符串转为数组),加载每个账号
nsTArray<nsCString> accountsArray;
ParseString(accountList, ACCOUNT_DELIMITER, accountsArray);
去重复及判断是否存在m_accounts中
nsCOMPtr<nsISupportsArray> m_accounts;

//8.创建账号
createKeyedAccount(accountsArray, getter_AddRefs(account))) || !account)    // nsCOMPtr<nsIMsgAccount> account = do_CreateInstance(kMsgAccountCID, &rv);

//9. secondsToLeaveUnavailable 和 timeFoundUnavailable 配置

//10.identities加载
nsCOMPtr<nsISupportsArray> identities;
    account->GetIdentities(getter_AddRefs(identities));

//创建账号服务
rv = account->CreateServer();

//即通过AccountManager服务获取到之前创建的服务,然后与账号的m_incomingServer变量关联,并通知NotifyServerLoaded
nsCOMPtr<nsIMsgAccountManager> accountManager =
         do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgIncomingServer> server;
rv = accountManager->GetIncomingServer(serverKey, getter_AddRefs(server));
NS_ENSURE_SUCCESS(rv, rv);
// store the server in this structure
m_incomingServer = server;
accountManager->NotifyServerLoaded(server);


}
页: [1]
查看完整版本: pop流程跟踪