Back to index

lightning-sunbird  0.9+nobinonly
nsIMAPNamespace.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "msgCore.h"  // for pre-compiled headers
00039 
00040 #include "nsImapCore.h"
00041 #include "nsIMAPNamespace.h"
00042 #include "nsImapProtocol.h"
00043 #include "nsMsgImapCID.h"
00044 #include "nsImapUrl.h"
00045 #include "nsString.h"
00046 
00048 
00049 static NS_DEFINE_CID(kCImapHostSessionListCID, NS_IIMAPHOSTSESSIONLIST_CID);
00050 
00051 nsIMAPNamespace::nsIMAPNamespace(EIMAPNamespaceType type, const char *prefix, char delimiter, PRBool from_prefs)
00052 {
00053        m_namespaceType = type;
00054        m_prefix = PL_strdup(prefix);
00055        m_fromPrefs = from_prefs;
00056 
00057        m_delimiter = delimiter;
00058        m_delimiterFilledIn = !m_fromPrefs;       // if it's from the prefs, we can't be sure about the delimiter until we list it.
00059 }
00060 
00061 nsIMAPNamespace::~nsIMAPNamespace()
00062 {
00063        PR_FREEIF(m_prefix);
00064 }
00065 
00066 void nsIMAPNamespace::SetDelimiter(char delimiter, PRBool delimiterFilledIn)
00067 {
00068   m_delimiter = delimiter;
00069   m_delimiterFilledIn = delimiterFilledIn;
00070 }
00071 
00072 // returns -1 if this box is not part of this namespace,
00073 // or the length of the prefix if it is part of this namespace
00074 int nsIMAPNamespace::MailboxMatchesNamespace(const char *boxname)
00075 {
00076        if (!boxname) return -1;
00077 
00078        // If the namespace is part of the boxname
00079     if (!m_prefix || !*m_prefix)
00080         return 0;
00081 
00082        if (PL_strstr(boxname, m_prefix) == boxname)
00083               return PL_strlen(m_prefix);
00084 
00085        // If the boxname is part of the prefix
00086        // (Used for matching Personal mailbox with Personal/ namespace, etc.)
00087        if (PL_strstr(m_prefix, boxname) == m_prefix)
00088               return PL_strlen(boxname);
00089        return -1;
00090 }
00091 
00092 
00093 nsIMAPNamespaceList *nsIMAPNamespaceList::CreatensIMAPNamespaceList()
00094 {
00095        nsIMAPNamespaceList *rv = new nsIMAPNamespaceList();
00096        return rv;
00097 }
00098 
00099 nsIMAPNamespaceList::nsIMAPNamespaceList()
00100 {
00101 }
00102 
00103 int nsIMAPNamespaceList::GetNumberOfNamespaces()
00104 {
00105        return m_NamespaceList.Count();
00106 }
00107 
00108 
00109 nsresult nsIMAPNamespaceList::InitFromString(const char *nameSpaceString, EIMAPNamespaceType nstype)
00110 {
00111        nsresult rv = NS_OK;
00112        if (nameSpaceString)
00113        {
00114               int numNamespaces = UnserializeNamespaces(nameSpaceString, nsnull, 0);
00115               char **prefixes = (char**) PR_CALLOC(numNamespaces * sizeof(char*));
00116               if (prefixes)
00117               {
00118                      int len = UnserializeNamespaces(nameSpaceString, prefixes, numNamespaces);
00119                      for (int i = 0; i < len; i++)
00120                      {
00121                             char *thisns = prefixes[i];
00122                             char delimiter = '/';       // a guess
00123                             if (PL_strlen(thisns) >= 1)
00124                                    delimiter = thisns[PL_strlen(thisns)-1];
00125                             nsIMAPNamespace *ns = new nsIMAPNamespace(nstype, thisns, delimiter, PR_TRUE);
00126                             if (ns)
00127                                    AddNewNamespace(ns);
00128                             PR_FREEIF(thisns);
00129                      }
00130                      PR_Free(prefixes);
00131               }
00132        }
00133 
00134        return rv;
00135 }
00136 
00137 nsresult nsIMAPNamespaceList::OutputToString(nsCString &string)
00138 {
00139        nsresult rv = NS_OK;
00140 
00141        return rv;
00142 }
00143 
00144 
00145 int nsIMAPNamespaceList::GetNumberOfNamespaces(EIMAPNamespaceType type)
00146 {
00147        int nodeIndex = 0, count = 0;
00148        for (nodeIndex=m_NamespaceList.Count()-1; nodeIndex >= 0; nodeIndex--)
00149        {
00150               nsIMAPNamespace *nspace = (nsIMAPNamespace *) m_NamespaceList.ElementAt(nodeIndex);
00151               if (nspace->GetType() == type)
00152               {
00153                      count++;
00154               }
00155        }
00156        return count;
00157 }
00158 
00159 int nsIMAPNamespaceList::AddNewNamespace(nsIMAPNamespace *ns)
00160 {
00161        // If the namespace is from the NAMESPACE response, then we should see if there
00162        // are any namespaces previously set by the preferences, or the default namespace.  If so, remove these.
00163 
00164        if (!ns->GetIsNamespaceFromPrefs())
00165        {
00166               int nodeIndex;
00167         // iterate backwards because we delete elements
00168               for (nodeIndex=m_NamespaceList.Count()-1; nodeIndex >= 0; nodeIndex--)
00169               {
00170                      nsIMAPNamespace *nspace = (nsIMAPNamespace *) m_NamespaceList.ElementAt(nodeIndex);
00171                      // if we find existing namespace(s) that matches the 
00172                      // new one, we'll just remove the old ones and let the
00173                      // new one get added when we've finished checking for
00174                      // matching namespaces or namespaces that came from prefs.
00175                      if (nspace &&
00176                             (nspace->GetIsNamespaceFromPrefs() ||
00177                             (!PL_strcmp(ns->GetPrefix(), nspace->GetPrefix()) &&
00178                           ns->GetType() == nspace->GetType() &&
00179                           ns->GetDelimiter() == nspace->GetDelimiter())))
00180                      {
00181                             m_NamespaceList.RemoveElementAt(nodeIndex);
00182                             delete nspace; 
00183                      }
00184               }
00185        }
00186 
00187        // Add the new namespace to the list.  This must come after the removing code,
00188        // or else we could never add the initial kDefaultNamespace type to the list.
00189        m_NamespaceList.AppendElement(ns);
00190 
00191        return 0;
00192 }
00193 
00194 
00195 // chrisf - later, fix this to know the real concept of "default" namespace of a given type
00196 nsIMAPNamespace *nsIMAPNamespaceList::GetDefaultNamespaceOfType(EIMAPNamespaceType type)
00197 {
00198        nsIMAPNamespace *rv = 0, *firstOfType = 0;
00199 
00200        int nodeIndex, count = m_NamespaceList.Count();
00201        for (nodeIndex= 0; nodeIndex < count && !rv; nodeIndex++)
00202        {
00203               nsIMAPNamespace *ns = (nsIMAPNamespace *) m_NamespaceList.ElementAt(nodeIndex);
00204               if (ns->GetType() == type)
00205               {
00206                      if (!firstOfType)
00207                             firstOfType = ns;
00208                      if (!(*(ns->GetPrefix())))
00209                      {
00210                             // This namespace's prefix is ""
00211                             // Therefore it is the default
00212                             rv = ns;
00213                      }
00214               }
00215        }
00216        if (!rv)
00217               rv = firstOfType;
00218        return rv;
00219 }
00220 
00221 nsIMAPNamespaceList::~nsIMAPNamespaceList()
00222 {
00223        ClearNamespaces(PR_TRUE, PR_TRUE, PR_TRUE);
00224 }
00225 
00226 // ClearNamespaces removes and deletes the namespaces specified, and if there are no namespaces left,
00227 void nsIMAPNamespaceList::ClearNamespaces(PRBool deleteFromPrefsNamespaces, PRBool deleteServerAdvertisedNamespaces, PRBool reallyDelete)
00228 {
00229        int nodeIndex;
00230        
00231     // iterate backwards because we delete elements
00232        for (nodeIndex=m_NamespaceList.Count()-1; nodeIndex >= 0; nodeIndex--)
00233        {
00234               nsIMAPNamespace *ns = (nsIMAPNamespace *) m_NamespaceList.ElementAt(nodeIndex);
00235               if (ns->GetIsNamespaceFromPrefs())
00236               {
00237                      if (deleteFromPrefsNamespaces)
00238                      {
00239                             m_NamespaceList.RemoveElementAt(nodeIndex);
00240                             if (reallyDelete)
00241                                    delete ns;
00242                      }
00243               }
00244               else if (deleteServerAdvertisedNamespaces)
00245               {
00246                      m_NamespaceList.RemoveElementAt(nodeIndex);
00247                      if (reallyDelete)
00248                             delete ns;
00249               }
00250        }
00251 }
00252 
00253 nsIMAPNamespace *nsIMAPNamespaceList::GetNamespaceNumber(int nodeIndex)
00254 {
00255   NS_ASSERTION(nodeIndex >= 0 && nodeIndex < GetNumberOfNamespaces(), "invalid IMAP namespace node index");
00256   if (nodeIndex < 0) nodeIndex = 0;
00257 
00258   // XXX really could be just ElementAt; that's why we have the assertion
00259   return      (nsIMAPNamespace *) m_NamespaceList.SafeElementAt(nodeIndex);
00260 }
00261 
00262 nsIMAPNamespace *nsIMAPNamespaceList::GetNamespaceNumber(int nodeIndex, EIMAPNamespaceType type)
00263 {
00264   int nodeCount, count = 0;
00265   for (nodeCount=m_NamespaceList.Count()-1; nodeCount >= 0; nodeCount--)
00266   {
00267     nsIMAPNamespace *nspace = (nsIMAPNamespace *) m_NamespaceList.ElementAt(nodeCount);
00268     if (nspace->GetType() == type)
00269     {
00270       count++;
00271       if (count == nodeIndex)
00272         return nspace;
00273     }
00274   }
00275   return nsnull;
00276 }
00277 
00278 nsIMAPNamespace *nsIMAPNamespaceList::GetNamespaceForMailbox(const char *boxname)
00279 {
00280   // We want to find the LONGEST substring that matches the beginning of this mailbox's path.
00281   // This accounts for nested namespaces  (i.e. "Public/" and "Public/Users/")
00282   
00283   // Also, we want to match the namespace's mailbox to that namespace also:
00284   // The Personal box will match the Personal/ namespace, etc.
00285   
00286   // these lists shouldn't be too long (99% chance there won't be more than 3 or 4)
00287   // so just do a linear search
00288   
00289   int lengthMatched = -1;
00290   int currentMatchedLength = -1;
00291   nsIMAPNamespace *rv = nsnull;
00292   int nodeIndex = 0;
00293   
00294   if (!PL_strcasecmp(boxname, "INBOX"))
00295     return GetDefaultNamespaceOfType(kPersonalNamespace);
00296   
00297   for (nodeIndex=m_NamespaceList.Count()-1; nodeIndex >= 0; nodeIndex--)
00298   {
00299     nsIMAPNamespace *nspace = (nsIMAPNamespace *) m_NamespaceList.ElementAt(nodeIndex);
00300     currentMatchedLength = nspace->MailboxMatchesNamespace(boxname);
00301     if (currentMatchedLength > lengthMatched)
00302     {
00303       rv = nspace;
00304       lengthMatched = currentMatchedLength;
00305     }
00306   }
00307   
00308   return rv;
00309 }
00310 
00311 #define SERIALIZER_SEPARATORS ","
00312 
00313 /* prefixes is an array of strings;  len is the length of that array.
00314    If there is only one string, simply copy it and return it.
00315    Otherwise, put them in quotes and comma-delimit them. 
00316    Returns a newly allocated string. */
00317 nsresult nsIMAPNamespaceList::SerializeNamespaces(char **prefixes, int len, nsCString &serializedNamespaces)
00318 {
00319        nsresult rv = NS_OK;
00320        if (len <= 0)
00321               return rv;
00322        if (len == 1)
00323        {
00324               serializedNamespaces = prefixes[0];
00325               return rv;
00326        }
00327        else
00328        {
00329               for (int i = 0; i < len; i++)
00330               {
00331                      char *temp = nsnull;
00332                      if (i == 0)
00333                      {
00334                             serializedNamespaces += "\"";
00335 
00336                             temp = PR_smprintf("\"%s\"",prefixes[i]); /* quote the string */
00337                      }
00338                      else
00339                      {
00340                             serializedNamespaces += ',';
00341                      }
00342                      serializedNamespaces += prefixes[i];
00343                      serializedNamespaces += "\"";
00344               }
00345               return rv;
00346        }
00347 }
00348 
00349 /* str is the string which needs to be unserialized.
00350    If prefixes is NULL, simply returns the number of namespaces in str.  (len is ignored)
00351    If prefixes is not NULL, it should be an array of length len which is to be filled in
00352    with newly-allocated string.  Returns the number of strings filled in.
00353 */
00354 int nsIMAPNamespaceList::UnserializeNamespaces(const char *str, char **prefixes, int len)
00355 {
00356   if (!str)
00357     return 0;
00358   if (!prefixes)
00359   {
00360     if (str[0] != '"')
00361       return 1;
00362     else
00363     {
00364       int count = 0;
00365       char *ourstr = PL_strdup(str);
00366       char *origOurStr = ourstr;
00367       if (ourstr)
00368       {
00369         char *token = nsCRT::strtok( ourstr, SERIALIZER_SEPARATORS, &ourstr );
00370         while (token != nsnull)
00371         {
00372           token = nsCRT::strtok( ourstr, SERIALIZER_SEPARATORS, &ourstr );
00373           count++;
00374         }
00375         PR_Free(origOurStr);
00376       }
00377       return count;
00378     }
00379   }
00380   else
00381   {
00382     if ((str[0] != '"') && (len >= 1))
00383     {
00384       prefixes[0] = PL_strdup(str);
00385       return 1;
00386     }
00387     else
00388     {
00389       int count = 0;
00390       char *ourstr = PL_strdup(str);
00391       char *origOurStr = ourstr;
00392       if (ourstr)
00393       {
00394         char *token = nsCRT::strtok( ourstr, SERIALIZER_SEPARATORS, &ourstr );
00395         while ((count < len) && (token != nsnull))
00396         {
00397           
00398           char *current = PL_strdup(token), *where = current;
00399           if (where[0] == '"')
00400             where++;
00401           if (where[PL_strlen(where)-1] == '"')
00402             where[PL_strlen(where)-1] = 0;
00403           prefixes[count] = PL_strdup(where);
00404           PR_FREEIF(current);
00405           token = nsCRT::strtok( ourstr, SERIALIZER_SEPARATORS, &ourstr );
00406           count++;
00407         }
00408         PR_Free(origOurStr);
00409       }
00410       return count;
00411     }
00412   }
00413 }
00414 
00415 
00416 
00417 
00418 char *nsIMAPNamespaceList::AllocateCanonicalFolderName(const char *onlineFolderName, char delimiter)
00419 {
00420   char *canonicalPath = nsnull;
00421   if (delimiter)
00422     canonicalPath = nsImapUrl::ReplaceCharsInCopiedString(onlineFolderName, delimiter , '/');
00423   else
00424     canonicalPath = PL_strdup(onlineFolderName);
00425   
00426   // eat any escape characters for escaped dir separators
00427   if (canonicalPath)
00428   {
00429     char *currentEscapeSequence = strstr(canonicalPath, "\\/");
00430     while (currentEscapeSequence)
00431     {
00432       strcpy(currentEscapeSequence, currentEscapeSequence+1);
00433       currentEscapeSequence = strstr(currentEscapeSequence+1, "\\/");
00434     }
00435   }
00436   
00437   return canonicalPath;
00438 }
00439 
00440 
00441 
00442 /*
00443   GetFolderNameWithoutNamespace takes as input a folder name
00444   in canonical form, and the namespace for the given folder.  It returns an allocated
00445   string of the folder's path with the namespace string stripped out.  For instance,
00446   when passed the folder Folders/a/b where the namespace is "Folders/", it will return
00447   "a/b".  Similarly, if the folder name is "#news/comp/mail/imap" in canonical form,
00448   with a real delimiter of "." and a namespace of "#news.", it will return "comp/mail/imap".
00449   The return value is always in canonical form.
00450 */
00451 char* nsIMAPNamespaceList::GetFolderNameWithoutNamespace(nsIMAPNamespace *namespaceForFolder, const char *canonicalFolderName)
00452 {
00453   NS_ASSERTION(canonicalFolderName, "null folder name");
00454 #ifdef DEBUG
00455   NS_ASSERTION(namespaceForFolder || !PL_strcasecmp(canonicalFolderName, "INBOX"), "need namespace or INBOX");
00456 #endif
00457   
00458   char *retFolderName = nsnull;
00459   
00460   if (!PL_strcasecmp(canonicalFolderName, "INBOX"))
00461     return PL_strdup(canonicalFolderName);
00462   
00463   // convert the canonical path to the online path
00464   char *convertedFolderName = nsIMAPNamespaceList::AllocateServerFolderName(canonicalFolderName, namespaceForFolder->GetDelimiter());
00465   if (convertedFolderName)
00466   {
00467     char *beginFolderPath = nsnull;
00468     if (strlen(convertedFolderName) <= strlen(namespaceForFolder->GetPrefix()))
00469       beginFolderPath = convertedFolderName;
00470     else
00471       beginFolderPath = convertedFolderName + strlen(namespaceForFolder->GetPrefix());
00472     NS_ASSERTION(beginFolderPath, "empty folder path");
00473     retFolderName = nsIMAPNamespaceList::AllocateCanonicalFolderName(beginFolderPath, namespaceForFolder->GetDelimiter());
00474     PR_Free(convertedFolderName);
00475   }
00476   
00477   NS_ASSERTION(retFolderName, "returning null folder name");
00478   return retFolderName;
00479 }
00480 
00481 
00482 nsIMAPNamespace* nsIMAPNamespaceList::GetNamespaceForFolder(const char *hostName,
00483                                                     const char *canonicalFolderName,
00484                                                     char delimiter)
00485 {
00486   if (!hostName || !canonicalFolderName)
00487     return nsnull;
00488   
00489   nsIMAPNamespace *resultNamespace = nsnull;
00490   nsresult rv;
00491   char *convertedFolderName = nsIMAPNamespaceList::AllocateServerFolderName(canonicalFolderName, delimiter);
00492 
00493   if (convertedFolderName)
00494   {
00495 
00496     nsCOMPtr<nsIImapHostSessionList> hostSessionList = 
00497              do_GetService(kCImapHostSessionListCID, &rv);
00498     if (NS_FAILED(rv)) 
00499       return nsnull;
00500     hostSessionList->GetNamespaceForMailboxForHost(hostName, convertedFolderName, resultNamespace);
00501     PR_Free(convertedFolderName);
00502   }
00503   else
00504   {
00505     NS_ASSERTION(PR_FALSE, "couldn't get converted folder name");
00506   }
00507   
00508   return resultNamespace;
00509 }
00510 
00511 /* static */
00512 char *nsIMAPNamespaceList::AllocateServerFolderName(const char *canonicalFolderName, char delimiter)
00513 {
00514   if (delimiter)
00515     return nsImapUrl::ReplaceCharsInCopiedString(canonicalFolderName, '/', delimiter);
00516   else
00517     return nsCRT::strdup(canonicalFolderName);
00518 }
00519 
00520 /*
00521        GetFolderOwnerNameFromPath takes as inputs a folder name
00522        in canonical form, and a namespace for that folder.
00523        The namespace MUST be of type kOtherUsersNamespace, hence the folder MUST be
00524        owned by another user.  This function extracts the folder owner's name from the
00525        canonical name of the folder, and returns an allocated copy of that owner's name
00526 */
00527 /* static */
00528 char *nsIMAPNamespaceList::GetFolderOwnerNameFromPath(nsIMAPNamespace *namespaceForFolder, const char *canonicalFolderName)
00529 {
00530   if (!namespaceForFolder || !canonicalFolderName)
00531   {
00532     NS_ASSERTION(PR_FALSE,"null namespace or canonical folder name");
00533     return nsnull;
00534   }
00535   
00536   char *rv = nsnull;
00537   
00538   // convert the canonical path to the online path
00539   char *convertedFolderName = AllocateServerFolderName(canonicalFolderName, namespaceForFolder->GetDelimiter());
00540   if (convertedFolderName)
00541   {
00542 #ifdef DEBUG
00543     NS_ASSERTION(strlen(convertedFolderName) > strlen(namespaceForFolder->GetPrefix()), "server folder name invalid");
00544 #endif
00545     if (strlen(convertedFolderName) > strlen(namespaceForFolder->GetPrefix()))
00546     {
00547       char *owner = convertedFolderName + strlen(namespaceForFolder->GetPrefix());
00548       NS_ASSERTION(owner, "couldn't find folder owner");
00549       char *nextDelimiter = strchr(owner, namespaceForFolder->GetDelimiter());
00550       // if !nextDelimiter, then the path is of the form Shared/Users/chrisf   (no subfolder)
00551       if (nextDelimiter)
00552       {
00553         *nextDelimiter = 0;
00554       }
00555       rv = PL_strdup(owner);
00556     }
00557     PR_Free(convertedFolderName);
00558   }
00559   else
00560   {
00561     NS_ASSERTION(PR_FALSE, "couldn't allocate server folder name");
00562   }
00563   
00564   return rv;
00565 }
00566 
00567 /*
00568 GetFolderIsNamespace returns TRUE if the given folder is the folder representing
00569 a namespace.
00570 */
00571 
00572 PRBool nsIMAPNamespaceList::GetFolderIsNamespace(const char *hostName,
00573                                                  const char *canonicalFolderName,
00574                                                  char delimiter,nsIMAPNamespace *namespaceForFolder)
00575 {
00576   NS_ASSERTION(namespaceForFolder, "null namespace");
00577   
00578   PRBool rv = PR_FALSE;
00579   
00580   const char *prefix = namespaceForFolder->GetPrefix();
00581   NS_ASSERTION(prefix, "namespace has no prefix");
00582   if (!prefix || !*prefix)  // empty namespace prefix
00583     return PR_FALSE;
00584   
00585   char *convertedFolderName = AllocateServerFolderName(canonicalFolderName, delimiter);
00586   if (convertedFolderName)
00587   {
00588     PRBool lastCharIsDelimiter = (prefix[strlen(prefix) - 1] == delimiter);
00589     
00590     if (lastCharIsDelimiter)
00591     {
00592       rv = ((strncmp(convertedFolderName, prefix, strlen(convertedFolderName)) == 0) &&
00593         (strlen(convertedFolderName) == strlen(prefix) - 1));
00594     }
00595     else
00596     {
00597       rv = (strcmp(convertedFolderName, prefix) == 0);
00598     }
00599     
00600     PR_Free(convertedFolderName);
00601   }
00602   else
00603   {
00604     NS_ASSERTION(PR_FALSE, "couldn't allocate server folder name");
00605   }
00606   
00607   return rv;
00608 }
00609 
00610 /*
00611   SuggestHierarchySeparatorForNamespace takes a namespace from libmsg
00612   and a hierarchy delimiter.  If the namespace has not been filled in from
00613   online NAMESPACE command yet, it fills in the suggested delimiter to be
00614   used from then on (until it is overridden by an online response).
00615 */
00616 
00617 void nsIMAPNamespaceList::SuggestHierarchySeparatorForNamespace(nsIMAPNamespace *namespaceForFolder, char delimiterFromFolder)
00618 {
00619   NS_ASSERTION(namespaceForFolder, "need namespace");
00620   if (namespaceForFolder && !namespaceForFolder->GetIsDelimiterFilledIn())
00621     namespaceForFolder->SetDelimiter(delimiterFromFolder, PR_FALSE);
00622 }
00623 
00624 
00625 /*
00626  GenerateFullFolderNameWithDefaultNamespace takes a folder name in canonical form,
00627   converts it to online form, allocates a string to contain the full online server name
00628   including the namespace prefix of the default namespace of the given type, in the form:
00629   PR_smprintf("%s%s", prefix, onlineServerName) if there is a NULL owner
00630   PR_smprintf("%s%s%c%s", prefix, owner, delimiter, onlineServerName) if there is an owner
00631   It then converts this back to canonical form and returns it (allocated) to libmsg.
00632   It returns NULL if there is no namespace of the given type.
00633   If nsUsed is not passed in as NULL, then *nsUsed is filled in and returned;  it is the
00634   namespace used for generating the folder name.
00635 */
00636 char *nsIMAPNamespaceList::GenerateFullFolderNameWithDefaultNamespace(const char *hostName,
00637                                                                                 const char *canonicalFolderName,
00638                                                                                 const char *owner,
00639                                                                                 EIMAPNamespaceType nsType,
00640                                                                                 nsIMAPNamespace **nsUsed)
00641 {
00642   nsresult rv = NS_OK;
00643 
00644   nsCOMPtr<nsIImapHostSessionList> hostSession = 
00645            do_GetService(kCImapHostSessionListCID, &rv);
00646   NS_ENSURE_SUCCESS(rv, nsnull);
00647   nsIMAPNamespace *ns;
00648   char *fullFolderName = nsnull;
00649   rv = hostSession->GetDefaultNamespaceOfTypeForHost(hostName, nsType, ns);
00650   NS_ENSURE_SUCCESS(rv, nsnull);
00651   if (ns)
00652   {
00653     if (nsUsed)
00654       *nsUsed = ns;
00655     const char *prefix = ns->GetPrefix();
00656     char *convertedFolderName = AllocateServerFolderName(canonicalFolderName, ns->GetDelimiter());
00657     if (convertedFolderName)
00658     {
00659       char *convertedReturnName = nsnull;
00660       if (owner)
00661       {
00662         convertedReturnName = PR_smprintf("%s%s%c%s", prefix, owner, ns->GetDelimiter(), convertedFolderName);
00663       }
00664       else
00665       {
00666         convertedReturnName = PR_smprintf("%s%s", prefix, convertedFolderName);
00667       }
00668       
00669       if (convertedReturnName)
00670       {
00671         fullFolderName = AllocateCanonicalFolderName(convertedReturnName, ns->GetDelimiter());
00672         PR_Free(convertedReturnName);
00673       }
00674       PR_Free(convertedFolderName);
00675     }
00676     else
00677     {
00678       NS_ASSERTION(PR_FALSE, "couldn't allocate server folder name");
00679     }
00680   }
00681   else
00682   {
00683     // Could not find other users namespace on the given host
00684     NS_ASSERTION(PR_FALSE, "couldn't find namespace for given host");
00685   }
00686   return (fullFolderName);
00687 }
00688