Mercurial > libpst
view src/pst2ldif.cpp @ 59:7d5c637aaafb
General cleanup and code fixes.
Use autoscan to cleanup our autoconf system.
Use autoconf to detect when we need to use our XGetopt files and other header files.
Decode BCC field.
Fix missing LE32_CPU byte swapping for FILETIME types.
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 14 Feb 2008 14:55:32 -0800 |
parents | 034641c26ab9 |
children | 3cb02cb1e6cd |
line wrap: on
line source
/* Copyright (c) 2004 Carl Byington - 510 Software Group, released under the GPL version 2 or any later version at your choice available at http://www.fsf.org/licenses/gpl.txt Based on readpst.c by David Smith */ using namespace std; // needed for std c++ collections #include <set> extern "C" { #include "define.h" #include "libstrfunc.h" #include "libpst.h" #include "common.h" #include "timeconv.h" #include "lzfu.h" } int32_t usage(); int32_t version(); char *my_stristr(char *haystack, char *needle); char *check_filename(char *fname); char *single(char *str); char *folded(char *str); void multi(char *fmt, char *str); char *rfc2426_escape(char *str); int32_t chr_count(char *str, char x); char *prog_name; pst_file pstfile; char *ldap_base = NULL; // 'o=some.domain.tld, c=US' char *ldap_class = NULL; // 'newPerson' char *ldap_org = NULL; // 'o=some.domain.tld', computed from ldap_base //////////////////////////////////////////////// // define our ordering struct ltstr { bool operator()(char* s1, char* s2) const { return strcasecmp(s1, s2) < 0; } }; // define our set typedef set<char *, ltstr> string_set; // make a static set to hold the cn values static string_set all_strings; //////////////////////////////////////////////// // helper to free all the strings in a set // static void free_strings(string_set &s); static void free_strings(string_set &s) { for (string_set::iterator i=s.begin(); i!=s.end(); i++) { free(*i); } s.clear(); } //////////////////////////////////////////////// // helper to register a string in a string set // static char* register_string(string_set &s, char *name); static char* register_string(string_set &s, char *name) { string_set::iterator i = s.find(name); if (i != s.end()) return *i; char *x = strdup(name); s.insert(x); return x; } //////////////////////////////////////////////// // register a global string // static char* register_string(char *name); static char* register_string(char *name) { return register_string(all_strings, name); } //////////////////////////////////////////////// // make a unique string // static char* unique_string(char *name); static char* unique_string(char *name) { int unique = 2; string_set::iterator i = all_strings.find(name); if (i == all_strings.end()) return register_string(name); while (true) { char n[strlen(name)+10]; snprintf(n, sizeof(n), "%s %d", name, unique++); string_set::iterator i = all_strings.find(n); if (i == all_strings.end()) return register_string(n); } } //////////////////////////////////////////////// // remove leading and trailing blanks // static char *trim(char *name); static char *trim(char *name) { char *p; while (*name == ' ') name++; p = name + strlen(name) - 1; while ((p >= name) && (*p == ' ')) *p-- = '\0'; return name; } static void process(pst_desc_ll *d_ptr); static void process(pst_desc_ll *d_ptr) { pst_item *item = NULL; while (d_ptr) { if (d_ptr->desc) { item = pst_parse_item(&pstfile, d_ptr); DEBUG_INFO(("item pointer is %p\n", item)); if (item) { if (item->message_store) { // there should only be one message_store, and we have already done it DIE(("main: A second message_store has been found. Sorry, this must be an error.\n")); } if (item->folder && d_ptr->child && strcasecmp(item->file_as, "Deleted Items")) { //if this is a non-empty folder other than deleted items, we want to recurse into it fprintf(stderr, "entering folder %s\n", item->file_as); process(d_ptr->child); } else if (item->contact) { // deal with a contact if (item->type != PST_TYPE_CONTACT) { DIE(("type should be contact\n")); } else if (item->contact == NULL) { // this is an incorrect situation. Inform user DIE(("null item contact\n")); } else { char cn[1000]; snprintf(cn, sizeof(cn), "%s %s %s %s", single(item->contact->display_name_prefix), single(item->contact->first_name), single(item->contact->surname), single(item->contact->suffix)); if (strcmp(cn, " ")) { // fprintf(stderr, "\n\n\n"); // fprintf(stderr, "access_method %s\n", item->contact->access_method); // fprintf(stderr, "account_name %s\n", item->contact->account_name); // fprintf(stderr, "address1 %s\n", item->contact->address1); // fprintf(stderr, "address1_desc %s\n", item->contact->address1_desc); // fprintf(stderr, "address1_transport %s\n", item->contact->address1_transport); // fprintf(stderr, "address2 %s\n", item->contact->address2); // fprintf(stderr, "address2_desc %s\n", item->contact->address2_desc); // fprintf(stderr, "address2_transport %s\n", item->contact->address2_transport); // fprintf(stderr, "address3 %s\n", item->contact->address3); // fprintf(stderr, "address3_desc %s\n", item->contact->address3_desc); // fprintf(stderr, "address3_transport %s\n", item->contact->address3_transport); // fprintf(stderr, "assistant_name %s\n", item->contact->assistant_name); // fprintf(stderr, "assistant_phone %s\n", item->contact->assistant_phone); // fprintf(stderr, "billing_information %s\n", item->contact->billing_information); // fprintf(stderr, "business_address %s\n", item->contact->business_address); // fprintf(stderr, "business_city %s\n", item->contact->business_city); // fprintf(stderr, "business_country %s\n", item->contact->business_country); // fprintf(stderr, "business_fax %s\n", item->contact->business_fax); // fprintf(stderr, "business_homepage %s\n", item->contact->business_homepage); // fprintf(stderr, "business_phone %s\n", item->contact->business_phone); // fprintf(stderr, "business_phone2 %s\n", item->contact->business_phone2); // fprintf(stderr, "business_po_box %s\n", item->contact->business_po_box); // fprintf(stderr, "business_postal_code %s\n", item->contact->business_postal_code); // fprintf(stderr, "business_state %s\n", item->contact->business_state); // fprintf(stderr, "business_street %s\n", item->contact->business_street); // fprintf(stderr, "callback_phone %s\n", item->contact->callback_phone); // fprintf(stderr, "car_phone %s\n", item->contact->car_phone); // fprintf(stderr, "company_main_phone %s\n", item->contact->company_main_phone); // fprintf(stderr, "company_name %s\n", item->contact->company_name); // fprintf(stderr, "computer_name %s\n", item->contact->computer_name); // fprintf(stderr, "customer_id %s\n", item->contact->customer_id); // fprintf(stderr, "def_postal_address %s\n", item->contact->def_postal_address); // fprintf(stderr, "department %s\n", item->contact->department); // fprintf(stderr, "display_name_prefix %s\n", item->contact->display_name_prefix); // fprintf(stderr, "first_name %s\n", item->contact->first_name); // fprintf(stderr, "followup %s\n", item->contact->followup); // fprintf(stderr, "free_busy_address %s\n", item->contact->free_busy_address); // fprintf(stderr, "ftp_site %s\n", item->contact->ftp_site); // fprintf(stderr, "fullname %s\n", item->contact->fullname); // fprintf(stderr, "gov_id %s\n", item->contact->gov_id); // fprintf(stderr, "hobbies %s\n", item->contact->hobbies); // fprintf(stderr, "home_address %s\n", item->contact->home_address); // fprintf(stderr, "home_city %s\n", item->contact->home_city); // fprintf(stderr, "home_country %s\n", item->contact->home_country); // fprintf(stderr, "home_fax %s\n", item->contact->home_fax); // fprintf(stderr, "home_phone %s\n", item->contact->home_phone); // fprintf(stderr, "home_phone2 %s\n", item->contact->home_phone2); // fprintf(stderr, "home_po_box %s\n", item->contact->home_po_box); // fprintf(stderr, "home_postal_code %s\n", item->contact->home_postal_code); // fprintf(stderr, "home_state %s\n", item->contact->home_state); // fprintf(stderr, "home_street %s\n", item->contact->home_street); // fprintf(stderr, "initials %s\n", item->contact->initials); // fprintf(stderr, "isdn_phone %s\n", item->contact->isdn_phone); // fprintf(stderr, "job_title %s\n", item->contact->job_title); // fprintf(stderr, "keyword %s\n", item->contact->keyword); // fprintf(stderr, "language %s\n", item->contact->language); // fprintf(stderr, "location %s\n", item->contact->location); // fprintf(stderr, "manager_name %s\n", item->contact->manager_name); // fprintf(stderr, "middle_name %s\n", item->contact->middle_name); // fprintf(stderr, "mileage %s\n", item->contact->mileage); // fprintf(stderr, "mobile_phone %s\n", item->contact->mobile_phone); // fprintf(stderr, "nickname %s\n", item->contact->nickname); // fprintf(stderr, "office_loc %s\n", item->contact->office_loc); // fprintf(stderr, "org_id %s\n", item->contact->org_id); // fprintf(stderr, "other_address %s\n", item->contact->other_address); // fprintf(stderr, "other_city %s\n", item->contact->other_city); // fprintf(stderr, "other_country %s\n", item->contact->other_country); // fprintf(stderr, "other_phone %s\n", item->contact->other_phone); // fprintf(stderr, "other_po_box %s\n", item->contact->other_po_box); // fprintf(stderr, "other_postal_code %s\n", item->contact->other_postal_code); // fprintf(stderr, "other_state %s\n", item->contact->other_state); // fprintf(stderr, "other_street %s\n", item->contact->other_street); // fprintf(stderr, "pager_phone %s\n", item->contact->pager_phone); // fprintf(stderr, "personal_homepage %s\n", item->contact->personal_homepage); // fprintf(stderr, "pref_name %s\n", item->contact->pref_name); // fprintf(stderr, "primary_fax %s\n", item->contact->primary_fax); // fprintf(stderr, "primary_phone %s\n", item->contact->primary_phone); // fprintf(stderr, "profession %s\n", item->contact->profession); // fprintf(stderr, "radio_phone %s\n", item->contact->radio_phone); // fprintf(stderr, "spouse_name %s\n", item->contact->spouse_name); // fprintf(stderr, "suffix %s\n", item->contact->suffix); // fprintf(stderr, "surname %s\n", item->contact->surname); // fprintf(stderr, "telex %s\n", item->contact->telex); // fprintf(stderr, "transmittable_display_name %s\n", item->contact->transmittable_display_name); // fprintf(stderr, "ttytdd_phone %s\n", item->contact->ttytdd_phone); // have a valid cn char *ucn = unique_string(folded(trim(cn))); printf("dn: cn=%s, %s\n", ucn, ldap_base); printf("cn: %s\n", ucn); if (item->contact->first_name) { snprintf(cn, sizeof(cn), "%s %s", single(item->contact->display_name_prefix), single(item->contact->first_name)); printf("givenName: %s\n", trim(cn)); } if (item->contact->surname) { snprintf(cn, sizeof(cn), "%s %s", single(item->contact->surname), single(item->contact->suffix)); printf("sn: %s\n", trim(cn)); } else if (item->contact->company_name) { printf("sn: %s\n", single(item->contact->company_name)); } else printf("sn: %s\n", ucn); // use cn as sn if we cannot find something better if (item->contact->job_title) printf("personalTitle: %s\n", single(item->contact->job_title)); if (item->contact->company_name) printf("company: %s\n", single(item->contact->company_name)); if (item->contact->address1 && *item->contact->address1) printf("mail: %s\n", single(item->contact->address1)); if (item->contact->address2 && *item->contact->address2) printf("mail: %s\n", single(item->contact->address2)); if (item->contact->address3 && *item->contact->address3) printf("mail: %s\n", single(item->contact->address3)); if (item->contact->address1a && *item->contact->address1a) printf("mail: %s\n", single(item->contact->address1a)); if (item->contact->address2a && *item->contact->address2a) printf("mail: %s\n", single(item->contact->address2a)); if (item->contact->address3a && *item->contact->address3a) printf("mail: %s\n", single(item->contact->address3a)); if (item->contact->business_address) { if (item->contact->business_po_box) printf("postalAddress: %s\n", single(item->contact->business_po_box)); if (item->contact->business_street) multi("postalAddress: %s\n", item->contact->business_street); if (item->contact->business_city) printf("l: %s\n", single(item->contact->business_city)); if (item->contact->business_state) printf("st: %s\n", single(item->contact->business_state)); if (item->contact->business_postal_code) printf("postalCode: %s\n", single(item->contact->business_postal_code)); } else if (item->contact->home_address) { if (item->contact->home_po_box) printf("postalAddress: %s\n", single(item->contact->home_po_box)); if (item->contact->home_street) multi("postalAddress: %s\n", item->contact->home_street); if (item->contact->home_city) printf("l: %s\n", single(item->contact->home_city)); if (item->contact->home_state) printf("st: %s\n", single(item->contact->home_state)); if (item->contact->home_postal_code) printf("postalCode: %s\n", single(item->contact->home_postal_code)); } else if (item->contact->other_address) { if (item->contact->other_po_box) printf("postalAddress: %s\n", single(item->contact->other_po_box)); if (item->contact->other_street) multi("postalAddress: %s\n", item->contact->other_street); if (item->contact->other_city) printf("l: %s\n", single(item->contact->other_city)); if (item->contact->other_state) printf("st: %s\n", single(item->contact->other_state)); if (item->contact->other_postal_code) printf("postalCode: %s\n", single(item->contact->other_postal_code)); } if (item->contact->business_fax) printf("facsimileTelephoneNumber: %s\n", single(item->contact->business_fax)); else if (item->contact->home_fax) printf("facsimileTelephoneNumber: %s\n", single(item->contact->home_fax)); if (item->contact->business_phone) printf("telephoneNumber: %s\n", single(item->contact->business_phone)); if (item->contact->home_phone) printf("homePhone: %s\n", single(item->contact->home_phone)); if (item->contact->car_phone) printf("mobile: %s\n", single(item->contact->car_phone)); else if (item->contact->mobile_phone) printf("mobile: %s\n", single(item->contact->mobile_phone)); else if (item->contact->other_phone) printf("mobile: %s\n", single(item->contact->other_phone)); if (item->comment) printf("description: %s\n", single(item->comment)); printf("objectClass: %s\n\n", ldap_class); } } } else { DEBUG_INFO(("item is not a contact\n")); } } pst_freeItem(item); } d_ptr = d_ptr->next; } } int main(int argc, char** argv) { pst_desc_ll *d_ptr; char *fname = NULL; char *temp = NULL; //temporary char pointer char c; char *d_log = NULL; prog_name = argv[0]; pst_item *item = NULL; while ((c = getopt(argc, argv, "b:c:d:Vh"))!= -1) { switch (c) { case 'b': ldap_base = optarg; temp = strchr(ldap_base, ','); if (temp) { *temp = '\0'; ldap_org = strdup(ldap_base+2); // assume first 2 chars are o= *temp = ','; } break; case 'c': ldap_class = optarg; break; case 'd': d_log = optarg; break; case 'h': usage(); exit(0); break; case 'V': version(); exit(0); break; default: usage(); exit(1); break; } } if ((argc > optind) && (ldap_base) && (ldap_class) && (ldap_org)) { fname = argv[optind]; } else { usage(); exit(2); } #ifdef DEBUG_ALL // force a log file if (!d_log) d_log = "pst2ldif.log"; #endif DEBUG_INIT(d_log); DEBUG_REGISTER_CLOSE(); DEBUG_ENT("main"); RET_DERROR(pst_open(&pstfile, fname), 1, ("Error opening File\n")); RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n")); pst_load_extended_attributes(&pstfile); d_ptr = pstfile.d_head; // first record is main record item = (pst_item*)pst_parse_item(&pstfile, d_ptr); if (!item || !item->message_store) { DEBUG_RET(); DIE(("main: Could not get root record\n")); } d_ptr = pst_getTopOfFolders(&pstfile, item); if (!d_ptr) { DEBUG_RET(); DIE(("Top of folders record not found. Cannot continue\n")); } pst_freeItem(item); // write the ldap header printf("dn: %s\n", ldap_base); printf("o: %s\n", ldap_org); printf("objectClass: organization\n\n"); printf("dn: cn=root, %s\n", ldap_base); printf("cn: root\n"); printf("objectClass: %s\n\n", ldap_class); process(d_ptr->child); // do the children of TOPF pst_close(&pstfile); DEBUG_RET(); free_strings(all_strings); return 0; } int usage() { version(); printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); printf("OPTIONS:\n"); printf("\t-h\t- Help. This screen\n"); printf("\t-V\t- Version. Display program version\n"); printf("\t-b ldapbase\t- set the ldap base value\n"); printf("\t-c class \t- set the class of the ldap objects\n"); return 0; } int version() { printf("pst2ldif v%s\n", VERSION); #if BYTE_ORDER == BIG_ENDIAN printf("Big Endian implementation being used.\n"); #elif BYTE_ORDER == LITTLE_ENDIAN printf("Little Endian implementation being used.\n"); #else # error "Byte order not supported by this library" #endif #ifdef __GNUC__ printf("GCC %d.%d : %s %s\n", __GNUC__, __GNUC_MINOR__, __DATE__, __TIME__); #endif return 0; } // my_stristr varies from strstr in that its searches are case-insensitive char * my_stristr(char *haystack, char *needle) { char *x=haystack, *y=needle, *z = NULL; if (haystack == NULL || needle == NULL) return NULL; while (*y != '\0' && *x != '\0') { if (tolower(*y) == tolower(*x)) { // move y on one y++; if (z == NULL) { z = x; // store first position in haystack where a match is made } } else { y = needle; // reset y to the beginning of the needle z = NULL; // reset the haystack storage point } x++; // advance the search in the haystack } return z; } char *check_filename(char *fname) { char *t = fname; if (t == NULL) { return fname; } while ((t = strpbrk(t, "/\\:"))) { // while there are characters in the second string that we don't want *t = '_'; //replace them with an underscore } return fname; } char *single(char *str) { if (!str) return ""; char *ret = rfc2426_escape(str); char *n = strchr(ret, '\n'); if (n) *n = '\0'; return ret; } char *folded(char *str) { if (!str) return ""; char *ret = rfc2426_escape(str); char *n = ret; while (n = strchr(n, '\n')) { *n = ' '; } n = ret; while (n = strchr(n, ',')) { *n = ' '; } return ret; } void multi(char *fmt, char *str) { if (!str) return; char *ret = rfc2426_escape(str); char *n = ret; while (n = strchr(ret, '\n')) { *n = '\0'; printf(fmt, ret); ret = n+1; } if (*ret) printf(fmt, ret); } char *rfc2426_escape(char *str) { static char* buf = NULL; char *ret, *a, *b; int x = 0, y, z; if (str == NULL) ret = str; else { // calculate space required to escape all the following characters y = chr_count(str, '\\') + chr_count(str, ';'); z = chr_count(str, '\r'); if (y == 0 && z == 0) // there isn't any extra space required ret = str; else { x = strlen(str) + y - z + 1; // don't forget room for the NUL buf = (char*) realloc(buf, x); a = str; b = buf; while (*a != '\0') { switch(*a) { case '\\': case ';' : *(b++)='\\'; *b=*a; break; case '\r': // skip cr b--; break; default: *b=*a; } b++; a++; } *b = '\0'; // NUL-terminate the string (buf) ret = buf; } } return ret; } int chr_count(char *str, char x) { int r = 0; while (*str != '\0') { if (*str == x) r++; str++; } return r; }