diff options
| author | George Hazan <george.hazan@gmail.com> | 2013-02-10 19:26:03 +0000 | 
|---|---|---|
| committer | George Hazan <george.hazan@gmail.com> | 2013-02-10 19:26:03 +0000 | 
| commit | 271cf1987ef0dc4d6561d14e0ba89c17bb125903 (patch) | |
| tree | ef7d07417ad78bb9701dee50ee5877f044f8fde4 /plugins/NotifyAnything/src | |
| parent | e8688ad378c46c963c66fa6a4c09b9419e02efc0 (diff) | |
NotifyAnything plugin
git-svn-id: http://svn.miranda-ng.org/main/trunk@3539 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/NotifyAnything/src')
| -rw-r--r-- | plugins/NotifyAnything/src/common.h | 61 | ||||
| -rw-r--r-- | plugins/NotifyAnything/src/main.cpp | 1057 | ||||
| -rw-r--r-- | plugins/NotifyAnything/src/options.cpp | 209 | ||||
| -rw-r--r-- | plugins/NotifyAnything/src/resource.h | 27 | ||||
| -rw-r--r-- | plugins/NotifyAnything/src/stdafx.cpp | 18 | 
5 files changed, 1372 insertions, 0 deletions
diff --git a/plugins/NotifyAnything/src/common.h b/plugins/NotifyAnything/src/common.h new file mode 100644 index 0000000000..264b5adee8 --- /dev/null +++ b/plugins/NotifyAnything/src/common.h @@ -0,0 +1,61 @@ +// disable warnings about underscore in stdc functions
 +#pragma warning(disable: 4996)
 +
 +#include <windows.h>
 +
 +#include <string.h>
 +#include <stdio.h>
 +#include <winsock.h>
 +#include <time.h>
 +#include <stdio.h>
 +#include <direct.h>
 +#include <process.h>
 +#include <sys/types.h>
 +#include <sys/timeb.h>
 +
 +#include <string>
 +#include <map>
 +#include <set>
 +#include <vector>
 +
 +#include "newpluginapi.h"
 +#include "m_system_cpp.h"
 +#include "m_options.h"
 +#include "m_skin.h"
 +#include "m_langpack.h"
 +#include "m_database.h"
 +#include "m_utils.h"
 +
 +#include "m_popup.h"
 +#include "m_LogService.h"
 +
 +extern HINSTANCE hInst;
 +
 +const char PlugName[] = "NotifyAnything";
 +
 +//---------------------------
 +//---Internal Hooks (see main.c)
 +//---(Workaround till CallServiceSync is available)
 +
 +struct NASettings {
 +	enum sound_t { never, always, request };
 +
 +	bool local_only, debug_messages, log_to_file, use_pcspeaker, allow_execute;
 +	sound_t sound;
 +	int port;
 +	std::string password, log_filename;
 +};
 +
 +extern NASettings g_settings;
 +
 +void stop_threads();
 +void start_threads();
 +
 +void save_settings();
 +void load_settings();
 +
 +int OptionsInitialize(WPARAM wParam, LPARAM lParam);
 +
 +extern std::string g_mirandaDir;
 +extern bool IsLogService;
 +#define LOG_ID "NotifyAnything"
 diff --git a/plugins/NotifyAnything/src/main.cpp b/plugins/NotifyAnything/src/main.cpp new file mode 100644 index 0000000000..7ef581fb24 --- /dev/null +++ b/plugins/NotifyAnything/src/main.cpp @@ -0,0 +1,1057 @@ +#include "common.h"
 +
 +#define EnterCS(cs) EnterCriticalSection(cs)
 +#define LeaveCS(cs) LeaveCriticalSection(cs)
 +
 +//---------------------------
 +//---Internal Hooks
 +//---(Workaround till CallServiceSync is available)
 +
 +/*
 +Stolen from NewEventNotify:
 +The idea for this is taken from "NewStatusNotify" by Hrk, thx *g*
 +This is needed to send a message with safe multithrading.
 +We'll create a private hook and we'll call it via NotifyEventHooks, which brings execution
 +back to the main thread.
 +*/
 +
 +void cslog(const char *what, const char *file, int line)
 +{
 +	if (IsLogService){
 +		std::string LogString;
 +		char buf[10];
 +        LogString = what;
 +		LogString += ": ";
 +		LogString += file;
 +		LogString += ":";
 +		LogString += itoa(line, buf, 10);
 +		logservice_log(LOG_ID, NULL, (TCHAR *) LogString.c_str());
 +	}
 +	else {
 +		if (g_settings.log_to_file) {
 +			time_t t_;
 +			time(&t_);
 +			tm *t = localtime(&t_);
 +			//FILE *f = fopen("na.log", "a");
 +			FILE *f = fopen(g_settings.log_filename.c_str(), "a");
 +			if (f) {
 +				//fprintf(f, "%s: %s:%i\n", what, file, line);
 +				fprintf(f, "[%04i-%02i-%02i %02i:%02i:%02i cs] %s: %s:%i\n",
 +					int(t->tm_year+1900), int(t->tm_mon), int(t->tm_mday),
 +					int(t->tm_hour), int(t->tm_min), int(t->tm_sec), what, file, line);
 +				fclose(f);
 +			}
 +		}
 +	}
 +}
 +
 +void EnterCSHelper(CRITICAL_SECTION *cs, const char *file, int line)
 +{
 +	cslog(">enter", file, line);
 +	EnterCriticalSection(cs);
 +	cslog("<enter", file, line);
 +}
 +
 +void LeaveCSHelper(CRITICAL_SECTION *cs, const char *file, int line)
 +{
 +	cslog(">leave", file, line);
 +	LeaveCriticalSection(cs);
 +	cslog("<leave", file, line);
 +}
 +
 +HANDLE g_udp_thread, g_tcp_thread;
 +SOCKET g_udp_socket, g_tcp_socket;
 +volatile bool g_exit_threads, g_firstrun;
 +std::string g_mirandaDir;
 +CRITICAL_SECTION g_wsocklock;
 +bool IsLogService;
 +
 +HINSTANCE hInst;
 +int hLangpack;
 +
 +PLUGININFOEX pluginInfo = {
 +	sizeof(PLUGININFOEX),
 +	"NotifyAnything",
 +	PLUGIN_MAKE_VERSION(0, 0, 2, 8),
 +	"Displays popups for custom events, triggered by UDP packages.",
 +	"Daniel Wesslén, Korney San",
 +	"wesslen@users.sourceforge.net, kora@users.sourceforge.net",
 +	"Public Domain 2003 Daniel Wesslén",
 +	"http://miranda-ng.org",
 +	UNICODE_AWARE,
 +	// {E92874EC-594A-4A2F-BDED-C0BE8B5A45D1}
 +	{ 0xe92874ec, 0x594a, 0x4a2f, { 0xbd, 0xed, 0xc0, 0xbe, 0x8b, 0x5a, 0x45, 0xd1 }}
 +};
 +
 +BOOL WINAPI DllMain(HINSTANCE hi, DWORD, LPVOID)
 +{
 +	hInst = hi;
 +	DisableThreadLibraryCalls(hInst);
 +	return TRUE;
 +}
 +
 +enum replace_mode_t {
 +	xno,
 +	xappend,
 +	xprepend,
 +	xreplace
 +};
 +
 +struct popup_t {
 +	std::string id, contact, message, icon, sound, passwd;
 +	std::string left, right, opened, closed;
 +	COLORREF foreground, background;
 +	int delay;
 +	bool beep;
 +	replace_mode_t replace;
 +	HWND hwnd;
 +};
 +
 +typedef std::map<std::string, popup_t *> popups_t;
 +typedef std::set<popup_t *> anon_popups_t;
 +popups_t g_popups;
 +anon_popups_t g_anon_popups;
 +CRITICAL_SECTION g_popups_cs;
 +
 +std::string strip(std::string str)
 +{
 +	while (!str.empty() && isspace(str[0]))
 +		str.erase(0, 1);
 +	while (!str.empty() && isspace(*(str.end()-1)))
 +		str.erase(str.size()-1);
 +	return str;
 +}
 +
 +void dbg_msg(std::string str, int type)
 +{
 +	str = strip(str);
 +
 +	if (g_settings.debug_messages)
 +		CallServiceSync(MS_POPUP_SHOWMESSAGE, (WPARAM) const_cast<char *>(str.c_str()), (LPARAM) type);
 +
 +	if (IsLogService){
 +		logservice_log(LOG_ID, NULL, (TCHAR *) str.c_str());
 +	}
 +	else {
 +		if (g_settings.log_to_file) {
 +			time_t t_;
 +			time(&t_);
 +			tm *t = localtime(&t_);
 +			FILE *f = fopen(g_settings.log_filename.c_str(), "a");
 +			if (f) {
 +				fprintf(f, "[%04i-%02i-%02i %02i:%02i:%02i dbg_msg] %s\n",
 +					int(t->tm_year+1900), int(t->tm_mon), int(t->tm_mday),
 +					int(t->tm_hour), int(t->tm_min), int(t->tm_sec), str.c_str());
 +				fclose(f);
 +			}
 +		}
 +	}
 +}
 +
 +void showLastError()
 +{
 +	int err = GetLastError();
 +
 +	LPVOID lpMsgBuf;
 +	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
 +		NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
 +
 +	dbg_msg((char *) lpMsgBuf, SM_WARNING);
 +
 +	LocalFree(lpMsgBuf);
 +}
 +
 +struct enum_icons_t {
 +	int nr;
 +	LPCTSTR name;
 +	bool found;
 +};
 +
 +BOOL CALLBACK enum_icons_func(HMODULE, LPCTSTR, LPTSTR name, LONG_PTR data)
 +{
 +	enum_icons_t *info = (enum_icons_t *) data;
 +	if (!--info->nr) {
 +		info->found = true;
 +		info->name = name;
 +		return FALSE;
 +	}
 +	return TRUE;
 +}
 +
 +void registerSound(const std::string &name)
 +{
 +	static std::set<std::string> sset;
 +
 +	if (sset.find(name) != sset.end())
 +		return;
 +	sset.insert(name);
 +
 +	std::string id = "NotifyAnything_" + name;
 +	std::string desc = "NotifyAnything: " + name;
 +	std::string file = name + ".wav";
 +	SkinAddNewSound(id.c_str(), Translate(desc.c_str()), file.c_str());
 +}
 +
 +HICON getIcon(const std::string &name)
 +{
 +	static std::map<std::string, HICON> icons;
 +	static HICON deficon;
 +	static bool init;
 +	if (!init) {
 +		init = true;
 +
 +		// windows icons
 +		icons["exclamation"] = icons["warning"] = LoadIcon(NULL, IDI_WARNING);
 +		deficon = icons["information"] = icons["asterisk"] = LoadIcon(NULL, IDI_ASTERISK);
 +		icons["hand"] = icons["error"] = LoadIcon(NULL, IDI_ERROR);
 +		icons["question"] = LoadIcon(NULL, IDI_QUESTION);
 +		icons["winlogo"] = LoadIcon(NULL, IDI_WINLOGO);
 +
 +		// miranda icons
 +		icons["online"] = LoadSkinnedIcon(SKINICON_STATUS_ONLINE);
 +		icons["offline"] = LoadSkinnedIcon(SKINICON_STATUS_OFFLINE);
 +		icons["away"] = LoadSkinnedIcon(SKINICON_STATUS_AWAY);
 +		icons["na"] = LoadSkinnedIcon(SKINICON_STATUS_NA);
 +		icons["occupied"] = LoadSkinnedIcon(SKINICON_STATUS_OCCUPIED);
 +		icons["dnd"] = LoadSkinnedIcon(SKINICON_STATUS_DND);
 +		icons["free4chat"] = LoadSkinnedIcon(SKINICON_STATUS_FREE4CHAT);
 +		icons["invisible"] = LoadSkinnedIcon(SKINICON_STATUS_INVISIBLE);
 +		icons["onthephone"] = LoadSkinnedIcon(SKINICON_STATUS_ONTHEPHONE);
 +		icons["outtolunch"] = LoadSkinnedIcon(SKINICON_STATUS_OUTTOLUNCH);
 +
 +		icons["message"] = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
 +		icons["url"] = LoadSkinnedIcon(SKINICON_EVENT_URL);
 +		icons["file"] = LoadSkinnedIcon(SKINICON_EVENT_FILE);
 +	}
 +
 +	std::map<std::string, HICON>::iterator i = icons.find(name);
 +	if (i != icons.end())
 +		return i->second;
 +
 +	size_t p = name.rfind(',');
 +	if (p == name.npos) {
 +		// try to load icon file
 +		HANDLE h = LoadImageA(NULL, name.c_str(), IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
 +		if (h != NULL) 
 +			return icons[name] = (HICON) h;
 +
 +		showLastError();
 +		return deficon;
 +	}
 +
 +	std::tstring file((TCHAR*)_A2T(name.c_str()), 0, p);
 +
 +	std::tstring rname(file.c_str(), p+1);
 +	if (rname.empty()) {
 +		dbg_msg(Translate("No resource name given."), SM_WARNING);
 +		return deficon;
 +	}
 +
 +	HMODULE module = LoadLibraryEx(file.c_str(), NULL, LOAD_LIBRARY_AS_DATAFILE);
 +	if (!module) {
 +		showLastError();
 +		return deficon;
 +	}
 +
 +	LPCTSTR resname = rname.c_str();
 +	if (isdigit(rname[0])) {
 +		enum_icons_t info;
 +		info.found = false;
 +		info.nr = _ttoi(rname.c_str());
 +		if (info.nr <= 0) {
 +			dbg_msg(Translate("Icon indices start at 1."), SM_WARNING);
 +			return deficon;
 +		}
 +		
 +		BOOL ok = EnumResourceNames(module, RT_GROUP_ICON, enum_icons_func, (LONG_PTR) &info);
 +		if (!info.found) {
 +			if (!ok) {
 +				if (GetLastError()) {
 +					showLastError();
 +					return deficon;
 +				}
 +			}
 +			dbg_msg(Translate("Could not find the requested icon."), SM_WARNING);
 +			return deficon;
 +		}
 +		resname = info.name;
 +	}
 +
 +	HICON icon = (HICON) LoadImage(module, resname, IMAGE_ICON, 16, 16, 0);
 +	FreeLibrary(module);
 +
 +	if (!icon) {
 +		showLastError();
 +		return deficon;
 +	}
 +
 +	return icons[name] = (HICON) icon;
 +}
 +
 +bool getNext(std::string &out, std::string &in, char sep)
 +{
 +	while (!in.empty() && in[0] == ' ')
 +		in.erase(0, 1);
 +
 +	out.erase();
 +
 +	while (!in.empty()) {
 +		if (in[0] == sep) {
 +			in.erase(0,1);
 +			return true;
 +		}
 +		if (in[0] == '\"') {
 +			in.erase(0,1);
 +			size_t p = in.find('\"');
 +			if (p == in.npos)
 +				throw "Unterminated quote: \"" + in;
 +			out += '"';
 +			out.append(in, 0, p);
 +			out += '"';
 +			in.erase(0, p+1);
 +			return true;
 +		}
 +		if (!in.compare(0, 3, "<[[")) {
 +			in.erase(0, 3);
 +			size_t p = in.find("]]>");
 +			if (p == in.npos)
 +				throw "Unterminated \"<[[\": <[[" + in;
 +			out.append(in, 0, p);
 +			in.erase(0, p+3);
 +			return true;
 +		}
 +
 +		out += in[0];
 +		in.erase(0,1);
 +		return true;
 +	}
 +	return false;
 +}
 +
 +std::string unquote(std::string str)
 +{
 +	size_t p;
 +	while ((p = str.find('\"')) != str.npos)
 +		str.erase(p, 1);
 +	return str;
 +}
 +
 +void getAll(std::vector<std::string> &out, std::string &in, char sep, bool unquote_)
 +{
 +	std::string arg;
 +	while (getNext(arg, in, sep))
 +		if (!arg.empty()) {
 +			if (unquote_)
 +				arg = unquote(arg);
 +			out.push_back(arg);
 +		}
 +}
 +
 +const char *decode_se_arg(std::string &str)
 +{
 +	return (str.empty()) ? 0 : str.c_str();
 +}
 +
 +void processSingleAction(const std::string &what, bool &closeflag)
 +{
 +	if (!what.compare(0, 7, "system:")) {
 +		if (!g_settings.allow_execute) {
 +			dbg_msg(Translate("Application launching is disabled."), SM_WARNING);
 +			return;
 +		}
 +
 +		std::string argstr(what, 7);
 +
 +		if (system(argstr.c_str()) == -1)
 +			dbg_msg("Failed to execute: " + argstr, SM_WARNING);
 +	}
 +	else if (!what.compare(0, 4, "cmd:")) {
 +		if (!g_settings.allow_execute) {
 +			dbg_msg(Translate("Application launching is disabled."), SM_WARNING);
 +			return;
 +		}
 +
 +		std::string argstr(what, 4);
 +		std::vector<std::string> args;
 +
 +		getAll(args, argstr, ' ', true);
 +
 +		if (args.empty())
 +			throw "Insufficient arguments: " + what;
 +
 +		std::vector<const char *> cargs;
 +		for (std::vector<std::string>::iterator i=args.begin(), e=args.end(); i!=e; ++i)
 +			cargs.push_back(i->c_str());
 +		cargs.push_back(0);
 +
 +		if (_spawnvp(_P_DETACH, cargs[0], &cargs[0]) == -1)
 +			dbg_msg("Failed to execute: " + what.substr(4), SM_WARNING);
 +
 +	}
 +	else if (!what.compare(0, 5, "open:")) {
 +		if (!g_settings.allow_execute) {
 +			dbg_msg(Translate("Application launching is disabled."), SM_WARNING);
 +			return;
 +		}
 +
 +		std::string argstr(what, 5);
 +
 +		std::string file, args;
 +		if (!getNext(file, argstr, ' '))
 +			throw "No filename provided: " + what;
 +		file = strip(file);
 +		args = strip(argstr);
 +
 +		const char *cargs = decode_se_arg(args);
 +
 +		if ((int) ShellExecuteA(0, "open", file.c_str(), cargs, 0, SW_SHOWNORMAL) <= 32)
 +			throw "Failed to open: " + file + " " + args;
 +
 +	} else if (!what.compare(0, 6, "shell:")) {
 +		if (!g_settings.allow_execute) {
 +			dbg_msg(Translate("Application launching is disabled."), SM_WARNING);
 +			return;
 +		}
 +
 +		std::string argstr(what, 6);
 +
 +		std::string verb, file, args, dir;
 +		if (!getNext(verb, argstr, ':'))
 +			throw "No verb provided: " + what;
 +		if (!getNext(file, argstr, ','))
 +			throw "No filename provided: " + what;
 +		getNext(args, argstr, ',');
 +		getNext(dir, argstr, ',');
 +		verb = unquote(strip(verb));
 +		file = /*unquote(*/strip(file)/*)*/;
 +		args = strip(args);
 +		dir = /*unquote(*/strip(dir)/*)*/;
 +
 +		if ((int) ShellExecuteA(0, decode_se_arg(verb), decode_se_arg(file),
 +			decode_se_arg(args), decode_se_arg(dir), SW_SHOWNORMAL) <= 32)
 +			throw "Failed: " + what;
 +	} else if (what == "close")
 +		closeflag = true;
 +	else
 +		throw "Action not recognized: " + what;
 +}
 +
 +void processAction(const std::string &what, bool &closeflag)
 +{
 +	try
 +	{
 +		std::string argstr = what;
 +		std::vector<std::string> actions;
 +
 +		std::string action;
 +		while (getNext(action, argstr, ';'))
 +			if (!action.empty())
 +				processSingleAction(action, closeflag);
 +	}
 +	catch (std::string err) {
 +		dbg_msg(err, SM_WARNING);
 +	}
 +}
 +
 +static int CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 +{
 +	popup_t *pd = 0;
 +	pd = (popup_t *) CallService(MS_POPUP_GETPLUGINDATA, (WPARAM) hWnd, (LPARAM) pd);
 +	if (!pd)
 +		return FALSE;
 +
 +	switch (message) {
 +	case WM_COMMAND:
 +		{
 +			EnterCS(&g_popups_cs);
 +			std::string left;
 +			if (pd)
 +				left = pd->left;
 +			LeaveCS(&g_popups_cs);
 +
 +			if (left.empty())
 +				PUDeletePopUp(hWnd);
 +			else {
 +				bool closeflag = false;
 +				processAction(left, closeflag);
 +				if (closeflag)
 +					PUDeletePopUp(hWnd);
 +			}
 +		}
 +		return TRUE;
 +
 +	case WM_CONTEXTMENU:
 +		{
 +			EnterCS(&g_popups_cs);
 +			std::string right;
 +			if (pd)
 +				right = pd->right;
 +			LeaveCS(&g_popups_cs);
 +
 +			if (right.empty())
 +				PUDeletePopUp(hWnd);
 +			else {
 +				bool closeflag = false;
 +				processAction(right, closeflag);
 +				if (closeflag)
 +					PUDeletePopUp(hWnd);
 +			}
 +		}
 +		return TRUE;
 +
 +	case UM_INITPOPUP:
 +		EnterCS(&g_popups_cs);
 +		pd->hwnd = hWnd;
 +		LeaveCS(&g_popups_cs);
 +		return TRUE;
 +
 +	case UM_FREEPLUGINDATA:
 +		EnterCS(&g_popups_cs);
 +		std::string closed;
 +		if (pd)
 +			closed = pd->closed;
 +
 +		g_popups.erase(pd->id);
 +		g_anon_popups.erase(pd);
 +		delete pd;
 +		LeaveCS(&g_popups_cs);
 +
 +		if (!closed.empty()) {
 +			bool closeflag = false;
 +			processAction(closed, closeflag);
 +		}
 +
 +		return TRUE;
 +	}
 +	return DefWindowProc(hWnd, message, wParam, lParam);
 +}
 +
 +int showMessage(const popup_t &msg)
 +{
 +	POPUPDATAEX ppd = { 0 };
 +	strncpy(ppd.lpzText, strip(msg.message).c_str(), MAX_SECONDLINE);
 +	strncpy(ppd.lpzContactName, msg.contact.c_str(), MAX_CONTACTNAME);
 +	ppd.colorBack = msg.background;
 +	ppd.colorText = msg.foreground;
 +	ppd.lchIcon = getIcon(msg.icon);
 +	ppd.PluginWindowProc = (WNDPROC) PopupDlgProc;
 +	ppd.iSeconds = msg.delay;
 +
 +	EnterCS(&g_popups_cs);
 +
 +	popup_t *msgp = new popup_t(msg);
 +
 +	if (!msg.id.empty())
 +		g_popups[msg.id] = msgp;
 +	g_anon_popups.insert(msgp);
 +	ppd.PluginData = msgp;
 +
 +	LeaveCS(&g_popups_cs);
 +
 +	return CallServiceSync(MS_POPUP_ADDPOPUPEX, (WPARAM)&ppd, 0);
 +}
 +
 +void replaceMessage(const popup_t &msg)
 +{
 +	EnterCS(&g_popups_cs);
 +
 +	popups_t::iterator i = g_popups.find(msg.id);
 +	if (i != g_popups.end()) {
 +		if (i->second->hwnd) {
 +
 +			popup_t &nmsg = *i->second;
 +
 +			switch (msg.replace) {
 +			case xreplace:
 +				nmsg.message = msg.message; break;
 +			case xappend:
 +				nmsg.message += msg.message; break;
 +			case xprepend:
 +				nmsg.message = msg.message + nmsg.message; break;
 +			default:
 +				break;
 +			}
 +
 +			if (!msg.left.empty())
 +				nmsg.left = msg.left;
 +			if (!msg.right.empty())
 +				nmsg.right = msg.right;
 +			if (!msg.opened.empty())
 +				nmsg.opened = msg.opened;
 +			if (!msg.closed.empty())
 +				nmsg.closed = msg.closed;
 +
 +			LeaveCS(&g_popups_cs);
 +
 +			CallServiceSync(MS_POPUP_CHANGETEXT, (WPARAM)i->second->hwnd, (LPARAM)strip(i->second->message).c_str());
 +			return;
 +		}
 +	}
 +
 +	LeaveCS(&g_popups_cs);
 +}
 +
 +inline int dehex(int c) {
 +	if (c >= '0' && c <= '9')
 +		return c - '0';
 +	else if (c >= 'a' && c <= 'f')
 +		return c - 'a' + 10;
 +	else if (c >= 'A' && c <= 'F')
 +		return c - 'A' + 10;
 +	else
 +		return 0;
 +}
 +
 +COLORREF parseColor(const std::string &buf, bool &ok)
 +{
 +	ok = false;
 +	for (int i=0; i!=buf.size(); ++i)
 +		if (!isxdigit(buf[i]))
 +			return RGB(0,0,0);
 +	if (buf.size() == 6) {
 +		int r = (dehex(buf[0]) << 4) + dehex(buf[1]);
 +		int g = (dehex(buf[2]) << 4) + dehex(buf[3]);
 +		int b = (dehex(buf[4]) << 4) + dehex(buf[5]);
 +		ok = true;
 +		return RGB(r,g,b);
 +	} else if (buf.size() == 3) {
 +		int r = dehex(buf[0])*17;
 +		int g = dehex(buf[1])*17;
 +		int b = dehex(buf[2])*17;
 +		ok = true;
 +		return RGB(r,g,b);
 +	} else
 +		return RGB(0,0,0);
 +}
 +
 +void loadDefaults(popup_t &msg, char ch)
 +{
 +	msg.hwnd = NULL;
 +	msg.replace = xno;
 +	msg.delay = 0;
 +	switch (ch) {
 +	case '%':
 +		msg.icon = "message";
 +		msg.background = RGB(173,206,247);
 +		msg.foreground = RGB(0,0,0);
 +		msg.contact = "Message";
 +		msg.beep = true;
 +		msg.sound = "Message";
 +		return;
 +	case '!':
 +		msg.icon = "exclamation";
 +		msg.background = RGB(191,0,0);
 +		msg.foreground = RGB(255,245,225);
 +		msg.contact = "Error";
 +		msg.beep = true;
 +		msg.sound = "Error";
 +		return;
 +	case ' ':
 +	default:
 +		msg.icon = "information";
 +		msg.background = RGB(255,245,225);
 +		msg.foreground = RGB(0,0,0);
 +		msg.contact = "Notice";
 +		msg.beep = true;
 +		msg.sound = "Notice";
 +		return;
 +	}
 +}
 +
 +bool parseSimpleMessage(const std::string &buf, popup_t &msg, char sep)
 +{
 +	size_t p = buf.find(sep);
 +	if (p == buf.npos)
 +		msg.message = buf;
 +	else {
 +		msg.contact.assign(buf, 0, p);
 +		msg.message.assign(buf, p+1, buf.npos);
 +	}
 +	return true;
 +}
 +
 +bool parseComplexMessage(const std::string &buf, popup_t &msg, char sep)
 +{
 +	const char *p = buf.c_str();
 +	const char *npos = strchr(p, sep);
 +	bool passok = false;
 +
 +	while ((p = npos)) {
 +		++p;
 +		const char *cpos = strchr(p, ':');
 +		npos = strchr(p, sep);
 +
 +		const char *wend = cpos;
 +		if (!wend || npos && npos < wend)
 +			wend = npos;
 +		if (!wend) {
 +			dbg_msg(Translate("Unterminated option."), SM_WARNING);
 +			return false;
 +		}
 +
 +		std::string what(p, wend);
 +		std::string arg;
 +		if (wend == cpos && wend && npos)
 +			arg.assign(cpos+1, npos);
 +		else if (!cpos)
 +			arg.erase();
 +		else
 +			arg = cpos+1;
 +
 +		if (!g_settings.password.empty() && !passok) {
 +			if (what == "passwd" && arg == g_settings.password) {
 +				passok = true;
 +				continue;
 +			} else
 +				return false;
 +		}
 +
 +		if (what == "passwd")
 +			;
 +		else if (what == "icon")
 +			msg.icon = arg;
 +		else if (what == "msg") {
 +			if (!cpos) {
 +				dbg_msg(Translate("No argument given to msg option."), SM_WARNING);
 +				return false;
 +			} else if (msg.replace != xno && msg.id.empty()) {
 +				dbg_msg(Translate("Id is required for replacement."), SM_WARNING);
 +				return false;
 +			}
 +			msg.message = arg;
 +			return true;
 +		} else if (what == "replace") {
 +			if (arg == "yes")
 +				msg.replace = xreplace;
 +			else if (arg == "append")
 +				msg.replace = xappend;
 +			else if (arg == "prepend")
 +				msg.replace = xprepend;
 +			else if (arg == "no")
 +				msg.replace = xno;
 +			else
 +				dbg_msg(Translate("Invalid argument for replace option: ") + arg, SM_WARNING);
 +		} else if (what == "sound") {
 +			if (arg.empty())
 +				msg.beep = false;
 +			else {
 +				msg.beep = true;
 +				msg.sound = arg;
 +				registerSound(arg);
 +			}
 +		} else if (what == "left") {
 +			msg.left = arg;
 +		} else if (what == "right") {
 +			msg.right = arg;
 +		} else if (what == "opened") {
 +			msg.opened = arg;
 +		} else if (what == "closed") {
 +			msg.closed = arg;
 +		} else if (what == "delay") {
 +			msg.delay = atoi(arg.c_str());
 +		} else if (what == "id") {
 +			msg.id = arg;
 +		} else if (what == "bg") {
 +			bool ok;
 +			msg.background = parseColor(arg, ok);
 +			if (!ok)
 +				dbg_msg("Invalid color: " + arg, SM_WARNING);
 +		} else if (what == "fg") {
 +			bool ok;
 +			msg.foreground = parseColor(arg, ok);
 +			if (!ok)
 +				dbg_msg("Invalid color: " + arg, SM_WARNING);
 +		} else if (what == "from")
 +			msg.contact = arg;
 +		else if (what == "sep") {
 +			if (arg.size() == 1)
 +				sep = arg[0];
 +			else
 +				dbg_msg("Invalid argument for sep option: " + arg, SM_WARNING);
 +		} else if (what == "beep") {
 +			if (arg == "1")
 +				msg.beep = true;
 +			else if (arg == "0")
 +				msg.beep = false;
 +			else
 +				dbg_msg("Invalid argument for beep option: " + arg, SM_WARNING);
 +		} else
 +			dbg_msg("Unknown option: " + what, SM_NOTIFY);
 +	}
 +	return true;
 +}
 +
 +bool parseMessage(const std::string &abuf, popup_t &msg)
 +{
 +	if (abuf.empty()) {
 +		dbg_msg(Translate("Empty message ignored."), SM_NOTIFY);
 +		return false;
 +	}
 +
 +	std::string buf = abuf;
 +	char sep = '#';
 +	if (buf.size() >= 3 && !isalnum(buf[0]) && buf[0] == buf[1] && buf[1] == buf[2]) {
 +		sep = buf[0];
 +		buf.erase(0, 3);
 +	}
 +
 +	if (strchr("*!%", buf[0]) && sep != buf[0]) {
 +		if (buf.size() < 2) return false;
 +		loadDefaults(msg, buf[0]);
 +		buf.erase(0, 1);
 +	} else
 +		loadDefaults(msg, ' ');
 +
 +	if (buf[0] == sep)
 +		return parseComplexMessage(buf, msg, sep);
 +	else if (g_settings.password.empty())
 +		return parseSimpleMessage(buf, msg, sep);
 +	else
 +		return false;
 +}
 +
 +void processMessage(std::string buf)
 +{
 +	if (IsLogService){
 +		logservice_log(LOG_ID, NULL, (TCHAR *) buf.c_str());
 +	}
 +	else {
 +		if (g_settings.log_to_file) {
 +			time_t t_;
 +			time(&t_);
 +			tm *t = localtime(&t_);
 +			FILE *f = fopen(g_settings.log_filename.c_str(), "a");
 +			if (f) {
 +				bool err = fprintf(f, "[%04i-%02i-%02i %02i:%02i:%02i] %s\n",
 +					int(t->tm_year+1900), int(t->tm_mon+1), int(t->tm_mday),
 +					int(t->tm_hour), int(t->tm_min), int(t->tm_sec), buf.c_str()) < 0;
 +				if (fclose(f) == EOF || err)
 +					dbg_msg(Translate("Failed to write to log file."), SM_WARNING);
 +			} else
 +				dbg_msg(Translate("Failed to open log file."), SM_WARNING);
 +		}
 +	}
 +
 +	popup_t msg;
 +	if (parseMessage(buf, msg)) {
 +
 +		if (!msg.opened.empty()) {
 +			bool close = false;
 +			processAction(msg.opened, close);
 +			if (close)
 +				return;
 +		}
 +
 +		if (msg.replace) {
 +			replaceMessage(msg);
 +			return;
 +		}
 +
 +		showMessage(msg);
 +
 +		if (g_settings.sound == g_settings.always
 +			|| g_settings.sound == g_settings.request
 +				&& msg.beep)
 +		{
 +			if (g_settings.use_pcspeaker)
 +				Beep(650, 50);
 +			else {
 +				std::string sname = "NotifyAnything_"
 +					+ msg.sound;
 +				SkinPlaySound(sname.c_str());
 +			}
 +		}
 +	}
 +}
 +
 +void initWinsock()
 +{
 +	EnterCS(&g_wsocklock);
 +	if (g_firstrun) {
 +		// probably not needed, but just in case...
 +		// give PopUp a second to sort itself out
 +		Sleep(1000);
 +		g_firstrun = false;
 +
 +		WSADATA wsaData;
 +		int err = WSAStartup(MAKEWORD(2, 0), &wsaData);
 +		if (err)
 +			throw "WSAStartup failed";
 +	}
 +	LeaveCS(&g_wsocklock);
 +}
 +
 +DWORD udptcpThreadFunc(LPVOID useUdp)
 +{
 +	try
 +	{
 +		initWinsock();
 +
 +		SOCKET sock = socket(AF_INET, useUdp ? SOCK_DGRAM : SOCK_STREAM, 0/*IPPROTO_UDP*/);
 +		if (sock == INVALID_SOCKET)
 +			throw "socket failed";
 +
 +		if (useUdp)
 +			g_udp_socket = sock;
 +		else
 +			g_tcp_socket = sock;
 +
 +		SOCKADDR_IN addr;
 +		ZeroMemory(&addr, sizeof addr);
 +		addr.sin_family = AF_INET;
 +		addr.sin_port = htons(g_settings.port);
 +		if (g_settings.local_only) {
 +			addr.sin_addr.S_un.S_un_b.s_b1 = 127;
 +			addr.sin_addr.S_un.S_un_b.s_b2 = 0;
 +			addr.sin_addr.S_un.S_un_b.s_b3 = 0;
 +			addr.sin_addr.S_un.S_un_b.s_b4 = 1;
 +		}
 +
 +		if (bind(sock, reinterpret_cast<sockaddr *>(&addr), sizeof addr))
 +			throw "bind failed";
 +
 +		SOCKADDR_IN from;
 +		char buf[4097];
 +
 +		if (useUdp) {
 +			while (!g_exit_threads) {
 +				int fromSize = sizeof from;
 +				int err = recvfrom(sock, buf, sizeof buf - 1, 0, reinterpret_cast<sockaddr *>(&from), &fromSize);
 +
 +				if (g_exit_threads)
 +					return 0;
 +
 +				if (err == SOCKET_ERROR)
 +					throw "socket error";
 +
 +				buf[err] = '\0';
 +
 +				if (err > 0)
 +					processMessage(buf);
 +			}
 +		} else {
 +			listen(sock, SOMAXCONN);
 +			while (!g_exit_threads) {
 +				int fromSize = sizeof from;
 +				SOCKET msgsock = accept(sock, reinterpret_cast<sockaddr *>(&from), &fromSize);
 +
 +				if (g_exit_threads)
 +					return 0;
 +
 +				if (msgsock == INVALID_SOCKET)
 +					throw "socket error";
 +
 +				std::string totalbuf;
 +				int totallen = 0;
 +				while (true) {
 +					int err = recv(msgsock, buf, sizeof buf - 1, 0);
 +					if (err < 0) {
 +						totalbuf.clear();
 +						break;
 +					} else if (err == 0)
 +						break;
 +					else {
 +						totallen += err;
 +						buf[err] = '\0';
 +						totalbuf += buf;
 +					}
 +				}
 +				if (!totalbuf.empty())
 +					processMessage(buf);
 +			}
 +		}
 +		return 0;
 +	}
 +	catch (const char *err) {
 +		std::string t = err;
 +		t += "\nWSAGetLastError: ";
 +
 +		DWORD ec = WSAGetLastError();
 +
 +		char buf[4096];
 +		strcpy(buf, Translate("N/A: Failed to format error message"));
 +
 +		DWORD fm = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
 +			NULL, ec, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 4096, NULL);
 +
 +		if (!fm) {
 +			t += Translate("N/A: FormatMessage failed, error code was 0x");
 +			char tbuf[10];
 +			t += itoa(ec, tbuf, 16);
 +		} else
 +			t += buf;
 +
 +		MessageBoxA(0, t.c_str(), Translate("Error"), MB_OK);
 +		return 1;
 +	}
 +}
 +
 +void start_threads()
 +{
 +	g_exit_threads = false;
 +	DWORD id;
 +	g_udp_thread = CreateThread(NULL, 0, 
 +		(LPTHREAD_START_ROUTINE) udptcpThreadFunc, (LPVOID) 1, 0, &id);
 +	g_tcp_thread = CreateThread(NULL, 0, 
 +		(LPTHREAD_START_ROUTINE) udptcpThreadFunc, NULL, 0, &id);
 +}
 +
 +void stop_threads()
 +{
 +	g_exit_threads = true;
 +	shutdown(g_udp_socket, 2);
 +	shutdown(g_tcp_socket, 2);
 +	closesocket(g_udp_socket);
 +	closesocket(g_tcp_socket);
 +	WaitForSingleObject(g_udp_thread, INFINITE);
 +	WaitForSingleObject(g_tcp_thread, INFINITE);
 +}
 +
 +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) 
 +{
 +	return &pluginInfo;
 +}
 +
 +int ModulesLoaded(WPARAM wParam, LPARAM lParam)
 +{
 +	IsLogService = ServiceExists(MS_LOGSERVICE_REGISTER) != 0;
 +	if (IsLogService)
 +		logservice_register(LOG_ID, LPGENT(LOG_ID), NULL, NULL);
 +
 +	return 0;
 +}
 +
 +extern "C" int __declspec(dllexport) Load()
 +{
 +	g_firstrun = true;
 +	mir_getLP(&pluginInfo);
 +
 +	char buf[MAX_PATH+1];
 +	strcpy(buf, ".");
 +	g_mirandaDir = getcwd(buf, MAX_PATH);
 +
 +	InitializeCriticalSection(&g_popups_cs);
 +	InitializeCriticalSection(&g_wsocklock);
 +
 +	registerSound("Notice");
 +	registerSound("Message");
 +	registerSound("Error");
 +
 +	load_settings();
 +
 +	HookEvent(ME_OPT_INITIALISE, OptionsInitialize);
 +	HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
 +
 +	start_threads();
 +	return 0;
 +}
 +
 +extern "C" int __declspec(dllexport) Unload(void)
 +{
 +	stop_threads();
 +	WSACleanup();
 +
 +	DeleteCriticalSection(&g_popups_cs);
 +	DeleteCriticalSection(&g_wsocklock);
 +	return 0;
 +}
 diff --git a/plugins/NotifyAnything/src/options.cpp b/plugins/NotifyAnything/src/options.cpp new file mode 100644 index 0000000000..53c06ecf23 --- /dev/null +++ b/plugins/NotifyAnything/src/options.cpp @@ -0,0 +1,209 @@ +
 +#include <windows.h>
 +
 +#include "common.h"
 +#include "resource.h"
 +
 +NASettings g_settings;
 +
 +INT_PTR CALLBACK DlgProcOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 +{
 +	switch (msg) {
 +	case WM_INITDIALOG:
 +		TranslateDialogDefault(hwndDlg);
 +		{
 +			char buf[10];
 +			CheckDlgButton(hwndDlg, NA_LOCAL_CHECK, g_settings.local_only ? BST_CHECKED : BST_UNCHECKED);
 +			CheckDlgButton(hwndDlg, NA_DEBUG_MSG_CHECK, g_settings.debug_messages ? BST_CHECKED : BST_UNCHECKED);
 +			if (IsLogService) {
 +				LS_LOGINFO pli;
 +				pli.szID = LOG_ID;
 +				pli.hContact = NULL;
 +				pli.szLogPath = NULL;
 +				pli.Flags = 0;
 +				pli.cbSize = sizeof(LS_LOGINFO);
 +				if (!CallService(MS_LOGSERVICE_GETLOGINFO, (WPARAM)(LS_LOGINFO *) &pli, 0)) {
 +					CheckDlgButton(hwndDlg, NA_LOG_CHECK, (pli.Flags && LSLI_LOGENABLED) ? BST_CHECKED : BST_UNCHECKED);
 +				}
 +				std::tstring InLogService = TranslateT("Services");
 +				InLogService += _T(" -> ");
 +				InLogService += TranslateT("LogService");
 +				InLogService += _T(" -> ");
 +				InLogService += TranslateT(LOG_ID);
 +				SetDlgItemText(hwndDlg, NA_LOG_FILENAME, InLogService.c_str());
 +			}
 +			else {
 +				CheckDlgButton(hwndDlg, NA_LOG_CHECK, g_settings.log_to_file ? BST_CHECKED : BST_UNCHECKED);
 +				SetDlgItemTextA(hwndDlg, NA_LOG_FILENAME, g_settings.log_filename.c_str());
 +			}
 +			EnableWindow(GetDlgItem(hwndDlg, NA_LOG_CHECK), !IsLogService);
 +			EnableWindow(GetDlgItem(hwndDlg, NA_LOG_FILENAME), !IsLogService);
 +			EnableWindow(GetDlgItem(hwndDlg, NA_LOG_BROWSE), !IsLogService);
 +			EnableWindow(GetDlgItem(hwndDlg, NA_DEBUG_MSG_CHECK), IsDlgButtonChecked(hwndDlg, NA_LOG_CHECK) ? 1 : 0);
 +			CheckDlgButton(hwndDlg, NA_PCSPEAKER_CHECK, g_settings.use_pcspeaker ? BST_CHECKED : BST_UNCHECKED);
 +			CheckDlgButton(hwndDlg, NA_ALLOW_EXECUTE, g_settings.allow_execute ? BST_CHECKED : BST_UNCHECKED);
 +			SetDlgItemTextA(hwndDlg, NA_PORT, itoa(g_settings.port, buf, 10));
 +			SetDlgItemTextA(hwndDlg, NA_PASSWORD, g_settings.password.c_str());
 +			UINT state;
 +			switch (g_settings.sound) {
 +			case g_settings.always:
 +				state = BST_CHECKED; break;
 +			case g_settings.never:
 +				state = BST_UNCHECKED; break;
 +			case g_settings.request:
 +			default:
 +				state = BST_INDETERMINATE; break;
 +			}
 +			CheckDlgButton(hwndDlg, NA_SOUND_CHECK, state);
 +		}
 +		return TRUE;
 +
 +	case WM_COMMAND:
 +		switch(LOWORD(wParam)) {
 +		case NA_SOUND_CHECK:
 +		case NA_PCSPEAKER_CHECK:
 +		case NA_LOCAL_CHECK:
 +		case NA_DEBUG_MSG_CHECK:
 +		case NA_LOG_CHECK:
 +		case NA_PORT:
 +		case NA_PASSWORD:
 +		case NA_LOG_FILENAME:
 +			SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +		}
 +		
 +		if (HIWORD(wParam) == BN_CLICKED) {
 +			switch (LOWORD(wParam)) {
 +			case NA_LOG_BROWSE:
 +				TCHAR szTemp[MAX_PATH+1], szTemp1[MAX_PATH+1], szProfileDir[MAX_PATH+1];
 +				GetDlgItemText(hwndDlg, NA_LOG_FILENAME, szTemp, MAX_PATH);
 +				OPENFILENAME ofn = {0};
 +				ofn.lStructSize = sizeof(ofn);
 +				ofn.lpstrFile = szTemp;
 +				ofn.nMaxFile = MAX_PATH;
 +				ofn.hwndOwner = hwndDlg;
 +				ofn.lpstrFilter = TranslateT("Log (*.log)\0*.log\0Text (*.txt)\0*.txt\0All Files (*.*)\0*.*\0");
 +				ofn.nFilterIndex = 1;
 +				// Use profile directory as default, if path is not specified
 +				CallService(MS_DB_GETPROFILEPATH, (WPARAM)MAX_PATH, (LPARAM) szProfileDir);
 +				ofn.lpstrInitialDir = szProfileDir;
 +				ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
 +				ofn.lpstrDefExt = _T("log");
 +				if ( GetOpenFileName(&ofn)) {
 +					CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)(char*) szTemp, (LPARAM)(char*) szTemp1);
 +					SetDlgItemText(hwndDlg, NA_LOG_FILENAME, szTemp1);
 +					SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
 +				}
 +
 +				return 0;
 +			}
 +		}
 +		break;
 +
 +	case WM_NOTIFY:
 +		if (((LPNMHDR)lParam)->idFrom != 0)
 +			break;
 +
 +		switch (((LPNMHDR)lParam)->code) {
 +		case PSN_RESET:
 +			return TRUE;
 +
 +		case PSN_APPLY: {
 +			UINT state = IsDlgButtonChecked(hwndDlg, NA_SOUND_CHECK);
 +			NASettings s;
 +			switch (state) {
 +			case BST_CHECKED:
 +				s.sound = s.always; break;
 +			case BST_INDETERMINATE:
 +				s.sound = s.request; break;
 +			case BST_UNCHECKED:
 +			default:
 +				s.sound = s.never; break;
 +			}
 +			s.local_only = IsDlgButtonChecked(hwndDlg, NA_LOCAL_CHECK) != BST_UNCHECKED;
 +			s.debug_messages = IsDlgButtonChecked(hwndDlg, NA_DEBUG_MSG_CHECK) != BST_UNCHECKED;
 +			s.log_to_file = IsDlgButtonChecked(hwndDlg, NA_LOG_CHECK) != BST_UNCHECKED;
 +			s.use_pcspeaker = IsDlgButtonChecked(hwndDlg, NA_PCSPEAKER_CHECK) != BST_UNCHECKED;
 +			s.allow_execute = IsDlgButtonChecked(hwndDlg, NA_ALLOW_EXECUTE) != BST_UNCHECKED;
 +
 +			TCHAR buf[1000];
 +			if (!GetDlgItemText(hwndDlg, NA_PORT, buf, sizeof buf - 1))
 +				buf[0] = '\0';
 +			int port = _ttoi(buf);
 +			if (port <= 0 || port > 65535)
 +				MessageBox(0, TranslateT("Invalid port number"), TranslateT("NotifyAnything"), MB_ICONWARNING | MB_OK);
 +			else
 +				s.port = port;
 +
 +			if (!GetDlgItemText(hwndDlg, NA_PASSWORD, buf, sizeof buf - 1))
 +				buf[0] = '\0';
 +			s.password = _T2A(buf);
 +			
 +			if (!IsLogService) {
 +				if (!GetDlgItemText(hwndDlg, NA_LOG_FILENAME, buf, sizeof buf - 1))
 +					buf[0] = '\0';
 +				s.log_filename = _T2A(buf);
 +			}
 +
 +			g_settings = s;
 +			save_settings();
 +			stop_threads();
 +			start_threads();
 +			return TRUE;
 +		}
 +		}
 +		break;
 +	}
 +	return FALSE;
 +}
 +
 +void save_settings()
 +{
 +	db_set_b(NULL, PlugName, "local_only", g_settings.local_only);
 +	db_set_b(NULL, PlugName, "debug_messages", g_settings.debug_messages);
 +	db_set_b(NULL, PlugName, "log_to_file", g_settings.log_to_file);
 +	db_set_b(NULL, PlugName, "beep", g_settings.sound);
 +	db_set_b(NULL, PlugName, "use_pcspeaker", g_settings.use_pcspeaker);
 +	db_set_b(NULL, PlugName, "allow_execute", g_settings.allow_execute);
 +	db_set_dw(NULL, PlugName, "port", g_settings.port);
 +	db_set_s(NULL, PlugName, "password", g_settings.password.c_str());
 +	db_set_s(NULL, PlugName, "log_filename", g_settings.log_filename.c_str());
 +}
 +
 +void load_settings()
 +{
 +	g_settings.local_only = db_get_b(NULL, PlugName, "local_only", 1) != 0;
 +	g_settings.debug_messages = db_get_b(NULL, PlugName, "debug_messages", 0) != 0;
 +	g_settings.log_to_file = db_get_b(NULL, PlugName, "log_to_file", 0) != 0;
 +	g_settings.sound = NASettings::sound_t(db_get_b(NULL, PlugName, "beep", g_settings.request));
 +	g_settings.use_pcspeaker = db_get_b(NULL, PlugName, "use_pcspeaker", 0) != 0;
 +	g_settings.allow_execute = db_get_b(NULL, PlugName, "allow_execute", 0) != 0;
 +	g_settings.port = db_get_dw(NULL, PlugName, "port", 12001);
 +
 +	DBVARIANT dbv;
 +	if(!DBGetContactSetting(NULL, PlugName, "password", &dbv)) {
 +		g_settings.password = dbv.pszVal;
 +		DBFreeVariant(&dbv);
 +	}
 +
 +	if(!DBGetContactSetting(NULL, PlugName, "log_filename", &dbv)) {
 +		g_settings.log_filename = dbv.pszVal;
 +		DBFreeVariant(&dbv);
 +	}
 +	else
 +        g_settings.log_filename = g_mirandaDir + "\\"+LOG_ID+".log";
 +}
 +
 +int OptionsInitialize(WPARAM wParam, LPARAM lParam)
 +{
 +	OPTIONSDIALOGPAGE odp = { sizeof(odp) };
 +	odp.pszTemplate = MAKEINTRESOURCEA(NA_OPTIONS);
 +	odp.pfnDlgProc = DlgProcOpts;
 +	odp.pszTitle = "Notify Anything";
 +	odp.pszGroup = Translate("Plugins");
 +	odp.position = 100000000;
 +	odp.hInstance = hInst;
 +	odp.groupPosition = 910000000;
 +	odp.flags = ODPF_BOLDGROUPS;
 +	Options_AddPage(wParam, &odp);
 +	return 0;
 +}
 diff --git a/plugins/NotifyAnything/src/resource.h b/plugins/NotifyAnything/src/resource.h new file mode 100644 index 0000000000..8eee335059 --- /dev/null +++ b/plugins/NotifyAnything/src/resource.h @@ -0,0 +1,27 @@ +//{{NO_DEPENDENCIES}}
 +// Microsoft Visual C++ generated include file.
 +// Used by NotifyAnything.rc
 +//
 +#define NA_OPTIONS                      106
 +#define NA_LOCAL_CHECK                  1002
 +#define NA_SOUND_CHECK                  1007
 +#define NA_LOG_CHECK                    1008
 +#define NA_DEBUG_MSG_CHECK              1009
 +#define NA_PCSPEAKER_CHECK              1011
 +#define NA_PORT                         1012
 +#define NA_ALLOW_EXECUTE                1013
 +#define NA_PASSWORD                     1014
 +#define NA_LOG_FILENAME                 1015
 +#define NA_LOG_SELECT                   1016
 +#define NA_LOG_BROWSE                   1017
 +
 +// Next default values for new objects
 +// 
 +#ifdef APSTUDIO_INVOKED
 +#ifndef APSTUDIO_READONLY_SYMBOLS
 +#define _APS_NEXT_RESOURCE_VALUE        104
 +#define _APS_NEXT_COMMAND_VALUE         40001
 +#define _APS_NEXT_CONTROL_VALUE         1018
 +#define _APS_NEXT_SYMED_VALUE           101
 +#endif
 +#endif
 diff --git a/plugins/NotifyAnything/src/stdafx.cpp b/plugins/NotifyAnything/src/stdafx.cpp new file mode 100644 index 0000000000..7a516adf58 --- /dev/null +++ b/plugins/NotifyAnything/src/stdafx.cpp @@ -0,0 +1,18 @@ +/*
 +Copyright (C) 2012 Miranda NG team (http://miranda-ng.org)
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation version 2
 +of the License.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program. If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +#include "common.h"
\ No newline at end of file  | 
