コード例 #1
0
ファイル: ui_win_gui.c プロジェクト: ssem/rat
NOEXPORT void CALLBACK timer_proc(HWND hwnd, UINT msg, UINT_PTR id, DWORD t) {
    (void)hwnd; /* squash the unused parameter warning */
    (void)msg; /* squash the unused parameter warning */
    (void)id; /* squash the unused parameter warning */
    (void)t; /* squash the unused parameter warning */
    if(visible)
        update_logs();
    tray_update(num_clients); /* needed when explorer.exe (re)starts */
}
コード例 #2
0
ファイル: tray.c プロジェクト: lp0/temperhum
void tray_reset(HWND hWnd, struct th_data *data) {
	odprintf("tray[reset]");

	/* Try this anyway... */
	tray_remove(hWnd, data);

	/* Assume it has been removed */
	data->tray_ok = 0;

	/* Add it again */
	tray_add(hWnd, data);
	tray_update(hWnd, data);
}
コード例 #3
0
ファイル: ui_win_gui.c プロジェクト: ssem/rat
NOEXPORT void valid_config() {
    /* update the main window title */
    win32_name=TEXT("stunnel ") TEXT(STUNNEL_VERSION) TEXT(" on ")
        TEXT(STUNNEL_PLATFORM);
    SetWindowText(hwnd, win32_name);

    tray_update(num_clients); /* idle or busy icon (on reload) */
    update_peer_menu(); /* one menu item per section */

    /* enable IDM_REOPEN_LOG menu if a log file is used, disable otherwise */
#ifndef _WIN32_WCE
    EnableMenuItem(main_menu_handle, IDM_REOPEN_LOG,
        (UINT)(global_options.output_file ? MF_ENABLED : MF_GRAYED));
#endif
    if(tray_menu_handle)
        EnableMenuItem(tray_menu_handle, IDM_REOPEN_LOG,
            (UINT)(global_options.output_file ? MF_ENABLED : MF_GRAYED));
}
コード例 #4
0
ファイル: ui_win_gui.c プロジェクト: ssem/rat
NOEXPORT void invalid_config() {
    /* update the main window title */
    win32_name=TEXT("stunnel ") TEXT(STUNNEL_VERSION) TEXT(" on ")
        TEXT(STUNNEL_PLATFORM) TEXT(" (invalid configuration file)");
    SetWindowText(hwnd, win32_name);

    /* log window is hidden by default */
    ShowWindow(hwnd, SW_SHOWNORMAL); /* show window */
    SetForegroundWindow(hwnd); /* bring on top */

    tray_update(-1); /* error icon */
    update_peer_menu(); /* purge the list of sections */

    win_log(TEXT(""));
    s_log(LOG_ERR, "Server is down");
    message_box(TEXT("Stunnel server is down due to an error.\n")
        TEXT("You need to exit and correct the problem.\n")
        TEXT("Click OK to see the error log window."),
        MB_ICONERROR);
}
コード例 #5
0
ファイル: profanity.c プロジェクト: anossov/profanity
void
prof_run(char *log_level, char *account_name)
{
    _init(log_level);
    plugins_on_start();
    _connect_default(account_name);

    ui_update();

    log_info("Starting main event loop");

    session_init_activity();

    char *line = NULL;
    while(cont && !force_quit) {
        log_stderr_handler();
        session_check_autoaway();

        line = inp_readline();
        if (line) {
            ProfWin *window = wins_get_current();
            cont = cmd_process_input(window, line);
            free(line);
            line = NULL;
        } else {
            cont = TRUE;
        }

#ifdef HAVE_LIBOTR
        otr_poll();
#endif
        plugins_run_timed();
        notify_remind();
        session_process_events();
        iq_autoping_check();
        ui_update();
#ifdef HAVE_GTK
        tray_update();
#endif
    }
}
コード例 #6
0
ファイル: comms.c プロジェクト: lp0/temperhum
int comms_connect(HWND hWnd, struct th_data *data) {
	struct tray_status *status = &data->status;
	struct tcp_keepalive ka_get;
	struct tcp_keepalive ka_set = {
		.onoff = 1,
		.keepalivetime = 5000, /* 5 seconds */
		.keepaliveinterval = 5000 /* 5 seconds */
	};
	int timeout = 5000; /* 5 seconds */
	INT ret;
	DWORD retd;
	DWORD err;

	odprintf("comms[connect]");

	if (!data->running)
		return 0;

	if (data->s != INVALID_SOCKET)
		return 0;

	status->conn = NOT_CONNECTED;
	tray_update(hWnd, data);

#if HAVE_GETADDRINFO
	if (data->addrs_cur == NULL && data->addrs_res != NULL) {
		freeaddrinfo(data->addrs_res);
		data->addrs_res = NULL;
	}

	if (data->addrs_res == NULL) {
		SetLastError(0);
		ret = getaddrinfo(data->node, data->service, &data->hints, &data->addrs_res);
		err = GetLastError();
		odprintf("getaddrinfo: %d (%ld)", ret, err);
		if (ret != 0) {
			ret = snprintf(status->msg, sizeof(status->msg), "Unable to resolve node \"%s\" service \"%s\" (%d)", data->node, data->service, ret);
			if (ret < 0)
				status->msg[0] = 0;
			tray_update(hWnd, data);

			return 1;
		}

		if (data->addrs_res == NULL) {
			odprintf("no results");
			ret = snprintf(status->msg, sizeof(status->msg), "No results resolving node \"%s\" service \"%s\"", data->node, data->service);
			if (ret < 0)
				status->msg[0] = 0;
			tray_update(hWnd, data);

			return 1;
		}

		data->addrs_cur = data->addrs_res;
	}

	SetLastError(0);
	ret = getnameinfo(data->addrs_cur->ai_addr, data->addrs_cur->ai_addrlen, data->hbuf, sizeof(data->hbuf), data->sbuf, sizeof(data->sbuf), NI_NUMERICHOST|NI_NUMERICSERV);
	err = GetLastError();
	odprintf("getnameinfo: %d (%ld)", ret, err);
	if (ret == 0) {
		odprintf("trying to connect to node \"%s\" service \"%s\"", data->hbuf, data->sbuf);
	} else {
		data->hbuf[0] = 0;
		data->sbuf[0] = 0;
	}
#else
	odprintf("trying to connect to node \"%s\" service \"%s\"", data->node, data->service);
#endif

	SetLastError(0);
#if HAVE_GETADDRINFO
	data->s = socket(data->addrs_cur->ai_family, SOCK_STREAM, IPPROTO_TCP);
#else
	data->s = socket(data->family, SOCK_STREAM, IPPROTO_TCP);
#endif
	err = GetLastError();
	odprintf("socket: %d (%ld)", data->s, err);

	if (data->s == INVALID_SOCKET) {
		ret = snprintf(status->msg, sizeof(status->msg), "Unable to create socket (%ld)", err);
		if (ret < 0)
			status->msg[0] = 0;
		tray_update(hWnd, data);

#if HAVE_GETADDRINFO
		data->addrs_cur = data->addrs_cur->ai_next;
#endif
		return 1;
	}

	SetLastError(0);
	ret = setsockopt(data->s, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, sizeof(timeout));
	err = GetLastError();
	odprintf("setsockopt: %d (%ld)", ret, err);
	if (ret != 0) {
		ret = snprintf(status->msg, sizeof(status->msg), "Unable to set socket timeout (%ld)", err);
		if (ret < 0)
			status->msg[0] = 0;
		tray_update(hWnd, data);

		SetLastError(0);
		ret = closesocket(data->s);
		err = GetLastError();
		odprintf("closesocket: %d (%ld)", ret, err);
		data->s = INVALID_SOCKET;

#if HAVE_GETADDRINFO
		data->addrs_cur = data->addrs_cur->ai_next;
#endif
		return 1;
	}

	SetLastError(0);
	ret = WSAIoctl(data->s, SIO_KEEPALIVE_VALS, (void*)&ka_set, sizeof(ka_set), (void*)&ka_get, sizeof(ka_get), &retd, NULL, NULL);
	err = GetLastError();
	odprintf("WSAIoctl: %d, %d (%ld)", ret, retd, err);
	if (ret != 0) {
		ret = snprintf(status->msg, sizeof(status->msg), "Unable to set socket keepalive options (%ld)", err);
		if (ret < 0)
			status->msg[0] = 0;
		tray_update(hWnd, data);

		SetLastError(0);
		ret = closesocket(data->s);
		err = GetLastError();
		odprintf("closesocket: %d (%ld)", ret, err);
		data->s = INVALID_SOCKET;

#if HAVE_GETADDRINFO
		data->addrs_cur = data->addrs_cur->ai_next;
#endif
		return 1;
	}

	SetLastError(0);
	ret = WSAAsyncSelect(data->s, hWnd, WM_APP_SOCK, FD_CONNECT|FD_READ|FD_CLOSE);
	err = GetLastError();
	odprintf("WSAAsyncSelect: %d (%ld)", ret, err);
	if (ret != 0) {
		ret = snprintf(status->msg, sizeof(status->msg), "Unable to async select on socket (%ld)", err);
		if (ret < 0)
			status->msg[0] = 0;
		tray_update(hWnd, data);

		SetLastError(0);
		ret = closesocket(data->s);
		err = GetLastError();
		odprintf("closesocket: %d (%ld)", ret, err);
		data->s = INVALID_SOCKET;

#if HAVE_GETADDRINFO
		data->addrs_cur = data->addrs_cur->ai_next;
#endif
		return 1;
	}

	status->conn = CONNECTING;
#if HAVE_GETADDRINFO
	if (data->hbuf[0] != 0 && data->sbuf[0] != 0) {
		ret = snprintf(status->msg, sizeof(status->msg), "node \"%s\" service \"%s\" (%ld)", data->hbuf, data->sbuf, err);
	} else {
#endif
		ret = snprintf(status->msg, sizeof(status->msg), "node \"%s\" service \"%s\" (%ld)", data->node, data->service, err);
#if HAVE_GETADDRINFO
	}
#endif
	if (ret < 0)
		status->msg[0] = 0;
	tray_update(hWnd, data);

	SetLastError(0);
#if HAVE_GETADDRINFO
	ret = connect(data->s, data->addrs_cur->ai_addr, data->addrs_cur->ai_addrlen);
#else
	ret = connect(data->s, data->sa, data->sa_len);
#endif
	err = GetLastError();
	odprintf("connect: %d (%ld)", ret, err);
	if (ret == 0 || err == WSAEWOULDBLOCK) {
		return 0;
	} else {
		status->conn = NOT_CONNECTED;
#if HAVE_GETADDRINFO
		if (data->hbuf[0] != 0 && data->sbuf[0] != 0) {
			ret = snprintf(status->msg, sizeof(status->msg), "Error connecting to node \"%s\" service \"%s\"", data->hbuf, data->sbuf);
		} else {
#endif
			ret = snprintf(status->msg, sizeof(status->msg), "Error connecting to node \"%s\" service \"%s\"", data->node, data->service);
#if HAVE_GETADDRINFO
		}
#endif
		if (ret < 0)
			status->msg[0] = 0;
		tray_update(hWnd, data);

		SetLastError(0);
		ret = closesocket(data->s);
		err = GetLastError();
		odprintf("closesocket: %d (%ld)", ret, err);
		data->s = INVALID_SOCKET;

#if HAVE_GETADDRINFO
		data->addrs_cur = data->addrs_cur->ai_next;
#endif
		return 1;
	}
}

