summaryrefslogtreecommitdiffstats
path: root/mailnews/addrbook/src/nsAbLDIFService.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2019-11-03 00:17:46 -0400
committerMatt A. Tobin <email@mattatobin.com>2019-11-03 00:17:46 -0400
commit302bf1b523012e11b60425d6eee1221ebc2724eb (patch)
treeb191a895f8716efcbe42f454f37597a545a6f421 /mailnews/addrbook/src/nsAbLDIFService.cpp
parent21b3f6247403c06f85e1f45d219f87549862198f (diff)
downloadUXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.gz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.lz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.xz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.zip
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
Diffstat (limited to 'mailnews/addrbook/src/nsAbLDIFService.cpp')
-rw-r--r--mailnews/addrbook/src/nsAbLDIFService.cpp868
1 files changed, 868 insertions, 0 deletions
diff --git a/mailnews/addrbook/src/nsAbLDIFService.cpp b/mailnews/addrbook/src/nsAbLDIFService.cpp
new file mode 100644
index 000000000..95eb4b96a
--- /dev/null
+++ b/mailnews/addrbook/src/nsAbLDIFService.cpp
@@ -0,0 +1,868 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "nsIAddrDatabase.h"
+#include "nsStringGlue.h"
+#include "nsAbLDIFService.h"
+#include "nsIFile.h"
+#include "nsILineInputStream.h"
+#include "nsIInputStream.h"
+#include "nsNetUtil.h"
+#include "nsISeekableStream.h"
+#include "mdb.h"
+#include "plstr.h"
+#include "prmem.h"
+#include "prprf.h"
+#include "nsCRTGlue.h"
+#include "nsTArray.h"
+
+#include <ctype.h>
+
+NS_IMPL_ISUPPORTS(nsAbLDIFService, nsIAbLDIFService)
+
+// If we get a line longer than 32K it's just toooooo bad!
+#define kTextAddressBufferSz (64 * 1024)
+
+nsAbLDIFService::nsAbLDIFService()
+{
+ mStoreLocAsHome = false;
+ mLFCount = 0;
+ mCRCount = 0;
+}
+
+nsAbLDIFService::~nsAbLDIFService()
+{
+}
+
+#define RIGHT2 0x03
+#define RIGHT4 0x0f
+#define CONTINUED_LINE_MARKER '\001'
+
+// XXX TODO fix me
+// use the NSPR base64 library. see plbase64.h
+// see bug #145367
+static unsigned char b642nib[0x80] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+NS_IMETHODIMP nsAbLDIFService::ImportLDIFFile(nsIAddrDatabase *aDb, nsIFile *aSrc, bool aStoreLocAsHome, uint32_t *aProgress)
+{
+ NS_ENSURE_ARG_POINTER(aSrc);
+ NS_ENSURE_ARG_POINTER(aDb);
+
+ mStoreLocAsHome = aStoreLocAsHome;
+
+ char buf[1024];
+ char* pBuf = &buf[0];
+ int32_t startPos = 0;
+ uint32_t len = 0;
+ nsTArray<int32_t> listPosArray; // where each list/group starts in ldif file
+ nsTArray<int32_t> listSizeArray; // size of the list/group info
+ int32_t savedStartPos = 0;
+ int32_t filePos = 0;
+ uint64_t bytesLeft = 0;
+
+ nsCOMPtr<nsIInputStream> inputStream;
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aSrc);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Initialize the parser for a run...
+ mLdifLine.Truncate();
+
+ while (NS_SUCCEEDED(inputStream->Available(&bytesLeft)) && bytesLeft > 0)
+ {
+ if (NS_SUCCEEDED(inputStream->Read(pBuf, sizeof(buf), &len)) && len > 0)
+ {
+ startPos = 0;
+
+ while (NS_SUCCEEDED(GetLdifStringRecord(buf, len, startPos)))
+ {
+ if (mLdifLine.Find("groupOfNames") == -1)
+ AddLdifRowToDatabase(aDb, false);
+ else
+ {
+ //keep file position for mailing list
+ listPosArray.AppendElement(savedStartPos);
+ listSizeArray.AppendElement(filePos + startPos-savedStartPos);
+ ClearLdifRecordBuffer();
+ }
+ savedStartPos = filePos + startPos;
+ }
+ filePos += len;
+ if (aProgress)
+ *aProgress = (uint32_t)filePos;
+ }
+ }
+ //last row
+ if (!mLdifLine.IsEmpty() && mLdifLine.Find("groupOfNames") == -1)
+ AddLdifRowToDatabase(aDb, false);
+
+ // mail Lists
+ int32_t i, pos;
+ uint32_t size;
+ int32_t listTotal = listPosArray.Length();
+ char *listBuf;
+ ClearLdifRecordBuffer(); // make sure the buffer is clean
+
+ nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(inputStream, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ for (i = 0; i < listTotal; i++)
+ {
+ pos = listPosArray[i];
+ size = listSizeArray[i];
+ if (NS_SUCCEEDED(seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, pos)))
+ {
+ // Allocate enough space for the lists/groups as the size varies.
+ listBuf = (char *) PR_Malloc(size);
+ if (!listBuf)
+ continue;
+ if (NS_SUCCEEDED(inputStream->Read(listBuf, size, &len)) && len > 0)
+ {
+ startPos = 0;
+
+ while (NS_SUCCEEDED(GetLdifStringRecord(listBuf, len, startPos)))
+ {
+ if (mLdifLine.Find("groupOfNames") != -1)
+ {
+ AddLdifRowToDatabase(aDb, true);
+ if (NS_SUCCEEDED(seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, 0)))
+ break;
+ }
+ }
+ }
+ PR_FREEIF(listBuf);
+ }
+ }
+
+ rv = inputStream->Close();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Finally commit everything to the database and return.
+ return aDb->Commit(nsAddrDBCommitType::kLargeCommit);
+}
+
+/*
+ * str_parse_line - takes a line of the form "type:[:] value" and splits it
+ * into components "type" and "value". if a double colon separates type from
+ * value, then value is encoded in base 64, and parse_line un-decodes it
+ * (in place) before returning.
+ * in LDIF, non-ASCII data is treated as base64 encoded UTF-8
+ */
+
+nsresult nsAbLDIFService::str_parse_line(char *line, char **type, char **value, int *vlen) const
+{
+ char *p, *s, *d, *byte, *stop;
+ char nib;
+ int i, b64;
+
+ /* skip any leading space */
+ while ( isspace( *line ) ) {
+ line++;
+ }
+ *type = line;
+
+ for ( s = line; *s && *s != ':'; s++ )
+ ; /* NULL */
+ if ( *s == '\0' ) {
+ return NS_ERROR_FAILURE;
+ }
+
+ /* trim any space between type and : */
+ for ( p = s - 1; p > line && isspace( *p ); p-- ) {
+ *p = '\0';
+ }
+ *s++ = '\0';
+
+ /* check for double : - indicates base 64 encoded value */
+ if ( *s == ':' ) {
+ s++;
+ b64 = 1;
+ /* single : - normally encoded value */
+ } else {
+ b64 = 0;
+ }
+
+ /* skip space between : and value */
+ while ( isspace( *s ) ) {
+ s++;
+ }
+
+ /* if no value is present, error out */
+ if ( *s == '\0' ) {
+ return NS_ERROR_FAILURE;
+ }
+
+ /* check for continued line markers that should be deleted */
+ for ( p = s, d = s; *p; p++ ) {
+ if ( *p != CONTINUED_LINE_MARKER )
+ *d++ = *p;
+ }
+ *d = '\0';
+
+ *value = s;
+ if ( b64 ) {
+ stop = PL_strchr( s, '\0' );
+ byte = s;
+ for ( p = s, *vlen = 0; p < stop; p += 4, *vlen += 3 ) {
+ for ( i = 0; i < 3; i++ ) {
+ if ( p[i] != '=' && (p[i] & 0x80 ||
+ b642nib[ p[i] & 0x7f ] > 0x3f) ) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ /* first digit */
+ nib = b642nib[ p[0] & 0x7f ];
+ byte[0] = nib << 2;
+ /* second digit */
+ nib = b642nib[ p[1] & 0x7f ];
+ byte[0] |= nib >> 4;
+ byte[1] = (nib & RIGHT4) << 4;
+ /* third digit */
+ if ( p[2] == '=' ) {
+ *vlen += 1;
+ break;
+ }
+ nib = b642nib[ p[2] & 0x7f ];
+ byte[1] |= nib >> 2;
+ byte[2] = (nib & RIGHT2) << 6;
+ /* fourth digit */
+ if ( p[3] == '=' ) {
+ *vlen += 2;
+ break;
+ }
+ nib = b642nib[ p[3] & 0x7f ];
+ byte[2] |= nib;
+
+ byte += 3;
+ }
+ s[ *vlen ] = '\0';
+ } else {
+ *vlen = (int) (d - s);
+ }
+ return NS_OK;
+}
+
+/*
+ * str_getline - return the next "line" (minus newline) of input from a
+ * string buffer of lines separated by newlines, terminated by \n\n
+ * or \0. this routine handles continued lines, bundling them into
+ * a single big line before returning. if a line begins with a white
+ * space character, it is a continuation of the previous line. the white
+ * space character (nb: only one char), and preceeding newline are changed
+ * into CONTINUED_LINE_MARKER chars, to be deleted later by the
+ * str_parse_line() routine above.
+ *
+ * it takes a pointer to a pointer to the buffer on the first call,
+ * which it updates and must be supplied on subsequent calls.
+ */
+
+char* nsAbLDIFService::str_getline(char **next) const
+{
+ char *lineStr;
+ char c;
+
+ if ( *next == nullptr || **next == '\n' || **next == '\0' ) {
+ return( nullptr);
+ }
+
+ lineStr = *next;
+ while ( (*next = PL_strchr( *next, '\n' )) != NULL ) {
+ c = *(*next + 1);
+ if ( isspace( c ) && c != '\n' ) {
+ **next = CONTINUED_LINE_MARKER;
+ *(*next+1) = CONTINUED_LINE_MARKER;
+ } else {
+ *(*next)++ = '\0';
+ break;
+ }
+ }
+
+ return( lineStr );
+}
+
+nsresult nsAbLDIFService::GetLdifStringRecord(char* buf, int32_t len, int32_t& stopPos)
+{
+ for (; stopPos < len; stopPos++)
+ {
+ char c = buf[stopPos];
+
+ if (c == 0xA)
+ {
+ mLFCount++;
+ }
+ else if (c == 0xD)
+ {
+ mCRCount++;
+ }
+ else
+ {
+ if (mLFCount == 0 && mCRCount == 0)
+ mLdifLine.Append(c);
+ else if (( mLFCount > 1) || ( mCRCount > 2 && mLFCount ) ||
+ ( !mLFCount && mCRCount > 1 ))
+ {
+ return NS_OK;
+ }
+ else if ((mLFCount == 1 || mCRCount == 1))
+ {
+ mLdifLine.Append('\n');
+ mLdifLine.Append(c);
+ mLFCount = 0;
+ mCRCount = 0;
+ }
+ }
+ }
+
+ if (((stopPos == len) && (mLFCount > 1)) || (mCRCount > 2 && mLFCount) ||
+ (!mLFCount && mCRCount > 1))
+ return NS_OK;
+
+ return NS_ERROR_FAILURE;
+}
+
+void nsAbLDIFService::AddLdifRowToDatabase(nsIAddrDatabase *aDatabase,
+ bool bIsList)
+{
+ // If no data to process then reset CR/LF counters and return.
+ if (mLdifLine.IsEmpty())
+ {
+ mLFCount = 0;
+ mCRCount = 0;
+ return;
+ }
+
+ nsCOMPtr <nsIMdbRow> newRow;
+ if (aDatabase)
+ {
+ if (bIsList)
+ aDatabase->GetNewListRow(getter_AddRefs(newRow));
+ else
+ aDatabase->GetNewRow(getter_AddRefs(newRow));
+
+ if (!newRow)
+ return;
+ }
+ else
+ return;
+
+ char* cursor = ToNewCString(mLdifLine);
+ char* saveCursor = cursor; /* keep for deleting */
+ char* line = 0;
+ char* typeSlot = 0;
+ char* valueSlot = 0;
+ int length = 0; // the length of an ldif attribute
+ while ( (line = str_getline(&cursor)) != nullptr)
+ {
+ if (NS_SUCCEEDED(str_parse_line(line, &typeSlot, &valueSlot, &length))) {
+ AddLdifColToDatabase(aDatabase, newRow, typeSlot, valueSlot, bIsList);
+ }
+ else
+ continue; // parse error: continue with next loop iteration
+ }
+ free(saveCursor);
+ aDatabase->AddCardRowToDB(newRow);
+
+ if (bIsList)
+ aDatabase->AddListDirNode(newRow);
+
+ // Clear buffer for next record
+ ClearLdifRecordBuffer();
+}
+
+void nsAbLDIFService::AddLdifColToDatabase(nsIAddrDatabase *aDatabase,
+ nsIMdbRow* newRow, char* typeSlot,
+ char* valueSlot, bool bIsList)
+{
+ nsAutoCString colType(typeSlot);
+ nsAutoCString column(valueSlot);
+
+ // 4.x exports attributes like "givenname",
+ // mozilla does "givenName" to be compliant with RFC 2798
+ ToLowerCase(colType);
+
+ mdb_u1 firstByte = (mdb_u1)(colType.get())[0];
+ switch ( firstByte )
+ {
+ case 'b':
+ if (colType.EqualsLiteral("birthyear"))
+ aDatabase->AddBirthYear(newRow, column.get());
+ else if (colType.EqualsLiteral("birthmonth"))
+ aDatabase->AddBirthMonth(newRow, column.get());
+ else if (colType.EqualsLiteral("birthday"))
+ aDatabase->AddBirthDay(newRow, column.get());
+ break; // 'b'
+
+ case 'c':
+ if (colType.EqualsLiteral("cn") || colType.EqualsLiteral("commonname"))
+ {
+ if (bIsList)
+ aDatabase->AddListName(newRow, column.get());
+ else
+ aDatabase->AddDisplayName(newRow, column.get());
+ }
+ else if (colType.EqualsLiteral("c") || colType.EqualsLiteral("countryname"))
+ {
+ if (mStoreLocAsHome )
+ aDatabase->AddHomeCountry(newRow, column.get());
+ else
+ aDatabase->AddWorkCountry(newRow, column.get());
+ }
+
+ else if (colType.EqualsLiteral("cellphone") )
+ aDatabase->AddCellularNumber(newRow, column.get());
+
+ else if (colType.EqualsLiteral("carphone"))
+ aDatabase->AddCellularNumber(newRow, column.get());
+
+ else if (colType.EqualsLiteral("custom1"))
+ aDatabase->AddCustom1(newRow, column.get());
+
+ else if (colType.EqualsLiteral("custom2"))
+ aDatabase->AddCustom2(newRow, column.get());
+
+ else if (colType.EqualsLiteral("custom3"))
+ aDatabase->AddCustom3(newRow, column.get());
+
+ else if (colType.EqualsLiteral("custom4"))
+ aDatabase->AddCustom4(newRow, column.get());
+
+ else if (colType.EqualsLiteral("company"))
+ aDatabase->AddCompany(newRow, column.get());
+ break; // 'c'
+
+ case 'd':
+ if (colType.EqualsLiteral("description"))
+ {
+ if (bIsList)
+ aDatabase->AddListDescription(newRow, column.get());
+ else
+ aDatabase->AddNotes(newRow, column.get());
+ }
+
+ else if (colType.EqualsLiteral("department"))
+ aDatabase->AddDepartment(newRow, column.get());
+
+ else if (colType.EqualsLiteral("displayname"))
+ {
+ if (bIsList)
+ aDatabase->AddListName(newRow, column.get());
+ else
+ aDatabase->AddDisplayName(newRow, column.get());
+ }
+ break; // 'd'
+
+ case 'f':
+
+ if (colType.EqualsLiteral("fax") ||
+ colType.EqualsLiteral("facsimiletelephonenumber"))
+ aDatabase->AddFaxNumber(newRow, column.get());
+ break; // 'f'
+
+ case 'g':
+ if (colType.EqualsLiteral("givenname"))
+ aDatabase->AddFirstName(newRow, column.get());
+
+ break; // 'g'
+
+ case 'h':
+ if (colType.EqualsLiteral("homephone"))
+ aDatabase->AddHomePhone(newRow, column.get());
+
+ else if (colType.EqualsLiteral("homestreet"))
+ aDatabase->AddHomeAddress(newRow, column.get());
+
+ else if (colType.EqualsLiteral("homeurl"))
+ aDatabase->AddWebPage2(newRow, column.get());
+ break; // 'h'
+
+ case 'l':
+ if (colType.EqualsLiteral("l") || colType.EqualsLiteral("locality"))
+ {
+ if (mStoreLocAsHome)
+ aDatabase->AddHomeCity(newRow, column.get());
+ else
+ aDatabase->AddWorkCity(newRow, column.get());
+ }
+ // labeledURI contains a URI and, optionally, a label
+ // This will remove the label and place the URI as the work URL
+ else if (colType.EqualsLiteral("labeleduri"))
+ {
+ int32_t index = column.FindChar(' ');
+ if (index != -1)
+ column.SetLength(index);
+
+ aDatabase->AddWebPage1(newRow, column.get());
+ }
+
+ break; // 'l'
+
+ case 'm':
+ if (colType.EqualsLiteral("mail"))
+ aDatabase->AddPrimaryEmail(newRow, column.get());
+
+ else if (colType.EqualsLiteral("member") && bIsList)
+ aDatabase->AddLdifListMember(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mobile"))
+ aDatabase->AddCellularNumber(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozilla_aimscreenname"))
+ aDatabase->AddAimScreenName(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillacustom1"))
+ aDatabase->AddCustom1(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillacustom2"))
+ aDatabase->AddCustom2(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillacustom3"))
+ aDatabase->AddCustom3(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillacustom4"))
+ aDatabase->AddCustom4(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillahomecountryname"))
+ aDatabase->AddHomeCountry(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillahomelocalityname"))
+ aDatabase->AddHomeCity(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillahomestate"))
+ aDatabase->AddHomeState(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillahomestreet"))
+ aDatabase->AddHomeAddress(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillahomestreet2"))
+ aDatabase->AddHomeAddress2(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillahomepostalcode"))
+ aDatabase->AddHomeZipCode(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillahomeurl"))
+ aDatabase->AddWebPage2(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillanickname"))
+ {
+ if (bIsList)
+ aDatabase->AddListNickName(newRow, column.get());
+ else
+ aDatabase->AddNickName(newRow, column.get());
+ }
+
+ else if (colType.EqualsLiteral("mozillasecondemail"))
+ aDatabase->Add2ndEmail(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillausehtmlmail"))
+ {
+ ToLowerCase(column);
+ if (-1 != column.Find("true"))
+ aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::html);
+ else if (-1 != column.Find("false"))
+ aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::plaintext);
+ else
+ aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::unknown);
+ }
+
+ else if (colType.EqualsLiteral("mozillaworkstreet2"))
+ aDatabase->AddWorkAddress2(newRow, column.get());
+
+ else if (colType.EqualsLiteral("mozillaworkurl"))
+ aDatabase->AddWebPage1(newRow, column.get());
+
+ break; // 'm'
+
+ case 'n':
+ if (colType.EqualsLiteral("notes"))
+ aDatabase->AddNotes(newRow, column.get());
+
+ else if (colType.EqualsLiteral("nscpaimscreenname") ||
+ colType.EqualsLiteral("nsaimid"))
+ aDatabase->AddAimScreenName(newRow, column.get());
+
+ break; // 'n'
+
+ case 'o':
+ if (colType.EqualsLiteral("objectclass"))
+ break;
+
+ else if (colType.EqualsLiteral("ou") || colType.EqualsLiteral("orgunit"))
+ aDatabase->AddDepartment(newRow, column.get());
+
+ else if (colType.EqualsLiteral("o")) // organization
+ aDatabase->AddCompany(newRow, column.get());
+
+ break; // 'o'
+
+ case 'p':
+ if (colType.EqualsLiteral("postalcode"))
+ {
+ if (mStoreLocAsHome)
+ aDatabase->AddHomeZipCode(newRow, column.get());
+ else
+ aDatabase->AddWorkZipCode(newRow, column.get());
+ }
+
+ else if (colType.EqualsLiteral("postofficebox"))
+ {
+ nsAutoCString workAddr1, workAddr2;
+ SplitCRLFAddressField(column, workAddr1, workAddr2);
+ aDatabase->AddWorkAddress(newRow, workAddr1.get());
+ aDatabase->AddWorkAddress2(newRow, workAddr2.get());
+ }
+ else if (colType.EqualsLiteral("pager") || colType.EqualsLiteral("pagerphone"))
+ aDatabase->AddPagerNumber(newRow, column.get());
+
+ break; // 'p'
+
+ case 'r':
+ if (colType.EqualsLiteral("region"))
+ {
+ aDatabase->AddWorkState(newRow, column.get());
+ }
+
+ break; // 'r'
+
+ case 's':
+ if (colType.EqualsLiteral("sn") || colType.EqualsLiteral("surname"))
+ aDatabase->AddLastName(newRow, column.get());
+
+ else if (colType.EqualsLiteral("street"))
+ aDatabase->AddWorkAddress(newRow, column.get());
+
+ else if (colType.EqualsLiteral("streetaddress"))
+ {
+ nsAutoCString addr1, addr2;
+ SplitCRLFAddressField(column, addr1, addr2);
+ if (mStoreLocAsHome)
+ {
+ aDatabase->AddHomeAddress(newRow, addr1.get());
+ aDatabase->AddHomeAddress2(newRow, addr2.get());
+ }
+ else
+ {
+ aDatabase->AddWorkAddress(newRow, addr1.get());
+ aDatabase->AddWorkAddress2(newRow, addr2.get());
+ }
+ }
+ else if (colType.EqualsLiteral("st"))
+ {
+ if (mStoreLocAsHome)
+ aDatabase->AddHomeState(newRow, column.get());
+ else
+ aDatabase->AddWorkState(newRow, column.get());
+ }
+
+ break; // 's'
+
+ case 't':
+ if (colType.EqualsLiteral("title"))
+ aDatabase->AddJobTitle(newRow, column.get());
+
+ else if (colType.EqualsLiteral("telephonenumber") )
+ {
+ aDatabase->AddWorkPhone(newRow, column.get());
+ }
+
+ break; // 't'
+
+ case 'u':
+
+ if (colType.EqualsLiteral("uniquemember") && bIsList)
+ aDatabase->AddLdifListMember(newRow, column.get());
+
+ break; // 'u'
+
+ case 'w':
+ if (colType.EqualsLiteral("workurl"))
+ aDatabase->AddWebPage1(newRow, column.get());
+
+ break; // 'w'
+
+ case 'x':
+ if (colType.EqualsLiteral("xmozillanickname"))
+ {
+ if (bIsList)
+ aDatabase->AddListNickName(newRow, column.get());
+ else
+ aDatabase->AddNickName(newRow, column.get());
+ }
+
+ else if (colType.EqualsLiteral("xmozillausehtmlmail"))
+ {
+ ToLowerCase(column);
+ if (-1 != column.Find("true"))
+ aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::html);
+ else if (-1 != column.Find("false"))
+ aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::plaintext);
+ else
+ aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::unknown);
+ }
+
+ break; // 'x'
+
+ case 'z':
+ if (colType.EqualsLiteral("zip")) // alias for postalcode
+ {
+ if (mStoreLocAsHome)
+ aDatabase->AddHomeZipCode(newRow, column.get());
+ else
+ aDatabase->AddWorkZipCode(newRow, column.get());
+ }
+
+ break; // 'z'
+
+ default:
+ break; // default
+ }
+}
+
+void nsAbLDIFService::ClearLdifRecordBuffer()
+{
+ if (!mLdifLine.IsEmpty())
+ {
+ mLdifLine.Truncate();
+ mLFCount = 0;
+ mCRCount = 0;
+ }
+}
+
+// Some common ldif fields, it an ldif file has NONE of these entries
+// then it is most likely NOT an ldif file!
+static const char *const sLDIFFields[] = {
+ "objectclass",
+ "sn",
+ "dn",
+ "cn",
+ "givenName",
+ "mail",
+ nullptr
+};
+#define kMaxLDIFLen 14
+
+// Count total number of legal ldif fields and records in the first 100 lines of the
+// file and if the average legal ldif field is 3 or higher than it's a valid ldif file.
+NS_IMETHODIMP nsAbLDIFService::IsLDIFFile(nsIFile *pSrc, bool *_retval)
+{
+ NS_ENSURE_ARG_POINTER(pSrc);
+ NS_ENSURE_ARG_POINTER(_retval);
+
+ *_retval = false;
+
+ nsresult rv = NS_OK;
+
+ nsCOMPtr<nsIInputStream> fileStream;
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), pSrc);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsILineInputStream> lineInputStream(do_QueryInterface(fileStream, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ int32_t lineLen = 0;
+ int32_t lineCount = 0;
+ int32_t ldifFields = 0; // total number of legal ldif fields.
+ char field[kMaxLDIFLen];
+ int32_t fLen = 0;
+ const char *pChar;
+ int32_t recCount = 0; // total number of records.
+ int32_t i;
+ bool gotLDIF = false;
+ bool more = true;
+ nsCString line;
+
+ while (more && NS_SUCCEEDED(rv) && (lineCount < 100))
+ {
+ rv = lineInputStream->ReadLine(line, &more);
+
+ if (NS_SUCCEEDED(rv) && more)
+ {
+ pChar = line.get();
+ lineLen = line.Length();
+ if (!lineLen && gotLDIF)
+ {
+ recCount++;
+ gotLDIF = false;
+ }
+
+ if (lineLen && (*pChar != ' ') && (*pChar != '\t'))
+ {
+ fLen = 0;
+
+ while (lineLen && (fLen < (kMaxLDIFLen - 1)) && (*pChar != ':'))
+ {
+ field[fLen] = *pChar;
+ pChar++;
+ fLen++;
+ lineLen--;
+ }
+
+ field[fLen] = 0;
+
+ if (lineLen && (*pChar == ':') && (fLen < (kMaxLDIFLen - 1)))
+ {
+ // see if this is an ldif field (case insensitive)?
+ i = 0;
+ while (sLDIFFields[i])
+ {
+ if (!PL_strcasecmp( sLDIFFields[i], field))
+ {
+ ldifFields++;
+ gotLDIF = true;
+ break;
+ }
+ i++;
+ }
+ }
+ }
+ }
+ lineCount++;
+ }
+
+ // If we just saw ldif address, increment recCount.
+ if (gotLDIF)
+ recCount++;
+
+ rv = fileStream->Close();
+
+ if (recCount > 1)
+ ldifFields /= recCount;
+
+ // If the average field number >= 3 then it's a good ldif file.
+ if (ldifFields >= 3)
+ {
+ *_retval = true;
+ }
+
+ return rv;
+}
+
+void nsAbLDIFService::SplitCRLFAddressField(nsCString &inputAddress, nsCString &outputLine1, nsCString &outputLine2) const
+{
+ int32_t crlfPos = inputAddress.Find("\r\n");
+ if (crlfPos != -1)
+ {
+ outputLine1 = Substring(inputAddress, 0, crlfPos);
+ outputLine2 = Substring(inputAddress, crlfPos + 2);
+ }
+ else
+ outputLine1.Assign(inputAddress);
+}
+