#include "gnupgplugin.h" char PGP_PUBKEY_PROLOG[]="-----BEGIN PGP PUBLIC KEY BLOCK-----"; char PGP_PUBKEY_EPILOG[]="-----END PGP PUBLIC KEY BLOCK-----"; char PGP_MSG_PROLOG[]="-----BEGIN PGP MESSAGE-----"; char PGP_MSG_EPILOG[]="-----END PGP MESSAGE-----"; int SendMsgSvc(WPARAM wParam, LPARAM lParam) // ANSI mode: // ANSI source message is encrypted to ANSI cyphertext, then sent. // UNICODE mode: // ANSI part of source ANSI+UCS2 message is encrypted to ANSI cyphertext, // then the cyphertext is appended by UCS2 version of the ANSI // cyphertext, then the resulting ANSI+UCS2 cyphertext is sent. // Note: the UCS2 part of the source message is lost! This is a feature. { CCSDATA *ccs=(CCSDATA*)lParam; if (!ccs) { LogMessage("--- GnuPG.SendMsgSvc: ","ccs==NULL, not our case.","\n"); return CallService(MS_PROTO_CHAINSEND,wParam,lParam); } char *msg=(char*)(ccs->lParam); if (!msg) { LogMessage("--- GnuPG.SendMsgSvc: ","msg==NULL, not our case.","\n"); return CallService(MS_PROTO_CHAINSEND,wParam,lParam); } bool isUnicode=(bool)(ccs->wParam&PREF_UNICODE); LogMessage("--- GnuPG.SendMsgSvc: mode: ",(isUnicode?"UNICODE":"ANSI"),"\n"); LogMessage("--- GnuPG.SendMsgSvc: msg (ANSI part):\n",msg,"\n--- EOM ---\n"); #if defined(__GPG_DEBUG__) int binsiz=strlen(msg)+1; if (isUnicode) binsiz*=(sizeof(wchar_t)+1); FILE *fp=fopen("C:\\mir_SendMsgSvc_preenc.asc","wb"); if (fp) { fwrite(msg,1,binsiz,fp); fclose(fp); } #endif char keyuserid[keyuseridsize]; // get keyuserid { DBVARIANT dbv; strcpy(keyuserid,( DBGetContactSetting(ccs->hContact,pluginid,dbkeyuserid,&dbv)==0 ?dbv.pszVal :"")); DBFreeVariant(&dbv); } UINT useencryptionchecked =DBGetContactSettingByte(ccs->hContact,pluginid,dbuseencryption,FALSE); char *buf=NULL; if (useencryptionchecked && strlen(keyuserid)) { char keyid[keyidsize]; ZeroMemory(keyid,sizeof(keyid)); getNextPart(keyid,keyuserid,txtidseparator); if (gpgEncrypt(&buf,keyid,msg)!=gpgSuccess) { ErrorMessage(txterror,txtencryptfailed,txtverifyoptions); return 0; } // *** ENCRYPT if (buf) // now buf allocated and filled by encrypted message. { int binsiz=strlen(buf)+1; if (isUnicode) { char *mix=makemix_dup(buf); if (mix) { fnFALSE(&buf); buf=mix; binsiz*=(sizeof(wchar_t)+1); } else LogMessage("--- GnuPG.SendMsgSvc: MIX: ","FAILED.","\n"); } LogMessage("--- GnuPG.SendMsgSvc: Encrypted: \n",buf,"\n--- EOM ---\n"); #if defined(__GPG_DEBUG__) FILE *fp=fopen("C:\\mir_SendMsgSvc_encbuf.asc","wb"); if (fp) { fwrite(buf,1,binsiz,fp); fclose(fp); } #endif ccs->lParam=(LPARAM)buf; // *** THIS IS A FEATURE HACK FOR JABBERG CODE... *** ccs->wParam&=~PREF_UNICODE; // *** GO ANSI WAY! LogMessage("--- GnuPG.SendMsgSvc: ANSI MODE FORCED: ","JabberG feature hack.","\n"); // *** THIS IS A FEATURE HACK FOR JABBERG CODE... *** int rc=CallService(MS_PROTO_CHAINSEND,wParam,(LPARAM)ccs); // *** SEND ENCRYPTED! fnFALSE(&buf); ccs->lParam=(LPARAM)msg; return rc; } // buf not allocated, so... send unencrypted. } LogMessage("--- GnuPG.SendMsgSvc: sending: ","UNENCRYPTED.","\n"); return CallService(MS_PROTO_CHAINSEND,wParam,lParam); } // int SendMsgSvc(WPARAM wParam, LPARAM lParam) enum recv_event_type { re_undefined, re_pgpmessage, re_pgppublickey, re_unknown }; enum recv_event_type get_recv_event_type(const char *msg) { char *prolog,*epilog; prolog=(char*)strstr(msg,PGP_MSG_PROLOG); epilog=(char*)strstr(msg,PGP_MSG_EPILOG); if (prolog && epilog) { LogMessage("--- GnuPG.get_recv_event_type: ","re_pgpmessage","\n"); return re_pgpmessage; } prolog=(char*)strstr(msg,PGP_PUBKEY_PROLOG); epilog=(char*)strstr(msg,PGP_PUBKEY_EPILOG); if (prolog && epilog) { LogMessage("--- GnuPG.get_recv_event_type: ","re_pgppublickey","\n"); return re_pgppublickey; } LogMessage("--- GnuPG.get_recv_event_type: ","re_unknown","\n"); return re_unknown; } int parse_pgp_message(WPARAM wParam, CCSDATA *ccs) { PROTORECVEVENT *pre=(PROTORECVEVENT*)(ccs->lParam); char *msg=pre->szMessage; if (!msg) return CallService(MS_PROTO_CHAINRECV,wParam,(LPARAM)ccs); bool isUnicode=(bool)(pre->flags&PREF_UNICODE); bool isUtf=(bool)(pre->flags&PREF_UTF); LogMessage("--- GnuPG.parse_pgp_message: pre->flags: ", (isUnicode?"UNICODE":"ANSI"), (isUtf?"+UTF\n":"\n")); char *OrigMessage=msg; char *tmp=fixcrlf_dup(msg); if (tmp) msg=tmp; else LogMessage("--- GnuPG.parse_pgp_message: CR/LF: ","FAILED.","\n"); char keyuserid[keyuseridsize]; ZeroMemory(keyuserid,sizeof(keyuserid)); bool useridvalid=(gpgDetectUserID(keyuserid,msg)==gpgSuccess); char *storedpassphrase=NULL; char passphrase[passphrasesize]; if (useridvalid) { if (storepassphraseschecked==BST_CHECKED) storedpassphrase=getPassphrase(keyuserid); } else { ErrorMessage(txtwarning,txtdetectuseridfailed,txtverifyoptions); strcpy(keyuserid,txtunknownuserid); } gpgResult gpgresult=gpgUnknownError; char *decrypteddata=NULL; LogMessage("--- GnuPG.parse_pgp_message: keyuserid: ",keyuserid,"\n"); if (storedpassphrase) { strcpy(passphrase,storedpassphrase); gpgresult=gpgDecrypt(&decrypteddata,msg,passphrase); // *** DECRYPT } int dlgresult=IDOK; while (gpgresult!=gpgSuccess && dlgresult!=IDCANCEL) // if there were no stored passphrase or we just failed to decrypt... { dlgresult=DialogBoxParam(dllinstance,MAKEINTRESOURCE(IDD_PASSPHRASE_DLG), NULL,PassphraseDialogProcedure,(LPARAM)keyuserid); if (dlgresult==IDOK) // if some passphrase given... { strcpy(passphrase,dlgpassphrase); ZeroMemory(dlgpassphrase,passphrasesize); strcat(passphrase,txtcrlf); // wtf gpgresult=gpgDecrypt(&decrypteddata,msg,passphrase); // *** DECRYPT } } // here on cancel or successful decryption if (gpgresult==gpgSuccess) // if successfully decrypted { if (useridvalid && storepassphraseschecked==BST_CHECKED) addPassphrase(keyuserid,passphrase); // cache passphrase } if (decrypteddata) { // 0. not utf? => decode from utf to ANSI if (!isUtf) // !!! QUICK'N'DIRTY HACK for 0.7 <-> 0.7 only mir_utf8decode(decrypteddata,NULL); // We have some decrypted data, so let's: // 1. embrace 'em with tags. // 2. replace original message with the embraced decrypted data. char *tmp=(char*)mir_alloc(strlen(starttag)+strlen(decrypteddata)+strlen(endtag)+1); if (tmp) { strcpy(tmp,starttag); strcat(tmp,decrypteddata); strcat(tmp,endtag); mir_free(decrypteddata); decrypteddata=tmp; } // *** start and end tags added if possible LogMessage("--- GnuPG.parse_pgp_message: decrypteddata:\n", decrypteddata,"\n--- EOM ---\n"); pre->szMessage=decrypteddata; // swap for decrypted if (msg!=OrigMessage) fnFALSE(&msg); // throw away msg if not OrigMessage } else pre->szMessage=msg; // no decrypted, so show the cyphertext if (isUnicode && pre->szMessage!=OrigMessage) // in Unicode mode, only for mir_allocated message { char *mix=makemix_dup(pre->szMessage); if (mix) { mir_free(pre->szMessage); pre->szMessage=mix; // mix done } else { LogMessage("--- GnuPG.parse_pgp_message: MIX: ","FAILED.","\n"); mir_free(pre->szMessage); // *** whatever there were... pre->szMessage=OrigMessage; // failed to mix => original cyphertext! } } // Unicode mode? => we should use mix! ...or original message. ZeroMemory(passphrase,sizeof(passphrase)); // security kid int rc=CallService(MS_PROTO_CHAINRECV,wParam,(LPARAM)ccs); // RECEIVE IT FINALLY if (pre->szMessage!=OrigMessage) { mir_free(pre->szMessage); pre->szMessage=OrigMessage; // swap back to original encrypted } return rc; } int parse_pgp_public_key(WPARAM wParam, CCSDATA *ccs) { PROTORECVEVENT *pre=(PROTORECVEVENT*)(ccs->lParam); char *key=pre->szMessage; if (!key) return CallService(MS_PROTO_CHAINRECV,wParam,(LPARAM)ccs); bool isUnicode=(pre->flags&PREF_UNICODE)?true:false; char *OrigMessage=key; char *tmp=fixcrlf_dup(key); if (tmp) key=tmp; else LogMessage("--- GnuPG.parse_pgp_public_key: CR/LF: ","FAILED.","\n"); time_t now; time(&now); struct tm tms=*localtime(&now); const int ASCTIMESIZ=26; // *** as defined in asctime description. Dangerous? char atstr[ASCTIMESIZ]; strcpy(atstr,asctime(&tms)); replace(atstr,"\n",""); replace(atstr,"\r",""); DBWriteContactSettingString(ccs->hContact,pluginid,dbkeymodified,atstr); gpgResult gpgresult=gpgUnknownError; char *atprolog=strstr(key,PGP_PUBKEY_PROLOG); if (atprolog) { DBWriteContactSettingString(ccs->hContact,pluginid,dbkey,atprolog); if (autoimportpublickeyschecked==BST_CHECKED) gpgresult=gpgImportPublicKey(atprolog); // *** PUBKEY MAYBE IMPORTED } if (key && key!=OrigMessage) mir_free(key); // let's try to save some human-readable words for history! char *buf=(char*)mir_alloc( strlen(starttag) +strlen(Translate(txtpublickeyreceivedstored)) +strlen(Translate(txtpublickeyreceived)) +strlen(Translate(txtimportpublickeyfailed)) +strlen(Translate(txtverifyoptions)) +strlen(endtag) +3 // two ' ' and one '\0' ); if (buf) { strcpy(buf,starttag); if (gpgresult==gpgSuccess) strcat(buf,Translate(txtpublickeyreceivedstored)); else { strcat(buf,Translate(txtpublickeyreceived)); if (autoimportpublickeyschecked==BST_CHECKED) { strcat(buf," "); strcat(buf,Translate(txtimportpublickeyfailed)); strcat(buf," "); strcat(buf,Translate(txtverifyoptions)); } } strcat(buf,endtag); pre->flags&=~PREF_UNICODE; // no reason for Unicode here! pre->szMessage=buf; // for history int rc=CallService(MS_PROTO_CHAINRECV,wParam,(LPARAM)ccs); // *** some words for history should be written to db now. if (pre->szMessage!=OrigMessage) { mir_free(pre->szMessage); pre->szMessage=OrigMessage; // swap back... } return rc; } return CallService(MS_PROTO_CHAINRECV,wParam,(LPARAM)ccs); // as far as we have no chance to save our words for history, // let it be the original data. } int RecvMsgSvc(WPARAM wParam, LPARAM lParam) // wParam - used to call proto recv chain, not used internally. // lParam - points to CCSDATA structure // returns result of CallService(MS_PROTO_CHAINRECV,wParam,lParam) { CCSDATA *ccs=(CCSDATA*)lParam; if (!ccs) // ccs==NULL => not our case! return CallService(MS_PROTO_CHAINRECV,wParam,lParam); PROTORECVEVENT *pre=(PROTORECVEVENT*)(ccs->lParam); if (!pre) // pre==NULL => not our case! return CallService(MS_PROTO_CHAINRECV,wParam,lParam); char *msg=pre->szMessage; if (!msg) // No message => not our case! return CallService(MS_PROTO_CHAINRECV,wParam,lParam); bool isUnicode=(bool)(pre->flags&PREF_UNICODE); LogMessage("--- GnuPG.RecvMsgSvc: mode: ",(isUnicode?"UNICODE":"ANSI"),"\n"); LogMessage("--- GnuPG.RecvMsgSvc: msg (ANSI part):\n",msg,"\n--- EOM ---\n"); #if defined(__GPG_DEBUG__) FILE *fp=fopen("C:\\mir_RecvMsgSvc.bin","wb"); if (fp) { int binlen=strlen(msg)+1; if (isUnicode) binlen*=(sizeof(wchar_t)+1); fwrite(msg,1,binlen,fp); fclose(fp); } #endif switch (get_recv_event_type(msg)) { case re_pgpmessage: return parse_pgp_message(wParam,ccs); case re_pgppublickey: return parse_pgp_public_key(wParam,ccs); default: break; // unknown event type, so not our case! } return CallService(MS_PROTO_CHAINRECV,wParam,lParam); // not our case... } // int RecvMsgSvc(WPARAM wParam, LPARAM lParam)