firemail

标题: 通讯录导入功能流程跟踪 [打印本页]

作者: hechengjin    时间: 2016-3-27 23:38
标题: 通讯录导入功能流程跟踪
/////js调用导入csv格式导入通讯录////////
var importService = 0;
        importService = Components.classes["@mozilla.org/import/import-service;1"]
                                    .getService(Components.interfaces.nsIImportService);
    var module = 0;
     if (exprotType == 'vcard')
          {
            
             module = importService.GetModule("addressbook", 0);
          }
          else//csv
          {
            module = importService.GetModule("addressbook", 2);
          }

    addInterface = module.GetImportInterface( "addressbook");
          if (addInterface != null)
            addInterface = addInterface.QueryInterface( Components.interfaces.nsIImportGeneric);
          if (addInterface == null) {
            var errorText = bundle_import.GetStringFromName('ImportAddressBadModule');
            var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);

              promptService.alert(window, document.title, errorText);
            return( false);
          }

    addInterface.SetData("addressLocation", file);

  var map = addInterface.GetData( "fieldMap");
          if (map != null) {
            map = map.QueryInterface( Components.interfaces.nsIImportFieldMap);
            if (map != null) {
              var result = new Object();
              result.ok = false;
              top.window.openDialog(
                "chrome://messenger/content/fieldMapImport.xul",
                "",
                "chrome,modal,titlebar",
                {fieldMap: map,
                 addInterface: addInterface,
                 result: result});
            }
            if (result.ok == false)
              return( false);
          }


//fieldMapImport.xul确定按钮影响
function FieldImportOKButton()
{
  var max = gListbox.getRowCount();
  var fIndex;
  var on;
  // Ensure field map is the right size
  top.fieldMap.SetFieldMapSize(max);

  for (var i = 0; i < max; i++) {
    fIndex = gListbox.getItemAtIndex(i).getAttribute( 'field-index');
    on = gListbox.getItemAtIndex(i).firstChild.getAttribute('checked');
    top.fieldMap.SetFieldMap( i, fIndex);
    top.fieldMap.SetFieldActive( i, (on == "true"));
  }

  top.fieldMap.skipFirstRecord = gSkipFirstRecordButton.checked;

  top.dialogResult.ok = true;

  return true;
}


作者: hechengjin    时间: 2016-3-27 23:38

nsIImportService.idl

#include "nsISupports.idl"
#include "nsIMsgSend.idl"

interface nsIImportModule;
interface nsIImportMailboxDescriptor;
interface nsIImportABDescriptor;
interface nsIImportGeneric;
interface nsIImportFieldMap;
interface nsIMsgSendListener;
interface nsIMsgCompFields;
interface nsIMsgSendListener;
interface nsIArray;
/*
*scriptable:声明该接口可以被javascript使用,且必须从一个scriptable接口集成而来,接口使用的变量类型必须是可以javascript化的。
*idl接口可使用的类型:XPIDL types  
*/[scriptable, uuid(376fc4c2-76d3-4b47-8095-406260cb9b1f)]  //

interface nsIImportService : nsISupports
{
    void DiscoverModules();

  long GetModuleCount( in string filter);
  void GetModuleInfo( in string filter, in long index, out wstring name, out wstring description);
  wstring GetModuleName( in string filter, in long index);
  wstring GetModuleDescription( in string filter, in long index);
  nsIImportModule  GetModule( in string filter, in long index);
  nsIImportModule GetModuleWithCID( in nsCIDRef cid);

  nsIImportFieldMap      CreateNewFieldMap();
  nsIImportMailboxDescriptor  CreateNewMailboxDescriptor();
  nsIImportABDescriptor    CreateNewABDescriptor();
  nsIImportGeneric      CreateNewGenericMail();
  nsIImportGeneric      CreateNewGenericAddressBooks();
  void CreateRFC822Message(in nsIMsgIdentity aIdentity,
                           in nsIMsgCompFields aMsgFields,
                           in string aBodytype,
                           in string aBody,
                           in unsigned long aBodyLength,
                           in boolean aCreateAsDraft,
                           in nsIArray aLoadedAttachments,
                           in nsISupportsArray aEmbeddedObjects,
                           in nsIMsgSendListener aListener);

};

%{ C++
#define NS_IMPORTSERVICE_CID              \
{ /* 5df96d60-1726-11d3-a206-00a0cc26da63 */      \
   0x5df96d60, 0x1726, 0x11d3,                   \
   {0xa2, 0x06, 0x0, 0xa0, 0xcc, 0x26, 0xda, 0x63}}

#define NS_IMPORTSERVICE_CONTRACTID "@mozilla.org/import/import-service;1"
%}

