summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/addrbook/src/nsAbLDIFService.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mailnews/addrbook/src/nsAbLDIFService.cpp
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/mailnews/addrbook/src/nsAbLDIFService.cpp')
-rw-r--r--comm/mailnews/addrbook/src/nsAbLDIFService.cpp787
1 files changed, 787 insertions, 0 deletions
diff --git a/comm/mailnews/addrbook/src/nsAbLDIFService.cpp b/comm/mailnews/addrbook/src/nsAbLDIFService.cpp
new file mode 100644
index 0000000000..2d40bec9b2
--- /dev/null
+++ b/comm/mailnews/addrbook/src/nsAbLDIFService.cpp
@@ -0,0 +1,787 @@
+/* -*- 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 "nsIAbDirectory.h"
+#include "nsIAbCard.h"
+#include "nsString.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 "nsIComponentManager.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(nsIAbDirectory* aDirectory,
+ nsIFile* aSrc,
+ bool aStoreLocAsHome,
+ uint32_t* aProgress) {
+ NS_ENSURE_ARG_POINTER(aSrc);
+ NS_ENSURE_ARG_POINTER(aDirectory);
+
+ 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(aDirectory, 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(aDirectory, 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(aDirectory, true);
+ if (NS_SUCCEEDED(
+ seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, 0)))
+ break;
+ }
+ }
+ }
+ PR_FREEIF(listBuf);
+ }
+ }
+
+ rv = inputStream->Close();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return rv;
+}
+
+/*
+ * 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 preceding 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(nsIAbDirectory* aDirectory,
+ bool bIsList) {
+ if (!aDirectory) {
+ return;
+ }
+
+ // If no data to process then reset CR/LF counters and return.
+ if (mLdifLine.IsEmpty()) {
+ mLFCount = 0;
+ mCRCount = 0;
+ return;
+ }
+
+ nsCOMPtr<nsIAbCard> newCard =
+ do_CreateInstance("@mozilla.org/addressbook/cardproperty;1");
+ nsTArray<nsCString> members;
+
+ 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))) {
+ nsAutoCString colType(typeSlot);
+ nsAutoCString column(valueSlot);
+
+ // 4.x exports attributes like "givenname",
+ // mozilla does "givenName" to be compliant with RFC 2798
+ ToLowerCase(colType);
+
+ if (colType.EqualsLiteral("member") ||
+ colType.EqualsLiteral("uniquemember")) {
+ members.AppendElement(column);
+ } else {
+ AddLdifColToDatabase(aDirectory, newCard, colType, column, bIsList);
+ }
+ } else
+ continue; // parse error: continue with next loop iteration
+ }
+ free(saveCursor);
+
+ if (bIsList) {
+ nsCOMPtr<nsIAbDirectory> newList =
+ do_CreateInstance("@mozilla.org/addressbook/directoryproperty;1");
+ newList->SetIsMailList(true);
+
+ nsAutoString temp;
+ newCard->GetDisplayName(temp);
+ newList->SetDirName(temp);
+ temp.Truncate();
+ newCard->GetPropertyAsAString(kNicknameProperty, temp);
+ newList->SetListNickName(temp);
+ temp.Truncate();
+ newCard->GetPropertyAsAString(kNotesProperty, temp);
+ newList->SetDescription(temp);
+
+ nsIAbDirectory* outList;
+ nsresult rv = aDirectory->AddMailList(newList, &outList);
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ int32_t count = members.Length();
+ for (int32_t i = 0; i < count; ++i) {
+ nsAutoCString email;
+ int32_t emailPos = members[i].Find("mail=");
+ emailPos += strlen("mail=");
+ email = Substring(members[i], emailPos);
+
+ nsCOMPtr<nsIAbCard> emailCard;
+ aDirectory->CardForEmailAddress(email, getter_AddRefs(emailCard));
+ if (emailCard) {
+ nsIAbCard* outCard;
+ outList->AddCard(emailCard, &outCard);
+ }
+ }
+ } else {
+ nsIAbCard* outCard;
+ aDirectory->AddCard(newCard, &outCard);
+ }
+
+ // Clear buffer for next record
+ ClearLdifRecordBuffer();
+}
+
+void nsAbLDIFService::AddLdifColToDatabase(nsIAbDirectory* aDirectory,
+ nsIAbCard* newCard,
+ nsCString colType, nsCString column,
+ bool bIsList) {
+ nsString value = NS_ConvertUTF8toUTF16(column);
+
+ char firstByte = colType.get()[0];
+ switch (firstByte) {
+ case 'b':
+ if (colType.EqualsLiteral("birthyear"))
+ newCard->SetPropertyAsAString(kBirthYearProperty, value);
+ else if (colType.EqualsLiteral("birthmonth"))
+ newCard->SetPropertyAsAString(kBirthMonthProperty, value);
+ else if (colType.EqualsLiteral("birthday"))
+ newCard->SetPropertyAsAString(kBirthDayProperty, value);
+ break; // 'b'
+
+ case 'c':
+ if (colType.EqualsLiteral("cn") || colType.EqualsLiteral("commonname")) {
+ newCard->SetDisplayName(value);
+ } else if (colType.EqualsLiteral("c") ||
+ colType.EqualsLiteral("countryname")) {
+ if (mStoreLocAsHome)
+ newCard->SetPropertyAsAString(kHomeCountryProperty, value);
+ else
+ newCard->SetPropertyAsAString(kWorkCountryProperty, value);
+ }
+
+ else if (colType.EqualsLiteral("cellphone"))
+ newCard->SetPropertyAsAString(kCellularProperty, value);
+
+ else if (colType.EqualsLiteral("carphone"))
+ newCard->SetPropertyAsAString(kCellularProperty, value);
+
+ else if (colType.EqualsLiteral("custom1"))
+ newCard->SetPropertyAsAString(kCustom1Property, value);
+
+ else if (colType.EqualsLiteral("custom2"))
+ newCard->SetPropertyAsAString(kCustom2Property, value);
+
+ else if (colType.EqualsLiteral("custom3"))
+ newCard->SetPropertyAsAString(kCustom3Property, value);
+
+ else if (colType.EqualsLiteral("custom4"))
+ newCard->SetPropertyAsAString(kCustom4Property, value);
+
+ else if (colType.EqualsLiteral("company"))
+ newCard->SetPropertyAsAString(kCompanyProperty, value);
+ break; // 'c'
+
+ case 'd':
+ if (colType.EqualsLiteral("description"))
+ newCard->SetPropertyAsAString(kNotesProperty, value);
+
+ else if (colType.EqualsLiteral("department"))
+ newCard->SetPropertyAsAString(kDepartmentProperty, value);
+
+ else if (colType.EqualsLiteral("displayname"))
+ newCard->SetDisplayName(value);
+ break; // 'd'
+
+ case 'f':
+
+ if (colType.EqualsLiteral("fax") ||
+ colType.EqualsLiteral("facsimiletelephonenumber"))
+ newCard->SetPropertyAsAString(kFaxProperty, value);
+ break; // 'f'
+
+ case 'g':
+ if (colType.EqualsLiteral("givenname")) newCard->SetFirstName(value);
+ break; // 'g'
+
+ case 'h':
+ if (colType.EqualsLiteral("homephone"))
+ newCard->SetPropertyAsAString(kHomePhoneProperty, value);
+
+ else if (colType.EqualsLiteral("homestreet"))
+ newCard->SetPropertyAsAString(kHomeAddressProperty, value);
+
+ else if (colType.EqualsLiteral("homeurl"))
+ newCard->SetPropertyAsAString(kHomeWebPageProperty, value);
+ break; // 'h'
+
+ case 'l':
+ if (colType.EqualsLiteral("l") || colType.EqualsLiteral("locality")) {
+ if (mStoreLocAsHome)
+ newCard->SetPropertyAsAString(kHomeCityProperty, value);
+ else
+ newCard->SetPropertyAsAString(kWorkCityProperty, value);
+ }
+ // 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);
+
+ newCard->SetPropertyAsAString(kWorkWebPageProperty,
+ NS_ConvertUTF8toUTF16(column));
+ }
+
+ break; // 'l'
+
+ case 'm':
+ if (colType.EqualsLiteral("mail"))
+ newCard->SetPrimaryEmail(value);
+
+ else if (colType.EqualsLiteral("mobile"))
+ newCard->SetPropertyAsAString(kCellularProperty, value);
+
+ else if (colType.EqualsLiteral("mozilla_aimscreenname"))
+ newCard->SetPropertyAsAString(kAIMProperty, value);
+
+ else if (colType.EqualsLiteral("mozillacustom1"))
+ newCard->SetPropertyAsAString(kCustom1Property, value);
+
+ else if (colType.EqualsLiteral("mozillacustom2"))
+ newCard->SetPropertyAsAString(kCustom2Property, value);
+
+ else if (colType.EqualsLiteral("mozillacustom3"))
+ newCard->SetPropertyAsAString(kCustom3Property, value);
+
+ else if (colType.EqualsLiteral("mozillacustom4"))
+ newCard->SetPropertyAsAString(kCustom4Property, value);
+
+ else if (colType.EqualsLiteral("mozillahomecountryname"))
+ newCard->SetPropertyAsAString(kHomeCountryProperty, value);
+
+ else if (colType.EqualsLiteral("mozillahomelocalityname"))
+ newCard->SetPropertyAsAString(kHomeCityProperty, value);
+
+ else if (colType.EqualsLiteral("mozillahomestate"))
+ newCard->SetPropertyAsAString(kHomeStateProperty, value);
+
+ else if (colType.EqualsLiteral("mozillahomestreet"))
+ newCard->SetPropertyAsAString(kHomeAddressProperty, value);
+
+ else if (colType.EqualsLiteral("mozillahomestreet2"))
+ newCard->SetPropertyAsAString(kHomeAddress2Property, value);
+
+ else if (colType.EqualsLiteral("mozillahomepostalcode"))
+ newCard->SetPropertyAsAString(kHomeZipCodeProperty, value);
+
+ else if (colType.EqualsLiteral("mozillahomeurl"))
+ newCard->SetPropertyAsAString(kHomeWebPageProperty, value);
+
+ else if (colType.EqualsLiteral("mozillanickname"))
+ newCard->SetPropertyAsAString(kNicknameProperty, value);
+
+ else if (colType.EqualsLiteral("mozillasecondemail"))
+ newCard->SetPropertyAsAString(k2ndEmailProperty, value);
+
+ else if (colType.EqualsLiteral("mozillaworkstreet2"))
+ newCard->SetPropertyAsAString(kWorkAddress2Property, value);
+
+ else if (colType.EqualsLiteral("mozillaworkurl"))
+ newCard->SetPropertyAsAString(kWorkWebPageProperty, value);
+
+ break; // 'm'
+
+ case 'n':
+ if (colType.EqualsLiteral("notes"))
+ newCard->SetPropertyAsAString(kNotesProperty, value);
+
+ else if (colType.EqualsLiteral("nscpaimscreenname") ||
+ colType.EqualsLiteral("nsaimid"))
+ newCard->SetPropertyAsAString(kAIMProperty, value);
+
+ break; // 'n'
+
+ case 'o':
+ if (colType.EqualsLiteral("objectclass"))
+ break;
+
+ else if (colType.EqualsLiteral("ou") || colType.EqualsLiteral("orgunit"))
+ newCard->SetPropertyAsAString(kDepartmentProperty, value);
+
+ else if (colType.EqualsLiteral("o")) // organization
+ newCard->SetPropertyAsAString(kCompanyProperty, value);
+
+ break; // 'o'
+
+ case 'p':
+ if (colType.EqualsLiteral("postalcode")) {
+ if (mStoreLocAsHome)
+ newCard->SetPropertyAsAString(kHomeZipCodeProperty, value);
+ else
+ newCard->SetPropertyAsAString(kWorkZipCodeProperty, value);
+ }
+
+ else if (colType.EqualsLiteral("postofficebox")) {
+ nsAutoCString workAddr1, workAddr2;
+ SplitCRLFAddressField(column, workAddr1, workAddr2);
+ newCard->SetPropertyAsAString(kWorkAddressProperty,
+ NS_ConvertUTF8toUTF16(workAddr1));
+ newCard->SetPropertyAsAString(kWorkAddress2Property,
+ NS_ConvertUTF8toUTF16(workAddr2));
+ } else if (colType.EqualsLiteral("pager") ||
+ colType.EqualsLiteral("pagerphone"))
+ newCard->SetPropertyAsAString(kPagerProperty, value);
+
+ break; // 'p'
+
+ case 'r':
+ if (colType.EqualsLiteral("region")) {
+ newCard->SetPropertyAsAString(kWorkStateProperty, value);
+ }
+
+ break; // 'r'
+
+ case 's':
+ if (colType.EqualsLiteral("sn") || colType.EqualsLiteral("surname"))
+ newCard->SetPropertyAsAString(kLastNameProperty, value);
+
+ else if (colType.EqualsLiteral("street"))
+ newCard->SetPropertyAsAString(kWorkAddressProperty, value);
+
+ else if (colType.EqualsLiteral("streetaddress")) {
+ nsAutoCString addr1, addr2;
+ SplitCRLFAddressField(column, addr1, addr2);
+ if (mStoreLocAsHome) {
+ newCard->SetPropertyAsAString(kHomeAddressProperty,
+ NS_ConvertUTF8toUTF16(addr1));
+ newCard->SetPropertyAsAString(kHomeAddress2Property,
+ NS_ConvertUTF8toUTF16(addr2));
+ } else {
+ newCard->SetPropertyAsAString(kWorkAddressProperty,
+ NS_ConvertUTF8toUTF16(addr1));
+ newCard->SetPropertyAsAString(kWorkAddress2Property,
+ NS_ConvertUTF8toUTF16(addr2));
+ }
+ } else if (colType.EqualsLiteral("st")) {
+ if (mStoreLocAsHome)
+ newCard->SetPropertyAsAString(kHomeStateProperty, value);
+ else
+ newCard->SetPropertyAsAString(kWorkStateProperty, value);
+ }
+
+ break; // 's'
+
+ case 't':
+ if (colType.EqualsLiteral("title"))
+ newCard->SetPropertyAsAString(kJobTitleProperty, value);
+
+ else if (colType.EqualsLiteral("telephonenumber")) {
+ newCard->SetPropertyAsAString(kWorkPhoneProperty, value);
+ }
+
+ break; // 't'
+
+ case 'w':
+ if (colType.EqualsLiteral("workurl"))
+ newCard->SetPropertyAsAString(kWorkWebPageProperty, value);
+
+ break; // 'w'
+
+ case 'x':
+ if (colType.EqualsLiteral("xmozillanickname")) {
+ newCard->SetPropertyAsAString(kNicknameProperty, value);
+ }
+
+ break; // 'x'
+
+ case 'z':
+ if (colType.EqualsLiteral("zip")) // alias for postalcode
+ {
+ if (mStoreLocAsHome)
+ newCard->SetPropertyAsAString(kHomeZipCodeProperty, value);
+ else
+ newCard->SetPropertyAsAString(kWorkZipCodeProperty, value);
+ }
+
+ 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);
+}