Back to index

lightning-sunbird  0.9+nobinonly
nsAbLDAPAutoCompFormatter.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * 
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Dan Mosedale <dmose@netscape.com> (Original Author)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 // Work around lack of conditional build logic in codewarrior's
00041 // build system.  The MOZ_LDAP_XPCOM preprocessor symbol is only 
00042 // defined on Mac because noone else needs this weirdness; thus 
00043 // the XP_MAC check first.  This conditional encloses the entire
00044 // file, so that in the case where the ldap option is turned off
00045 // in the mac build, a dummy (empty) object will be generated.
00046 //
00047 #if !defined(XP_MAC) || defined(MOZ_LDAP_XPCOM)
00048 
00049 #include "nsAbLDAPAutoCompFormatter.h"
00050 #include "nsIAutoCompleteResults.h"
00051 #include "nsIServiceManager.h"
00052 #include "nsIMsgHeaderParser.h"
00053 #include "nsILDAPMessage.h"
00054 #include "nsLDAP.h"
00055 #include "nsReadableUtils.h"
00056 #include "nsIStringBundle.h"
00057 #include "nsXPCOM.h"
00058 #include "nsISupportsPrimitives.h"
00059 #include "nsNetError.h"
00060 
00061 NS_IMPL_ISUPPORTS2(nsAbLDAPAutoCompFormatter, 
00062                  nsILDAPAutoCompFormatter, 
00063                  nsIAbLDAPAutoCompFormatter)
00064 
00065 nsAbLDAPAutoCompFormatter::nsAbLDAPAutoCompFormatter() :
00066     mNameFormat(NS_LITERAL_STRING("[cn]")),
00067     mAddressFormat(NS_LITERAL_STRING("{mail}"))
00068 {
00069 }
00070 
00071 nsAbLDAPAutoCompFormatter::~nsAbLDAPAutoCompFormatter()
00072 {
00073 }
00074 
00075 NS_IMETHODIMP
00076 nsAbLDAPAutoCompFormatter::Format(nsILDAPMessage *aMsg, 
00077                                   nsIAutoCompleteItem **aItem) 
00078 {
00079     nsresult rv;
00080 
00081     nsCOMPtr<nsIMsgHeaderParser> msgHdrParser = 
00082         do_GetService("@mozilla.org/messenger/headerparser;1", &rv);
00083     if (NS_FAILED(rv)) {
00084         NS_ERROR("nsAbLDAPAutoCompFormatter::Format(): do_GetService()"
00085                  " failed trying to obtain"
00086                  " '@mozilla.org/messenger/headerparser;1'");
00087         return NS_ERROR_NOT_AVAILABLE;
00088     }
00089 
00090     // generate the appropriate string
00091     //
00092     nsCAutoString name;
00093     rv = ProcessFormat(mNameFormat, aMsg, &name, 0);
00094     if (NS_FAILED(rv)) {
00095         // Something went wrong lower down the stack; a message should
00096         // have already been logged there.  Return an error, rather
00097         // than trying to generate a bogus nsIAutoCompleteItem
00098         //
00099         return rv;
00100     }
00101 
00102     nsCAutoString address;
00103     rv = ProcessFormat(mAddressFormat, aMsg, &address, 0);
00104     if (NS_FAILED(rv)) {
00105         // Something went wrong lower down the stack; a message should have 
00106         // already been logged there.  Return an error, rather than trying to 
00107         // generate a bogus nsIAutoCompleteItem.
00108         //
00109         return rv;
00110     }
00111 
00112     nsXPIDLCString value;
00113     /* As far as I can tell, the documentation in nsIMsgHdrParser that 
00114      * nsnull means "US-ASCII" is actually wrong, it appears to mean UTF8
00115      */
00116     rv = msgHdrParser->MakeFullAddress(nsnull, name.get(), address.get(), 
00117                                        getter_Copies(value));
00118     if (NS_FAILED(rv)) {
00119         NS_ERROR("nsAbLDAPAutoCompFormatter::Format(): call to"
00120                  " MakeFullAddress() failed");
00121         return rv;
00122     }
00123 
00124     // create an nsIAutoCompleteItem to hold the returned value
00125     //
00126     nsCOMPtr<nsIAutoCompleteItem> item = do_CreateInstance(
00127         NS_AUTOCOMPLETEITEM_CONTRACTID, &rv);
00128 
00129     if (NS_FAILED(rv)) {
00130         NS_ERROR("nsAbLDAPAutoCompFormatter::Format(): couldn't"
00131                  " create " NS_AUTOCOMPLETEITEM_CONTRACTID "\n");
00132         return NS_ERROR_NOT_AVAILABLE;
00133     }
00134 
00135     // this is that part that actually gets autocompleted to
00136     //
00137     rv = item->SetValue(NS_ConvertUTF8toUCS2(value));
00138     if (NS_FAILED(rv)) {
00139         NS_ERROR("nsAbLDAPAutoCompFormatter::Format(): "
00140                  "item->SetValue failed");
00141         return rv;
00142     }
00143 
00144     // generate the appropriate string to appear as a comment off to the side
00145     //
00146     nsCAutoString comment;
00147     rv = ProcessFormat(mCommentFormat, aMsg, &comment, 0);
00148     if (NS_SUCCEEDED(rv)) {
00149         rv = item->SetComment(NS_ConvertUTF8toUCS2(comment).get());
00150         if (NS_FAILED(rv)) {
00151             NS_WARNING("nsAbLDAPAutoCompFormatter::Format():"
00152                        " item->SetComment() failed");
00153         }
00154     }
00155 
00156     rv = item->SetClassName("remote-abook");
00157     if (NS_FAILED(rv)) {
00158         NS_WARNING("nsAbLDAPAutoCompleteFormatter::Format():"
00159                    " item->SetClassName() failed");
00160     }
00161 
00162     // all done; return the item
00163     NS_IF_ADDREF(*aItem = item);
00164     return NS_OK;
00165 }
00166 
00167 NS_IMETHODIMP
00168 nsAbLDAPAutoCompFormatter::FormatException(PRInt32 aState, 
00169                                            nsresult aErrorCode, 
00170                                            nsIAutoCompleteItem **aItem) 
00171 {
00172     PRInt32 errorKey;
00173     nsresult rv;
00174 
00175     // create an nsIAutoCompleteItem to hold the returned value
00176     //
00177     nsCOMPtr<nsIAutoCompleteItem> item = do_CreateInstance(
00178         NS_AUTOCOMPLETEITEM_CONTRACTID, &rv);
00179 
00180     if (NS_FAILED(rv)) {
00181         NS_ERROR("nsAbLDAPAutoCompFormatter::FormatException(): couldn't"
00182                  " create " NS_AUTOCOMPLETEITEM_CONTRACTID "\n");
00183         return NS_ERROR_NOT_AVAILABLE;
00184     }
00185 
00186     // get the string bundle service
00187     //
00188     nsXPIDLString errMsg, ldapErrMsg, errCode, alertMsg, ldapHint;
00189     nsString errCodeNum;
00190 
00191     nsCOMPtr<nsIStringBundleService> stringBundleSvc(do_GetService(
00192                                             NS_STRINGBUNDLE_CONTRACTID, &rv)); 
00193     if (NS_FAILED(rv)) {
00194         NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException():"
00195                  " error getting string bundle service");
00196         return rv;
00197     }
00198 
00199     // get the string bundles relevant here: the main LDAP bundle,
00200     // and the ldap AutoCompletion-specific bundle
00201     //
00202     nsCOMPtr<nsIStringBundle> ldapBundle, ldapACBundle;
00203 
00204     rv = stringBundleSvc->CreateBundle(
00205         "chrome://mozldap/locale/ldap.properties",
00206         getter_AddRefs(ldapBundle));
00207     if (NS_FAILED(rv)) {
00208         NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException():"
00209                  " error creating string bundle"
00210                  " chrome://mozldap/locale/ldap.properties");
00211         return rv;
00212     } 
00213 
00214     rv = stringBundleSvc->CreateBundle(
00215         "chrome://global/locale/ldapAutoCompErrs.properties",
00216         getter_AddRefs(ldapACBundle));
00217     if (NS_FAILED(rv)) {
00218         NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException():"
00219                  " error creating string bundle"
00220                  " chrome://global/locale/ldapAutoCompErrs.properties");
00221         return rv;
00222     }
00223 
00224     // get the general error that goes in the dropdown and the window
00225     // title
00226     //
00227     rv = ldapACBundle->GetStringFromID(aState, getter_Copies(errMsg));
00228     if (NS_FAILED(rv)) {
00229         NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException():"
00230                  " error getting general error from bundle"
00231                  " chrome://global/locale/ldapAutoCompErrs.properties");
00232         return rv;
00233     }
00234 
00235     // get the phrase corresponding to "Error code"
00236     //
00237     rv = ldapACBundle->GetStringFromName(NS_LITERAL_STRING("errCode").get(), 
00238                                          getter_Copies(errCode));
00239     if (NS_FAILED(rv)) {
00240         NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException"
00241                    "(): error getting 'errCode' string from bundle "
00242                    "chrome://mozldap/locale/ldap.properties");
00243         return rv;
00244     }
00245 
00246     // for LDAP errors
00247     //
00248     if (NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_LDAP) {
00249 
00250         errorKey = NS_ERROR_GET_CODE(aErrorCode);
00251 
00252         // put the number itself in string form
00253         //
00254         errCodeNum.AppendInt(errorKey);
00255 
00256         // get the LDAP error message itself
00257         //
00258         rv = ldapBundle->GetStringFromID(NS_ERROR_GET_CODE(aErrorCode), 
00259                                                 getter_Copies(ldapErrMsg));
00260         if (NS_FAILED(rv)) {
00261             NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException"
00262                      "(): error getting string 2 from bundle "
00263                      "chrome://mozldap/locale/ldap.properties");
00264             return rv;
00265         }
00266   
00267     } else {
00268 
00269         // put the entire nsresult in string form
00270         //
00271         errCodeNum.AppendLiteral("0x");
00272         errCodeNum.AppendInt(aErrorCode, 16);    
00273 
00274         // figure out the key to index into the string bundle
00275         //
00276         const PRInt32 HOST_NOT_FOUND_ERROR=5000;
00277         const PRInt32 GENERIC_ERROR=9999;
00278         errorKey = ( (aErrorCode == NS_ERROR_UNKNOWN_HOST) ? 
00279                      HOST_NOT_FOUND_ERROR : GENERIC_ERROR );
00280 
00281         // get the specific error message itself
00282         rv = ldapACBundle->GetStringFromID(errorKey,
00283                                            getter_Copies(ldapErrMsg));
00284         if (NS_FAILED(rv)) {
00285             NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException"
00286                      "(): error getting specific non LDAP error-string "
00287                      "from bundle "
00288                      "chrome://mozldap/locale/ldap.properties");
00289             return rv;
00290         }
00291     }
00292 
00293     // and try to find a hint about what the user should do next
00294     //
00295     const PRInt32 HINT_BASE=10000;
00296     const PRInt32 GENERIC_HINT_CODE = 9999;
00297     rv = ldapACBundle->GetStringFromID(HINT_BASE + errorKey, 
00298                                        getter_Copies(ldapHint));
00299     if (NS_FAILED(rv)) {
00300         rv = ldapACBundle->GetStringFromID(HINT_BASE + GENERIC_HINT_CODE,
00301                                            getter_Copies(ldapHint));
00302         if (NS_FAILED(rv)) {
00303             NS_ERROR("nsAbLDAPAutoCompleteFormatter::FormatException()"
00304                      "(): error getting hint string from bundle "
00305                      "chrome://mozldap/locale/ldap.properties");
00306             return rv;
00307         }
00308     }
00309         
00310     const PRUnichar *stringParams[4] = { errCode.get(), errCodeNum.get(), 
00311                                          ldapErrMsg.get(), ldapHint.get() };
00312 
00313     rv = ldapACBundle->FormatStringFromName(
00314         NS_LITERAL_STRING("alertFormat").get(), stringParams, 4, 
00315         getter_Copies(alertMsg));
00316     if (NS_FAILED(rv)) {
00317         NS_WARNING("YYY");
00318     }
00319 
00320     // put the error message, between angle brackets, into the XPIDL |value|
00321     // attribute.  Note that the hardcoded string is only used since 
00322     // stringbundles have already failed us.
00323     //
00324     if (errMsg.Length()) {
00325         rv = item->SetValue(PromiseFlatString(NS_LITERAL_STRING("<") + errMsg
00326                                               + NS_LITERAL_STRING(">")));
00327     } else {
00328         rv = item->SetValue(
00329             NS_LITERAL_STRING("<Unknown LDAP autocompletion error>"));
00330     }
00331 
00332     if (NS_FAILED(rv)) {
00333         NS_ERROR("nsAbLDAPAutoCompFormatter::FormatException(): "
00334                  "item->SetValue failed");
00335         return rv;
00336     }
00337     
00338     // pass the alert message in as the param; if that fails, proceed anyway
00339     //
00340     nsCOMPtr<nsISupportsString> alert(do_CreateInstance(
00341                                            NS_SUPPORTS_STRING_CONTRACTID,
00342                                            &rv));
00343     if (NS_FAILED(rv)) {
00344         NS_WARNING("nsAbLDAPAutoCompFormatter::FormatException(): "
00345                    "could not create nsISupportsString");
00346     } else {
00347         rv = alert->SetData(alertMsg);
00348         if (NS_FAILED(rv)) {
00349             NS_WARNING("nsAbLDAPAutoCompFormatter::FormatException(): "
00350                      "alert.Set() failed");
00351         } else {
00352             rv = item->SetParam(alert);
00353             if (NS_FAILED(rv)) {
00354                 NS_WARNING("nsAbLDAPAutoCompFormatter::FormatException(): "
00355                            "item->SetParam failed");
00356             }
00357         }
00358     }
00359 
00360     // this is a remote addressbook, set the class name so the autocomplete 
00361     // item can be styled to show this
00362     //
00363     rv = item->SetClassName("remote-err");
00364     if (NS_FAILED(rv)) {
00365         NS_WARNING("nsAbLDAPAutoCompleteFormatter::FormatException():"
00366                    " item->SetClassName() failed");
00367     }
00368 
00369     // all done; return the item
00370     //
00371     NS_IF_ADDREF(*aItem = item);
00372     return NS_OK;
00373 }
00374 
00375 NS_IMETHODIMP
00376 nsAbLDAPAutoCompFormatter::GetAttributes(PRUint32 *aCount, char ** *aAttrs)
00377 {
00378     if (!aCount || !aAttrs) {
00379         return NS_ERROR_INVALID_POINTER;
00380     }
00381 
00382     nsCStringArray mSearchAttrs;
00383     nsresult rv = ProcessFormat(mNameFormat, 0, 0, &mSearchAttrs);
00384     if (NS_FAILED(rv)) {
00385         NS_WARNING("nsAbLDAPAutoCompFormatter::SetNameFormat(): "
00386                    "ProcessFormat() failed");
00387         return rv;
00388     }
00389     rv = ProcessFormat(mAddressFormat, 0, 0, &mSearchAttrs);
00390     if (NS_FAILED(rv)) {
00391         NS_WARNING("nsAbLDAPAutoCompFormatter::SetNameFormat(): "
00392                    "ProcessFormat() failed");
00393         return rv;
00394     }
00395     rv = ProcessFormat(mCommentFormat, 0, 0, &mSearchAttrs);
00396     if (NS_FAILED(rv)) {
00397         NS_WARNING("nsAbLDAPAutoCompFormatter::SetNameFormat(): "
00398                    "ProcessFormat() failed");
00399         return rv;
00400     }
00401 
00402     // none of the formatting templates require any LDAP attributes
00403     //
00404     PRUint32 count = mSearchAttrs.Count();   // size of XPCOM array we'll need
00405     if (!count) {
00406         NS_ERROR("nsAbLDAPAutoCompFormatter::GetAttributes(): "
00407                  "current output format (if set) requires no search "
00408                  "attributes");
00409         return NS_ERROR_NOT_INITIALIZED;
00410     }
00411 
00412     // build up the raw XPCOM array to return
00413     //
00414     PRUint32 rawSearchAttrsSize = 0;        // grown as XPCOM array is built
00415     char **rawSearchAttrs = 
00416         NS_STATIC_CAST(char **, nsMemory::Alloc(count * sizeof(char *)));
00417     if (!rawSearchAttrs) {
00418         NS_ERROR("nsAbLDAPAutoCompFormatter::GetAttributes(): out of "
00419                "memory");
00420         return NS_ERROR_OUT_OF_MEMORY;
00421     }
00422 
00423     // Loop through the string array, and build up the C-array.
00424     //
00425     while (rawSearchAttrsSize < count) {
00426         if (!(rawSearchAttrs[rawSearchAttrsSize] = 
00427               ToNewCString(*(mSearchAttrs.CStringAt(rawSearchAttrsSize))))) {
00428             NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(rawSearchAttrsSize, 
00429                                                   rawSearchAttrs);
00430             NS_ERROR("nsAbLDAPAutoCompFormatter::GetAttributes(): out "
00431                    "of memory");
00432             return NS_ERROR_OUT_OF_MEMORY;
00433         }
00434         rawSearchAttrsSize++;
00435     }
00436 
00437     *aCount = rawSearchAttrsSize;
00438     *aAttrs = rawSearchAttrs;
00439 
00440     return NS_OK;
00441 
00442 }
00443 // parse and process a formatting attribute.  If aStringArray is
00444 // non-NULL, return a list of the attributes from mNameFormat in
00445 // aStringArray.  Otherwise, generate an autocomplete value from the
00446 // information in aMessage and append it to aValue.  Any errors
00447 // (including failure to find a required attribute while building up aValue) 
00448 // return an NS_ERROR_* up the stack so that the caller doesn't try and
00449 // generate an nsIAutoCompleteItem from this.
00450 //
00451 nsresult
00452 nsAbLDAPAutoCompFormatter::ProcessFormat(const nsAString & aFormat,
00453                                          nsILDAPMessage *aMessage, 
00454                                          nsACString *aValue,
00455                                          nsCStringArray *aAttrs)
00456 {
00457     nsresult rv;    // temp for return values
00458 
00459     // get some iterators to parse aFormat
00460     //
00461     nsReadingIterator<PRUnichar> iter, iterEnd;
00462     aFormat.BeginReading(iter);
00463     aFormat.EndReading(iterEnd);
00464 
00465     // get the console service for error logging
00466     //
00467     nsCOMPtr<nsIConsoleService> consoleSvc = 
00468         do_GetService("@mozilla.org/consoleservice;1", &rv);
00469     if (NS_FAILED(rv)) {
00470         NS_WARNING("nsAbLDAPAutoCompFormatter::ProcessFormat(): "
00471                    "couldn't get console service");
00472     }
00473 
00474     PRBool attrRequired = PR_FALSE;     // is this attr required or optional?
00475     nsCAutoString attrName;             // current attr to get
00476 
00477     // parse until we hit the end of the string
00478     //
00479     while (iter != iterEnd) {
00480 
00481         switch (*iter) {            // process the next char
00482 
00483         case PRUnichar('{'):
00484 
00485             attrRequired = PR_TRUE;  // this attribute is required
00486 
00487             /*FALLTHROUGH*/
00488 
00489         case PRUnichar('['):
00490 
00491             rv = ParseAttrName(iter, iterEnd, attrRequired, consoleSvc, 
00492                                attrName);
00493             if ( NS_FAILED(rv) ) {
00494 
00495                 // something unrecoverable happened; stop parsing and 
00496                 // propagate the error up the stack
00497                 //
00498                 return rv;
00499             }
00500 
00501             // if we're building an array
00502             if ( aAttrs ) { 
00503 
00504                 // and it doesn't already contain this string
00505                 if (aAttrs->IndexOfIgnoreCase(attrName) == -1) { 
00506 
00507                     // add it
00508                     if (!aAttrs->AppendCString(attrName)) {
00509                         
00510                         // current AppendCString always returns PR_TRUE;
00511                         // if we hit this error, something has changed in
00512                         // that code
00513                         //
00514                         NS_ERROR(
00515                             "nsAbLDAPAutoCompFormatter::ProcessFormat():"
00516                             " aAttrs->AppendCString(attrName) failed");
00517                         return NS_ERROR_UNEXPECTED;
00518                     }
00519                 }
00520             } else {
00521 
00522                 // otherwise, append the first value of this attr to aValue
00523                 // XXXdmose should do better than this; bug 76595
00524 
00525                 rv = AppendFirstAttrValue(attrName, aMessage, attrRequired, 
00526                                           *aValue);
00527                 if ( NS_FAILED(rv) ) {
00528 
00529                     // something unrecoverable happened; stop parsing and 
00530                     // propagate the error up the stack
00531                     //
00532                     return rv;
00533                 }
00534             }
00535 
00536             attrName.Truncate();     // clear out for next pass
00537             attrRequired = PR_FALSE; // reset to the default for the next pass
00538 
00539             break;
00540 
00541         case PRUnichar('\\'):
00542 
00543             // advance the iterator and be sure we haven't run off the end
00544             //
00545             ++iter;
00546             if (iter == iterEnd) {
00547 
00548                 // abort; missing escaped char
00549                 //
00550                 if (consoleSvc) {
00551                     consoleSvc->LogStringMessage(
00552                         NS_LITERAL_STRING(
00553                             "LDAP addressbook autocomplete formatter: error parsing format string: premature end of string after \\ escape").get());
00554 
00555                     NS_ERROR("LDAP addressbook autocomplete formatter: error "
00556                              "parsing format string: premature end of string "
00557                              "after \\ escape");
00558                 }
00559 
00560                 return NS_ERROR_ILLEGAL_VALUE;
00561             }
00562 
00563             /*FALLTHROUGH*/
00564 
00565         default:
00566             
00567             // if we're not just building an array of attribute names, append
00568             // this character to the item we're generating.
00569             //
00570             if (!aAttrs) {
00571 
00572                 // this character gets treated as a literal
00573                 //
00574                 AppendUTF16toUTF8(nsDependentString(iter.get(), 1), *aValue); //XXXjag poke me about string generators
00575             }
00576         }
00577 
00578         ++iter; // advance the iterator
00579     }
00580 
00581     return NS_OK;
00582 }
00583 
00584 nsresult 
00585 nsAbLDAPAutoCompFormatter::ParseAttrName(
00586     nsReadingIterator<PRUnichar> &aIter,        // iterators for mOutputString
00587     nsReadingIterator<PRUnichar> &aIterEnd, 
00588     PRBool aAttrRequired,                       // required?  or just optional?
00589     nsCOMPtr<nsIConsoleService> &aConsoleSvc,   // no need to reacquire this
00590     nsACString &aAttrName)                      // attribute token
00591 {
00592     // reset attrname, and move past the opening brace
00593     //
00594     ++aIter;
00595 
00596     // get the rest of the attribute name
00597     //
00598     do {
00599 
00600         // be sure we haven't run off the end
00601         //
00602         if (aIter == aIterEnd) {
00603 
00604             // abort; missing closing delimiter
00605             //
00606             if (aConsoleSvc) {
00607                 aConsoleSvc->LogStringMessage(
00608                     NS_LITERAL_STRING(
00609                         "LDAP address book autocomplete formatter: error parsing format string: missing } or ]").get());
00610 
00611                 NS_ERROR("LDAP address book autocomplete formatter: error "
00612                          "parsing format string: missing } or ]");
00613             }
00614 
00615             return NS_ERROR_ILLEGAL_VALUE;
00616 
00617         } else if ( (aAttrRequired && *aIter == PRUnichar('}')) || 
00618                     (!aAttrRequired && *aIter == PRUnichar(']')) ) {
00619 
00620             // done with this attribute
00621             //
00622             break;
00623 
00624         } else {
00625 
00626             // this must be part of the attribute name
00627             //
00628             aAttrName.Append(NS_STATIC_CAST(char,*aIter));
00629         }
00630 
00631         ++aIter;
00632 
00633     } while (1);
00634 
00635     return NS_OK;
00636 }
00637 
00638 nsresult
00639 nsAbLDAPAutoCompFormatter::AppendFirstAttrValue(
00640     const nsACString &aAttrName, // attr to get
00641     nsILDAPMessage *aMessage, // msg to get values from
00642     PRBool aAttrRequired, // is this a required value?
00643     nsACString &aValue)
00644 {
00645     // get the attribute values for the field which will be used 
00646     // to fill in nsIAutoCompleteItem::value
00647     //
00648     PRUint32 numVals;
00649     PRUnichar **values;
00650 
00651     nsresult rv;
00652     rv = aMessage->GetValues(PromiseFlatCString(aAttrName).get(), &numVals, 
00653                              &values);
00654     if (NS_FAILED(rv)) {
00655 
00656         switch (rv) {
00657         case NS_ERROR_LDAP_DECODING_ERROR:
00658             // this may not be an error, per se; it could just be that the 
00659             // requested attribute does not exist in this particular message,
00660             // either because we didn't request it with the search operation,
00661             // or because it doesn't exist on the server.
00662             //
00663             break;
00664 
00665         case NS_ERROR_OUT_OF_MEMORY:
00666         case NS_ERROR_UNEXPECTED:
00667             break;
00668 
00669         default:
00670             NS_ERROR("nsLDAPAutoCompleteSession::OnLDAPSearchEntry(): "
00671                      "unexpected return code from aMessage->getValues()");
00672             rv = NS_ERROR_UNEXPECTED;
00673             break;
00674         }
00675 
00676         // if this was a required attribute, don't append anything to aValue
00677         // and return the error code
00678         //
00679         if (aAttrRequired) {
00680             return rv;
00681         } else {
00682             // otherwise forget about this attribute, but return NS_OK, which
00683             // will cause our caller to continue processing nameFormat in 
00684             // order to generate an nsIAutoCompleteItem.
00685             //
00686             return NS_OK;
00687         }
00688     }
00689 
00690     // append the value to our string; then free the array of results
00691     //
00692     AppendUTF16toUTF8(values[0], aValue);
00693     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numVals, values);
00694 
00695     // if this attribute wasn't required, we fall through to here, and return 
00696     // ok
00697     //
00698     return NS_OK;
00699 }
00700 
00701 // attribute AString nameFormat;
00702 NS_IMETHODIMP 
00703 nsAbLDAPAutoCompFormatter::GetNameFormat(nsAString & aNameFormat)
00704 {
00705     aNameFormat  = mNameFormat;
00706     return NS_OK;
00707 }
00708 NS_IMETHODIMP 
00709 nsAbLDAPAutoCompFormatter::SetNameFormat(const nsAString & aNameFormat)
00710 {
00711     mNameFormat = aNameFormat; 
00712     return NS_OK;
00713 }
00714 
00715 // attribute AString addressFormat;
00716 NS_IMETHODIMP 
00717 nsAbLDAPAutoCompFormatter::GetAddressFormat(nsAString & aAddressFormat)
00718 {
00719     aAddressFormat  = mAddressFormat;
00720     return NS_OK;
00721 }
00722 NS_IMETHODIMP 
00723 nsAbLDAPAutoCompFormatter::SetAddressFormat(const nsAString & 
00724                                             aAddressFormat)
00725 {
00726     mAddressFormat = aAddressFormat; 
00727     return NS_OK;
00728 }
00729 
00730 // attribute AString commentFormat;
00731 NS_IMETHODIMP 
00732 nsAbLDAPAutoCompFormatter::GetCommentFormat(nsAString & aCommentFormat)
00733 {
00734     aCommentFormat  = mCommentFormat;
00735     return NS_OK;
00736 }
00737 NS_IMETHODIMP 
00738 nsAbLDAPAutoCompFormatter::SetCommentFormat(const nsAString & 
00739                                             aCommentFormat)
00740 {
00741     mCommentFormat = aCommentFormat; 
00742 
00743     return NS_OK;
00744 }
00745 
00746 #endif