///////////////实现////////
nsImportService.h

class nsImportService : public nsIImportService
{
public:

  nsImportService();
  virtual ~nsImportService();

  NS_DECL_ISUPPORTS

    NS_DECL_NSIIMPORTSERVICE

private:
    nsresult LoadModuleInfo(const char*pClsId, const char *pSupports);
  nsresult DoDiscover(void);

private:
    nsImportModuleList * m_pModules;
  bool m_didDiscovery;
  nsCString m_sysCharset;
  nsIUnicodeDecoder * m_pDecoder;
  nsIUnicodeEncoder * m_pEncoder;
  nsCOMPtr<nsIStringBundle> m_stringBundle;
};

nsImportService.cpp

PRLogModuleInfo *IMPORTLOGMODULE = nullptr;  //日志模块

static nsIImportService *  gImportService = nullptr; //单例 什么时候创建?

nsImportService::nsImportService() : m_pModules(nullptr)
{
  // Init logging module.
  if (!IMPORTLOGMODULE)
    IMPORTLOGMODULE = PR_NewLogModule("IMPORT");  //日志模块配置
  IMPORT_LOG0("* nsImport Service Created\n");

  m_didDiscovery = false;
  m_pDecoder = nullptr;
  m_pEncoder = nullptr;
///#define IMPORT_MSGS_URL       "chrome://messenger/locale/importMsgs.properties"
  nsresult rv = nsImportStringBundle::GetStringBundle(IMPORT_MSGS_URL, getter_AddRefs(m_stringBundle));
  if (NS_FAILED(rv))
    IMPORT_LOG0("Failed to get string bundle for Importing Mail");
}


nsImportService::~nsImportService()
{
  NS_IF_RELEASE(m_pDecoder);
  NS_IF_RELEASE(m_pEncoder);

  gImportService = nullptr;

    if (m_pModules != nullptr)
        delete m_pModules;

  IMPORT_LOG0("* nsImport Service Deleted\n");
}


NS_IMETHODIMP nsImportService::GetModule(const char *filter, int32_t index, nsIImportModule **_retval)
{
    NS_PRECONDITION(_retval != nullptr, "null ptr");
    if (!_retval)
        return NS_ERROR_NULL_POINTER;
  *_retval = nullptr;

    DoDiscover();
    if (!m_pModules)
    return NS_ERROR_FAILURE;

  if ((index < 0) || (index >= m_pModules->GetCount()))
    return NS_ERROR_FAILURE;

  ImportModuleDesc *  pDesc;
  int32_t  count = 0;
  for (int32_t i = 0; i < m_pModules->GetCount(); i++) {
    pDesc = m_pModules->GetModuleDesc(i);
    if (pDesc->SupportsThings(filter)) {
      if (count == index) {
        *_retval = pDesc->GetModule();
        break;
      }
      else
        count++;
    }
  }
  if (! (*_retval))
    return NS_ERROR_FAILURE;

  return NS_OK;
}

nsresult nsImportService:: LoadModuleInfo(const char *pClsId, const char *pSupports)
{
  if (!pClsId || !pSupports)
    return NS_OK;

  if (m_pModules == nullptr)
    m_pModules = new nsImportModuleList();

  // load the component and get all of the info we need from it....
  // then call AddModule
  nsresult  rv;

  nsCID        clsId;
  clsId.Parse(pClsId);
  nsIImportModule *  module;
  rv = CallCreateInstance(clsId, &module);
  if (NS_FAILED(rv)) return rv;

  nsString  theTitle;
  nsString  theDescription;
  rv = module->GetName(getter_Copies(theTitle));
  if (NS_FAILED(rv))
    theTitle.AssignLiteral("Unknown");

  rv = module->GetDescription(getter_Copies(theDescription));
  if (NS_FAILED(rv))
    theDescription.AssignLiteral("Unknown description");

  // call the module to get the info we need
  m_pModules->AddModule(clsId, pSupports, theTitle.get(), theDescription.get());

  module->Release();

  return NS_OK;
}

