// // This C++ program converts an exported Netscape Messenger address book into // a Polarbar Mailer HTML address book file. // // This program is protected by US law and international treaty. // Copyright 2000 by David G. Holm, Berrien Springs, Michigan, USA. // All rights reserved. Permission for royalty-free distribute of the // source code and any programs derived from the source code is hereby // granted, provided that the copyright and permission notices remain // in the source code and are not modified in any manner. // #include #include #include #include #define VERSION "Beta 3" #define IN_BUF_MAX 4096 #define PATH_MAX 256 #define POLARBAR_ADDRESSBOOK_EXTENSION "AddressBook.html" #define POLARBAR_ADDRESSBOOK_PREFIX \ "\n" \ "J Street Address Book\n" \ "

NICKNAME: \n" \ "

DOMAIN: \n" \ "

SORTSTYLE: 0\n" \ "

SORTTYPE: 0\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" \ "\n" #define POLARBAR_ADDRESSBOOK_END \ "
NicknameEmail AddressFull NameGroupsAlertFolderNotesTitleOrganizationPostal AddressPhone NumberFax NumberShort ListPersona
\n" #define POLARBAR_ADDRESSBOOK_POSTFIX \ "\n" #define POLARBAR_GROUP_PREFIX \ "

%s [%s]\n" \ "

    \n" #define POLARBAR_GROUP_ENTRY \ "
  • %s\n" #define POLARBAR_GROUP_POSTFIX \ "
