#include "options.h" #include "utils.h" #include "store.h" #include "mail_handling.h" #include // only for debuging extern Store* match_pattern_store; extern Passwd* current_context_passwd; extern enum operation_mode_t operation_mode; extern options_t options; extern int expunged_mails; ////////////////////////////////////////////////////////////////////////// // // Store // ////////////////////////////////////////////////////////////////////////// void Store::clear() { name = ""; server = ""; prefix = ""; ref = ""; pat = ""; isremote = 0; delim = '!'; stream = NIL; passwd.clear(); } void Store::print(FILE* f) { fprintf( f, "store %s {", name.c_str() ); if (server != "") { fprintf( f, "\n\tserver "); print_with_escapes( f, server); } if (prefix != "") { fprintf( f, "\n\tprefix "); print_with_escapes( f, prefix); } if (ref != "") { fprintf( f, "\n\tref "); print_with_escapes( f, ref); } if (pat != "") { fprintf( f, "\n\tpat "); print_with_escapes( f, pat); } if (! passwd.nopasswd) { fprintf( f, "\n\tpasswd "); print_with_escapes( f, passwd.text); } fprintf( f, "\n}\n"); } ////////////////////////////////////////////////////////////////////////// // size_t Store::acquire_mail_list() // // Acquire mailbox list for store corresponding to it's pattern // // boxes will be filled up through the callback function "mm_list" // by c-client's mail_list function // // get_mail_list returns the number of mailboxes (that it found) // // This function corresponds to c-client's mail_list // ////////////////////////////////////////////////////////////////////////// { match_pattern_store = this; mail_list( this->stream, nccs(ref), nccs(pat)); match_pattern_store = NULL; return boxes.size(); } ////////////////////////////////////////////////////////////////////////// // void Store::get_delim( ) // // Determine the mailbox delimiter that "stream" is using. // ////////////////////////////////////////////////////////////////////////// { Store store_tmp; store_tmp.stream = this->stream; store_tmp.server = this->server; store_tmp.ref = this->ref; store_tmp.passwd = this->passwd; store_tmp.prefix = ""; store_tmp.pat = "INBOX"; store_tmp.acquire_mail_list(); this->delim = store_tmp.delim; } ////////////////////////////////////////////////////////////////////////// // string Store::full_mailbox_name(const string& box) // // Given the name of a mailbox, return its full IMAP name. // ////////////////////////////////////////////////////////////////////////// { string boxname = box; string fullbox; // Replace our DEFAULT_DELIMITER by the respective store delimiter for (unsigned int i=0; iserver.c_str(), c_client_options | ( options.debug_imap ? OP_DEBUG : 0 )); stream = mail_open( this->stream, nccs(this->server), c_client_options | ( options.debug_imap ? OP_DEBUG : 0 )); if (! this->stream) { fprintf( stderr, "Error: Can't contact server %s\n", this->server.c_str()); } return this->stream; } ////////////////////////////////////////////////////////////////////////// // MAILSTREAM* Store::mailbox_open( const string& boxname, long c_client_options) // // Opens the mailbox "boxname" inside with "c_client_options" options. // // The function will complain to STDERR on error. // // Returns NIL on failure. // ////////////////////////////////////////////////////////////////////////// { string fullboxname = this->full_mailbox_name(boxname); current_context_passwd = &passwd; if (options.debug) printf("Opening %s with options %ld\n", fullboxname.c_str(), c_client_options); stream = ::mailbox_open( this->stream, fullboxname, c_client_options); if (! this->stream) { fprintf( stderr, "Error: Couldn't open %s\n", fullboxname.c_str()); } return this->stream; } ////////////////////////////////////////////////////////////////////////// // bool Store::mailbox_create( const string& boxname ) // // Creates the mailbox "boxname" in the store // // Returns false on failure. // ////////////////////////////////////////////////////////////////////////// { string fullboxname = this->full_mailbox_name(boxname); current_context_passwd = &passwd; if ( options.simulate ) { // just fail if simulating printf( "Creating %s in %s\n", boxname.c_str(), this->name.c_str()); return false; } bool res; bool error_tmp = options.log_error; options.log_error = false; res = mail_create( this->stream, nccs( fullboxname.c_str() ) ); options.log_error = error_tmp; if ( options.debug) { if ( res ) printf( "Created %s in %s\n", boxname.c_str(), this->name.c_str()); else printf( "Failed to create %s in %s\n", boxname.c_str(), name.c_str()); } return res; } ////////////////////////////////////////////////////////////////////////// // bool Store::fetch_message_ids(MsgIdPositions& mids, MsgIdSet& remove_set) // // Fetch all the message ids that the currently open mailbox contains. // // If there are duplicates they will be added to the remove_set // (depending on the compile time option expunge_duplicates) // // returns: // 0 - failure // 1 - success // mids - a hash indexed by msgid containing the // position of the message in the mailbox // ////////////////////////////////////////////////////////////////////////// { // loop and fetch all the message ids from a mailbox unsigned long n = this->stream->nmsgs; unsigned long nabsent = 0, nduplicates = 0; if (options.debug) { printf( " Fetching message id's in mailbox \"%s\"\n", this->stream->mailbox); } for (unsigned long msgno=1; msgno<=n; msgno++) { MsgId msgid; ENVELOPE *envelope; bool isdup; envelope = mail_fetchenvelope( this->stream, msgno); if (! envelope) { fprintf( stderr, "Error: Couldn't fetch enveloppe #%lu from mailbox box %s\n", msgno, this->stream->mailbox); fprintf( stderr, " Aborting!\n"); return 0; } msgid = MsgId(envelope); if (msgid.length() == 0) { print_lead("no msg-id", ""); nabsent++; // Absent message-id. Don't touch message. continue; } isdup = mids.count( msgid ); if (isdup) { if ( options.expunge_duplicates ) { char seq[30]; sprintf( seq, "%lu", msgno); if (! options.simulate ) if ( msgid.empty() ) fprintf( stderr, "Not deleting duplicate message with empty " "Message-ID - see README"); else remove_set.insert( msgid ); // mail_setflag( this->stream, seq, "\\Deleted" ); } nduplicates++; if ( options.show_from ) print_lead( "duplicate", ""); } else { mids.insert(make_pair(msgid, msgno)); } if ( isdup && options.show_from ) { print_from( this->stream, msgno ); if ( options.show_message_id ) print_msgid( msgid.c_str() ); printf("\n"); } } if (nduplicates) { if (options.show_summary) { printf( "%lu duplicate%s", nduplicates, nduplicates==1 ? "" : "s" ); if ( operation_mode != mode_diff ) { printf(" in %s", name.c_str()); } printf(", "); } else { printf( "%lu duplicate%s for deletion in %s\n", nduplicates, nduplicates==1 ? "" : "s", name.c_str() ); } fflush(stdout); } return 1; } ////////////////////////////////////////////////////////////////////////// // bool Store::list_contents() // // Display contents of currently open mailbox // // The mailbox is defined by the name in "box" and by the "store" where the // mailbox resides // // returns: // 0 - failure // 1 - success // mailbox_stream - a stream "to" the mailbox // // This was copied from fetch_message_ids // ////////////////////////////////////////////////////////////////////////// { MsgIdPositions mids; // loop and fetch all the message ids from a mailbox unsigned long n = this->stream->nmsgs; for (unsigned long msgno=1; msgno<=n; msgno++) { MsgId msgid; ENVELOPE *envelope; bool isdup; envelope = mail_fetchenvelope( this->stream, msgno); if (! envelope) { fprintf( stderr, "Error: Couldn't fetch enveloppe #%lu from mailbox box %s\n", msgno, this->stream->mailbox); fprintf( stderr, " Aborting!\n"); return 0; } msgid = MsgId(envelope); if (msgid.length() == 0) print_lead( "no msg-id", ""); else { isdup = mids.count( msgid ); if (isdup) print_lead( "duplicate", ""); else mids.insert( make_pair(msgid, msgno)); if ( options.show_message_id ) print_msgid( msgid.c_str() ); } print_from( this->stream, msgno ); printf( "\n"); } return 1; } ////////////////////////////////////////////////////////////////////////// // bool Store::flag_message_for_removal( unsigned long msgno, const MsgId& msgid, char * place) // // returns !0 on success // ////////////////////////////////////////////////////////////////////////// { MsgId msgid_fetched; ENVELOPE *envelope; bool success = 1; current_context_passwd = &passwd; envelope = mail_fetchenvelope( this->stream, msgno ); if (! envelope) { fprintf( stderr, "Error: Couldn't fetch enveloppe #%lu from mailbox box %s\n", msgno, this->stream->mailbox); return 0; } msgid_fetched = MsgId(envelope); if (msgid_fetched.length() == 0) { printf( "Error: no message-id, so I won't delete the message.\n" ); // Possibly indicates concurrent access? success = 0; } else { if( msgid_fetched != msgid ) { printf( "Error: message-ids %s and %s don't match, " "so I won't delete the message.\n", msgid_fetched.c_str(), msgid.c_str() ); success = 0; } } if (success) { char seq[30]; sprintf( seq, "%lu", msgno); if (! options.simulate ) mail_setflag( this->stream, seq, "\\Deleted" ); } if (options.show_from) { if (success) { print_lead( "deleted", place); } else { print_lead( "deletefail", ""); } print_from( this->stream, msgno ); printf("\n"); } return success; } ////////////////////////////////////////////////////////////////////////// // char* Store::driver_name() // // Return the name of the driver we're using for accessing a store. // // The store must contain at least one valid mailbox name, otherwise the call // will return NULL. // // Returns NULL if no valid driver was found // ////////////////////////////////////////////////////////////////////////// { DRIVER* drv; char* full_name; if ( boxes.size() == 0 ) // boxes list is empty (no box with that name // exists) drv = mail_valid( this->stream, "", NIL); else drv = mail_valid( this->stream, nccs( full_mailbox_name( boxes.begin()->first) ), NIL); if (drv) return drv->name; else return NULL; } ////////////////////////////////////////////////////////////////////////// // void Store::display_driver() // // Display which drivers we're using for accessing a store // // The store must contain at least one valid mailbox name, otherwise the call // will return NULL. // ////////////////////////////////////////////////////////////////////////// { char* the_driver_name = driver_name(); if (the_driver_name) printf( "Using driver %s for store %s\n", the_driver_name, nccs( name)); else printf( "No driver for store %s found\n"); } ////////////////////////////////////////////////////////////////////////// // void Store::print_error(const char * cause, const string& mailbox) // ////////////////////////////////////////////////////////////////////////// { fprintf( stderr, "Error: Couldn't access mailbox \"%s\" in store \"%s\" for %s\n", mailbox.c_str(), name.c_str(), cause ); fprintf( stderr, " Continuing with next mailbox\n"); } ////////////////////////////////////////////////////////////////////////// // int Store::mailbox_expunge( string mailbox_name ) // ////////////////////////////////////////////////////////////////////////// { expunged_mails = 0; // is manipulated by the c-client callback mm_expunge mail_expunge( this->stream ); return expunged_mails; }