nsresult nsImportServiceDiscover(void)
{
  if (m_didDiscovery)
    return NS_OK;

  if (m_pModules != nullptr)
    m_pModules->ClearList();

  nsresult rv;

  nsCOMPtr<nsICategoryManager> catMan = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsISimpleEnumerator> e;
  rv = catMan->EnumerateCategory("mailnewsimport", getter_AddRefs(e));
  NS_ENSURE_SUCCESS(rv, rv);
  nsCOMPtr<nsISupportsCString> contractid;
  rv = e->GetNext(getter_AddRefs(contractid));
  while (NS_SUCCEEDED(rv) && contractid)
  {
    nsCString contractIdStr;
    contractid->ToString(getter_Copies(contractIdStr));
    nsCString supportsStr;
    rv = catMan->GetCategoryEntry("mailnewsimport", contractIdStr.get(), getter_Copies(supportsStr));
    if (NS_SUCCEEDED(rv))
      LoadModuleInfo(contractIdStr.get(), supportsStr.get());
    rv = e->GetNext(getter_AddRefs(contractid));
  }

  m_didDiscovery = true;

  return NS_OK;
}


作者: hechengjin    时间: 2016-3-27 23:39
导入服务类支持不同模块的导入:
如:
  module = importService.GetModule("addressbook", 0);  //vcard
  module = importService.GetModule("addressbook", 2);  //csv
模块列表为 m_pModules = new nsImportModuleList();中
其内部真正实现导入功能的是nsIImportModule *m_pModule;

各模块的初始加载通过 nsresult nsImportService:: DoDiscover(void) -->LoadModuleInfo(contractIdStr.get(), supportsStr.get()); -->m_pModules->AddModule(clsId, pSupports, theTitle.get(), theDescription.get());


importService.GetModule("addressbook", 2);  //csv 时触发 DoDiscover    nsCOMPtr<nsICategoryManager> catMan

//m_pModules列表内容
pSupports | theTitle | theDescription
[ "addressbook" | "vCard 文件 (.vcf)" | "从 vCard 格式导入一个地址簿" ]
[ "mail,addressbook,settings" | "Outlook" | "Outlook 邮件,通讯录和设置" ]
[ "settings" | "Windows Live Mail" | "Windows Live Mail 设置" ]
[ "addressbook" | "文本" | "从文本文件导入通讯录。包括:LDIF (.ldif, .ldi),tab 定界的格式或以逗号分隔的 (.csv) 格式。" ]
[ "mail,addressbook,settings" | "Outlook Express" | "Outlook Express 邮件,通讯录和设置" ]
[ "mail,addressbook,settings,filters" | "Eudora" | "Eudora 邮件,通讯录和设置" ]
catMan内容的初始化来自于组件注册,如下调用堆栈
         xul.dll!nsCategoryManager::AddCategoryEntry(const char * aCategoryName=0x01d17c8c, const char * aEntryName=0x01cfba18, const char * aValue=0x01f6995c, bool aReplace=true, char * * aOldValue=0x00000000)
         xul.dll!nsComponentManagerImpl::RegisterModule(const mozilla::Module * aModule=0x01d18504, mozilla::FileLocation * aFile=0x021d2078)  行 413 + 0x16 字节        C++
        xul.dll!nsComponentManagerImpl::Init()  行 350 + 0xe 字节        C++
         xul.dll!NS_InitXPCOM2_P(nsIServiceManager * * result=0x021a6fc0, nsIFile * binDirectory=0x003d6be0, nsIDirectoryServiceProvider * appFileLocationProvider=0x0012fca8)  行 466 + 0xb 字节        C++
         xul.dll!ScopedXPCOMStartup::Initialize()  行 1174 + 0x1b 字节        C++
         xul.dll!XREMain::XRE_main(int argc=1, char * * argv=0x003d4570, const nsXREAppData * aAppData=0x003d6870)  行 3894        C++





所有这些与导入相关的模块都可在 nsImportModule.cpp  中找到  -----导入相关的服务模块 thinkmail\mailnews\import
static const mozilla::Module kMailNewsImportModule = {
  mozilla::Module::kVersion,
  kMailNewsImportCIDs,
  kMailNewsImportContracts,
  kMailNewsImportCategories,
  NULL,
  NULL,
  importModuleDtor
};

importService.GetModule("addressbook", 2);   // rv = CallCreateInstance(m_cid, &m_pModule);  //{A5991D01-ADA7-11d3-A9C2-00A0CC26DA63}这里主要用到的是导入模块列表m_pModules中的cid为{A5991D01-ADA7-11d3-A9C2-00A0CC26DA63}的,即:2 [ "addressbook" | "文本" | "从文本文件导入通讯录。包括:LDIF (.ldif, .ldi),tab 定界的格式或以逗号分隔的 (.csv) 格式。" ]
////////////////////////////////////////////////////////////////////////////////
// text import factories
////////////////////////////////////////////////////////////////////////////////
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTextImport)