int comms_activity(HWND hWnd, struct th_data *data, SOCKET s, WORD sEvent, WORD sError) {
	struct tray_status *status = &data->status;
	INT ret;
	DWORD err;

	odprintf("comms[activity]: s=%p sEvent=%d sError=%d", s, sEvent, sError);

	if (!data->running)
		return 0;

	if (data->s != s)
		return 0;

	switch (sEvent) {
	case FD_CONNECT:
		odprintf("FD_CONNECT %s", status->conn == CONNECTING ? "OK" : "?");
		if (status->conn != CONNECTING)
			return 0;

		if (sError == 0) {
			status->conn = CONNECTED;
			status->msg[0] = 0;
			status->temperature_celsius = NAN;
			status->relative_humidity = NAN;
			status->dew_point = NAN;
			tray_update(hWnd, data);

#if HAVE_GETADDRINFO
			freeaddrinfo(data->addrs_res);
			data->addrs_res = NULL;
#endif
			data->parse_pos = 0;
			data->def_sensor = 0;
			return 0;
		} else {
			status->conn = NOT_CONNECTED;
#if HAVE_GETADDRINFO
			if (data->hbuf[0] != 0 && data->sbuf[0] != 0) {
				ret = snprintf(status->msg, sizeof(status->msg), "Error connecting to node \"%s\" service \"%s\" (%d)", data->hbuf, data->sbuf, sError);
			} else {
#endif
				ret = snprintf(status->msg, sizeof(status->msg), "Error connecting to node \"%s\" service \"%s\" (%d)", data->node, data->service, sError);
#if HAVE_GETADDRINFO
			}
#endif
			if (ret < 0)
				status->msg[0] = 0;
			tray_update(hWnd, data);

			SetLastError(0);
			ret = closesocket(data->s);
			err = GetLastError();
			odprintf("closesocket: %d (%ld)", ret, err);

			data->s = INVALID_SOCKET;
#if HAVE_GETADDRINFO
			data->addrs_cur = data->addrs_cur->ai_next;
#endif
			return 1;
		}

	case FD_READ:
		odprintf("FD_READ %s", status->conn == CONNECTED ? "OK" : "?");
		if (status->conn != CONNECTED)
			return 0;

		if (sError == 0) {
			char recv_buf[128];

			SetLastError(0);
			ret = recv(data->s, recv_buf, sizeof(recv_buf), 0);
			err = GetLastError();
			odprintf("recv: %d (%ld)", ret, err);
			if (ret <= 0) {
				status->conn = NOT_CONNECTED;
#if HAVE_GETADDRINFO
				if (data->hbuf[0] != 0 && data->sbuf[0] != 0) {
					ret = snprintf(status->msg, sizeof(status->msg), "Error reading from node \"%s\" service \"%s\" (%ld)", data->hbuf, data->sbuf, err);
				} else {
#endif
					ret = snprintf(status->msg, sizeof(status->msg), "Error reading from node \"%s\" service \"%s\" (%ld)", data->node, data->service, err);
#if HAVE_GETADDRINFO
				}
#endif
				if (ret < 0)
					status->msg[0] = 0;
				tray_update(hWnd, data);

				SetLastError(0);
				ret = closesocket(data->s);
				err = GetLastError();
				odprintf("closesocket: %d (%ld)", ret, err);

				data->s = INVALID_SOCKET;
				return 1;
			} else if (err == WSAEWOULDBLOCK) {
				return 0;
			} else {
				int size, i;

				size = ret;
				for (i = 0; i < size; i++) {
					/* find a newline and parse the buffer */
					if (recv_buf[i] == '\n') {
						comms_parse(hWnd, data);

						/* clear buffer */
						data->parse_pos = 0;

					/* buffer overflow */
					} else if (data->parse_pos == sizeof(data->parse_buf)/sizeof(char) - 1) {
						odprintf("parse: sender overflowed buffer waiting for '\\n'");
						data->parse_buf[0] = 0;
						data->parse_pos++;

					/* ignore */
					} else if (data->parse_pos > sizeof(data->parse_buf)/sizeof(char) - 1) {

					/* append to buffer */
					} else {
						data->parse_buf[data->parse_pos++] = recv_buf[i];
						data->parse_buf[data->parse_pos] = 0;
					}
				}
				return 0;
			}
		} else {
			status->conn = NOT_CONNECTED;
#if HAVE_GETADDRINFO
			if (data->hbuf[0] != 0 && data->sbuf[0] != 0) {
				ret = snprintf(status->msg, sizeof(status->msg), "Error reading from node \"%s\" service \"%s\" (%d)", data->hbuf, data->sbuf, sError);
			} else {
#endif
				ret = snprintf(status->msg, sizeof(status->msg), "Error reading from node \"%s\" service \"%s\" (%d)", data->node, data->service, sError);
#if HAVE_GETADDRINFO
			}
#endif
			if (ret < 0)
				status->msg[0] = 0;
			tray_update(hWnd, data);

			SetLastError(0);
			ret = closesocket(data->s);
			err = GetLastError();
			odprintf("closesocket: %d (%ld)", ret, err);

			data->s = INVALID_SOCKET;
			return 1;
		}

	case FD_CLOSE:
		odprintf("FD_CLOSE %s", status->conn == CONNECTED ? "OK" : "?");
		if (status->conn != CONNECTED)
			return 0;

		status->conn = NOT_CONNECTED;
#if HAVE_GETADDRINFO
		if (data->hbuf[0] != 0 && data->sbuf[0] != 0) {
			ret = snprintf(status->msg, sizeof(status->msg), "Lost connection to node \"%s\" service \"%s\" (%d)", data->hbuf, data->sbuf, sError);
		} else {
#endif
			ret = snprintf(status->msg, sizeof(status->msg), "Lost connection to node \"%s\" service \"%s\" (%d)", data->node, data->service, sError);
#if HAVE_GETADDRINFO
		}
#endif
		if (ret < 0)
			status->msg[0] = 0;
		tray_update(hWnd, data);

		SetLastError(0);
		ret = closesocket(data->s);
		err = GetLastError();
		odprintf("closesocket: %d (%ld)", ret, err);

		data->s = INVALID_SOCKET;
		return 1;

	default:
		return 0;
	}
}