\n" #define PAB_ADDRESS_LINE_SEPARATOR \ "
" #define PAB_ADDRESS_PART_SEPARATOR \ " " #define PAB_ENTRY_PREFIX \ "\n" #define PAB_ENTRY_POSTFIX \ "\n" #define PAB_FIELD_PREFIX \ "" #define PAB_FIELD_POSTFIX \ "\n" #define HTML_BOLD_PREFIX \ "" #define HTML_BOLD_POSTFIX \ "" #define NS_BASE64_FIELD_INDICATOR \ ":: " #define NS_FIELD_INDICATOR \ ": " static const size_t max_string = 256; struct entry_struct { char nickname[ max_string ]; char full_name[ max_string ]; char email[ max_string ]; entry_struct * next_ptr; }; class nick_class { private: int size; struct entry_struct * first_ptr, * current_ptr, * last_ptr; public: nick_class() { size = 0; first_ptr = NULL; last_ptr = NULL; current_ptr = NULL; }; ~nick_class() { size = 0; current_ptr = first_ptr; while( first_ptr ) { first_ptr = current_ptr->next_ptr; delete current_ptr; current_ptr = first_ptr; } }; int add_entry( const char * nick, const char * name, const char * email ) { int len, count = 0; current_ptr = new entry_struct; { // Insert the new entry into the singly linked list. current_ptr->next_ptr = NULL; if( last_ptr ) { last_ptr->next_ptr = current_ptr; last_ptr = current_ptr; } else if ( first_ptr ) { first_ptr->next_ptr = current_ptr; last_ptr = current_ptr; } else first_ptr = current_ptr; count = ++size; // Save the data into the new entry. len = max_string - 1; if( nick ) strncpy( current_ptr->nickname, nick, max_string ); else len = 0; current_ptr->nickname[ len ] = '\0'; len = max_string - 1; if( name ) strncpy( current_ptr->full_name, name, max_string ); else len = 0; current_ptr->full_name[ len ] = '\0'; if( email ) strncpy( current_ptr->email, email, max_string ); else len = 0; current_ptr->email[ len ] = '\0'; } return count; }; char * find_entry( const char * name, const char * email ) { current_ptr = first_ptr; for( int i = 0; i < size; i++ ) { if( strcmp( current_ptr->full_name, name ) == 0 && strcmp( current_ptr->email, email ) == 0 ) { return current_ptr->nickname; } current_ptr = current_ptr->next_ptr; } return NULL; }; int get_size() { return size; } void first( void ) { current_ptr = first_ptr; } void next( void ) { if( current_ptr ) current_ptr = current_ptr->next_ptr; } char * get_nickname( void ) { char * nick = NULL; if( current_ptr ) nick = current_ptr->nickname; return nick; } char * get_name( void ) { char * nick = NULL; if( current_ptr ) nick = current_ptr->full_name; return nick; } char * get_email( void ) { char * nick = NULL; if( current_ptr ) nick = current_ptr->email; return nick; } } nicknames; class group_class { private: int size; struct group_struct { entry_struct * entry; nick_class * nick; group_struct * next_ptr; } * first_ptr, * current_ptr, * last_ptr; public: group_class() { size = 0; first_ptr = NULL; last_ptr = NULL; current_ptr = NULL; }; ~group_class() { size = 0; current_ptr = first_ptr; while( first_ptr ) { first_ptr = current_ptr->next_ptr; delete current_ptr; current_ptr = first_ptr; } }; int add_group( const char * name, const char * nick ) { int len, count = 0; current_ptr = new group_struct; { // Insert the new entry into the singly linked list. current_ptr->next_ptr = NULL; current_ptr->nick = new nick_class; current_ptr->entry = new entry_struct; if( last_ptr ) { last_ptr->next_ptr = current_ptr; last_ptr = current_ptr; } else if ( first_ptr ) { first_ptr->next_ptr = current_ptr; last_ptr = current_ptr; } else first_ptr = current_ptr; count = ++size; // Save the data into the new group. len = max_string - 1; if( name ) strncpy( current_ptr->entry->full_name, name, max_string ); else len = 0; current_ptr->entry->full_name[ len ] = '\0'; len = max_string - 1; if( nick ) strncpy( current_ptr->entry->nickname, nick, max_string ); else len = 0; current_ptr->entry->nickname[ len ] = '\0'; len = max_string - 1; } return count; }; int add_nick( const char * nick, const char * name, const char * email ) { int entry = 0; if( current_ptr ) entry = current_ptr->nick->add_entry( nick, name, email ); return entry; }; int get_size() { return size; } void first( void ) { current_ptr = first_ptr; } void next( void ) { if( current_ptr ) current_ptr = current_ptr->next_ptr; } int get_nick_size( void ) { int count = 0; if( current_ptr ) count = current_ptr->nick->get_size(); return count; } char * get_group_name( void ) { char * name = NULL; if( current_ptr ) name = current_ptr->entry->full_name; return name; } char * get_group_nickname( void ) { char * nick = NULL; if( current_ptr ) nick = current_ptr->entry->nickname; return nick; } void first_nick( void ) { if( current_ptr ) current_ptr->nick->first(); } void next_nick( void ) { if( current_ptr ) current_ptr->nick->next(); } char * get_nickname( void ) { char * nick = NULL; if( current_ptr ) nick = current_ptr->nick->get_nickname(); return nick; } char * get_name( void ) { char * name = NULL; if( current_ptr ) name = current_ptr->nick->get_name(); return name; } char * get_email( void ) { char * name = NULL; if( current_ptr ) name = current_ptr->nick->get_email(); return name; } } group; static long next_nickname; static char decodeTable[ 256 ]; void initDecode() { static char map[ 65 ] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; for (int i = 0; i < 64; i++) decodeTable[ map[ i ] ] = i; } char * decode(const char * src) { char * decoded = NULL; size_t size = strlen( src ); if ((size % 4) == 0) { size_t t = 0; decoded = new char [ ( size * 3 ) / 4 ]; for( size_t i = 0; i < size; i += 4 ) { int i1 = decodeTable[ src[ i ] ]; int i2 = decodeTable[ src[ i + 1 ] ]; int i3 = decodeTable[ src[ i + 2 ] ] & 0x3f; int i4 = decodeTable[ src[ i + 3 ] ] & 0x3f; decoded[ t++ ] = ( ( i1 << 2 ) + ( i2 >> 4 ) ); if( src[ i + 2 ] != '=' ) { decoded[ t++ ] = ( ( ( i2 & 0xf ) << 4 ) + ( i3 >> 2 ) ); } if( src[ i + 3 ] != '=' ) { decoded[ t++ ] = ( ( ( i3 & 0x3 ) << 6 ) + i4 ); } } decoded[ t ] = '\0'; } return decoded; } char * remove_field_name( char * buffer ) { char * ptr = strstr( buffer, NS_BASE64_FIELD_INDICATOR ); if( ptr ) { ptr += strlen( NS_BASE64_FIELD_INDICATOR ); ptr = decode( ptr ); } else { ptr = strstr( buffer, NS_FIELD_INDICATOR ); if( ptr ) ptr += strlen( NS_FIELD_INDICATOR ); } return ptr; } char * write_entry( FILE * out_file, char * buffer, char * default_value = NULL ); char * write_entry( FILE * out_file, char * buffer, char * default_value ) { char * ptr = remove_field_name( buffer ); if( ptr == NULL ) ptr = default_value; if( ptr ) fputs( ptr, out_file ); return ptr; } char * write_field( FILE * out_file, char * buffer, char * default_value = NULL ); char * write_field( FILE * out_file, char * buffer, char * default_value ) { char * ptr; fputs( PAB_FIELD_PREFIX, out_file ); ptr = write_entry( out_file, buffer, default_value ); fputs( PAB_FIELD_POSTFIX, out_file ); return ptr; } char * write_nickname( FILE * out_file, char * buffer, char * default_1, char * default_2 ) { char * nickname_used, number[ 16 ]; fputs( PAB_FIELD_PREFIX, out_file ); fputs( HTML_BOLD_PREFIX, out_file ); sprintf( number, "%li", next_nickname++ ); if( *buffer ) nickname_used = write_entry( out_file, buffer ); else if( *default_1 ) nickname_used = write_entry( out_file, default_1 ); else nickname_used = write_entry( out_file, default_2, number ); fputs( HTML_BOLD_POSTFIX, out_file ); fputs( PAB_FIELD_POSTFIX, out_file ); return nickname_used; } void write_postal_address( FILE * out_file, char * street_address, char * locality, char * state, char * postal_code, char * country_name ) { fputs( PAB_FIELD_PREFIX, out_file ); write_entry( out_file, street_address ); fputs( PAB_ADDRESS_LINE_SEPARATOR, out_file ); write_entry( out_file, locality ); fputs( PAB_ADDRESS_PART_SEPARATOR, out_file ); write_entry( out_file, state ); fputs( PAB_ADDRESS_PART_SEPARATOR, out_file ); write_entry( out_file, postal_code ); fputs( PAB_ADDRESS_LINE_SEPARATOR, out_file ); write_entry( out_file, country_name ); fputs( PAB_FIELD_POSTFIX, out_file ); } int main( int argc, char * argv[] ) { int rc = 0; char path[ PATH_MAX ]; FILE * in_file; FILE * out_file = NULL; fputs( "\nCopyright 2000 by David G. Holm, Berrien Springs, Michigan, USA.\n", stderr ); if( argc != 3 ) rc = 1; else { // Convert the starting nickname value. next_nickname = strtol( argv[ 2 ], NULL, 10 ); if( next_nickname < 1L ) rc = 6; } if( rc == 0 ) { static char in_buf[ IN_BUF_MAX + 1 ]; static char nickname[ IN_BUF_MAX + 1 ]; static char email_address[ IN_BUF_MAX + 1 ]; static char full_name[ IN_BUF_MAX + 1 ]; static char notes[ ( IN_BUF_MAX * 4 ) + 1 ]; static char title[ IN_BUF_MAX + 1 ]; static char organization[ IN_BUF_MAX + 1 ]; static char street_address[ IN_BUF_MAX + 1 ]; static char locality[ IN_BUF_MAX + 1 ]; static char state[ IN_BUF_MAX + 1 ]; static char postal_code[ IN_BUF_MAX + 1 ]; static char country_name[ IN_BUF_MAX + 1 ]; static char phone_number[ IN_BUF_MAX + 1 ]; static char fax_number[ IN_BUF_MAX + 1 ]; char * last_entry = NULL; char * out_buf; size_t in_size; int group_member_count = 0; initDecode(); // Open the Netscape Messenger exported address book file. in_file = fopen( argv[ 1 ], "r" ); if( in_file == NULL ) rc = 2; // Check if the output file name buffer might overflow. else if( strlen( argv[ 1 ] ) > PATH_MAX - strlen( POLARBAR_ADDRESSBOOK_EXTENSION ) - 1 ) rc = 3; else { // Create the output file name from the input file name. strcpy( path, argv[ 1 ] ); for( int i = strlen( path ); i && path[ i - 1 ] != '.'; i-- ) { // Remove the current file name extension. path[ i - 1 ] = '\0'; } // Append the Polarbar Mailer address book file name extension. strcat( path, POLARBAR_ADDRESSBOOK_EXTENSION ); // If the file doesn't already exist, create it. if( access( path, 00 ) == 0 ) rc = 5; else { out_file = fopen( path, "w" ); if( !out_file ) rc = 4; else fputs( POLARBAR_ADDRESSBOOK_PREFIX, out_file ); } } while( !rc && !feof( in_file ) ) { // Read a line from the Netscape Messenger file // (they all end with a single LF character). if( fgets( in_buf, IN_BUF_MAX, in_file ) ) in_size = strlen( in_buf ); else in_size = 0; if( in_size ) { // Strip trailing end-of-line character, if any. if( in_buf[ in_size - 1 ] == '\n' ) { in_size--; in_buf[ in_size ] = '\0'; } // Accumulate select address book records for each entry. if( *in_buf == ' ' ) { // This line actually goes with the previous entry. // Only save it if the previous entry was saved. if( last_entry ) strcat( last_entry, & in_buf[ 1 ] ); } else if( strncmp( in_buf, "xmozillanickname:", 17 ) == 0 ) last_entry = strcpy( nickname, in_buf ); else if( strncmp( in_buf, "mail:", 5 ) == 0 ) last_entry = strcpy( email_address, in_buf ); else if( strncmp( in_buf, "cn:", 3 ) == 0 ) last_entry = strcpy( full_name, in_buf ); else if( strncmp( in_buf, "description:", 12 ) == 0 ) last_entry = strcpy( notes, in_buf ); else if( strncmp( in_buf, "title:", 6 ) == 0 ) last_entry = strcpy( title, in_buf ); else if( strncmp( in_buf, "o:", 2 ) == 0 ) last_entry = strcpy( organization, in_buf ); else if( strncmp( in_buf, "streetaddress:", 14 ) == 0 ) last_entry = strcpy( street_address, in_buf ); else if( strncmp( in_buf, "locality:", 9 ) == 0 ) last_entry = strcpy( locality, in_buf ); else if( strncmp( in_buf, "st:", 3 ) == 0 ) last_entry = strcpy( state, in_buf ); else if( strncmp( in_buf, "postalcode:", 11 ) == 0 ) last_entry = strcpy( postal_code, in_buf ); else if( strncmp( in_buf, "countryname:", 12 ) == 0 ) last_entry = strcpy( country_name, in_buf ); else if( strncmp( in_buf, "telephonenumber:", 16 ) == 0 ) last_entry = strcpy( phone_number, in_buf ); else if( strncmp( in_buf, "facsimiletelephonenumber:", 24 ) == 0 ) last_entry = strcpy( fax_number, in_buf ); else if( strncmp( in_buf, "member:", 7 ) == 0 ) { if( group_member_count == 0 ) { group.add_group( remove_field_name( full_name ), remove_field_name( nickname ) ); } char * cn = strstr( in_buf, "cn=" ); if( cn ) cn += 3; // Set up the name string. char * mail = strstr( in_buf, ",mail=" ); if( mail ) { // Null terminate the name string and setup the email string. * mail = '\0'; mail += 6; } group.add_nick( NULL, cn, mail ); group_member_count++; last_entry = NULL; } else last_entry = NULL; // Check for the end of an actual address book entry. if( strlen( in_buf ) == 0 ) { // Is this an address book entry that is to be saved? if( ( * email_address || * full_name ) && group_member_count == 0 ) { // Write the address book entry. fputs( PAB_ENTRY_PREFIX, out_file ); char * nick = write_nickname( out_file, nickname, full_name, organization ); char * email = write_field( out_file, email_address, "@" ); char * name = write_field( out_file, full_name ); write_field( out_file, "" ); write_field( out_file, "" ); write_field( out_file, "" ); write_field( out_file, notes ); write_field( out_file, title ); write_field( out_file, organization ); write_postal_address( out_file, street_address, locality, state, postal_code, country_name ); write_field( out_file, phone_number ); write_field( out_file, fax_number ); write_field( out_file, "false" ); write_field( out_file, "" ); fputs( PAB_ENTRY_POSTFIX, out_file ); // Save the current nickname, full name, and email values // for later use when creating groups from lists. nicknames.add_entry( nick, name, email ); } // Reset the address book entry accumulators. group_member_count = 0; *nickname = '\0'; *email_address = '\0'; *full_name = '\0'; *notes = '\0'; *title = '\0'; *organization = '\0'; *street_address = '\0'; *locality = '\0'; *state = '\0'; *postal_code = '\0'; *country_name = '\0'; *phone_number = '\0'; *fax_number = '\0'; } } } if( out_file ) { // Indicate the end of the address part of the address book. fputs( POLARBAR_ADDRESSBOOK_END, out_file ); } if( out_file && group.get_size() > 0 ) { // Convert any Netscape lists to Polarbar groups. char * nickname, * name, * email, number[ 16 ]; group.first(); for( int i = 0; i < group.get_size(); i++ ) { // Write the group prefix, name and nickname. name = group.get_group_name(); nickname = group.get_group_nickname(); sprintf( number, "%li", next_nickname++ ); if( !nickname || !*nickname ) nickname = name; else nickname = number; fprintf( out_file, POLARBAR_GROUP_PREFIX, name, nickname ); // Write all of the group member nicknames, starting with the first. group.first_nick(); for( int j = 0; j < group.get_nick_size(); j++ ) { // Get data values for current nickname entry for group. name = group.get_name(); email = group.get_email(); nickname = nicknames.find_entry( name, email ); // Write a group entry, if the nickname was located. if( nickname ) fprintf( out_file, POLARBAR_GROUP_ENTRY, nickname ); // Set up for next nickname entry for group. group.next_nick(); } // Write the group postfix and setup for the next group. fputs( POLARBAR_GROUP_POSTFIX, out_file ); group.next(); } } if( out_file ) { // Indicate the end of the address book file. fputs( POLARBAR_ADDRESSBOOK_POSTFIX, out_file ); fclose( out_file ); fprintf( stderr, "\nSuccess: The Netscape address book export file has been converted:\n %s\n => %s\n", argv[ 1 ], path ); } fclose( in_file ); } if( rc == 6 ) { fprintf( stderr, "\nError: Bad starting nickname value:\n %s\n", argv[ 2 ] ); } if( rc == 5 ) { fprintf( stderr, "\nError: The destination file already exists:\n %s\n", path ); } if( rc == 4 ) { fprintf( stderr, "\nError: The destination file could not be created:\n %s\n", path ); } if( rc == 3 ) { fprintf( stderr, "\nError: The source path is too long to create the destination file\n %s\n", argv[ 1 ] ); } if( rc == 2 ) { fprintf( stderr, "\nError: The source file could not be opened:\n %s\n", argv[ 1 ] ); } if( rc == 1 ) { // Find the start of the actual EXE file name. size_t count, last = 0; for( count = 0; count < strlen( argv[ 0 ] ); count++ ) { switch( argv[ 0 ][ count ] ) { case ':': case '\\': case '/': last = count + 1; } } // Display the correct command line syntax. fprintf( stderr, "\nSyntax: %s exported_Netscape_address_book first_nickname\n\n" "Version: " VERSION "\n\n" "This C++ program converts an exported Netscape Messenger\n" "address book LDIF file into a Polarbar Mailer HTML address\n" "book file the first nickname must be a numeric value. It is\n" "incremented for each Polarbar Mailer address book entry, but\n" "is only used for those entries that do not have a nickname,\n" "full name, or organization name in the Netscape address book.\n" , &argv[ 0 ][ last ] ); } return rc; }