即可找到其对应实现
nsTextImport.h   nsTextImport.cpp
class nsTextImport : public nsIImportModule
{
public:
  nsTextImport();
  virtual ~nsTextImport();

  NS_DECL_ISUPPORTS

  ////////////////////////////////////////////////////////////////////////////////////////
  // we suppport the nsIImportModule interface
  ////////////////////////////////////////////////////////////////////////////////////////

  NS_DECL_NSIIMPORTMODULE

protected:
  nsCOMPtr<nsIStringBundle>   m_stringBundle;
};
addInterface = module.GetImportInterface( "addressbook");  //  返回指向nsIImportGeneric 实现的kISupportsIID接口

NS_IMETHODIMP nsTextImport::GetImportInterface(const char *pImportType, nsISupports **ppInterface)
{
if (!strcmp(pImportType, "addressbook")) {
    // create the nsIImportMail interface and return it!
    nsIImportAddressBooks * pAddress = nullptr;
    nsIImportGeneric * pGeneric = nullptr;
    rv = ImportAddressImpl::Create(&pAddress, m_stringBundle);   //pAddress = new ImportAddressImpl(aStringBundle);
    if (NS_SUCCEEDED(rv)) {
      nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
      if (NS_SUCCEEDED(rv)) {
        rv = impSvc->CreateNewGenericAddressBooks(&pGeneric);  // new nsImportGenericAddressBooks();   pGen->QueryInterface(NS_GET_IID(nsIImportGeneric), (void **)aImportGeneric);
        if (NS_SUCCEEDED(rv)) {
          pGeneric->SetData("addressInterface", pAddress);  // item->QueryInterface(NS_GET_IID(nsIImportAddressBooks), (void **) &m_pInterface);
          rv = pGeneric->QueryInterface(kISupportsIID, (void **)ppInterface);
        }
      }
    }
}

this.addInterface = module.GetImportInterface( "addressbook"); //内部记录到通讯录字段  //nsIImportAddressBooks  m_pInterface nsImportGenericAddressBooks
this.addInterface.SetData("addressLocation", file);//内部通讯录字面和文件关联  //m_pLocation    m_pInterface->SetSampleLocation(m_pLocation); ImportAddressImpl


NS_IMETHODIMP nsImportGenericAddressBooks::SetData(const char *dataId, nsISupports *item)
{
  NS_PRECONDITION(dataId != nullptr, "null ptr");
  if (!dataId)
    return NS_ERROR_NULL_POINTER;

if (!PL_strcasecmp(dataId, "addressInterface")) {
    NS_IF_RELEASE(m_pInterface);
    if (item)
      item->QueryInterface(NS_GET_IID(nsIImportAddressBooks), (void **) &m_pInterface);
  }
  if (!PL_strcasecmp(dataId, "addressBooks")) {
    NS_IF_RELEASE(m_pBooks);
    if (item)
      item->QueryInterface(NS_GET_IID(nsISupportsArray), (void **) &m_pBooks);
  }

  if (!PL_strcasecmp(dataId, "addressLocation")) {
    m_pLocation = nullptr;
    if (item) {
      nsresult rv;
      m_pLocation = do_QueryInterface(item, &rv);
      NS_ENSURE_SUCCESS(rv,rv);
    }
    if (m_pInterface)
      m_pInterface->SetSampleLocation(m_pLocation);
  }

  if (!PL_strcasecmp(dataId, "addressDestination")) {
    if (item) {
      nsCOMPtr<nsISupportsCString> abString;
      item->QueryInterface(NS_GET_IID(nsISupportsCString), getter_AddRefs(abString));
      if (abString) {
        if (m_pDestinationUri)
          NS_Free(m_pDestinationUri);
        m_pDestinationUri = nullptr;
                nsCAutoString tempUri;
                abString->GetData(tempUri);
                m_pDestinationUri = ToNewCString(tempUri);
      }
    }
  }
  if (!PL_strcasecmp(dataId, "fieldMap")) {
    NS_IF_RELEASE(m_pFieldMap);
    if (item)
      item->QueryInterface(NS_GET_IID(nsIImportFieldMap), (void **) &m_pFieldMap);
  }
  return NS_OK;
}

this.addInterface nsImportGenericAddressBooks
this.fieldMap = addInterface.GetData( "fieldMap");   //m_pFieldMap[nsImportFieldMap] m_pInterface[通讯录接口]   m_pLocation[文件接口]


NS_IMETHODIMP nsImportGenericAddressBooks::GetData(const char *dataId, nsISupports **_retval)
{
  NS_PRECONDITION(_retval != nullptr, "null ptr");
  if (!_retval)
    return NS_ERROR_NULL_POINTER;

  nsresult rv;
  *_retval = nullptr;

if (!PL_strcasecmp(dataId, "fieldMap")) {
    if (m_pFieldMap) {
      *_retval = m_pFieldMap;
      m_pFieldMap->AddRef();
    }
    else {
      if (m_pInterface && m_pLocation) {
        bool needsIt = false;
        m_pInterface->GetNeedsFieldMap(m_pLocation, &needsIt); //这里判断是不是isLDIF文件,来确认要不要打开映射关系窗口
        if (needsIt) {
          GetDefaultFieldMap(); //这里通过代码中设置的要映射的字段赋初值 ,然后再根据用户以前使用过的先清空默认,再调整为mailnews.import.text.fieldmap中记录的
          if (m_pFieldMap) {
            *_retval = m_pFieldMap;
            m_pFieldMap->AddRef();
          }
        }
      }
    }
  }
  return NS_OK;
}

this.fieldMap.SetFieldMapSize(max);
this.fieldMap.SetFieldMap( this._listHandledInfoMap[tindex].abIndex, tindex); //先abindex [m_numFields]  后txtindex?           m_pFields[index] = fieldNum;  index(ab)-->fieldNum(txt)
this.fieldMap.SetFieldActive( this._listHandledInfoMap[tindex].abIndex, this._listHandledInfoMap[tindex].matchOK);  m_pActive[index] = active;  //如个ab字段是有效匹配的

this.addInterface.WantsProgress()
this.addInterface.BeginImport(success, error);

NS_IMETHODIMP nsImportGenericAddressBooks::WantsProgress(bool *_retval)
{
}
NS_IMETHODIMP nsImportGenericAddressBooks::BeginImport(nsISupportsString *successLog, nsISupportsString *errorLog, bool *_retval)
{
}

作者: hechengjin    时间: 2016-3-27 23:39
模块列表定义

class nsImportModuleList {
public:
  nsImportModuleList() { m_pList = nullptr; m_alloc = 0; m_count = 0;}
  ~nsImportModuleList() { ClearList(); }

  void  AddModule(const nsCID& cid, const char *pSupports, const PRUnichar *pName, const PRUnichar *pDesc);

  void  ClearList(void);

  int32_t  GetCount(void) { return m_count;}

  ImportModuleDesc *  GetModuleDesc(int32_t idx)
    { if ((idx < 0) || (idx >= m_count)) return nullptr; else return m_pList[idx];}

private:

private:
    ImportModuleDesc **  m_pList;
  int32_t        m_alloc;
  int32_t        m_count;
};


class ImportModuleDesc {
public:
  ImportModuleDesc() { m_pModule = nullptr;}
  ~ImportModuleDesc() { ReleaseModule();  }

  void  SetCID(const nsCID& cid) { m_cid = cid;}
  void  SetName(const PRUnichar *pName) { m_name = pName;}
  void  SetDescription(const PRUnichar *pDesc) { m_description = pDesc;}
  void  SetSupports(const char *pSupports) { m_supports = pSupports;}

  nsCID      GetCID(void) { return m_cid;}
  const PRUnichar *GetName(void) { return m_name.get();}
  const PRUnichar *GetDescription(void) { return m_description.get();}
  const char *  GetSupports(void) { return m_supports.get();}

  nsIImportModule *  GetModule(bool keepLoaded = false); // Adds ref
  void        ReleaseModule(void);

  bool        SupportsThings(const char *pThings);

private:
    nsCID m_cid;
  nsString m_name;
  nsString m_description;
  nsCString m_supports;
  nsIImportModule *m_pModule;
};

作者: hechengjin    时间: 2016-3-27 23:39
module = importService.GetModule("addressbook", 0);  //vcard
[ "addressbook" | "vCard 文件 (.vcf)" | "从 vCard 格式导入一个地址簿" ]

{0eb034a3-964a-4e2f-92eb-cc55d9ae9dd2}

firemail\mailnews\import\vcard\src\nsVCardImport.cpp
NS_IMETHODIMP nsVCardImport::GetImportInterface(




欢迎光临 firemail (http://firemail.wang:8088/) Powered by Discuz! X3