void comms_parse(HWND hWnd, struct th_data *data) {
	struct tray_status *status = &data->status;
	char msg_type[16];

	if (sscanf(data->parse_buf, "%16s", msg_type) == 1) {
		odprintf("msg_type: %s", msg_type);
		if (!strcmp(msg_type, "SENSD")) {
			data->def_sensor = 1;
		} else if (!strcmp(msg_type, "SENSR")) {
			data->def_sensor = 0;
		} else if (data->def_sensor) {
			if (!strcmp(msg_type, "TEMPC")) {
				if (sscanf(data->parse_buf, "%*s %lf", &status->temperature_celsius) != 1)
					status->temperature_celsius = NAN;
			} else if (!strcmp(msg_type, "RHUM%")) {
				if (sscanf(data->parse_buf, "%*s %lf", &status->relative_humidity) != 1)
					status->relative_humidity = NAN;
			} else if (!strcmp(msg_type, "DEWPC")) {
				if (sscanf(data->parse_buf, "%*s %lf", &status->dew_point) != 1)
					status->dew_point = NAN;
			} else if (!strcmp(msg_type, "SENSF")) {
				tray_update(hWnd, data);
			}
		}
	}
}
コード例 #7
0
ファイル: ui_win_gui.c プロジェクト: ssem/rat
NOEXPORT LRESULT CALLBACK window_proc(HWND main_window_handle,
        UINT message, WPARAM wParam, LPARAM lParam) {
    POINT pt;
    RECT rect;
    PAINTSTRUCT ps;
    SERVICE_OPTIONS *section;
    unsigned section_number;
    LPTSTR txt;

#if 0
    switch(message) {
    case WM_CTLCOLORSTATIC:
    case WM_TIMER:
    case WM_LOG:
        break;
    default:
        s_log(LOG_DEBUG, "Window message: 0x%x(0x%hx,0x%lx)",
            message, wParam, lParam);
    }
#endif
    switch(message) {
    case WM_CREATE:
#ifdef _WIN32_WCE
        /* create command bar */
        command_bar_handle=CommandBar_Create(ghInst, main_window_handle, 1);
        if(!command_bar_handle)
            error_box(TEXT("CommandBar_Create"));
        if(!CommandBar_InsertMenubar(command_bar_handle, ghInst, IDM_MAINMENU, 0))
            error_box(TEXT("CommandBar_InsertMenubar"));
        if(!CommandBar_AddAdornments(command_bar_handle, 0, 0))
            error_box(TEXT("CommandBar_AddAdornments"));
#endif

        /* create child edit window */
        edit_handle=CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), NULL,
            WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|ES_MULTILINE|ES_READONLY,
            0, 0, 0, 0, main_window_handle, (HMENU)IDE_EDIT, ghInst, NULL);
