Back to index

lightning-sunbird  0.9+nobinonly
nsAbLDIFService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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) 2005
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Mark Banner <bugzilla@standard8.demon.co.uk>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "nsIAddrDatabase.h"
00039 #include "nsString.h"
00040 #include "nsAbLDIFService.h"
00041 #include "nsIFileSpec.h"
00042 #include "nsVoidArray.h"
00043 #include "mdb.h"
00044 #include "plstr.h"
00045 #include "prmem.h"
00046 #include "prprf.h"
00047 
00048 NS_IMPL_ISUPPORTS1(nsAbLDIFService, nsIAbLDIFService)
00049 
00050 // If we get a line longer than 32K it's just toooooo bad!
00051 #define kTextAddressBufferSz    (64 * 1024)
00052 
00053 nsAbLDIFService::nsAbLDIFService()
00054 {
00055   mStoreLocAsHome = PR_FALSE;
00056   mLFCount = 0;
00057   mCRCount = 0;
00058 }
00059 
00060 nsAbLDIFService::~nsAbLDIFService()
00061 {
00062 }
00063 
00064 #define RIGHT2            0x03
00065 #define RIGHT4            0x0f
00066 #define CONTINUED_LINE_MARKER    '\001'
00067 
00068 // XXX TODO fix me
00069 // use the NSPR base64 library.  see plbase64.h
00070 // see bug #145367
00071 static unsigned char b642nib[0x80] = {
00072     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00073     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00074     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00075     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00076     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00077     0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
00078     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
00079     0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00080     0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
00081     0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
00082     0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
00083     0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
00084     0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
00085     0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
00086     0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
00087     0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
00088 };
00089 
00090 NS_IMETHODIMP nsAbLDIFService::ImportLDIFFile(nsIAddrDatabase *aDb, nsIFileSpec *aSrc, PRBool aStoreLocAsHome, PRUint32 *aProgress)
00091 {
00092   NS_ENSURE_ARG_POINTER(aSrc);
00093   NS_ENSURE_ARG_POINTER(aDb);
00094   mDatabase = aDb;
00095 
00096   mStoreLocAsHome = aStoreLocAsHome;
00097 
00098   char buf[1024];
00099   char* pBuf = &buf[0];
00100   PRInt32 startPos = 0;
00101   PRInt32 len = 0;
00102   PRBool bEof = PR_FALSE;
00103   nsVoidArray listPosArray;   // where each list/group starts in ldif file
00104   nsVoidArray listSizeArray;  // size of the list/group info
00105   PRInt32 savedStartPos = 0;
00106   PRInt32 filePos = 0;
00107 
00108   nsresult rv = aSrc->OpenStreamForReading();
00109   NS_ENSURE_SUCCESS(rv, rv);
00110 
00111   // Initialize the parser for a run...
00112   mLdifLine.Truncate();
00113 
00114   while (NS_SUCCEEDED(aSrc->Eof(&bEof)) && !bEof)
00115   {
00116     if (NS_SUCCEEDED(aSrc->Read(&pBuf, (PRInt32)sizeof(buf), &len)) && len > 0)
00117     {
00118       startPos = 0;
00119 
00120       while (NS_SUCCEEDED(GetLdifStringRecord(buf, len, startPos)))
00121       {
00122         if (mLdifLine.Find("groupOfNames") == kNotFound)
00123           AddLdifRowToDatabase(PR_FALSE);
00124         else
00125         {
00126           //keep file position for mailing list
00127           listPosArray.AppendElement((void*)savedStartPos);
00128           listSizeArray.AppendElement((void*)(filePos + startPos-savedStartPos));
00129           ClearLdifRecordBuffer();
00130         }
00131         savedStartPos = filePos + startPos;
00132       }
00133       filePos += len;
00134       if (aProgress)
00135         *aProgress = (PRUint32)filePos;
00136     }
00137   }
00138   //last row
00139   if (!mLdifLine.IsEmpty() && mLdifLine.Find("groupOfNames") == kNotFound)
00140     AddLdifRowToDatabase(PR_FALSE); 
00141 
00142   // mail Lists
00143   PRInt32 i, pos, size;
00144   PRInt32 listTotal = listPosArray.Count();
00145   char *listBuf;
00146   ClearLdifRecordBuffer();  // make sure the buffer is clean
00147   for (i = 0; i < listTotal; i++)
00148   {
00149     pos  = NS_PTR_TO_INT32(listPosArray.ElementAt(i));
00150     size = NS_PTR_TO_INT32(listSizeArray.ElementAt(i));
00151     if (NS_SUCCEEDED(aSrc->Seek(pos)))
00152     {
00153       // Allocate enough space for the lists/groups as the size varies.
00154       listBuf = (char *) PR_Malloc(size);
00155       if (!listBuf)
00156         continue;
00157       if (NS_SUCCEEDED(aSrc->Read(&listBuf, size, &len)) && len > 0)
00158       {
00159         startPos = 0;
00160 
00161         while (NS_SUCCEEDED(GetLdifStringRecord(listBuf, len, startPos)))
00162         {
00163           if (mLdifLine.Find("groupOfNames") != kNotFound)
00164           {
00165             AddLdifRowToDatabase(PR_TRUE);
00166             if (NS_SUCCEEDED(aSrc->Seek(0)))
00167               break;
00168           }
00169         }
00170       }
00171     PR_FREEIF(listBuf);
00172     }
00173   }
00174 
00175   rv = aSrc->CloseStream();
00176   NS_ENSURE_SUCCESS(rv, rv);
00177 
00178   // Finally commit everything to the database and return.
00179   return aDb->Commit(nsAddrDBCommitType::kLargeCommit);
00180 }
00181 
00182 /*
00183  * str_parse_line - takes a line of the form "type:[:] value" and splits it
00184  * into components "type" and "value".  if a double colon separates type from
00185  * value, then value is encoded in base 64, and parse_line un-decodes it
00186  * (in place) before returning.
00187  * in LDIF, non-ASCII data is treated as base64 encoded UTF-8 
00188  */
00189 
00190 nsresult nsAbLDIFService::str_parse_line(char *line, char **type, char **value, int *vlen) const
00191 {
00192   char    *p, *s, *d, *byte, *stop;
00193   char    nib;
00194   int    i, b64;
00195 
00196   /* skip any leading space */
00197   while ( NS_IS_SPACE( *line ) ) {
00198     line++;
00199   }
00200   *type = line;
00201 
00202   for ( s = line; *s && *s != ':'; s++ )
00203     ;    /* NULL */
00204   if ( *s == '\0' ) {
00205     return NS_ERROR_FAILURE;
00206   }
00207 
00208   /* trim any space between type and : */
00209   for ( p = s - 1; p > line && nsCRT::IsAsciiSpace( *p ); p-- ) {
00210     *p = '\0';
00211   }
00212   *s++ = '\0';
00213 
00214   /* check for double : - indicates base 64 encoded value */
00215   if ( *s == ':' ) {
00216     s++;
00217     b64 = 1;
00218   /* single : - normally encoded value */
00219   } else {
00220     b64 = 0;
00221   }
00222 
00223   /* skip space between : and value */
00224   while ( NS_IS_SPACE( *s ) ) {
00225     s++;
00226   }
00227 
00228   /* if no value is present, error out */
00229   if ( *s == '\0' ) {
00230     return NS_ERROR_FAILURE;
00231   }
00232 
00233   /* check for continued line markers that should be deleted */
00234   for ( p = s, d = s; *p; p++ ) {
00235     if ( *p != CONTINUED_LINE_MARKER )
00236       *d++ = *p;
00237   }
00238   *d = '\0';
00239 
00240   *value = s;
00241   if ( b64 ) {
00242     stop = PL_strchr( s, '\0' );
00243     byte = s;
00244     for ( p = s, *vlen = 0; p < stop; p += 4, *vlen += 3 ) {
00245       for ( i = 0; i < 3; i++ ) {
00246         if ( p[i] != '=' && (p[i] & 0x80 ||
00247              b642nib[ p[i] & 0x7f ] > 0x3f) ) {
00248           return NS_ERROR_FAILURE;
00249         }
00250       }
00251 
00252       /* first digit */
00253       nib = b642nib[ p[0] & 0x7f ];
00254       byte[0] = nib << 2;
00255       /* second digit */
00256       nib = b642nib[ p[1] & 0x7f ];
00257       byte[0] |= nib >> 4;
00258       byte[1] = (nib & RIGHT4) << 4;
00259       /* third digit */
00260       if ( p[2] == '=' ) {
00261         *vlen += 1;
00262         break;
00263       }
00264       nib = b642nib[ p[2] & 0x7f ];
00265       byte[1] |= nib >> 2;
00266       byte[2] = (nib & RIGHT2) << 6;
00267       /* fourth digit */
00268       if ( p[3] == '=' ) {
00269         *vlen += 2;
00270         break;
00271       }
00272       nib = b642nib[ p[3] & 0x7f ];
00273       byte[2] |= nib;
00274 
00275       byte += 3;
00276     }
00277     s[ *vlen ] = '\0';
00278   } else {
00279     *vlen = (int) (d - s);
00280   }
00281   return NS_OK;
00282 }
00283 
00284 /*
00285  * str_getline - return the next "line" (minus newline) of input from a
00286  * string buffer of lines separated by newlines, terminated by \n\n
00287  * or \0.  this routine handles continued lines, bundling them into
00288  * a single big line before returning.  if a line begins with a white
00289  * space character, it is a continuation of the previous line. the white
00290  * space character (nb: only one char), and preceeding newline are changed
00291  * into CONTINUED_LINE_MARKER chars, to be deleted later by the
00292  * str_parse_line() routine above.
00293  *
00294  * it takes a pointer to a pointer to the buffer on the first call,
00295  * which it updates and must be supplied on subsequent calls.
00296  */
00297 
00298 char* nsAbLDIFService::str_getline(char **next) const
00299 {
00300   char    *lineStr;
00301   char    c;
00302 
00303   if ( *next == nsnull || **next == '\n' || **next == '\0' ) {
00304     return( nsnull);
00305   }
00306 
00307   lineStr = *next;
00308   while ( (*next = PL_strchr( *next, '\n' )) != NULL ) {
00309     c = *(*next + 1);
00310     if ( NS_IS_SPACE ( c ) && c != '\n' ) {
00311       **next = CONTINUED_LINE_MARKER;
00312       *(*next+1) = CONTINUED_LINE_MARKER;
00313     } else {
00314       *(*next)++ = '\0';
00315       break;
00316     }
00317   }
00318 
00319   return( lineStr );
00320 }
00321 
00322 nsresult nsAbLDIFService::GetLdifStringRecord(char* buf, PRInt32 len, PRInt32& stopPos)
00323 {
00324   for (; stopPos < len; stopPos++) 
00325   {
00326     char c = buf[stopPos];
00327 
00328     if (c == 0xA)
00329     {
00330       mLFCount++;
00331     }
00332     else if (c == 0xD)
00333     {
00334       mCRCount++;
00335     }
00336     else
00337     {
00338       if (mLFCount == 0 && mCRCount == 0)
00339         mLdifLine.Append(c);
00340       else if (( mLFCount > 1) || ( mCRCount > 2 && mLFCount ) ||
00341                ( !mLFCount && mCRCount > 1 ))
00342       {
00343         return NS_OK;
00344       }
00345       else if ((mLFCount == 1 || mCRCount == 1))
00346       {
00347         mLdifLine.Append('\n');
00348         mLdifLine.Append(c);
00349         mLFCount = 0;
00350         mCRCount = 0;
00351       }
00352     }
00353   }
00354 
00355   if ((stopPos == len) && (mLFCount > 1) || (mCRCount > 2 && mLFCount) ||
00356       (!mLFCount && mCRCount > 1))
00357     return NS_OK;
00358 
00359   return NS_ERROR_FAILURE;
00360 }
00361 
00362 void nsAbLDIFService::AddLdifRowToDatabase(PRBool bIsList)
00363 {
00364   // If no data to process then reset CR/LF counters and return.
00365   if (mLdifLine.IsEmpty())
00366   {
00367     mLFCount = 0;
00368     mCRCount = 0;
00369     return;
00370   }
00371 
00372   nsCOMPtr <nsIMdbRow> newRow;
00373   if (mDatabase)
00374   {
00375     if (bIsList)
00376       mDatabase->GetNewListRow(getter_AddRefs(newRow)); 
00377     else
00378       mDatabase->GetNewRow(getter_AddRefs(newRow)); 
00379 
00380     if (!newRow)
00381       return;
00382   }
00383   else
00384     return;
00385 
00386   char* cursor = ToNewCString(mLdifLine); 
00387   char* saveCursor = cursor;  /* keep for deleting */ 
00388   char* line = 0; 
00389   char* typeSlot = 0; 
00390   char* valueSlot = 0; 
00391   int length = 0;  // the length  of an ldif attribute
00392   while ( (line = str_getline(&cursor)) != nsnull)
00393   {
00394     if ( str_parse_line(line, &typeSlot, &valueSlot, &length) == 0) {
00395       AddLdifColToDatabase(newRow, typeSlot, valueSlot, bIsList);
00396     }
00397     else
00398       continue; // parse error: continue with next loop iteration
00399   }
00400   nsMemory::Free(saveCursor);
00401   mDatabase->AddCardRowToDB(newRow);    
00402 
00403   if (bIsList)
00404     mDatabase->AddListDirNode(newRow);
00405         
00406   // Clear buffer for next record
00407   ClearLdifRecordBuffer();
00408 }
00409 
00410 void nsAbLDIFService::AddLdifColToDatabase(nsIMdbRow* newRow, char* typeSlot, char* valueSlot, PRBool bIsList)
00411 {
00412   nsCAutoString colType(typeSlot);
00413   nsCAutoString column(valueSlot);
00414 
00415   // 4.x exports attributes like "givenname", 
00416   // mozilla does "givenName" to be compliant with RFC 2798
00417   ToLowerCase(colType);
00418 
00419   mdb_u1 firstByte = (mdb_u1)(colType.get())[0];
00420   switch ( firstByte )
00421   {
00422   case 'b':
00423     if (colType.EqualsLiteral("birthyear"))
00424       mDatabase->AddBirthYear(newRow, column.get());
00425     break; // 'b'
00426 
00427   case 'c':
00428     if (colType.EqualsLiteral("cn") || colType.EqualsLiteral("commonname"))
00429     {
00430       if (bIsList)
00431         mDatabase->AddListName(newRow, column.get());
00432       else
00433         mDatabase->AddDisplayName(newRow, column.get());
00434     }
00435     else if (colType.EqualsLiteral("c") || colType.EqualsLiteral("countryname"))
00436     {
00437       if (mStoreLocAsHome )
00438         mDatabase->AddHomeCountry(newRow, column.get());
00439       else
00440         mDatabase->AddWorkCountry(newRow, column.get());
00441     }
00442 
00443     else if (colType.EqualsLiteral("cellphone") )
00444       mDatabase->AddCellularNumber(newRow, column.get());
00445 
00446     else if (colType.EqualsLiteral("carphone"))
00447       mDatabase->AddCellularNumber(newRow, column.get());
00448         
00449     else if (colType.EqualsLiteral("custom1"))
00450       mDatabase->AddCustom1(newRow, column.get());
00451         
00452     else if (colType.EqualsLiteral("custom2"))
00453       mDatabase->AddCustom2(newRow, column.get());
00454         
00455     else if (colType.EqualsLiteral("custom3"))
00456       mDatabase->AddCustom3(newRow, column.get());
00457         
00458     else if (colType.EqualsLiteral("custom4"))
00459       mDatabase->AddCustom4(newRow, column.get());
00460         
00461     else if (colType.EqualsLiteral("company"))
00462       mDatabase->AddCompany(newRow, column.get());
00463     break; // 'c'
00464 
00465   case 'd':
00466     if (colType.EqualsLiteral("description"))
00467     {
00468       if (bIsList)
00469         mDatabase->AddListDescription(newRow, column.get());
00470       else
00471         mDatabase->AddNotes(newRow, column.get());
00472     }
00473 
00474     else if (colType.EqualsLiteral("department"))
00475       mDatabase->AddDepartment(newRow, column.get());
00476 
00477     else if (colType.EqualsLiteral("displayname"))
00478     {
00479       if (bIsList)
00480         mDatabase->AddListName(newRow, column.get());
00481       else
00482         mDatabase->AddDisplayName(newRow, column.get());
00483     }
00484     break; // 'd'
00485 
00486   case 'f':
00487 
00488     if (colType.EqualsLiteral("fax") ||
00489         colType.EqualsLiteral("facsimiletelephonenumber"))
00490       mDatabase->AddFaxNumber(newRow, column.get());
00491     break; // 'f'
00492 
00493   case 'g':
00494     if (colType.EqualsLiteral("givenname"))
00495       mDatabase->AddFirstName(newRow, column.get());
00496 
00497     break; // 'g'
00498 
00499   case 'h':
00500     if (colType.EqualsLiteral("homephone"))
00501       mDatabase->AddHomePhone(newRow, column.get());
00502 
00503     else if (colType.EqualsLiteral("homestreet"))
00504       mDatabase->AddHomeAddress(newRow, column.get());
00505 
00506     else if (colType.EqualsLiteral("homeurl"))
00507       mDatabase->AddWebPage2(newRow, column.get());
00508     break; // 'h'
00509 
00510   case 'l':
00511     if (colType.EqualsLiteral("l") || colType.EqualsLiteral("locality"))
00512     {
00513       if (mStoreLocAsHome)
00514         mDatabase->AddHomeCity(newRow, column.get());
00515       else
00516         mDatabase->AddWorkCity(newRow, column.get());
00517     }
00518 
00519     break; // 'l'
00520 
00521   case 'm':
00522     if (colType.EqualsLiteral("mail"))
00523       mDatabase->AddPrimaryEmail(newRow, column.get());
00524 
00525     else if (colType.EqualsLiteral("member") && bIsList)
00526       mDatabase->AddLdifListMember(newRow, column.get());
00527 
00528     else if (colType.EqualsLiteral("mobile"))
00529       mDatabase->AddCellularNumber(newRow, column.get());
00530 
00531     else if (colType.EqualsLiteral("mozilla_aimscreenname"))
00532       mDatabase->AddAimScreenName(newRow, column.get());
00533 
00534     else if (colType.EqualsLiteral("mozillacustom1"))
00535       mDatabase->AddCustom1(newRow, column.get());
00536         
00537     else if (colType.EqualsLiteral("mozillacustom2"))
00538       mDatabase->AddCustom2(newRow, column.get());
00539         
00540     else if (colType.EqualsLiteral("mozillacustom3"))
00541       mDatabase->AddCustom3(newRow, column.get());
00542         
00543     else if (colType.EqualsLiteral("mozillacustom4"))
00544       mDatabase->AddCustom4(newRow, column.get());
00545 
00546     else if (colType.EqualsLiteral("mozilladefaultemail"))
00547       mDatabase->AddDefaultEmail(newRow, column.get());
00548 
00549     else if (colType.EqualsLiteral("mozillahomecountryname"))
00550       mDatabase->AddHomeCountry(newRow, column.get());
00551 
00552     else if (colType.EqualsLiteral("mozillahomelocalityname"))
00553       mDatabase->AddHomeCity(newRow, column.get());
00554 
00555     else if (colType.EqualsLiteral("mozillahomestate"))
00556       mDatabase->AddHomeState(newRow, column.get());
00557 
00558     else if (colType.EqualsLiteral("mozillahomestreet2"))
00559       mDatabase->AddHomeAddress2(newRow, column.get());
00560 
00561     else if (colType.EqualsLiteral("mozillahomepostalcode"))
00562       mDatabase->AddHomeZipCode(newRow, column.get());
00563 
00564     else if (colType.EqualsLiteral("mozillahomeurl"))
00565       mDatabase->AddWebPage2(newRow, column.get());
00566 
00567     else if (colType.EqualsLiteral("mozillanickname"))
00568     {
00569       if (bIsList)
00570         mDatabase->AddListNickName(newRow, column.get());
00571       else
00572         mDatabase->AddNickName(newRow, column.get());
00573     }
00574 
00575     else if (colType.EqualsLiteral("mozillasecondemail"))
00576       mDatabase->Add2ndEmail(newRow, column.get());
00577 
00578     else if (colType.EqualsLiteral("mozillausehtmlmail"))
00579     {
00580       ToLowerCase(column);
00581       if (kNotFound != column.Find("true"))
00582         mDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::html);
00583       else if (kNotFound != column.Find("false"))
00584         mDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::plaintext);
00585       else
00586         mDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::unknown);
00587     }
00588 
00589     else if (colType.EqualsLiteral("mozillaworkstreet2"))
00590       mDatabase->AddWorkAddress2(newRow, column.get());
00591 
00592     else if (colType.EqualsLiteral("mozillaworkurl"))
00593       mDatabase->AddWebPage1(newRow, column.get());
00594 
00595     break; // 'm'
00596 
00597   case 'n':
00598     if (colType.EqualsLiteral("notes"))
00599       mDatabase->AddNotes(newRow, column.get());
00600 
00601     else if (colType.EqualsLiteral("nscpaimscreenname") || 
00602              colType.EqualsLiteral("nsaimid"))
00603       mDatabase->AddAimScreenName(newRow, column.get());
00604 
00605     break; // 'n'
00606 
00607   case 'o':
00608     if (colType.EqualsLiteral("objectclass"))
00609       break;
00610 
00611     else if (colType.EqualsLiteral("ou") || colType.EqualsLiteral("orgunit"))
00612       mDatabase->AddDepartment(newRow, column.get());
00613 
00614     else if (colType.EqualsLiteral("o")) // organization
00615       mDatabase->AddCompany(newRow, column.get());
00616 
00617     break; // 'o'
00618 
00619   case 'p':
00620     if (colType.EqualsLiteral("postalcode"))
00621     {
00622       if (mStoreLocAsHome)
00623         mDatabase->AddHomeZipCode(newRow, column.get());
00624       else
00625         mDatabase->AddWorkZipCode(newRow, column.get());
00626     }
00627 
00628     else if (colType.EqualsLiteral("postofficebox"))
00629     {
00630       nsCAutoString workAddr1, workAddr2;
00631       SplitCRLFAddressField(column, workAddr1, workAddr2);
00632       mDatabase->AddWorkAddress(newRow, workAddr1.get());
00633       mDatabase->AddWorkAddress2(newRow, workAddr2.get());
00634     }
00635     else if (colType.EqualsLiteral("pager") || colType.EqualsLiteral("pagerphone"))
00636       mDatabase->AddPagerNumber(newRow, column.get());
00637 
00638     break; // 'p'
00639 
00640   case 'r':
00641     if (colType.EqualsLiteral("region"))
00642     {
00643       if (mStoreLocAsHome)
00644         mDatabase->AddWorkState(newRow, column.get());
00645       else
00646         mDatabase->AddWorkState(newRow, column.get());
00647     }
00648 
00649     break; // 'r'
00650 
00651   case 's':
00652     if (colType.EqualsLiteral("sn") || colType.EqualsLiteral("surname"))
00653       mDatabase->AddLastName(newRow, column.get());
00654 
00655     else if (colType.EqualsLiteral("street"))
00656       mDatabase->AddWorkAddress(newRow, column.get());
00657 
00658     else if (colType.EqualsLiteral("streetaddress"))
00659     {
00660       nsCAutoString addr1, addr2;
00661       SplitCRLFAddressField(column, addr1, addr2);
00662       if (mStoreLocAsHome)
00663       {
00664         mDatabase->AddHomeAddress(newRow, addr1.get());
00665         mDatabase->AddHomeAddress2(newRow, addr2.get());
00666       }
00667       else
00668       {
00669         mDatabase->AddWorkAddress(newRow, addr1.get());
00670         mDatabase->AddWorkAddress2(newRow, addr2.get());
00671       }
00672     }
00673     else if (colType.EqualsLiteral("st"))
00674     {
00675     if (mStoreLocAsHome)
00676       mDatabase->AddHomeState(newRow, column.get());
00677     else
00678       mDatabase->AddWorkState(newRow, column.get());
00679     }
00680         
00681     break; // 's'
00682 
00683   case 't':
00684     if (colType.EqualsLiteral("title"))
00685       mDatabase->AddJobTitle(newRow, column.get());
00686 
00687     else if (colType.EqualsLiteral("telephonenumber") )
00688     {
00689       mDatabase->AddWorkPhone(newRow, column.get());
00690     }
00691 
00692     break; // 't'
00693 
00694   case 'u':
00695 
00696     if (colType.EqualsLiteral("uniquemember") && bIsList)
00697       mDatabase->AddLdifListMember(newRow, column.get());
00698 
00699     break; // 'u'
00700 
00701   case 'w':
00702     if (colType.EqualsLiteral("workurl"))
00703       mDatabase->AddWebPage1(newRow, column.get());
00704 
00705     break; // 'w'
00706 
00707   case 'x':
00708     if (colType.EqualsLiteral("xmozillanickname"))
00709     {
00710       if (bIsList)
00711         mDatabase->AddListNickName(newRow, column.get());
00712       else
00713         mDatabase->AddNickName(newRow, column.get());
00714     }
00715 
00716     else if (colType.EqualsLiteral("xmozillausehtmlmail"))
00717     {
00718       ToLowerCase(column);
00719       if (kNotFound != column.Find("true"))
00720         mDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::html);
00721       else if (kNotFound != column.Find("false"))
00722         mDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::plaintext);
00723       else
00724         mDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::unknown);
00725     }
00726 
00727     break; // 'x'
00728 
00729   case 'z':
00730     if (colType.EqualsLiteral("zip")) // alias for postalcode
00731     {
00732       if (mStoreLocAsHome)
00733         mDatabase->AddHomeZipCode(newRow, column.get());
00734       else
00735         mDatabase->AddWorkZipCode(newRow, column.get());
00736     }
00737 
00738     break; // 'z'
00739 
00740   default:
00741     break; // default
00742   }
00743 }
00744 
00745 void nsAbLDIFService::ClearLdifRecordBuffer()
00746 {
00747   if (!mLdifLine.IsEmpty())
00748   {
00749     mLdifLine.Truncate();
00750     mLFCount = 0;
00751     mCRCount = 0;
00752   }
00753 }
00754 
00755 // Some common ldif fields, it an ldif file has NONE of these entries
00756 // then it is most likely NOT an ldif file!
00757 static const char *const sLDIFFields[] = {
00758     "objectclass",
00759     "sn",
00760     "dn",
00761     "cn",
00762     "givenName",
00763     "mail",
00764     nsnull
00765 };
00766 #define kMaxLDIFLen        14
00767 
00768 // Count total number of legal ldif fields and records in the first 100 lines of the 
00769 // file and if the average legal ldif field is 3 or higher than it's a valid ldif file.
00770 NS_IMETHODIMP nsAbLDIFService::IsLDIFFile( nsIFileSpec *pSrc, PRBool *_retval)
00771 {
00772     *_retval = PR_FALSE;
00773 
00774     nsresult rv = pSrc->OpenStreamForReading();
00775     NS_ENSURE_SUCCESS(rv, rv);
00776     
00777     char *pLine = new char[kTextAddressBufferSz];
00778     PRBool    eof = PR_FALSE;
00779     rv = pSrc->Eof( &eof);
00780     if (NS_FAILED( rv)) {
00781         pSrc->CloseStream();
00782         return( rv);
00783     }
00784     
00785     PRBool    wasTruncated = PR_FALSE;
00786     PRInt32    lineLen = 0;
00787     PRInt32    lineCount = 0;
00788     PRInt32    ldifFields = 0;  // total number of legal ldif fields.
00789     char    field[kMaxLDIFLen];
00790     PRInt32    fLen = 0;
00791     char *    pChar;
00792     PRInt32    recCount = 0;  // total number of records.
00793     PRInt32    i;
00794     PRBool    gotLDIF = PR_FALSE;
00795 
00796     while (!eof && NS_SUCCEEDED( rv) && (lineCount < 100)) {
00797         wasTruncated = PR_FALSE;
00798         rv = pSrc->ReadLine( &pLine, kTextAddressBufferSz, &wasTruncated);
00799         if (wasTruncated)
00800             pLine[kTextAddressBufferSz - 1] = 0;
00801         if (NS_SUCCEEDED( rv)) {
00802             lineLen = strlen( pLine);            
00803             pChar = pLine;
00804             if (!lineLen && gotLDIF) {
00805                 recCount++;
00806                 gotLDIF = PR_FALSE;
00807             }
00808                     
00809             if (lineLen && (*pChar != ' ') && (*pChar != 9)) {
00810                 fLen = 0;
00811                 while (lineLen && (fLen < (kMaxLDIFLen - 1)) && (*pChar != ':')) {
00812                     field[fLen] = *pChar;
00813                     pChar++;
00814                     fLen++;
00815                     lineLen--;
00816                 }
00817                 
00818                 field[fLen] = 0;
00819                 if (lineLen && (*pChar == ':') && (fLen < (kMaxLDIFLen - 1))) {
00820                     // see if this is an ldif field (case insensitive)?
00821                     i = 0;
00822                     while (sLDIFFields[i]) {
00823                         if (!nsCRT::strcasecmp( sLDIFFields[i], field)) {
00824                             ldifFields++;
00825                             gotLDIF = PR_TRUE;
00826                             break;
00827                         }
00828                         i++;
00829                     }
00830                     
00831                 }
00832             }
00833 
00834             rv = pSrc->Eof( &eof);
00835         }
00836         lineCount++;
00837     }
00838 
00839     // If we just saw ldif address, increment recCount.
00840     if (gotLDIF)
00841       recCount++;
00842     
00843     rv = pSrc->CloseStream();
00844         
00845     delete [] pLine;
00846     
00847     if (recCount > 1)
00848       ldifFields /= recCount;
00849 
00850     // If the average field number >= 3 then it's a good ldif file.
00851     if (ldifFields >= 3)
00852     {
00853       *_retval = PR_TRUE;
00854     }
00855 
00856     return rv;
00857 }
00858 
00859 void nsAbLDIFService::SplitCRLFAddressField(nsCString &inputAddress, nsCString &outputLine1, nsCString &outputLine2) const
00860 {
00861   PRInt32 crlfPos = inputAddress.Find("\r\n");
00862   if (crlfPos != kNotFound)
00863   {
00864     inputAddress.Left(outputLine1, crlfPos);
00865     inputAddress.Right(outputLine2, inputAddress.Length() - (crlfPos + 2));
00866   }
00867   else
00868     outputLine1.Assign(inputAddress);
00869 }
00870