#! /usr/bin/env pike // Big improvement ? // note that in mapping keys, datetime values Date_h_{min,max} must be // given in mysql syntax // TODO: caching?? #include "config.h" import "./lib"; object(Dbclient) db; object(Gz.deflate) gz; object(Gz.inflate) gunz; function(string:string) quote; int inject_single( object(Message) mesg ) { // return Id of injected mesg or 0 if reject int result; // First, try to insert sender record db->query( "lock tables " + MS_ADDRESSBOOK + " write," + MS_TABLE + " write" ); // sorry... db->query( "insert ignore into " + MS_ADDRESSBOOK + " ( Real_name, Email ) " + " values ( " + quote( mesg->sender_real_name )+ ", " + quote( mesg->sender_email ) + " )" ); int did_put = db->master_sql->affected_rows(); // aaargh there ought to be a better way mapping(string:string) this_sender = (db->query( "select Sender_id from " + MS_ADDRESSBOOK + " where Email=" + quote( mesg->sender_email ) ) )[0]; if( !did_put && mesg->sender_real_name ) // was duplicate value for Email // look if need to add alias... hmm FIXME -- how does this make sense? if( !this_sender->Aliases || !has_value( this_sender->Aliases / "\0", mesg->sender_real_name ) ) { string newaliases = (this_sender->Aliases || "" ) + mesg->sender_real_name + "\0"; db->query( "update " + MS_ADDRESSBOOK + " set Aliases=" + quote( newaliases ) + " where Sender_id=" + this_sender->Sender_id ); } // now inject the actual message object res = db->big_query( "insert ignore into " + MS_TABLE + " ( Sender_id, Date_h, Mesg_id_h, Subject_h, Mesg_data ) " + " values ( " + this_sender->Sender_id + ", " + db->encode_datetime( mesg->sent_date ) + ", " + quote( mesg->message_id )+ ", " + quote( mesg->headers["subject"] ) + ", " + quote( gz->deflate( mesg->_data, Gz.FINISH ) ) + " )" ); if (res) werror( "Warning: SQL insert returned result!\n" ); // can't happen ?? did_put = db->master_sql->affected_rows(); // OK, return the Id of injected message, or 0 if a reject; re-init gz object too... result = did_put ? db->master_sql->insert_id() : 0; db->query( "unlock tables" ); gz->create(); return result; } int inject_mbox( object(Mbox) mbox, int|void verbose ) { object(Message) message; int count = 0; int which = 0; mbox->rewind(); // just in case while( string rawmsg = mbox->next_mesg() ) { which++; verbose && ( werror( "\rProcessing message " + which ), 0 ); if( !catch( message = Message( rawmsg ) ) && inject_single( message ) ) count++; else verbose && ( werror( "\nSkipped message " + which +"\n" ), 0 ); continue; } verbose && ( werror( "\nInjected " + count + " messages\n" ), 0 ); return count; } int stats( mapping keys ) { string where_clause = " where " + ( has_index( keys, "Real_name" ) ? (" Real_name rlike " + quote( keys["Real_name"] ) + " and ") : "" ) + ( has_index( keys, "Email" ) ? ( " Email rlike " + quote( keys["Email"] ) + " and ") : "" ) + ( has_index( keys, "Subject_h" ) ? (" Subject_h rlike " + quote( keys["Subject_h"] ) + " and ") : "" ) + ( has_index( keys, "Date_h_min" ) ? (" Date_h >= " + keys["Date_h_min"] + " and ") : "" ) + ( has_index( keys, "Date_h_max" ) ? (" Date_h <= " + keys["Date_h_max"]) : "" ); string temp = String.trim_all_whites( where_clause ); if( temp == "where" ) where_clause = " "; else if( (temp/"and" )[-1] == "" ) where_clause = " " + temp[..strlen( temp )-4] + " "; else where_clause = " " + temp + " "; string table_ref = ( has_index( keys, "Real_name" ) || has_index( keys, "Email" ) ) ? ( MS_TABLE + " left join " + MS_ADDRESSBOOK + " using (Sender_id) " ) : ( " " + MS_TABLE + " " ); string sql_query_string = "select count(*) from " + table_ref + where_clause; int count = (int)((db->query( sql_query_string ))[0])["count(*)"]; return count; } object(Message) retr_single( int Id ) { string sql_query_string = "select Mesg_data from " + MS_TABLE + " where Id=" + (string)Id; object ret = Message( gunz->inflate( ((db->query( sql_query_string ))[0])["Mesg_data"] ) ); gunz->create(); // cleanup return ret; } array(mapping(string:string)) xover( mapping keys ) { // xover() string where_clause = " where " + ( has_index( keys, "Real_name" ) ? (" Real_name rlike " + quote( keys["Real_name"] ) + " and ") : "" ) + ( has_index( keys, "Email" ) ? ( " Email rlike " + quote( keys["Email"] ) + " and ") : "" ) + ( has_index( keys, "Subject_h" ) ? (" Subject_h rlike " + quote( keys["Subject_h"] ) + " and ") : "" ) + ( has_index( keys, "Date_h_min" ) ? (" Date_h >= " + keys["Date_h_min"] + " and ") : "" ) + ( has_index( keys, "Date_h_max" ) ? (" Date_h <= " + keys["Date_h_max"]) : "" ); string temp = String.trim_all_whites( where_clause ); if( temp == "where" ) where_clause = " "; else if( (temp/"and" )[-1] == "" ) where_clause = " " + temp[..strlen( temp )-4] + " "; else where_clause = " " + temp + " "; string table_ref = MS_TABLE + " left join " + MS_ADDRESSBOOK + " using (Sender_id) "; string limit_clause = ( has_index( keys, "limit" ) ? ( " limit " + ( has_index( keys, "start" ) ? ( keys["start"] + ", " ) : "" ) + ( has_index( keys, "limit" ) ? ( keys["limit"] ) : "" ) ) : "" ); string order_clause = " order by Date_h desc "; string sql_query_string = "select Id, Date_h, Subject_h, " + MS_TABLE + ".Sender_id as Sender_id, Email from " + table_ref + where_clause + order_clause + limit_clause; array res = db->query( sql_query_string ); return res; } void create() { gz = Gz.deflate(); gunz = Gz.inflate(); db = Dbclient(); quote = db->really_quote; } int main( int argc, array(string) argv ) { if( argc<2 ) { werror( "Bad args.\n" ); return 1; } #ifdef VERBOSE #if !constant(Calendar_I)||!defined(USE_CALENDAR_II) werror( "Using /bin/date kludge...\n" ); #else werror( "Using Calendar II ...\n" ); #endif #endif // VERBOSE foreach( argv[1..], string file ) { #ifdef VERBOSE werror( "\nProcessing file " + file + " ...\n" ); #endif // VERBOSE inject_mbox( Mbox( file ) #ifdef VERBOSE , 1 #endif // VERBOSE ); } return 0; }