#ifndef _WIN32_WCE
        SendMessage(edit_handle, WM_SETFONT,
            (WPARAM)CreateFont(-12, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
                DEFAULT_CHARSET, OUT_RASTER_PRECIS, CLIP_DEFAULT_PRECIS,
                PROOF_QUALITY, DEFAULT_PITCH, TEXT("Courier")),
            MAKELPARAM(FALSE, 0)); /* no need to redraw right now */
#endif
        /* NOTE: there's no return statement here -> proceeding with resize */

    case WM_SIZE:
        GetClientRect(main_window_handle, &rect);
#ifdef _WIN32_WCE
        MoveWindow(edit_handle, 0, CommandBar_Height(command_bar_handle),
            rect.right, rect.bottom-CommandBar_Height(command_bar_handle),
            TRUE);
        SendMessage(command_bar_handle, TB_AUTOSIZE, 0L, 0L);
        CommandBar_AlignAdornments(command_bar_handle);
#else
        MoveWindow(edit_handle, 0, 0, rect.right, rect.bottom, TRUE);
#endif
        UpdateWindow(edit_handle);
        /* CommandBar_Show(command_bar_handle, TRUE); */
        return 0;

    case WM_SETFOCUS:
        SetFocus(edit_handle);
        return 0;

    case WM_PAINT:
        BeginPaint(hwnd, &ps);
        EndPaint(hwnd, &ps);
        break;

    case WM_CLOSE:
        ShowWindow(main_window_handle, SW_HIDE);
        return 0;

