diff options
author | sje <sje@4f64403b-2f21-0410-a795-97e2b3489a10> | 2006-11-01 14:40:04 +0000 |
---|---|---|
committer | sje <sje@4f64403b-2f21-0410-a795-97e2b3489a10> | 2006-11-01 14:40:04 +0000 |
commit | 9c6d8a640911d336cc1e758310bbfccaf547d2d2 (patch) | |
tree | eb774abda400857f9dbbcb0fc4f1b5be686aed67 | |
parent | 3aeb41e399a944450223bbbc160b7d984985d9d8 (diff) |
git-svn-id: https://server.scottellis.com.au/svn/mim_plugs@10 4f64403b-2f21-0410-a795-97e2b3489a10
-rw-r--r-- | otr/IcoLib.h | 37 | ||||
-rw-r--r-- | otr/Makefile.win | 46 | ||||
-rw-r--r-- | otr/common.h | 71 | ||||
-rw-r--r-- | otr/dll.h | 10 | ||||
-rw-r--r-- | otr/dllmain.cpp | 1200 | ||||
-rw-r--r-- | otr/libotr.def | 5 | ||||
-rw-r--r-- | otr/menu.cpp | 102 | ||||
-rw-r--r-- | otr/menu.h | 9 | ||||
-rw-r--r-- | otr/options.cpp | 418 | ||||
-rw-r--r-- | otr/options.h | 24 | ||||
-rw-r--r-- | otr/otr.layout | 87 | ||||
-rw-r--r-- | otr/otr.mdsp | 108 | ||||
-rw-r--r-- | otr/otr_private.h | 24 | ||||
-rw-r--r-- | otr/otr_private.rc | 35 | ||||
-rw-r--r-- | otr/resource.h | 20 | ||||
-rw-r--r-- | otr/resource.rc | 111 | ||||
-rw-r--r-- | otr/start.ico | bin | 0 -> 2550 bytes | |||
-rw-r--r-- | otr/stop.ico | bin | 0 -> 2550 bytes | |||
-rw-r--r-- | otr/utils.cpp | 282 | ||||
-rw-r--r-- | otr/utils.h | 15 |
20 files changed, 2604 insertions, 0 deletions
diff --git a/otr/IcoLib.h b/otr/IcoLib.h new file mode 100644 index 0000000..1817df6 --- /dev/null +++ b/otr/IcoLib.h @@ -0,0 +1,37 @@ +typedef struct {
+ int cbSize;
+ char *pszSection; //section name used to group icons
+ char *pszDescription; //description for options dialog
+ char *pszName; //name to refer to icon when playing and in db
+ //this name is miranda-wide. so use prefixes of your plugin
+ //e.g: "isee_connect", "clist_delete", etc
+ char *pszDefaultFile; //default icon file to use
+ int iDefaultIndex;
+} SKINICONDESC;
+
+typedef struct {
+ int cbSize;
+ char *pszSection;
+ char *pszDescription;
+ char *pszName;
+ char *pszDefaultFile;
+ int iDefaultIndex;
+ HICON hDefaultIcon;
+} SKINICONDESC2;
+
+//
+// Add a icon into options UI
+//
+// wParam = (WPARAM)0
+// lParam = (LPARAM)(SKINICONDESC*)sid;
+//
+#define MS_SKIN2_ADDICON "Skin2/Icons/AddIcon"
+//
+// Retrieve HICON with name specified in lParam
+// Returned HICON SHOULDN'T be destroyed, it managed by IcoLib
+//
+#define MS_SKIN2_GETICON "Skin2/Icons/GetIcon"
+//
+// Icons change notification
+//
+#define ME_SKIN2_ICONSCHANGED "Skin2/IconsChanged"
diff --git a/otr/Makefile.win b/otr/Makefile.win new file mode 100644 index 0000000..c40937a --- /dev/null +++ b/otr/Makefile.win @@ -0,0 +1,46 @@ +# Project: otr
+# Makefile created by Dev-C++ 4.9.9.2
+
+CPP = g++.exe
+CC = gcc.exe
+WINDRES = windres.exe
+RES = otr_private.res
+OBJ = dllmain.o options.o menu.o utils.o $(RES)
+LINKOBJ = dllmain.o options.o menu.o utils.o $(RES)
+LIBS = -L"lib" -L"C:/rcslib-2005.June/lib" -L"C:/wxWidgets-2.6.2/lib" -L"C:/SDL-1.2.9/src/.libs" -L"C:/msys/1.0/local/lib" -lcomctl32 -lotr -lgcrypt -lgpg-error -s -s
+INCS = -I"include" -I"C:/rcslib-2005.June/include" -I"C:/msys/1.0/local/include" -I"C:/msys/1.0/local/include/libotr"
+CXXINCS = -I"lib/gcc/mingw32/3.4.2/include" -I"include/c++/3.4.2/backward" -I"include/c++/3.4.2/mingw32" -I"include/c++/3.4.2" -I"include" -I"C:/rcslib-2005.June/include" -I"C:/wxWidgets-2.6.2/lib/wx/include/msw-ansi-release-2.6" -I"C:/wxWidgets-2.6.2/include" -I"C:/SDL-1.2.9/include" -I"C:/msys/1.0/local/include" -I"C:/msys/1.0/local/include/libotr"
+BIN = otr.dll
+CXXFLAGS = $(CXXINCS) -DBUILDING_DLL=1 -O3 -s -fexpensive-optimizations -O3
+CFLAGS = $(INCS) -DBUILDING_DLL=1 -fexpensive-optimizations -O3
+RM = rm -f
+
+.PHONY: all all-before all-after clean clean-custom
+
+all: all-before otr.dll all-after
+
+
+clean: clean-custom
+ ${RM} $(OBJ) $(BIN)
+
+DLLWRAP=dllwrap.exe
+DEFFILE=libotr.def
+STATICLIB=libotr.a
+
+$(BIN): $(LINKOBJ)
+ $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN)
+
+dllmain.o: dllmain.cpp
+ $(CPP) -c dllmain.cpp -o dllmain.o $(CXXFLAGS)
+
+options.o: options.cpp
+ $(CPP) -c options.cpp -o options.o $(CXXFLAGS)
+
+menu.o: menu.cpp
+ $(CPP) -c menu.cpp -o menu.o $(CXXFLAGS)
+
+utils.o: utils.cpp
+ $(CPP) -c utils.cpp -o utils.o $(CXXFLAGS)
+
+otr_private.res: otr_private.rc resource.rc
+ $(WINDRES) -i otr_private.rc --input-format=rc -o otr_private.res -O coff
diff --git a/otr/common.h b/otr/common.h new file mode 100644 index 0000000..062ae78 --- /dev/null +++ b/otr/common.h @@ -0,0 +1,71 @@ +#ifndef _COMMON_INC
+#define _COMMON_INC
+
+#define _WIN32_WINNT 0x0500
+#define WINVER 0x0500
+#define _WIN32_IE 0x0300
+
+#include <windows.h>
+//#include <process.h>
+//#include <shlobj.h>
+#include <stdio.h>
+#include <commctrl.h>
+#include <malloc.h>
+#include <process.h>
+
+#include "resource.h"
+
+#include <newpluginapi.h>
+#include <statusmodes.h>
+#include <m_options.h>
+#include <m_langpack.h>
+#include <m_popup.h>
+#include <m_system.h>
+#include <m_skin.h>
+#include <m_netlib.h>
+#include <m_database.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_ignore.h>
+#include <m_clist.h>
+#include <m_clui.h>
+#include <m_utils.h>
+#include <m_message.h>
+
+#include <m_updater.h>
+#include <m_metacontacts.h>
+
+#include <m_popup.h>
+#include "IcoLib.h"
+
+#define MODULE "OTR"
+
+extern "C" {
+#include "proto.h"
+#include "message.h"
+#include "privkey.h"
+};
+
+// modified manual policy - so that users set to 'opportunistic' will automatically start OTR with users set to 'manual'
+#define OTRL_POLICY_MANUAL_MOD (OTRL_POLICY_MANUAL | OTRL_POLICY_WHITESPACE_START_AKE | OTRL_POLICY_ERROR_START_AKE)
+
+// use the same filenames as the gaim plugin, for compatibility
+#define PRIVATE_KEY_FILENAME "otr.private_key"
+#define FINGERPRINT_STORE_FILENAME "otr.fingerprints"
+
+
+extern HINSTANCE hInst;
+extern HANDLE mainThread;
+extern DWORD mainThreadId;
+
+extern OtrlUserState otr_user_state;
+extern char private_key_filename[MAX_PATH];
+
+#define MS_OTR_MENUSTART "OTR/Start"
+#define MS_OTR_MENUSTOP "OTR/Stop"
+
+#define INLINE_PREFIX "[OTR Message] "
+#define INLINE_PREFIX_LEN 14
+
+#endif
diff --git a/otr/dll.h b/otr/dll.h new file mode 100644 index 0000000..f735bc0 --- /dev/null +++ b/otr/dll.h @@ -0,0 +1,10 @@ +#ifndef _DLL_H_
+#define _DLL_H_
+
+#if BUILDING_DLL
+# define DLLIMPORT __declspec (dllexport)
+#else /* Not BUILDING_DLL */
+# define DLLIMPORT __declspec (dllimport)
+#endif /* Not BUILDING_DLL */
+
+#endif /* _DLL_H_ */
diff --git a/otr/dllmain.cpp b/otr/dllmain.cpp new file mode 100644 index 0000000..522a3bc --- /dev/null +++ b/otr/dllmain.cpp @@ -0,0 +1,1200 @@ +/* Replace "dll.h" with the name of your header */
+
+#include "common.h"
+#include "dll.h"
+#include "options.h"
+#include "menu.h"
+#include "utils.h"
+
+#include "otr_private.h"
+
+///////////////////////////////////////////////
+// Common Plugin Stuff
+///////////////////////////////////////////////
+HINSTANCE hInst;
+PLUGINLINK *pluginLink;
+
+HANDLE mainThread;
+DWORD mainThreadId;
+
+HANDLE hEventDbEventAdded, hEventDbEventAddedFilter, hEventWindow, hEventIconPressed;
+
+CRITICAL_SECTION lib_cs;
+
+int code_page = CP_ACP;
+
+#include <list>
+std::list<void *> alloc_list;
+
+// plugin stuff
+PLUGININFO pluginInfo={
+ sizeof(PLUGININFO),
+ MODULE,
+ PLUGIN_MAKE_VERSION(VER_MAJOR, VER_MINOR, VER_RELEASE, VER_BUILD),
+ DESC_STRING,
+ "Scott Ellis",
+ "mail@scottellis.com.au",
+ "© 2005 Scott Ellis",
+ "http://www.scottellis.com.au/",
+ 0, //not transient
+ 0 //doesn't replace anything built-in
+};
+
+extern "C" BOOL APIENTRY DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) {
+ hInst=hinstDLL;
+ return TRUE;
+}
+
+extern "C" DLLIMPORT PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion) {
+ return &pluginInfo;
+}
+
+/////////////////////////
+// dodgy, INNEFFICIENT, utility function
+////////////////////////
+HANDLE get_contact(const char *protocol, const char *disp_name) {
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if(proto && strcmp(proto, protocol) == 0) {
+ char *name = (char *)CallService( MS_CLIST_GETCONTACTDISPLAYNAME, ( WPARAM )hContact, 0 );
+ if(name && strcmp(name, disp_name) == 0) {
+ return hContact;
+ }
+ }
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+
+ return 0;
+}
+
+// wish there was an EVENTTYPE_INLINEMSG :)
+void ShowMessageInline(const HANDLE hContact, const char *msg) {
+ char buff[1024];
+ mir_snprintf(buff, 1024, "%s%s", INLINE_PREFIX, msg);
+
+ /*
+ // bypasses filters etc - including metacontacts
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(DBEVENTINFO);
+ dbei.szModule = MODULE;
+ dbei.timestamp = time(0);
+ //dbei.flags = DBEF_READ;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = strlen(buff);
+ dbei.pBlob = (BYTE *)buff;
+
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei);
+ */
+
+ PROTORECVEVENT pre = {0};
+ pre.timestamp = time(0);
+ pre.szMessage = buff;
+ //CallContactService(hContact, PSR_MESSAGE, 0, (LPARAM)&pre);
+
+ CCSDATA ccs = {0};
+ ccs.hContact = hContact;
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.lParam = (LPARAM)⪯
+
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+}
+
+// set SRMM icon status, if applicable
+void SetEncryptionStatus(HANDLE hContact, bool encrypted) {
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ bool chat_room = (proto && DBGetContactSettingByte(hContact, proto, "ChatRoom", 0));
+
+ if(!chat_room) DBWriteContactSettingByte(hContact, MODULE, "Encrypted", (encrypted ? 1 : 0));
+
+ if(ServiceExists(MS_MSG_MODIFYICON)) {
+ StatusIconData sid = {0};
+ sid.cbSize = sizeof(sid);
+ sid.szModule = MODULE;
+ sid.dwId = 0;
+ sid.flags = (chat_room ? MBF_HIDDEN : (encrypted ? 0 : MBF_DISABLED));
+ CallService(MS_MSG_MODIFYICON, (WPARAM)hContact, (LPARAM)&sid);
+
+ if(!chat_room && ServiceExists(MS_MC_GETMETACONTACT)) {
+ HANDLE hMeta = (HANDLE)CallService(MS_MC_GETMETACONTACT, (WPARAM)hContact, 0);
+ if(hContact == (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hMeta, 0))
+ SetEncryptionStatus(hMeta, encrypted);
+ }
+ }
+}
+
+///////////////////////////////////////////////
+// OTR stuff
+///////////////////////////////////////////////
+
+void add_appdata(void *data, ConnContext *context) {
+ if(context) context->app_data = data; // data is hContact
+}
+
+void lib_cs_lock() {
+ EnterCriticalSection(&lib_cs);
+}
+
+void lib_cs_unlock() {
+ LeaveCriticalSection(&lib_cs);
+}
+
+char fingerprint_store_filename[MAX_PATH];
+char private_key_filename[MAX_PATH];
+
+OtrlUserState otr_user_state = 0;
+
+/* Return the OTR policy for the given context. */
+extern "C" OtrlPolicy otr_gui_policy(void *opdata, ConnContext *context) {
+ HANDLE hContact = (HANDLE)opdata;
+ if(hContact) {
+ WORD pol = DBGetContactSettingWord(hContact, MODULE, "Policy", CONTACT_DEFAULT_POLICY);
+ if(pol == CONTACT_DEFAULT_POLICY)
+ return options.default_policy | OTRL_POLICY_NOHTML;
+ else return pol | OTRL_POLICY_NOHTML;
+ }
+
+ return options.default_policy | OTRL_POLICY_NOHTML;
+}
+
+typedef struct {
+ char *account_name;
+ char *protocol;
+} NewKeyData;
+
+void CALLBACK newKeyAPC(DWORD data) {
+//DWORD CALLBACK newKeyThread(VOID *data) {
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+
+ NewKeyData *nkd = (NewKeyData *)data;
+ otrl_privkey_generate(otr_user_state, private_key_filename, nkd->account_name, nkd->protocol);
+
+ free(nkd->account_name);
+ free(nkd->protocol);
+ free(nkd);
+
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ //return 0;
+}
+
+BOOL CALLBACK NullDlgFunc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hWndDlg);
+ break;
+ }
+ return FALSE;
+}
+
+/* Create a private key for the given accountname/protocol if
+ * desired. */
+extern "C" void otr_gui_create_privkey(void *opdata, const char *account_name, const char *protocol) {
+ //if(MessageBox(0, Translate("Would you like to generate a new private key for this protocol?"), Translate("OTR"), MB_YESNO) == IDYES)
+ //if(options.err_method == ED_POP)
+ //ShowPopup(Translate("Generating new private key."), 0 /*Translate("Please wait.")*/, 5);
+
+ //NewKeyData *nkd = (NewKeyData *)malloc(sizeof(NewKeyData));
+ //nkd->account_name = strdup(account_name);
+ //nkd->protocol = strdup(protocol);
+
+ //DWORD tid;
+ //CloseHandle(CreateThread(0, 0, newKeyThread, (VOID *)nkd, 0, &tid));
+ //QueueUserAPC(newKeyAPC, mainThread, (DWORD)nkd);
+ HWND hWndNotifyDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_GENKEYNOTIFY), GetDesktopWindow(), NullDlgFunc);
+ SetClassLong(hWndNotifyDlg, GCL_HICON, (LONG)hLockIcon);
+ ShowWindow(hWndNotifyDlg, SW_SHOW);
+ UpdateWindow(hWndNotifyDlg);
+ otrl_privkey_generate(otr_user_state, private_key_filename, account_name, protocol);
+ DestroyWindow(hWndNotifyDlg);
+
+}
+
+/* Report whether you think the given user is online. Return 1 if
+ * you think he is, 0 if you think he isn't, -1 if you're not sure.
+ *
+ * If you return 1, messages such as heartbeats or other
+ * notifications may be sent to the user, which could result in "not
+ * logged in" errors if you're wrong. */
+extern "C" int otr_gui_is_logged_in(void *opdata, const char *accountname, const char *protocol, const char *recipient) {
+ HANDLE hContact = (HANDLE)opdata;
+ if(hContact) {
+ WORD status = DBGetContactSettingWord(hContact, (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0), "Status", ID_STATUS_OFFLINE);
+ if(status == ID_STATUS_OFFLINE) return 0;
+ else return 1;
+ }
+
+ return -1;
+}
+
+/* Send the given IM to the given recipient from the given
+ * accountname/protocol. */
+extern "C" void otr_gui_inject_message(void *opdata, const char *accountname, const char *protocol, const char *recipient, const char *message) {
+ //MessageBox(0, message, "OTR Inject", MB_OK);
+ HANDLE hContact = (HANDLE)opdata;
+
+ // bypass filters (including this module, metacontacts, etc) - go direct to proto level
+ if(protocol && DBGetContactSettingWord(hContact, protocol, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) {
+ CCSDATA ccs = {0};
+ ccs.hContact = hContact;
+ ccs.szProtoService = PSS_MESSAGE;
+ ccs.lParam = (LPARAM)Translate(message);
+ CallProtoService(protocol, PSS_MESSAGE, 0, (LPARAM)&ccs);
+ }
+}
+
+/* Display a notification message for a particular accountname /
+ * protocol / username conversation. */
+extern "C" void otr_gui_notify(void *opdata, OtrlNotifyLevel level, const char *accountname, const char *protocol, const char *username, const char *title, const char *primary, const char *secondary) {
+ char buff1[512], buff2[512];
+ mir_snprintf(buff1, 512, "%s: %s", username, title);
+ mir_snprintf(buff2, 512, "%s\n%s", primary, secondary);
+ ShowPopup(buff1, buff2, 0);
+}
+
+/* Display an OTR control message for a particular accountname /
+ * protocol / username conversation. Return 0 if you are able to
+ * successfully display it. If you return non-0 (or if this
+ * function is NULL), the control message will be displayed inline,
+ * as a received message, or else by using the above notify()
+ * callback. */
+extern "C" int otr_gui_display_otr_message(void *opdata, const char *accountname, const char *protocol, const char *username, const char *msg) {
+ /*
+ * char buff[512];
+ * mir_snprintf(buff, 512, Translate("%s(%s)"), protocol, username);
+ *ShowPopup(buff, msg, 0);
+
+ return 0;
+ */
+ //return 1;
+
+ ShowMessageInline((HANDLE)opdata, msg);
+ return 0;
+}
+
+/* When the list of ConnContexts changes (including a change in
+ * state), this is called so the UI can be updated. */
+extern "C" void otr_gui_update_context_list(void *opdata) {
+ //MessageBox(0, "Update Context List", "OTR Callback", MB_OK);
+}
+
+/* Return a newly-allocated string containing a human-friendly name
+ * for the given protocol id */
+extern "C" const char *otr_gui_protocol_name(void *opdata, const char *protocol) {
+ //return strdup(protocol);
+ return protocol;
+}
+
+/* Deallocate a string allocated by protocol_name */
+extern "C" void otr_gui_protocol_name_free(void *opdata, const char *protocol_name) {
+ //free((void *)protocol_name);
+}
+
+unsigned int CALLBACK trust_fp_thread(void *param) {
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+
+ Fingerprint *fp = (Fingerprint *)param;
+
+ char hash[45];
+ otrl_privkey_hash_to_human(hash, fp->fingerprint);
+
+ char msg[1024];
+ mir_snprintf(msg, 1024, Translate("A new fingerprint has been recieved from '%s'\n\n%s\n\nDo you trust it?"), fp->context->username, hash);
+ if(MessageBox(0, msg, Translate("OTR New Fingerprint"), MB_YESNO) == IDYES) {
+ lib_cs_lock();
+ otrl_context_set_trust(fp, "verified");
+ lib_cs_unlock();
+ } else {
+ lib_cs_lock();
+ otrl_context_set_trust(fp, "unknown");
+ lib_cs_unlock();
+ }
+
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ return 0;
+}
+
+/* A new fingerprint for the given user has been received. */
+extern "C" void otr_gui_new_fingerprint(void *opdata, OtrlUserState us, const char *accountname, const char *protocol, const char *username, unsigned char fingerprint[20]) {
+ //MessageBox(0, username, Translate("OTR New Fingerprint"), MB_OK);
+ ConnContext *context = otrl_context_find(us, username, accountname, protocol, TRUE, 0, add_appdata, opdata);
+ Fingerprint *fp = otrl_context_find_fingerprint(context, fingerprint, TRUE, 0);
+
+ //CloseHandle((HANDLE)_beginthreadex(0, 0, trust_fp_thread, (void *)fp, 0, 0));
+
+ otrl_context_set_trust(fp, "unknown");
+ otrl_privkey_write_fingerprints(otr_user_state, fingerprint_store_filename);
+}
+
+/* The list of known fingerprints has changed. Write them to disk. */
+extern "C" void otr_gui_write_fingerprints(void *opdata) {
+ //if(MessageBox(0, Translate("Would you like to save the current fingerprint list?"), Translate(MODULE), MB_YESNO) == IDYES)
+ otrl_privkey_write_fingerprints(otr_user_state, fingerprint_store_filename);
+}
+
+// forward dec
+void Disconnect(ConnContext *context);
+
+unsigned int CALLBACK verify_fp_thread(void *param) {
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+
+ ConnContext *context = (ConnContext *)param;
+ Fingerprint *fp = context->active_fingerprint;
+
+ char hash[45];
+ otrl_privkey_hash_to_human(hash, fp->fingerprint);
+
+ char buff[1024];
+ mir_snprintf(buff, 1024, Translate("OTR encrypted session with '%s'.\n\nFingerprint is UNVERIFIED.\n\n%s\n\nVerify?"), context->username, hash);
+ if(MessageBox(0, buff, Translate("OTR Information"), MB_YESNO) == IDNO) {
+ //Disconnect(context);
+ return 0;
+ }
+
+ lib_cs_lock();
+ otrl_context_set_trust(context->active_fingerprint, "verified");
+ otrl_privkey_write_fingerprints(otr_user_state, fingerprint_store_filename);
+ lib_cs_unlock();
+
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ return 0;
+}
+/* A ConnContext has entered a secure state. */
+extern "C" void otr_gui_gone_secure(void *opdata, ConnContext *context) {
+ bool trusted = (context->active_fingerprint && context->active_fingerprint->trust && strcmp(context->active_fingerprint->trust, "verified") == 0);
+ char buff[1024];
+ if(trusted) {
+ mir_snprintf(buff, 1024, Translate("Beggining OTR encrypted session with '%s'"), context->username);
+ //MessageBox(0, buff, Translate("OTR Information"), MB_OK);
+ if(options.msg_inline)
+ ShowMessageInline((HANDLE)opdata, buff);
+ else
+ ShowPopup(Translate("OTR Information"), buff, 0);
+
+ // opdata is hContact
+ SetEncryptionStatus((HANDLE)opdata, true);
+ } else {
+ CloseHandle((HANDLE)_beginthreadex(0, 0, verify_fp_thread, context, 0, 0));
+
+ mir_snprintf(buff, 1024, Translate("Beggining OTR encrypted session with '%s'"), context->username);
+ //MessageBox(0, buff, Translate("OTR Information"), MB_OK);
+ if(options.msg_inline)
+ ShowMessageInline((HANDLE)opdata, buff);
+ else
+ ShowPopup(Translate("OTR Information"), buff, 0);
+
+ // opdata is hContact
+ SetEncryptionStatus((HANDLE)opdata, true);
+ }
+}
+
+/* A ConnContext has left a secure state. */
+extern "C" void otr_gui_gone_insecure(void *opdata, ConnContext *context) {
+ char buff[256];
+ mir_snprintf(buff, 256, Translate("OTR encrypted session with '%s' has ended"), context->username);
+ //MessageBox(0, buff, Translate("OTR Information"), MB_OK);
+ if(options.msg_inline)
+ ShowMessageInline((HANDLE)opdata, buff);
+ else
+ ShowPopup(Translate("OTR Information"), buff, 0);
+
+ // opdata is hContact
+ SetEncryptionStatus((HANDLE)opdata, false);
+}
+
+/* We have completed an authentication, using the D-H keys we
+ * already knew. is_reply indicates whether we initiated the AKE. */
+extern "C" void otr_gui_still_secure(void *opdata, ConnContext *context, int is_reply) {
+ if(is_reply) {
+ char buff[256];
+ mir_snprintf(buff, 256, Translate("OTR encrypted session with '%s' is being continued"), context->username);
+ //MessageBox(0, buff, Translate("OTR Information"), MB_OK);
+ if(options.msg_inline)
+ ShowMessageInline((HANDLE)opdata, buff);
+ else
+ ShowPopup(Translate("OTR Information"), buff, 0);
+ }
+
+ // opdata is hContact
+ SetEncryptionStatus((HANDLE)opdata, true);
+}
+
+/* Log a message. The passed message will end in "\n". */
+extern "C" void otr_gui_log_message(void *opdata, const char *message) {
+ //MessageBox(0, message, Translate("OTR Log Message"), MB_OK);
+ //ShowMessageInline((HANDLE)opdata, message);
+}
+
+OtrlMessageAppOps ops = {
+ otr_gui_policy,
+ otr_gui_create_privkey,
+ otr_gui_is_logged_in,
+ otr_gui_inject_message,
+ otr_gui_notify,
+ otr_gui_display_otr_message,
+ otr_gui_update_context_list,
+ otr_gui_protocol_name,
+ otr_gui_protocol_name_free,
+ otr_gui_new_fingerprint,
+ otr_gui_write_fingerprints,
+ otr_gui_gone_secure,
+ otr_gui_gone_insecure,
+ otr_gui_still_secure,
+ otr_gui_log_message
+};
+
+void Disconnect(ConnContext *context) {
+ otrl_message_disconnect(otr_user_state, &ops, 0, MODULE, context->protocol, context->username);
+}
+
+//////////////////////////////////////////////////
+/// Miranda filter plugin stuff
+//////////////////////////////////////////////////
+
+int SettingChanged(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam;
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *)lParam;
+
+ // only care about contacts
+ if(!hContact) return 0;
+
+ // to which this filter is attached
+ if(!CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)hContact, (LPARAM)MODULE))
+ return 0;
+
+ // and who are changing status to offline
+ if(strcmp(cws->szSetting, "Status") == 0 && cws->value.type != DBVT_DELETED && cws->value.wVal == ID_STATUS_OFFLINE) {
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ char *uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
+ if(!proto || !uname) return 0; // error - just bail
+
+ lib_cs_lock();
+ ConnContext *context = otrl_context_find(otr_user_state, uname, MODULE, proto, FALSE, 0, 0, 0);
+
+ if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
+ otrl_message_disconnect(otr_user_state, &ops, hContact, MODULE, proto, uname);
+
+ // removed - don't need a popup everytime an OTR user goes offline!
+ //char buff[512];
+ //mir_snprintf(buff, 512, Translate("User '%s' ended encrypted session"), uname);
+ //ShowPopup(Translate("OTR Information"), buff, 0);
+
+ // opdata is hContact
+ SetEncryptionStatus(hContact, false);
+ }
+ lib_cs_unlock();
+ }
+
+ return 0;
+}
+
+int OTRSendMessage(WPARAM wParam,LPARAM lParam){
+ if(!lParam) return 0;
+
+ CCSDATA *ccs = (CCSDATA *) lParam;
+
+ //MessageBox(0, (char *)ccs->lParam, "OTR - sending raw message", MB_OK);
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0);
+ if(proto && strcmp(proto, "MetaContacts") == 0) // bypass for metacontacts
+ return CallService(MS_PROTO_CHAINSEND, wParam, lParam);
+ if(!proto) return 1; // error
+
+ gcry_error_t err;
+ char *newmessage = 0;
+ char *oldmessage = (char *)ccs->lParam;
+ char *oldmessage_utf = 0;
+
+ //MessageBox(0, "Send message - converting to UTF-8", "msg", MB_OK);
+
+ if(ccs->wParam & PREF_UNICODE) {
+ int size = WideCharToMultiByte(CP_UTF8, 0, (wchar_t *)&oldmessage[strlen(oldmessage)+1], -1, 0, 0, 0, 0);
+ oldmessage_utf = (char *)malloc(size);
+ if(!oldmessage_utf) return 1;
+ WideCharToMultiByte(CP_UTF8, 0, (wchar_t *)&oldmessage[strlen(oldmessage)+1], -1, oldmessage_utf, size, 0, 0);
+ } else {
+ wchar_t *temp = 0;
+ int size_temp, size;
+ size_temp = MultiByteToWideChar(code_page, 0, oldmessage, -1, 0, 0);
+ temp = (wchar_t *)malloc(size_temp * sizeof(wchar_t));
+ if(!temp) return 1;
+
+ MultiByteToWideChar(code_page, 0, oldmessage, -1, temp, size_temp);
+
+ size = WideCharToMultiByte(CP_UTF8, 0, temp, -1, 0, 0, 0, 0);
+ oldmessage_utf = (char *)malloc(size);
+ if(!oldmessage_utf) {
+ free(temp);
+ return 1;
+ }
+ WideCharToMultiByte(CP_UTF8, 0, temp, -1, oldmessage_utf, size, 0, 0);
+
+ free(temp);
+ }
+
+ char *username = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)ccs->hContact, 0);
+ // check if we're waiting for the other side to accept a new key from us
+ lib_cs_lock();
+ /*
+ ConnContext *context = otrl_context_find(otr_user_state, username, MODULE, proto, FALSE, 0, 0, 0);
+ if(context && context->otr_offer == context::OFFER_SENT) {
+ lib_cs_unlock();
+ if(MessageBox(0, Translate("The receiver has not yet accepted or rejected your fingerprint.\nSend the message unencrypted?"), Translate("OTR Warning"), MB_ICONWARNING | MB_YESNO) == IDYES)
+ return CallService(MS_PROTO_CHAINSEND, wParam, lParam);
+ else
+ return 1;
+ }
+ */
+ //MessageBox(0, "Send message - passing through OTR library", "msg", MB_OK);
+ err = otrl_message_sending(otr_user_state, &ops, ccs->hContact, MODULE, proto, username, oldmessage_utf, 0, &newmessage, add_appdata, ccs->hContact);
+ lib_cs_unlock();
+ free(oldmessage_utf);
+ if(err) {
+ // failure to encrypt message!
+ return 1;
+ }
+
+ if(newmessage) {
+ //MessageBox(0, "Send message - message encoded - decoding UTF-8", "msg", MB_OK);
+ // decode utf8 into unicode message
+ wchar_t *temp;
+ char *text;
+
+ // forward message
+ int size = MultiByteToWideChar(CP_UTF8, 0, (const char *)newmessage, -1, 0, 0);
+ temp = (wchar_t *)malloc(size * sizeof(wchar_t));
+ if(!temp) return 1;
+ MultiByteToWideChar(CP_UTF8, 0, (const char *)newmessage, -1, temp, size);
+
+ size = WideCharToMultiByte(code_page, 0, temp, -1, 0, 0, 0, 0);
+ text = (char *)malloc(size);
+ if(!text) {
+ free(temp);
+ return 1;
+ }
+ WideCharToMultiByte(code_page, 0, temp, -1, text, size, 0, 0);
+
+ lib_cs_lock();
+ otrl_message_free(newmessage);
+ lib_cs_unlock();
+
+ int tMsgBodyLen = strlen(text);
+ int tRealBodyLen = wcslen(temp);
+
+ int tMsgBufLen = (tMsgBodyLen+1) * sizeof(char) + (tRealBodyLen+1)*sizeof( wchar_t );
+ char* tMsgBuf = ( char* )malloc( tMsgBufLen );
+ if(!tMsgBuf) {
+ free(temp);
+ free(text);
+ return 1;
+ }
+
+ char* p = tMsgBuf;
+
+ strcpy(p, text);
+ p += (tMsgBodyLen+1);
+ free(text);
+
+ WPARAM old_flags = ccs->wParam;
+ if ( tRealBodyLen != 0 ) {
+ wcscpy((wchar_t *)p, temp);
+ ccs->wParam |= PREF_UNICODE;
+ }
+ free(temp);
+ //MessageBox(0, "Send message - forwarding message", "msg", MB_OK);
+ // forward new message
+ ccs->lParam = (LPARAM)tMsgBuf;
+ int ret = CallService(MS_PROTO_CHAINSEND, wParam, lParam);
+ // free decrypted message and conversion buffer
+ free(tMsgBuf);
+
+ // restore state of chain message, for freeing, db, etc etc.
+ ccs->wParam = old_flags;
+ //ccs->szProtoService=PSS_MESSAGE"W";
+ ccs->lParam = (LPARAM)oldmessage;
+
+ return ret;
+ } //else
+ //MessageBox(0, "Send message - no action", "msg", MB_OK);
+
+ return CallService(MS_PROTO_CHAINSEND, wParam, lParam);
+}
+
+int OTRSendMessageW(WPARAM wParam, LPARAM lParam){
+ if(!lParam) return 0;
+
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ ccs->wParam |= PREF_UNICODE;
+
+ return OTRSendMessage(wParam, lParam);
+}
+
+/*
+#define MESSAGE_PREFIX "(OTR) "
+#define MESSAGE_PREFIXW L"(OTR) "
+#define MESSAGE_PREFIX_LEN 6
+*/
+
+int RecvMessage(WPARAM wParam,LPARAM lParam){
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ PROTORECVEVENT *pre = (PROTORECVEVENT *) ccs->lParam;
+
+ char MESSAGE_PREFIX[64];
+ wchar_t MESSAGE_PREFIXW[64];
+ MultiByteToWideChar(CP_UTF8, 0, options.prefix, -1, MESSAGE_PREFIXW, 64);
+ WideCharToMultiByte(code_page, 0, MESSAGE_PREFIXW, -1, MESSAGE_PREFIX, 64, 0, 0);
+
+ int ignore_message;
+ char *newmessage = 0;
+
+ char *oldmessage = pre->szMessage;
+ char *oldmessage_utf = 0;
+ OtrlTLV *tlvs = 0;
+ OtrlTLV *tlv = 0;
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0);
+ if(proto && strcmp(proto, "MetaContacts") == 0) // bypass for metacontacts
+ return CallService(MS_PROTO_CHAINRECV, wParam, lParam);
+
+ if(strlen(oldmessage) > INLINE_PREFIX_LEN && strncmp(oldmessage, INLINE_PREFIX, INLINE_PREFIX_LEN) == 0) // bypass for our inline messages
+ return CallService(MS_PROTO_CHAINRECV, wParam, lParam);
+
+ char *uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)ccs->hContact, 0);
+ if(!proto || !uname) return 1; // error
+
+ // convert oldmessage to utf-8
+ if(ccs->wParam & PREF_UNICODE) {
+ int size = WideCharToMultiByte(CP_UTF8, 0, (wchar_t *)&oldmessage[strlen(oldmessage)+1], -1, 0, 0, 0, 0);
+ oldmessage_utf = (char *)malloc(size * sizeof(char));
+ if(!oldmessage_utf) return 1;
+ WideCharToMultiByte(CP_UTF8, 0, (wchar_t *)&oldmessage[strlen(oldmessage)+1], -1, oldmessage_utf, size, 0, 0);
+ } else {
+ wchar_t *temp = 0;
+ int size_temp, size;
+ size_temp = MultiByteToWideChar(code_page, 0, oldmessage, -1, 0, 0);
+ temp = (wchar_t *)malloc(size_temp * sizeof(wchar_t));
+ if(!temp) return 1;
+ MultiByteToWideChar(code_page, 0, oldmessage, -1, temp, size_temp);
+
+ size = WideCharToMultiByte(CP_UTF8, 0, temp, -1, 0, 0, 0, 0);
+ oldmessage_utf = (char *)malloc(size * sizeof(char));
+ if(!oldmessage_utf) {
+ free(temp);
+ return 1;
+ }
+ WideCharToMultiByte(CP_UTF8, 0, temp, -1, oldmessage_utf, size, 0, 0);
+
+ free(temp);
+ }
+
+ lib_cs_lock();
+ ignore_message = otrl_message_receiving(otr_user_state, &ops, ccs->hContact, MODULE, proto, uname, oldmessage_utf, &newmessage, &tlvs, add_appdata, ccs->hContact);
+ lib_cs_unlock();
+ free(oldmessage_utf);
+
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
+ if (tlv) {
+ lib_cs_lock();
+ otrl_message_disconnect(otr_user_state, &ops, 0, MODULE, proto, uname);
+ lib_cs_unlock();
+ //MessageBox(0, Translate("User ended encrypted session"), Translate("OTR Information"), MB_OK);
+ char buff[512];
+ mir_snprintf(buff, 512, Translate("User '%s' ended encrypted session"), uname);
+ ShowPopup(Translate("OTR Information"), buff, 0);
+ if(tlvs) otrl_tlv_free(tlvs); // do we need these? (can be used to tell that the other side has terminated encrypted connection)
+
+ SetEncryptionStatus(ccs->hContact, false);
+
+ return 1;
+ }
+
+ if(tlvs) otrl_tlv_free(tlvs); // do we need these? (can be used to tell that the other side has terminated encrypted connection)
+
+ if(ignore_message) // internal OTR library message - ignore it
+ //if(ignore_message == 1) // internal OTR library message - ignore it
+ return 1;
+
+ if(newmessage) {
+ // user should receive newmessage instead of message
+
+ // decode utf8 into unicode message
+ wchar_t *temp;
+ char *text;
+
+ int size = MultiByteToWideChar(CP_UTF8, 0, (const char *)newmessage, -1, 0, 0);
+ temp = (wchar_t *)malloc(size * sizeof(wchar_t));
+ if(!temp) return 1;
+ MultiByteToWideChar(CP_UTF8, 0, (const char *)newmessage, -1, temp, size);
+
+ size = WideCharToMultiByte(code_page, 0, temp, -1, 0, 0, 0, 0);
+ text = (char *)malloc(size);
+ if(!text) {
+ free(temp);
+ return 1;
+ }
+ WideCharToMultiByte(code_page, 0, temp, -1, text, size, 0, 0);
+
+ lib_cs_lock();
+ otrl_message_free(newmessage);
+ lib_cs_unlock();
+
+ int tMsgBodyLen = strlen(text);
+ int tRealBodyLen = wcslen(temp);
+
+ // it may not be encrypted however (e.g. tagged plaintext with tags stripped)
+ ConnContext *context = otrl_context_find(otr_user_state, uname, MODULE, proto, FALSE, 0, 0, 0);
+ bool encrypted = context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED;
+
+ if(options.prefix_messages && encrypted) {
+ tMsgBodyLen += strlen(MESSAGE_PREFIX);
+ tRealBodyLen += wcslen(MESSAGE_PREFIXW);
+ }
+
+ int tMsgBufLen = (tMsgBodyLen+1) * sizeof(char) + (tRealBodyLen+1)*sizeof( wchar_t );
+ char* tMsgBuf = ( char* )malloc( tMsgBufLen );
+ if(!tMsgBuf) {
+ free(temp);
+ free(text);
+ return 1;
+ }
+
+ char* p = tMsgBuf;
+
+ if(options.prefix_messages && encrypted) {
+ strcpy(p, MESSAGE_PREFIX);
+ strcat(p + strlen(MESSAGE_PREFIX), text);
+ } else
+ strcpy(p, text);
+ p += (tMsgBodyLen+1);
+ free(text);
+
+ WPARAM old_flags = pre->flags;
+ if ( tRealBodyLen != 0 ) {
+ if(options.prefix_messages && encrypted) {
+ wcscpy((wchar_t *)p, MESSAGE_PREFIXW);
+ wcscat((wchar_t *)p + wcslen(MESSAGE_PREFIXW), temp );
+ } else
+ wcscpy((wchar_t *)p, temp);
+ pre->flags |= PREF_UNICODE;
+ }
+ free(temp);
+
+ pre->szMessage = tMsgBuf;
+ int ret = CallService(MS_PROTO_CHAINRECV, wParam, lParam);
+ // free decrypted message and conversion buffer
+ free(tMsgBuf);
+
+ // restore old message, so it can be freed etc
+ pre->flags = old_flags;
+ pre->szMessage = oldmessage;
+
+ return ret;
+ }
+
+ return CallService(MS_PROTO_CHAINRECV, wParam, lParam);
+}
+
+// add prefix to sent messages
+int OnDatabaseEventPreAdd(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam;
+ DBEVENTINFO *dbei = (DBEVENTINFO *)lParam;
+
+ if(!options.prefix_messages)
+ return 0;
+
+ if ((dbei->eventType != EVENTTYPE_MESSAGE) || !(dbei->flags & DBEF_SENT))
+ return 0;
+
+ if(dbei->cbBlob == 0 || dbei->pBlob == 0)
+ return 0; // just to be safe
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ char *uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
+
+ if(!proto || !uname || DBGetContactSettingByte(hContact, proto, "ChatRoom", 0) == 1) {
+ return 0;
+ }
+
+ if(strcmp(proto, "MetaContacts") == 0) {
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0);
+ if(!hSubContact)
+ return 0;
+ uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hSubContact, 0);
+ proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hSubContact, 0);
+ }
+
+ ConnContext *context = otrl_context_find(otr_user_state, uname, MODULE, proto, FALSE, 0, 0, 0);
+ bool encrypted = context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED;
+
+ if(!encrypted) return 0;
+
+ char MESSAGE_PREFIX[64];
+ wchar_t MESSAGE_PREFIXW[64];
+ MultiByteToWideChar(CP_UTF8, 0, options.prefix, -1, MESSAGE_PREFIXW, 64);
+ WideCharToMultiByte(code_page, 0, MESSAGE_PREFIXW, -1, MESSAGE_PREFIX, 64, 0, 0);
+
+ DBEVENTINFO my_dbei = *dbei; // copy the other event
+
+ char *msg = (char *)dbei->pBlob;
+ wchar_t *msgw = 0;
+ unsigned int msglen = strlen(msg) + 1;
+
+ if((msglen > strlen(MESSAGE_PREFIX) && strncmp(msg, MESSAGE_PREFIX, strlen(MESSAGE_PREFIX)) == 0) || (msglen > INLINE_PREFIX_LEN && strncmp(msg, INLINE_PREFIX, INLINE_PREFIX_LEN) == 0))
+ return 0; // already contains prefix, or it's an inline message
+
+ // here we detect the double-zero wide char zero terminator - in case of messages that are not unicode but have
+ // other data after the message (e.g. metacontact copied messages with source identifier)
+ bool dz = false;
+ for(unsigned int i = msglen; i < dbei->cbBlob; i++) {
+ if(msg[i] == 0 && msg[i - 1] == 0) { // safe since msglen + 1 above
+ dz = true;
+ break;
+ }
+ }
+
+ // does blob contain unicode message?
+ if(msglen < dbei->cbBlob && dz) {
+ // yes
+ msgw = (wchar_t *)&msg[msglen];
+ } else {
+ // no, convert to unciode (allocate stack memory);
+ int size = MultiByteToWideChar(code_page, 0, (char *) msg, -1, 0, 0);
+ msgw = (wchar_t *) _alloca(sizeof(wchar_t) * size);
+ MultiByteToWideChar(code_page, 0, msg, -1, msgw, size);
+ }
+
+ int tMsgBodyLen = strlen(msg) + strlen(MESSAGE_PREFIX);
+ int tRealBodyLen = wcslen(msgw) + wcslen(MESSAGE_PREFIXW);
+
+ int tMsgBufLen = (tMsgBodyLen+1) * sizeof(char) + (tRealBodyLen+1)*sizeof( wchar_t );
+ char* tMsgBuf = ( char* )_alloca( tMsgBufLen );
+
+ char* p = tMsgBuf;
+
+ strcpy(p, MESSAGE_PREFIX);
+ strcat(p + strlen(MESSAGE_PREFIX), msg);
+ p += (tMsgBodyLen+1);
+
+ if ( tRealBodyLen != 0 ) {
+ wcscpy((wchar_t *)p, MESSAGE_PREFIXW);
+ wcscat((wchar_t *)p + wcslen(MESSAGE_PREFIXW), msgw);
+ }
+
+ my_dbei.pBlob = (BYTE *)tMsgBuf;
+ my_dbei.cbBlob = tMsgBufLen;
+
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&my_dbei);
+
+ // stop original event from being added
+ return 1;
+}
+
+
+int OnDatabaseEventAdd(WPARAM wParam, LPARAM lParam) {
+ // DISABLED - we should only remove sent events and received events when they are marked read - e.g. NoHistory plugin
+ /*
+ if(!options.delete_history) return 0;
+
+ // remove the event - hopefully SRMM has received the event by now (since we hooked this in 'modules loaded')!
+ HANDLE hContact = (HANDLE)wParam, hDbEvent = (HANDLE)lParam;
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ char *uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
+
+ if(!proto || !uname || DBGetContactSettingByte(hContact, proto, "ChatRoom", 0) == 1) {
+ return 0;
+ }
+
+ if(strcmp(proto, "MetaContacts") == 0) {
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0);
+ if(!hSubContact)
+ return 0;
+ uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hSubContact, 0);
+ proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hSubContact, 0);
+ }
+
+ ConnContext *context = otrl_context_find(otr_user_state, uname, MODULE, proto, FALSE, 0, 0, 0);
+ bool encrypted = context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED;
+
+ if(encrypted)
+ CallService(MS_DB_EVENT_DELETE, (WPARAM)hContact, (LPARAM)hDbEvent);
+
+ // continuing processing of this event could cause trouble
+ return 1;
+ */
+
+ return 0;
+}
+
+////////////////////////////////
+///////// Menu Services
+///////////////////////
+int StartOTR(WPARAM wParam, LPARAM lParam) {
+ // prevent this filter from acting on injeceted messages for metas, when they are passed though the subcontact's proto send chain
+ HANDLE hContact = (HANDLE)wParam, hSub;
+ if(ServiceExists(MS_MC_GETMOSTONLINECONTACT) && (hSub = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0)) != 0) {
+ hContact = hSub;
+ }
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ char *uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
+ if(!proto || !uname) return 1; // error
+
+ WORD pol = DBGetContactSettingWord(hContact, MODULE, "Policy", CONTACT_DEFAULT_POLICY);
+ if(pol == CONTACT_DEFAULT_POLICY) pol = options.default_policy | OTRL_POLICY_NOHTML;
+
+ lib_cs_lock();
+ char *msg = otrl_proto_default_query_msg(MODULE, pol);
+ otr_gui_inject_message(hContact, MODULE, proto, uname, msg ? msg : "?OTRv2?");
+ lib_cs_unlock();
+ free(msg);
+
+ return 0;
+}
+
+int StopOTR(WPARAM wParam, LPARAM lParam) {
+
+ // prevent this filter from acting on injeceted messages for metas, when they are passed though the subcontact's proto send chain
+ HANDLE hContact = (HANDLE)wParam, hSub;
+ if(ServiceExists(MS_MC_GETMOSTONLINECONTACT) && (hSub = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0)) != 0) {
+ hContact = hSub;
+ }
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ char *uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
+ if(!proto || !uname) return 1; // error
+
+ lib_cs_lock();
+ otrl_message_disconnect(otr_user_state, &ops, hContact, MODULE, proto, uname);
+ lib_cs_unlock();
+
+ SetEncryptionStatus(hContact, false);
+
+ return 0;
+}
+
+///////////////////////////////////////////////
+/////// Plugin init and deinit
+////////////////////////////////////////////////
+
+
+int WindowEvent(WPARAM wParam, LPARAM lParam) {
+ MessageWindowEventData *mwd = (MessageWindowEventData *)lParam;
+ if(mwd->uType != MSG_WINDOW_EVT_OPEN) return 0;
+ if(!ServiceExists(MS_MSG_MODIFYICON)) return 0;
+
+ if(!CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)mwd->hContact, (LPARAM)MODULE))
+ return 0;
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)mwd->hContact, 0);
+ char *uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)mwd->hContact, 0);
+ if(!proto || !uname) return 0; // error - just bail
+
+ lib_cs_lock();
+ ConnContext *context = otrl_context_find(otr_user_state, uname, MODULE, proto, FALSE, 0, 0, 0);
+
+ bool encrypted = (context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED);
+ lib_cs_unlock();
+
+ SetEncryptionStatus(mwd->hContact, encrypted);
+
+ return 0;
+}
+
+int IconPressed(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam;
+ StatusIconClickData *sicd = (StatusIconClickData *)lParam;
+ if(sicd->cbSize < (int)sizeof(StatusIconClickData))
+ return 0;
+
+ if(sicd->flags & MBCF_RIGHTBUTTON) return 0; // ignore right clicks
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if(proto && DBGetContactSettingByte(hContact, proto, "ChatRoom", 0))
+ return 0;
+
+
+ if(strcmp(sicd->szModule, MODULE) == 0) {
+ if(DBGetContactSettingByte(hContact, MODULE, "Encrypted", 0) == 1)
+ StopOTR((WPARAM)hContact, 0);
+ else
+ StartOTR((WPARAM)hContact, 0);
+ }
+
+ return 0;
+}
+
+int ModulesLoaded(WPARAM wParam, LPARAM lParam) {
+ if(ServiceExists(MS_UPDATE_REGISTER)) {
+ // register with updater
+ Update update = {0};
+ char szVersion[16];
+
+ update.cbSize = sizeof(Update);
+
+ update.szComponentName = pluginInfo.shortName;
+ update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion);
+ update.cpbVersion = strlen((char *)update.pbVersion);
+
+ update.szUpdateURL = UPDATER_AUTOREGISTER;
+
+ // these are the three lines that matter - the archive, the page containing the version string, and the text (or data)
+ // before the version that we use to locate it on the page
+ // (note that if the update URL and the version URL point to standard file listing entries, the backend xml
+ // data will be used to check for updates rather than the actual web page - this is not true for beta urls)
+ update.szBetaUpdateURL = "http://www.scottellis.com.au/miranda_plugins/otr.zip";
+ update.szBetaVersionURL = "http://www.scottellis.com.au/miranda_plugins/ver_otr.html";
+ update.pbBetaVersionPrefix = (BYTE *)"OTR (Off The Record) encryption plugin, version ";
+
+ update.cpbBetaVersionPrefix = strlen((char *)update.pbBetaVersionPrefix);
+
+ CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update);
+ }
+
+ InitUtils();
+ InitMenu();
+
+ // filter added db events, so that we can add the prefix if the option is enabled
+ // (done here rather than in Load, so that MessageNotify and other such plugins can hook first - this hooks
+ // later, so it's at the start of the event chain, and can replace db events without e.g. double popups)
+ hEventDbEventAddedFilter = HookEvent(ME_DB_EVENT_FILTER_ADD, OnDatabaseEventPreAdd);
+
+ // hooked so we can remove OFF THE RECORD items from the database
+ hEventDbEventAdded = HookEvent(ME_DB_EVENT_ADDED, OnDatabaseEventAdd);
+
+ // add icon to srmm status icons
+ if(ServiceExists(MS_MSG_ADDICON)) {
+ StatusIconData sid = {0};
+ sid.cbSize = sizeof(sid);
+ sid.szModule = MODULE;
+ sid.dwId = 0;
+ sid.hIcon = hLockIcon;
+ sid.hIconDisabled = hUnlockIcon;
+ sid.flags = MBF_DISABLED;
+ sid.szTooltip = Translate("OTR Encryption Status");
+ CallService(MS_MSG_ADDICON, 0, (LPARAM)&sid);
+
+ // hook the window events so that we can can change the status of the icon
+ hEventWindow = HookEvent(ME_MSG_WINDOWEVENT, WindowEvent);
+ hEventIconPressed = HookEvent(ME_MSG_ICONPRESSED, IconPressed);
+ }
+
+
+ return 0;
+}
+
+int NewContact(WPARAM wParam, LPARAM lParam) {
+ // add filter
+ HANDLE hContact = (HANDLE)wParam;
+ CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact, ( LPARAM )MODULE );
+
+ return 0;
+}
+
+extern "C" DLLIMPORT int Load(PLUGINLINK *link) {
+ pluginLink=link;
+
+ DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainThread, THREAD_SET_CONTEXT, FALSE, 0 );
+ mainThreadId = GetCurrentThreadId();
+
+ InitializeCriticalSection(&lib_cs);
+
+ INITCOMMONCONTROLSEX icex;
+ // Ensure that the common control DLL is loaded (for listview)
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_LISTVIEW_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ if(ServiceExists(MS_DB_SETSETTINGRESIDENT)) { // 0.6+
+ CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)(MODULE "/Encrypted"));
+ }
+ //////////////
+ /// create secure data filenames, prefixed with profile name (minus extention) and an underscore
+ char mod_fname[MAX_PATH];
+ if(CallService(MS_DB_GETPROFILEPATH, (WPARAM)MAX_PATH, (LPARAM)mod_fname)) {
+ GetModuleFileName(0, mod_fname, MAX_PATH);
+ char *p = strrchr(mod_fname, '\\');
+ if(p) *p = 0;
+ }
+
+ strcat(mod_fname, "\\OTR_data");
+ CreatePath(mod_fname);
+ strcat(mod_fname, "\\");
+
+ strcpy(fingerprint_store_filename, mod_fname);
+ strcpy(private_key_filename, mod_fname);
+
+ char mod_prefix[128];
+ CallService(MS_DB_GETPROFILENAME, 128, (LPARAM)mod_prefix);
+ char *p = strrchr(mod_prefix, '.'); // cut off extention if present
+ if(p) *p = 0;
+
+ strcat(fingerprint_store_filename, mod_prefix);
+ strcat(private_key_filename, mod_prefix);
+ strcat(fingerprint_store_filename, "_");
+ strcat(private_key_filename, "_");
+
+ strcat(fingerprint_store_filename, FINGERPRINT_STORE_FILENAME);
+ strcat(private_key_filename, PRIVATE_KEY_FILENAME);
+ //////////////
+ /////// init OTR // no need to lock critical section here - only one thread
+ OTRL_INIT;
+ otr_user_state = otrl_userstate_create();
+ otrl_privkey_read(otr_user_state, private_key_filename);
+ otrl_privkey_read_fingerprints(otr_user_state, fingerprint_store_filename, 0, 0);
+
+ /////////////
+ ////// init plugin
+ PROTOCOLDESCRIPTOR pd = {0};
+ pd.cbSize = sizeof(pd);
+ pd.szName = MODULE;
+ pd.type = PROTOTYPE_ENCRYPTION;
+ CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd);
+
+ // add us as a filter to all contacts
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact, ( LPARAM )MODULE );
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+ HookEvent(ME_DB_CONTACT_ADDED, NewContact);
+
+ // create our services
+ CreateProtoServiceFunction(MODULE, PSS_MESSAGE, OTRSendMessage);
+ CreateProtoServiceFunction(MODULE, PSS_MESSAGE"W", OTRSendMessageW);
+ CreateProtoServiceFunction(MODULE, PSR_MESSAGE, RecvMessage);
+
+ CreateServiceFunction(MS_OTR_MENUSTART, StartOTR);
+ CreateServiceFunction(MS_OTR_MENUSTOP, StopOTR);
+
+ // init options
+ LoadOptions();
+ HookEvent(ME_OPT_INITIALISE, OptInit);
+
+ if(ServiceExists(MS_LANGPACK_GETCODEPAGE))
+ code_page = CallService(MS_LANGPACK_GETCODEPAGE, 0, 0);
+
+ // hook modules loaded for updater support
+ HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
+
+ // hook setting changed to monitor status
+ HookEvent(ME_DB_CONTACT_SETTINGCHANGED, SettingChanged);
+
+ return 0;
+}
+
+extern "C" DLLIMPORT int Unload(void) {
+ UnhookEvent(hEventWindow);
+ UnhookEvent(hEventDbEventAddedFilter);
+ UnhookEvent(hEventDbEventAdded);
+
+ DeinitMenu();
+ DeinitUtils();
+
+ lib_cs_lock();
+ otrl_userstate_free(otr_user_state);
+ lib_cs_unlock();
+
+ DeleteCriticalSection(&lib_cs);
+ return 0;
+}
diff --git a/otr/libotr.def b/otr/libotr.def new file mode 100644 index 0000000..74ac50a --- /dev/null +++ b/otr/libotr.def @@ -0,0 +1,5 @@ +; c:\Dev-Cpp\Bin\dlltool --base-file C:\DOCUME~1\sje\LOCALS~1\Temp/cca03408.base --output-exp otr.exp --dllname otr.dll --output-def libotr.def --exclude-symbol=DllMainCRTStartup@12 --def C:\DOCUME~1\sje\LOCALS~1\Temp/cca03408.def --output-lib libotr.a
+EXPORTS
+ MirandaPluginInfo @ 1
+ Unload @ 2
+ Load @ 3
diff --git a/otr/menu.cpp b/otr/menu.cpp new file mode 100644 index 0000000..88c385d --- /dev/null +++ b/otr/menu.cpp @@ -0,0 +1,102 @@ +#include "common.h"
+#include "menu.h"
+#include "options.h"
+#include "utils.h"
+
+HANDLE hMenuBuildEvent, hStartItem, hStopItem;
+
+void FixMenuIcons() {
+ // fix menu icons
+ CLISTMENUITEM menu;
+ ZeroMemory(&menu,sizeof(menu));
+ menu.cbSize=sizeof(menu);
+ menu.flags = CMIM_ICON;
+
+ menu.hIcon = hLockIcon;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hStartItem, (LPARAM)&menu);
+ menu.hIcon = hUnlockIcon;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hStopItem, (LPARAM)&menu);
+}
+
+int PrebuildContactMenu(WPARAM wParam, LPARAM lParam) {
+ HANDLE hContact = (HANDLE)wParam;
+
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE;
+
+ char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ char *uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
+ WORD pol = CONTACT_DEFAULT_POLICY;
+
+ if(!proto || !uname || DBGetContactSettingByte(hContact, proto, "ChatRoom", 0) == 1) {
+ goto hide_all;
+ }
+
+ if(strcmp(proto, "MetaContacts") == 0) {
+ // make menu act as per most online subcontact
+ hContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0);
+ if(!hContact)
+ goto hide_all;
+ uname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
+ proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ }
+
+ pol = DBGetContactSettingWord(hContact, MODULE, "Policy", CONTACT_DEFAULT_POLICY);
+ if(pol == CONTACT_DEFAULT_POLICY) pol = options.default_policy;
+
+ if(pol == OTRL_POLICY_NEVER || pol == OTRL_POLICY_ALWAYS) {
+ goto hide_all;
+ }
+
+ {
+ ConnContext *context = otrl_context_find(otr_user_state, uname, MODULE, proto, FALSE, 0, 0, 0);
+ bool encrypted = context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED;
+ if(encrypted) {
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hStopItem, (LPARAM)&mi);
+ mi.flags |= CMIF_HIDDEN;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hStartItem, (LPARAM)&mi);
+ } else {
+ if(pol == OTRL_POLICY_MANUAL_MOD) {
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hStartItem, (LPARAM)&mi);
+ mi.flags |= CMIF_HIDDEN;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hStopItem, (LPARAM)&mi);
+ } else { // should only be 'opportunistic'
+ goto hide_all;
+ }
+ }
+ }
+
+ return 0;
+
+hide_all:
+ mi.flags |= CMIF_HIDDEN;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hStopItem, (LPARAM)&mi);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hStartItem, (LPARAM)&mi);
+ return 0;
+}
+
+void InitMenu() {
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_NOTOFFLINE;
+ mi.position = -400000;
+
+ mi.pszName = Translate("Stop OTR");
+ mi.pszService = MS_OTR_MENUSTOP;
+ mi.hIcon = hUnlockIcon;
+
+ hStopItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ mi.pszName = Translate("Start OTR");
+ mi.pszService = MS_OTR_MENUSTART;
+ mi.hIcon = hLockIcon;
+
+ hStartItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ hMenuBuildEvent = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildContactMenu);
+
+}
+
+void DeinitMenu() {
+}
diff --git a/otr/menu.h b/otr/menu.h new file mode 100644 index 0000000..bd1c190 --- /dev/null +++ b/otr/menu.h @@ -0,0 +1,9 @@ +#ifndef _MENU_INC
+#define _MENU_INC
+
+void FixMenuIcons();
+
+void InitMenu();
+void DeinitMenu();
+
+#endif
diff --git a/otr/options.cpp b/otr/options.cpp new file mode 100644 index 0000000..4e81895 --- /dev/null +++ b/otr/options.cpp @@ -0,0 +1,418 @@ +#include "common.h"
+#include "options.h"
+
+Options options;
+
+#define WMU_REFRESHLIST (WM_USER + 241)
+#define CONTACT_DEFAULT_POLICY 0xFFFF
+
+#include <map>
+typedef std::map<HANDLE, OtrlPolicy> ContactPolicyMap;
+
+void LoadOptions() {
+ options.default_policy = DBGetContactSettingWord(0, MODULE, "DefaultPolicy", OTRL_POLICY_OPPORTUNISTIC);
+ // deal with changed flags in proto.h and new interpretation of 'manual' mode (see common.h)
+ switch(options.default_policy) {
+ case OTRL_POLICY_MANUAL:
+ options.default_policy = OTRL_POLICY_MANUAL_MOD;
+ break;
+ case OTRL_POLICY_OPPORTUNISTIC:
+ case OTRL_POLICY_MANUAL_MOD:
+ case OTRL_POLICY_ALWAYS:
+ case OTRL_POLICY_NEVER:
+ break;
+ default:
+ options.default_policy = OTRL_POLICY_OPPORTUNISTIC;
+ break;
+ }
+ if(options.default_policy == OTRL_POLICY_MANUAL)
+ options.default_policy = OTRL_POLICY_MANUAL_MOD;
+ options.err_method = (ErrorDisplay)DBGetContactSettingWord(0, MODULE, "ErrorDisplay", ED_POP);
+ options.prefix_messages = (DBGetContactSettingByte(0, MODULE, "PrefixMessages", 0) == 1);
+ options.msg_inline = (DBGetContactSettingByte(0, MODULE, "MsgInline", 0) == 1);
+
+ DBVARIANT dbv;
+ if(!DBGetContactSetting(0, MODULE, "Prefix", &dbv)) {
+ strncpy(options.prefix, dbv.pszVal, 64);
+ options.prefix[63] = 0;
+ DBFreeVariant(&dbv);
+ } else
+ strcpy(options.prefix, "OTR: ");
+
+ options.delete_history = (DBGetContactSettingByte(0, MODULE, "DeleteHistory", 1) == 1);
+}
+
+void SaveOptions(ContactPolicyMap *contact_policies) {
+ DBWriteContactSettingWord(0, MODULE, "DefaultPolicy", options.default_policy);
+ DBWriteContactSettingWord(0, MODULE, "ErrorDisplay", (int)options.err_method);
+ DBWriteContactSettingByte(0, MODULE, "PrefixMessages", options.prefix_messages ? 1 : 0);
+ DBWriteContactSettingByte(0, MODULE, "MsgInline", options.msg_inline ? 1 : 0);
+
+ for(ContactPolicyMap::iterator i = contact_policies->begin(); i != contact_policies->end(); i++) {
+ DBWriteContactSettingWord(i->first, MODULE, "Policy", i->second);
+ }
+
+ DBWriteContactSettingStringUtf(0, MODULE, "Prefix", options.prefix);
+
+ DBWriteContactSettingByte(0, MODULE, "DeleteHistory", options.delete_history ? 1 : 0);
+}
+
+INT_PTR CALLBACK DlgProcOpts1(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ // set contact to policy map
+ ContactPolicyMap *contact_policies = new ContactPolicyMap();
+ SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)contact_policies);
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ char *proto;
+ while ( hContact != NULL ) {
+ proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ if(proto && DBGetContactSettingByte(hContact, proto, "ChatRoom", 0) == 0 && CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)hContact, (LPARAM)MODULE)) {
+ WORD pol = DBGetContactSettingWord(hContact, MODULE, "Policy", CONTACT_DEFAULT_POLICY);
+ // deal with changed flags in proto.h and new interpretation of 'manual' mode (see common.h)
+ switch(pol) {
+ case OTRL_POLICY_MANUAL:
+ pol = OTRL_POLICY_MANUAL_MOD;
+ break;
+ case OTRL_POLICY_OPPORTUNISTIC:
+ case OTRL_POLICY_MANUAL_MOD:
+ case OTRL_POLICY_ALWAYS:
+ case OTRL_POLICY_NEVER:
+ break;
+ default:
+ pol = CONTACT_DEFAULT_POLICY;
+ break;
+ }
+
+ contact_policies->operator[](hContact) = pol;
+ }
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+ }
+ switch(options.default_policy) {
+ case OTRL_POLICY_OPPORTUNISTIC:
+ CheckDlgButton(hwndDlg, IDC_RAD_OPP, TRUE);
+ break;
+ case OTRL_POLICY_MANUAL_MOD:
+ CheckDlgButton(hwndDlg, IDC_RAD_MANUAL, TRUE);
+ break;
+ case OTRL_POLICY_ALWAYS:
+ CheckDlgButton(hwndDlg, IDC_RAD_ALWAYS, TRUE);
+ break;
+ case OTRL_POLICY_NEVER:
+ CheckDlgButton(hwndDlg, IDC_RAD_NEVER, TRUE);
+ break;
+ }
+
+ SendMessage(GetDlgItem(hwndDlg, IDC_CLIST),LVM_SETEXTENDEDLISTVIEWSTYLE, 0,LVS_EX_FULLROWSELECT);// | LVS_EX_CHECKBOXES);
+
+ {
+ // add list columns
+ LVCOLUMN lvc;
+ // Initialize the LVCOLUMN structure.
+ // The mask specifies that the format, width, text, and
+ // subitem members of the structure are valid.
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+ lvc.fmt = LVCFMT_LEFT;
+
+ lvc.iSubItem = 0;
+ lvc.pszText = Translate("Contact");
+ lvc.cx = 150; // width of column in pixels
+ ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_CLIST), 0, &lvc);
+
+ lvc.iSubItem = 1;
+ lvc.pszText = Translate("Protocol");
+ lvc.cx = 100; // width of column in pixels
+ ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_CLIST), 1, &lvc);
+
+ lvc.iSubItem = 2;
+ lvc.pszText = Translate("Policy");
+ lvc.cx = 100; // width of column in pixels
+ ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_CLIST), 2, &lvc);
+ }
+ SendMessage(hwndDlg, WMU_REFRESHLIST, 0, 0);
+
+ // fill proto list box
+ {
+ int num_protocols;
+ PROTOCOLDESCRIPTOR **pppDesc;
+
+ CallService(MS_PROTO_ENUMPROTOCOLS, (LPARAM)&num_protocols, (WPARAM)&pppDesc);
+ HWND hw = GetDlgItem(hwndDlg, IDC_LIST_PROTOS);
+ for(int i = 0; i < num_protocols; i++) {
+ if(pppDesc[i]->type == PROTOTYPE_PROTOCOL && strcmp(pppDesc[i]->szName, "MetaContacts") != 0
+ && CallProtoService(pppDesc[i]->szName, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IM == PF1_IM)
+ {
+ SendMessage(hw, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)pppDesc[i]->szName);
+ }
+ }
+ }
+
+ CheckDlgButton(hwndDlg, IDC_CHK_PREFIX, options.prefix_messages ? TRUE : FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHK_MSGINLINE, options.msg_inline ? TRUE : FALSE);
+
+ SetDlgItemText(hwndDlg, IDC_ED_PREFIX, options.prefix);
+ return TRUE;
+
+ case WMU_REFRESHLIST:
+ //enumerate contacts, fill in list
+ {
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_CLIST));
+
+ LVITEM lvI = {0};
+
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all
+ // items.
+ lvI.mask = LVIF_TEXT | LVIF_PARAM;// | LVIF_NORECOMPUTE;// | LVIF_IMAGE;
+
+ char *proto;
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ proto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 );
+ if(proto && DBGetContactSettingByte(hContact, proto, "ChatRoom", 0) == 0 && CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)hContact, (LPARAM)MODULE) // ignore chatrooms
+ && (proto && strcmp(proto, "MetaContacts") != 0)) // and MetaContacts
+ {
+ lvI.iSubItem = 0;
+ lvI.lParam = (LPARAM)hContact;
+ lvI.pszText = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
+ lvI.iItem = ListView_InsertItem(GetDlgItem(hwndDlg, IDC_CLIST), &lvI);
+
+ lvI.iSubItem = 1;
+ lvI.pszText = LPSTR_TEXTCALLBACK;
+ ListView_SetItem(GetDlgItem(hwndDlg, IDC_CLIST), &lvI);
+
+ lvI.iSubItem = 2;
+ lvI.pszText = LPSTR_TEXTCALLBACK;
+ ListView_SetItem(GetDlgItem(hwndDlg, IDC_CLIST), &lvI);
+ }
+
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+ }
+
+ return TRUE;
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ } else + if (HIWORD( wParam ) == LBN_SELCHANGE && LOWORD(wParam) == IDC_LIST_PROTOS) {
+ HWND hw = GetDlgItem(hwndDlg, IDC_LIST_PROTOS);
+ int sel = -1;
+ if((sel = SendMessage(hw, LB_GETCURSEL, 0, 0)) != -1) {
+ char proto[512];
+ SendMessage(hw, LB_GETTEXT, (WPARAM)sel, (LPARAM)proto);
+
+ char fingerprint[45];
+ if(otrl_privkey_fingerprint(otr_user_state, fingerprint, MODULE, proto))
+ SetDlgItemText(hwndDlg, IDC_ED_FINGERPRINT, fingerprint);
+ else
+ SetDlgItemText(hwndDlg, IDC_ED_FINGERPRINT, "");
+
+ hw = GetDlgItem(hwndDlg, IDC_BUT_NEWKEY);
+ EnableWindow(hw, TRUE);
+
+ return TRUE;
+ } else {
+ hw = GetDlgItem(hwndDlg, IDC_BUT_NEWKEY);
+ EnableWindow(hw, FALSE);
+ }
+ return FALSE;
+ } else
+ if ( HIWORD( wParam ) == BN_CLICKED ) {
+ switch( LOWORD( wParam )) {
+ case IDC_BUT_NEWKEY:
+ {
+ HWND hw = GetDlgItem(hwndDlg, IDC_LIST_PROTOS);
+ int sel = -1;
+ if((sel = SendMessage(hw, LB_GETCURSEL, 0, 0)) != -1) {
+ char proto[512];
+ SendMessage(hw, LB_GETTEXT, (WPARAM)sel, (LPARAM)proto);
+
+ SetDlgItemText(hwndDlg, IDC_ED_FINGERPRINT, Translate("Generating new key...please wait"));
+ otrl_privkey_generate(otr_user_state, private_key_filename, MODULE, proto);
+
+ char fingerprint[45];
+ if(otrl_privkey_fingerprint(otr_user_state, fingerprint, MODULE, proto))
+ SetDlgItemText(hwndDlg, IDC_ED_FINGERPRINT, fingerprint);
+ else
+ SetDlgItemText(hwndDlg, IDC_ED_FINGERPRINT, "");
+
+ return TRUE;
+ }
+ }
+
+ break;
+
+ case IDC_RAD_OPP:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ return TRUE;
+ case IDC_RAD_MANUAL:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ return TRUE;
+ case IDC_RAD_ALWAYS:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ return TRUE;
+ case IDC_RAD_NEVER:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ return TRUE;
+ case IDC_CHK_PREFIX:
+ case IDC_CHK_MSGINLINE:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ return TRUE;
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ if(((LPNMHDR) lParam)->hwndFrom == GetDlgItem(hwndDlg, IDC_CLIST)) {
+ switch (((LPNMHDR) lParam)->code) {
+ case NM_CLICK:
+ if (((LPNMLISTVIEW)lParam)->iSubItem == 2) {
+ LVITEM lvi;
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = ((LPNMLISTVIEW)lParam)->iItem;
+ lvi.iSubItem = 0;
+ SendMessage(GetDlgItem(hwndDlg, IDC_CLIST), LVM_GETITEM, 0, (LPARAM)&lvi);
+
+ HANDLE hContact = (HANDLE)lvi.lParam;
+ ContactPolicyMap *contact_policies = (ContactPolicyMap *)GetWindowLong(hwndDlg, GWL_USERDATA);
+ ContactPolicyMap::iterator i = contact_policies->find(hContact);
+ WORD pol = CONTACT_DEFAULT_POLICY;
+ if(i != contact_policies->end())
+ pol = i->second;
+
+ switch(pol) {
+ case CONTACT_DEFAULT_POLICY:
+ pol = OTRL_POLICY_MANUAL_MOD;
+ break;
+ case OTRL_POLICY_OPPORTUNISTIC:
+ pol = OTRL_POLICY_ALWAYS;
+ break;
+ case OTRL_POLICY_MANUAL_MOD:
+ pol = OTRL_POLICY_OPPORTUNISTIC;
+ break;
+ case OTRL_POLICY_ALWAYS:
+ pol = OTRL_POLICY_NEVER;
+ break;
+ case OTRL_POLICY_NEVER:
+ pol = CONTACT_DEFAULT_POLICY;
+ break;
+ }
+
+ contact_policies->operator[](hContact) = pol;
+ ListView_RedrawItems(GetDlgItem(hwndDlg, IDC_CLIST), lvi.iItem, lvi.iItem);
+
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ }
+ break;
+ case LVN_GETDISPINFO:
+ {
+ LVITEM lvi;
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = ((NMLVDISPINFO *)lParam)->item.iItem;
+ lvi.iSubItem = 0;
+ SendMessage(GetDlgItem(hwndDlg, IDC_CLIST), LVM_GETITEM, 0, (LPARAM)&lvi);
+ switch (((NMLVDISPINFO *)lParam)->item.iSubItem) {
+ case 0:
+ MessageBox(0, "LVN_GETDISPINFO (0)", "msg", MB_OK);
+ break;
+ case 1:
+ {
+ HANDLE hContact = (HANDLE)lvi.lParam;
+ ((NMLVDISPINFO *)lParam)->item.pszText = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ }
+ break;
+ case 2:
+ {
+
+ char *text = 0;
+ HANDLE hContact = (HANDLE)lvi.lParam;
+ ContactPolicyMap *contact_policies = (ContactPolicyMap *)GetWindowLong(hwndDlg, GWL_USERDATA);
+ ContactPolicyMap::iterator i = contact_policies->find(hContact);
+ WORD pol = CONTACT_DEFAULT_POLICY;
+ if(i != contact_policies->end())
+ pol = i->second;
+ switch(pol) {
+ case CONTACT_DEFAULT_POLICY:
+ text = Translate("Default");
+ break;
+ case OTRL_POLICY_OPPORTUNISTIC:
+ text = Translate("Opportunistic");
+ break;
+ case OTRL_POLICY_MANUAL_MOD:
+ text = Translate("Manual");
+ break;
+ case OTRL_POLICY_ALWAYS:
+ text = Translate("Always");
+ break;
+ case OTRL_POLICY_NEVER:
+ text = Translate("Never");
+ break;
+ }
+ ((NMLVDISPINFO *)lParam)->item.pszText = text;
+
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+ } else
+ if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY ) {
+ if(IsDlgButtonChecked(hwndDlg, IDC_RAD_OPP))
+ options.default_policy = OTRL_POLICY_OPPORTUNISTIC;
+ else if(IsDlgButtonChecked(hwndDlg, IDC_RAD_MANUAL))
+ options.default_policy = OTRL_POLICY_MANUAL_MOD;
+ else if(IsDlgButtonChecked(hwndDlg, IDC_RAD_ALWAYS))
+ options.default_policy = OTRL_POLICY_ALWAYS;
+ else if(IsDlgButtonChecked(hwndDlg, IDC_RAD_NEVER))
+ options.default_policy = OTRL_POLICY_NEVER;
+
+ options.prefix_messages = IsDlgButtonChecked(hwndDlg, IDC_CHK_PREFIX) ? true : false;
+ options.msg_inline = IsDlgButtonChecked(hwndDlg, IDC_CHK_MSGINLINE) ? true : false;
+ GetDlgItemText(hwndDlg, IDC_ED_PREFIX, options.prefix, 64);
+
+ ContactPolicyMap *contact_policies = (ContactPolicyMap *)GetWindowLong(hwndDlg, GWL_USERDATA);
+
+ SaveOptions(contact_policies);
+ return TRUE;
+ }
+ break;
+
+ case WM_DESTROY:
+ {
+ ContactPolicyMap *contact_policies = (ContactPolicyMap *)GetWindowLong(hwndDlg, GWL_USERDATA);
+ SetWindowLong(hwndDlg, GWL_USERDATA, 0);
+ delete contact_policies;
+ }
+ }
+
+ return FALSE;
+}
+
+int OptInit(WPARAM wParam, LPARAM lParam) {
+ OPTIONSDIALOGPAGE odp = { 0 };
+#define OPTIONPAGE_OLD_SIZE2 60
+ //odp.cbSize = sizeof(odp);
+ odp.cbSize = OPTIONPAGE_OLD_SIZE2;
+ odp.position = 100;
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCE(IDD_OPT1);
+ odp.pszTitle = Translate(MODULE);
+ odp.pszGroup = Translate("Plugins");
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = 0;
+ odp.pfnDlgProc = DlgProcOpts1;
+ CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp );
+
+ return 0;
+}
+
+void OptDeinit() {
+}
diff --git a/otr/options.h b/otr/options.h new file mode 100644 index 0000000..475e566 --- /dev/null +++ b/otr/options.h @@ -0,0 +1,24 @@ +#ifndef _OPTIONS_INC
+#define _OPTIONS_INC
+
+#define CONTACT_DEFAULT_POLICY 0xFFFF
+
+typedef enum {ED_POP, ED_BAL, ED_MB} ErrorDisplay;
+
+typedef struct {
+ OtrlPolicy default_policy;
+ ErrorDisplay err_method;
+ bool prefix_messages;
+ bool msg_inline;
+ char prefix[64];
+
+ bool delete_history;
+} Options;
+
+extern Options options;
+
+int OptInit(WPARAM wParam, LPARAM lParam);
+
+void LoadOptions();
+
+#endif
diff --git a/otr/otr.layout b/otr/otr.layout new file mode 100644 index 0000000..40a374f --- /dev/null +++ b/otr/otr.layout @@ -0,0 +1,87 @@ +[Editor_0]
+CursorCol=69
+CursorRow=479
+TopLine=451
+LeftChar=1
+Open=1
+Top=1
+[Editor_1]
+CursorCol=19
+CursorRow=7
+TopLine=1
+LeftChar=1
+Open=0
+Top=0
+[Editor_2]
+CursorCol=8
+CursorRow=52
+TopLine=14
+LeftChar=1
+Open=1
+Top=0
+[Editor_3]
+CursorCol=11
+CursorRow=13
+TopLine=1
+LeftChar=1
+Open=1
+Top=0
+[Editor_4]
+CursorCol=4
+CursorRow=219
+TopLine=216
+LeftChar=1
+Open=1
+Top=0
+[Editor_5]
+CursorCol=54
+CursorRow=5
+TopLine=1
+LeftChar=1
+Open=0
+Top=0
+[Editor_6]
+CursorCol=27
+CursorRow=10
+TopLine=1
+LeftChar=1
+Open=0
+Top=0
+[Editors]
+Focused=0
+Order=2,10,9,3,4,0
+[Editor_7]
+Open=0
+Top=0
+CursorCol=1
+CursorRow=6
+TopLine=1
+LeftChar=1
+[Editor_8]
+Open=0
+Top=0
+CursorCol=1
+CursorRow=81
+TopLine=36
+LeftChar=1
+[Editor_9]
+Open=1
+Top=0
+CursorCol=25
+CursorRow=72
+TopLine=58
+LeftChar=1
+[Editor_10]
+Open=1
+Top=0
+CursorCol=1
+CursorRow=12
+TopLine=1
+LeftChar=1
+[Editor_11]
+Open=0
+Top=0
+CursorCol=18
+CursorRow=12
+TopLine=1
+LeftChar=1
diff --git a/otr/otr.mdsp b/otr/otr.mdsp new file mode 100644 index 0000000..f09edad --- /dev/null +++ b/otr/otr.mdsp @@ -0,0 +1,108 @@ +[Project]
+name=otr
+type=2
+defaultConfig=0
+
+
+[Debug]
+// compiler
+workingDirectory=
+arguments=
+intermediateFilesDirectory=Debug
+outputFilesDirectory=Debug
+compilerPreprocessor=BUILDING_DLL
+extraCompilerOptions=
+compilerIncludeDirectory=c:\msys\local\include\libotr,..\..\include
+noWarning=0
+defaultWarning=0
+allWarning=1
+extraWarning=0
+isoWarning=0
+warningsAsErrors=0
+debugType=1
+debugLevel=3
+exceptionEnabled=0
+runtimeTypeEnabled=0
+optimizeLevel=0
+
+// linker
+libraryPath=
+outputFilename=..\..\bin\debug\plugins\otr.dll
+libraries=otr, gcrypt, gpg-error, comctl32, shell32
+extraLinkerOptions=-shared
+ignoreStartupFile=0
+ignoreDefaultLibs=0
+stripExecutableFile=0
+
+// archive
+extraArchiveOptions=
+
+//resource
+resourcePreprocessor=
+resourceIncludeDirectory=
+extraResourceOptions=
+
+[Release]
+// compiler
+workingDirectory=
+arguments=
+intermediateFilesDirectory=Release
+outputFilesDirectory=Release
+compilerPreprocessor=BUILDING_DLL
+extraCompilerOptions=
+compilerIncludeDirectory=c:\msys\local\include\libotr,..\..\include
+noWarning=0
+defaultWarning=0
+allWarning=1
+extraWarning=0
+isoWarning=0
+warningAsErrors=0
+debugType=0
+debugLevel=1
+exceptionEnabled=0
+runtimeTypeEnabled=0
+optimizeLevel=4
+
+// linker
+libraryPath=
+outputFilename=..\..\bin\release\plugins\otr.dll
+libraries=otr, gcrypt, gpg-error, comctl32, shell32
+extraLinkerOptions=
+ignoreStartupFile=0
+ignoreDefaultLibs=0
+stripExecutableFile=1
+
+// archive
+extraArchiveOptions=
+
+//resource
+resourcePreprocessor=
+resourceIncludeDirectory=
+extraResourceOptions=
+
+[Source]
+1=dllmain.cpp
+2=menu.cpp
+3=options.cpp
+4=utils.cpp
+[Header]
+1=common.h
+2=dll.h
+3=menu.h
+4=options.h
+5=otr_private.h
+6=resource.h
+7=utils.h
+8=IcoLib.h
+[Resource]
+1=otr_private.rc
+2=resource.rc
+[Other]
+[History]
+libotr\libotr\src\context.h,0
+common.h,263
+options.h,0
+..\..\include\m_message.h,1556
+..\MetaContacts\meta_main.c,6362
+otr_private.h,149
+dllmain.cpp,35050
diff --git a/otr/otr_private.h b/otr/otr_private.h new file mode 100644 index 0000000..c6f9c2e --- /dev/null +++ b/otr/otr_private.h @@ -0,0 +1,24 @@ +#ifndef OTR_PRIVATE_H
+#define OTR_PRIVATE_H
+
+/* VERSION DEFINITIONS */
+#define VER_MAJOR 0
+#define VER_MINOR 4
+#define VER_RELEASE 3
+#define VER_BUILD 0
+
+#define __STRINGIZE(x) #x
+#define VER_STRING __STRINGIZE( VER_MAJOR.VER_MINOR.VER_RELEASE.VER_BUILD )
+
+#define DESC_STRING "OTR (Off-the-Record) plugin for Miranda IM"
+#define COMPANY_NAME ""
+#define FILE_VERSION VER_STRING
+#define FILE_DESCRIPTION DESC_STRING
+#define INTERNAL_NAME ""
+#define LEGAL_COPYRIGHT "© Scott Ellis 2005"
+#define LEGAL_TRADEMARKS ""
+#define ORIGINAL_FILENAME "otr.dll"
+#define PRODUCT_NAME DESC_STRING
+#define PRODUCT_VERSION VER_STRING
+
+#endif /*OTR_PRIVATE_H*/
diff --git a/otr/otr_private.rc b/otr/otr_private.rc new file mode 100644 index 0000000..0f774cb --- /dev/null +++ b/otr/otr_private.rc @@ -0,0 +1,35 @@ +/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */
+/* DO NOT EDIT! */
+
+#include "otr_private.h"
+#include "resource.rc"
+
+//
+// TO CHANGE VERSION INFORMATION, EDIT PROJECT OPTIONS...
+//
+1 VERSIONINFO
+FILEVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD
+PRODUCTVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "0C0904E4"
+ {
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileVersion", FILE_VERSION
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", LEGAL_COPYRIGHT
+ VALUE "LegalTrademarks", LEGAL_TRADEMARKS
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0C09, 1252
+ }
+}
+
diff --git a/otr/resource.h b/otr/resource.h new file mode 100644 index 0000000..45e58dc --- /dev/null +++ b/otr/resource.h @@ -0,0 +1,20 @@ +
+#define IDD_OPT1 101
+#define IDC_RAD_OPP 1002
+#define IDC_RAD_ALWAYS 1003
+#define IDC_RAD_NEVER 1004
+#define IDC_CLIST 1005
+#define IDC_RAD_MANUAL 1006
+#define IDC_LIST_PROTOS 1007
+#define IDC_ED_FINGERPRINT 1008
+#define IDC_BUT_NEWKEY 1009
+#define IDC_CHK_PREFIX 1010
+#define IDC_CHK_MSGINLINE 1011
+#define IDC_ED_PREFIX 1012
+
+#define IDD_GENKEYNOTIFY 102
+
+#define IDI_START 2000
+#define IDI_STOP 2001
+
+#define IDC_STATIC -1
diff --git a/otr/resource.rc b/otr/resource.rc new file mode 100644 index 0000000..c52fe28 --- /dev/null +++ b/otr/resource.rc @@ -0,0 +1,111 @@ +// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (Australia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_START ICON "start.ico"
+IDI_STOP ICON "stop.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT1 DIALOGEX 0, 0, 288, 217
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CONTROL "List1",IDC_CLIST,"SysListView32",LVS_REPORT | LVS_SORTASCENDING | WS_BORDER | WS_TABSTOP,8,7,271,112
+ GROUPBOX "Default Policy",IDC_STATIC,8,150,109,59
+ CONTROL "Manual",IDC_RAD_MANUAL,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,16,160,95,10
+ CONTROL "Opportunistic",IDC_RAD_OPP,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,16,172,95,10
+ CONTROL "Always",IDC_RAD_ALWAYS,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,16,184,95,10
+ CONTROL "Never",IDC_RAD_NEVER,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,16,195,95,10
+ LISTBOX IDC_LIST_PROTOS,127,124,152,60,WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_ED_FINGERPRINT,127,185,152,12,ES_AUTOHSCROLL | ES_READONLY
+ PUSHBUTTON "New Private Key",IDC_BUT_NEWKEY,127,200,152,10,WS_DISABLED
+ CONTROL "Prefix:",IDC_CHK_PREFIX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,125,48,10
+ CONTROL "Show start/stop inline",IDC_CHK_MSGINLINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,137,110,10
+ EDITTEXT IDC_ED_PREFIX,64,124,53,12,ES_AUTOHSCROLL
+END
+
+IDD_GENKEYNOTIFY DIALOG 0, 0, 200, 80
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CHILD | WS_CAPTION | WS_SYSMENU | WS_GROUP
+CAPTION "OTR Generating Private Key"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CTEXT "Generating new private key - please wait.",IDC_STATIC,10,35,180,10
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resrc1.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""resource.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (Australia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/otr/start.ico b/otr/start.ico Binary files differnew file mode 100644 index 0000000..d6abe72 --- /dev/null +++ b/otr/start.ico diff --git a/otr/stop.ico b/otr/stop.ico Binary files differnew file mode 100644 index 0000000..90b38e5 --- /dev/null +++ b/otr/stop.ico diff --git a/otr/utils.cpp b/otr/utils.cpp new file mode 100644 index 0000000..2950504 --- /dev/null +++ b/otr/utils.cpp @@ -0,0 +1,282 @@ +#include "common.h"
+#include "utils.h"
+#include "../../include/m_popup.h"
+#include "options.h"
+#include "menu.h"
+
+#include <shlobj.h>
+
+HICON hProtoIcon, hLockIcon, hUnlockIcon;
+HANDLE hIcoLibIconsChanged = 0;
+
+LRESULT CALLBACK NullWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+ switch( message ) {
+ case WM_COMMAND: {
+ PUDeletePopUp( hWnd );
+ break;
+ }
+
+ case WM_CONTEXTMENU:
+ PUDeletePopUp( hWnd );
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void CALLBACK sttMainThreadCallback( ULONG dwParam )
+{
+ POPUPDATAEX* ppd = ( POPUPDATAEX* )dwParam;
+
+ if ( ServiceExists(MS_POPUP_ADDPOPUPEX) )
+ CallService( MS_POPUP_ADDPOPUPEX, ( WPARAM )ppd, 0 );
+ else
+ if ( ServiceExists(MS_POPUP_ADDPOPUP) )
+ CallService( MS_POPUP_ADDPOPUP, ( WPARAM )ppd, 0 );
+
+ free( ppd );
+}
+
+void ShowPopup( const char* line1, const char* line2, int timeout )
+{
+ if(CallService(MS_SYSTEM_TERMINATED, 0, 0)) return;
+
+ if ( !ServiceExists( MS_POPUP_ADDPOPUP )) {
+ char title[256];
+ sprintf(title, "%s Message", MODULE);
+
+ if(line1 && line2) {
+ char *message = new char[strlen(line1) + strlen(line2) + 2]; // newline and null terminator
+ sprintf(message, "%s\n%s", line1, line2);
+ MessageBox( NULL, message, title, MB_OK | MB_ICONINFORMATION );
+ delete message;
+ } else if(line1) {
+ MessageBox( NULL, line1, title, MB_OK | MB_ICONINFORMATION );
+ } else if(line2) {
+ MessageBox( NULL, line2, title, MB_OK | MB_ICONINFORMATION );
+ }
+ return;
+ }
+
+ POPUPDATAEX* ppd = ( POPUPDATAEX* )calloc( sizeof( POPUPDATAEX ), 1 );
+ memset((void *)ppd, 0, sizeof(POPUPDATAEX));
+
+ ppd->lchContact = NULL;
+ ppd->lchIcon = hProtoIcon;
+
+ if(line1 && line2) {
+ strcpy( ppd->lpzContactName, line1 );
+ strcpy( ppd->lpzText, line2 );
+ } else if(line1) strcpy( ppd->lpzText, line1 );
+ else if(line2) strcpy( ppd->lpzText, line2 );
+
+ //ppd->colorBack = GetSysColor( COLOR_BTNFACE );
+ //ppd->colorText = GetSysColor( COLOR_WINDOWTEXT );
+
+ //ppd->colorText = 0x00FFFFFF; // for old popup modules
+ //ppd->colorBack = POPUP_USE_SKINNED_BG;
+
+ ppd->iSeconds = timeout;
+
+ //ppd->lpzClass = POPUP_CLASS_DEFAULT;
+
+ ppd->PluginWindowProc = ( WNDPROC )NullWindowProc;
+ ppd->PluginData = NULL;
+
+ QueueUserAPC( sttMainThreadCallback , mainThread, ( ULONG )ppd );
+}
+
+void ShowWarning(char *msg) {
+ char buffer[512];
+ ErrorDisplay disp = options.err_method;
+ // funny logic :) ... try to avoid message boxes
+ // if want baloons but no balloons, try popups
+ // if want popups but no popups, try baloons
+ // if, after that, you want balloons but no balloons, revert to message boxes
+ if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_POP;
+ if(disp == ED_POP && !ServiceExists(MS_POPUP_SHOWMESSAGE)) disp = ED_BAL;
+ if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_MB;
+
+ sprintf(buffer, "%s Warning", MODULE);
+
+
+ switch(disp) {
+ case ED_POP:
+ ShowPopup(buffer, msg, 0);
+ break;
+ case ED_MB:
+ MessageBox(0, msg, buffer, MB_OK | MB_ICONWARNING);
+ break;
+ case ED_BAL:
+ {
+ MIRANDASYSTRAYNOTIFY sn = {0};
+ sn.cbSize = sizeof(sn);
+ sn.szProto = MODULE;
+ sn.szInfoTitle = buffer;
+ sn.szInfo = msg;
+ sn.dwInfoFlags = NIIF_WARNING;
+ sn.uTimeout = 10;
+
+ CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&sn);
+ }
+
+ break;
+ }
+}
+
+void ShowError(char *msg) {
+ char buffer[512];
+ ErrorDisplay disp = options.err_method;
+ // funny logic :) ... try to avoid message boxes
+ // if want baloons but no balloons, try popups
+ // if want popups but no popups, try baloons
+ // if, after that, you want balloons but no balloons, revert to message boxes
+ if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_POP;
+ if(disp == ED_POP && !ServiceExists(MS_POPUP_SHOWMESSAGE)) disp = ED_BAL;
+ if(disp == ED_BAL && !ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) disp = ED_MB;
+
+ sprintf(buffer, "%s Error", MODULE);
+
+
+ switch(disp) {
+ case ED_POP:
+ ShowPopup(buffer, msg, 0);
+ break;
+ case ED_MB:
+ MessageBox(0, msg, buffer, MB_OK | MB_ICONWARNING);
+ break;
+ case ED_BAL:
+ {
+ MIRANDASYSTRAYNOTIFY sn = {0};
+ sn.cbSize = sizeof(sn);
+ sn.szProto = MODULE;
+ sn.szInfoTitle = buffer;
+ sn.szInfo = msg;
+ sn.dwInfoFlags = NIIF_ERROR;
+ sn.uTimeout = 10;
+
+ CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&sn);
+ }
+
+ break;
+ }
+}
+
+bool CreatePath(const char *path) {
+ if(!path) return false;
+
+ char folder[MAX_PATH];
+ strcpy(folder, path);
+ int i = 0;
+
+ SetLastError(ERROR_SUCCESS);
+ char *p = &folder[i];
+ while(folder[i]) {
+ p = strchr(p, _T('\\'));
+ if(p) {
+ i = p - folder;
+ p++;
+
+ if(folder[i]) folder[i] = 0;
+ } else
+ i = strlen(folder);
+
+ /*
+ // this fails when the user does not have permission to create intermediate folders
+ if(!CreateDirectory(folder, 0)) {
+ DWORD err = GetLastError();
+ if(err != ERROR_ALREADY_EXISTS) {
+ //MessageBox(0, Translate("Could not create temporary folder."), Translate("Error"), MB_OK | MB_ICONERROR);
+ //return 1;
+ return false;
+ }
+ }
+ */
+ CreateDirectory(folder, 0);
+
+ folder[i] = path[i];
+ }
+
+ DWORD lerr = GetLastError();
+ return (lerr == ERROR_SUCCESS || lerr == ERROR_ALREADY_EXISTS);
+
+ /*
+ // this function seems to be unavailable in shell32.dll under NT4
+ int ret = SHCreateDirectoryEx(0, path, 0);
+ return (ret == ERROR_SUCCESS) || (ret == ERROR_FILE_EXISTS) || (ret == ERROR_ALREADY_EXISTS);
+ */
+}
+
+
+int ReloadIcons(WPARAM wParam, LPARAM lParam) {
+ hProtoIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"otr_popups");
+ hLockIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"otr_secure");
+ hUnlockIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"otr_insecure");
+
+ if(ServiceExists(MS_MSG_MODIFYICON)) {
+ StatusIconData sid = {0};
+ sid.cbSize = sizeof(sid);
+ sid.szModule = MODULE;
+ sid.dwId = 0;
+ sid.hIcon = hLockIcon;
+ sid.hIconDisabled = hUnlockIcon;
+ sid.flags = MBF_DISABLED;
+ sid.szTooltip = Translate("OTR Encryption Status");
+ CallService(MS_MSG_MODIFYICON, 0, (LPARAM)&sid);
+ }
+
+ FixMenuIcons();
+
+ return 0;
+}
+
+void InitUtils() {
+ if(ServiceExists(MS_SKIN2_ADDICON)) {
+ SKINICONDESC2 sid;
+
+ sid.cbSize = sizeof(SKINICONDESC2);
+ sid.pszSection = "OTR";
+ sid.hDefaultIcon = 0;
+
+ sid.pszDescription = Translate("Popups Icon");
+ sid.pszName = "otr_popups";
+ sid.pszDefaultFile = "otr.dll";
+ sid.iDefaultIndex = 0;
+ sid.hDefaultIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_START), IMAGE_ICON, 0, 0, 0);
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszDescription = Translate("Secure");
+ sid.pszName = "otr_secure";
+ sid.pszDefaultFile = "otr.dll";
+ sid.iDefaultIndex = 1;
+ sid.hDefaultIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_START), IMAGE_ICON, 0, 0, 0);//LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS );
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszDescription = Translate("Insecure");
+ sid.pszName = "otr_insecure";
+ sid.pszDefaultFile = "otr.dll";
+ sid.iDefaultIndex = 2;
+ sid.hDefaultIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_STOP), IMAGE_ICON, 0, 0, 0);//LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS );
+ CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ hProtoIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"otr_popups");
+ hLockIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"otr_secure");
+ hUnlockIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"otr_insecure");
+
+ hIcoLibIconsChanged = HookEvent(ME_SKIN2_ICONSCHANGED, ReloadIcons);
+ } else {
+ hProtoIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_START), IMAGE_ICON, 16, 16, 0);
+ hLockIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_START), IMAGE_ICON, 16, 16, 0);
+ hUnlockIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_STOP), IMAGE_ICON, 16, 16, 0);
+ }
+}
+
+void DeinitUtils() {
+ if(hIcoLibIconsChanged) UnhookEvent(hIcoLibIconsChanged);
+ else {
+ DestroyIcon(hProtoIcon);
+ DestroyIcon(hLockIcon);
+ DestroyIcon(hUnlockIcon);
+ }
+}
diff --git a/otr/utils.h b/otr/utils.h new file mode 100644 index 0000000..4b78e28 --- /dev/null +++ b/otr/utils.h @@ -0,0 +1,15 @@ +#ifndef _UTILS_INC
+#define _UTILS_INC
+
+extern HICON hProtoIcon, hLockIcon, hUnlockIcon;
+
+void InitUtils();
+void DeinitUtils();
+
+void ShowPopup( const char* line1, const char* line2, int timeout);
+void ShowWarning(char *msg);
+void ShowError(char *msg);
+
+bool CreatePath(const char *path);
+
+#endif
|