#ifdef WM_SHOWWINDOW
    case WM_SHOWWINDOW:
        visible=(BOOL)wParam;
#else /* this works for Pierre Delaage, but not for me... */
    case WM_WINDOWPOSCHANGED:
        visible=IsWindowVisible(main_window_handle);
#endif
        if(tray_menu_handle)
            CheckMenuItem(tray_menu_handle, IDM_SHOW_LOG,
                visible ? MF_CHECKED : MF_UNCHECKED);
        if(visible)
            update_logs();
#ifdef WM_SHOWWINDOW
        return 0;
#else
        break; /* proceed to DefWindowProc() */
#endif

    case WM_DESTROY:
#ifdef _WIN32_WCE
        CommandBar_Destroy(command_bar_handle);
#else
        if(main_menu_handle) {
            if(!DestroyMenu(main_menu_handle))
                ioerror("DestroyMenu");
            main_menu_handle=NULL;
        }
#endif
        tray_delete(); /* remove the taskbark icon if exists */
        PostQuitMessage(0);
        return 0;

    case WM_COMMAND:
        if(wParam>=IDM_PEER_MENU && wParam<IDM_PEER_MENU+number_of_sections) {
            for(section=service_options.next, section_number=0;
                    section && wParam!=IDM_PEER_MENU+section_number;
                    section=section->next, ++section_number)
                ;
            if(!section)
                return 0;
            if(save_text_file(section->file, section->chain))
                return 0;
#ifndef _WIN32_WCE
            if(main_menu_handle)
                CheckMenuItem(main_menu_handle, (UINT)wParam, MF_CHECKED);
#endif
            if(tray_menu_handle)
                CheckMenuItem(tray_menu_handle, (UINT)wParam, MF_CHECKED);
            message_box(section->help, MB_ICONINFORMATION);
            return 0;
        }
        switch(wParam) {
        case IDM_ABOUT:
            DialogBox(ghInst, TEXT("AboutBox"), main_window_handle,
                (DLGPROC)about_proc);
            break;
        case IDM_SHOW_LOG:
            if(visible) {
                ShowWindow(main_window_handle, SW_HIDE); /* hide window */
            } else {
                ShowWindow(main_window_handle, SW_SHOWNORMAL); /* show window */
                SetForegroundWindow(main_window_handle); /* bring on top */
            }
            break;
        case IDM_CLOSE:
            ShowWindow(main_window_handle, SW_HIDE); /* hide window */
            break;
        case IDM_EXIT:
            if(num_clients>=0) /* signal_pipe is active */
                signal_post(SIGNAL_TERMINATE);
            DestroyWindow(main_window_handle);
            break;
        case IDM_SAVE_LOG:
            if(!cmdline.service) /* security */
                save_log();
            break;
        case IDM_EDIT_CONFIG:
#ifndef _WIN32_WCE
            if(!cmdline.service) /* security */
                edit_config(main_window_handle);
#endif
            break;
        case IDM_RELOAD_CONFIG:
            if(num_clients>=0) /* signal_pipe is active */
                signal_post(SIGNAL_RELOAD_CONFIG);
            else
                SetEvent(config_ready); /* unlock daemon_thread() */
            break;
        case IDM_REOPEN_LOG:
            signal_post(SIGNAL_REOPEN_LOG);
            break;
        case IDM_MANPAGE:
#ifndef _WIN32_WCE
            if(!cmdline.service) /* security */
                ShellExecute(main_window_handle, TEXT("open"),
                    TEXT("..\\doc\\stunnel.html"), NULL, NULL, SW_SHOWNORMAL);
#endif
            break;
        case IDM_HOMEPAGE:
#ifndef _WIN32_WCE
            if(!cmdline.service) /* security */
                ShellExecute(main_window_handle, TEXT("open"),
                    TEXT("http://www.stunnel.org/"), NULL, NULL, SW_SHOWNORMAL);
#endif
            break;
        }
        return 0;

    case WM_SYSTRAY: /* a taskbar event */
        switch(lParam) {
#ifdef _WIN32_WCE
        case WM_LBUTTONDOWN: /* no right mouse button on Windows CE */
            GetWindowRect(GetDesktopWindow(), &rect); /* no cursor position */
            pt.x=rect.right;
            pt.y=rect.bottom-25;
#else
        case WM_RBUTTONDOWN:
            GetCursorPos(&pt);
#endif
            SetForegroundWindow(main_window_handle);
            if(tray_menu_handle)
                TrackPopupMenuEx(GetSubMenu(tray_menu_handle, 0),
                    TPM_BOTTOMALIGN, pt.x, pt.y, main_window_handle, NULL);
            PostMessage(main_window_handle, WM_NULL, 0, 0);
            break;
#ifndef _WIN32_WCE
        case WM_LBUTTONDBLCLK: /* switch log window visibility */
            if(visible) {
                ShowWindow(main_window_handle, SW_HIDE); /* hide window */
            } else {
                ShowWindow(main_window_handle, SW_SHOWNORMAL); /* show window */
                SetForegroundWindow(main_window_handle); /* bring on top */
            }
            break;
#endif
        }
        return 0;

    case WM_VALID_CONFIG:
        valid_config();
        return 0;

    case WM_INVALID_CONFIG:
        invalid_config();
        return 0;

    case WM_LOG:
        txt=(LPTSTR)wParam;
        win_log(txt);
        str_free(txt);
        return 0;

    case WM_NEW_CHAIN:
#ifndef _WIN32_WCE
        if(main_menu_handle)
            EnableMenuItem(main_menu_handle,
                (UINT)(IDM_PEER_MENU+wParam), MF_ENABLED);
#endif
        if(tray_menu_handle)
            EnableMenuItem(tray_menu_handle,
                (UINT)(IDM_PEER_MENU+wParam), MF_ENABLED);
        return 0;

    case WM_CLIENTS:
        tray_update((int)wParam);
        return 0;
    }

    return DefWindowProc(main_window_handle, message, wParam, lParam);
}