Respect the server's keep-alive value if it's below ours.
[privoxy.git] / w32log.c
1 const char w32log_rcs[] = "$Id: w32log.c,v 1.32 2009/03/09 18:32:48 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/w32log.c,v $
5  *
6  * Purpose     :  Functions for creating and destroying the log window,
7  *                ouputting strings, processing messages and so on.
8  *
9  * Copyright   :  Written by and Copyright (C) 2001-2009 members of
10  *                the Privoxy team.  http://www.privoxy.org/
11  *
12  *                Written by and Copyright (C) 1999 Adam Lock
13  *                <locka@iol.ie>
14  *
15  *                This program is free software; you can redistribute it 
16  *                and/or modify it under the terms of the GNU General
17  *                Public License as published by the Free Software
18  *                Foundation; either version 2 of the License, or (at
19  *                your option) any later version.
20  *
21  *                This program is distributed in the hope that it will
22  *                be useful, but WITHOUT ANY WARRANTY; without even the
23  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
24  *                PARTICULAR PURPOSE.  See the GNU General Public
25  *                License for more details.
26  *
27  *                The GNU General Public License should be included with
28  *                this file.  If not, you can view it at
29  *                http://www.gnu.org/copyleft/gpl.html
30  *                or write to the Free Software Foundation, Inc., 59
31  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
32  *
33  * Revisions   :
34  *    $Log: w32log.c,v $
35  *    Revision 1.32  2009/03/09 18:32:48  fabiankeil
36  *    Use the Privoxy icon in the alt+tab window.
37  *    Patch submitted by Burberry in #2674342.
38  *
39  *    Revision 1.31  2009/03/07 17:58:02  fabiankeil
40  *    Fix two mingw32-only buffer overflows. Note that triggering
41  *    them requires control over the configuration file in which
42  *    case all bets are off anyway.
43  *
44  *    Revision 1.30  2009/01/01 15:09:23  ler762
45  *    Change the Windows taskbar icon when privoxy is toggled off.
46  *
47  *    Revision 1.29  2008/12/20 15:27:40  ler762
48  *    The crunch log message format changed, so update the strings to highlight
49  *    in the log window.
50  *
51  *    Revision 1.28  2008/11/02 14:37:47  ler762
52  *    commit the part of the patches I've been using that were written by torford and gjmurphy
53  *      [ 1824315 ] Minor code cleanup
54  *      [ 1781135 ] Patch - Add clear log, select all, and Accelerators for w32
55  *        http://sourceforge.net/tracker/?func=detail&atid=311118&aid=1781135&group_id=11118
56  *    The full patch adds control keys A(select all), C(copy) and D(delete all) to the
57  *    Privoxy log window menu.  Select all and copy work for me without the patch
58  *    (albeit without showing the accelerator keys on the menu), so the only part of the
59  *    patch I've been using for the last year or so has been the ctrl-d to delete
60  *    everything in the Privoxy log window.
61  *
62  *    Revision 1.27  2006/07/18 14:48:48  david__schmidt
63  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
64  *    with what was really the latest development (the v_3_0_branch branch)
65  *
66  *    Revision 1.25.2.5  2003/04/04 12:48:51  oes
67  *    Fixed bug #711865:
68  *     - Made tray menu correctly reflect initial window visibility state
69  *     - Hopefully fixed problem where log window contents wasn't visible
70  *       until vertical scroll bar was clicked. Thanks to Guy for the fix!
71  *
72  *    Revision 1.25.2.4  2003/03/11 11:53:59  oes
73  *    Cosmetic: Renamed cryptic variable
74  *
75  *    Revision 1.25.2.3  2002/11/20 14:39:05  oes
76  *    Fixed compiler warning
77  *
78  *    Revision 1.25.2.2  2002/09/25 15:23:10  oes
79  *    Uncheck the "Show Privoxy Window" taskbar menu item when window gets minimized. Fixes bug #606804
80  *
81  *    Revision 1.25.2.1  2002/08/21 17:59:05  oes
82  *     - "Show Privoxy Window" now a toggle
83  *     - Temp kludge to let user and default action file be edited through win32 GUI (FR 592080)
84  *
85  *    Revision 1.25  2002/04/04 00:36:36  gliptak
86  *    always use pcre for matching
87  *
88  *    Revision 1.24  2002/03/31 17:19:00  jongfoster
89  *    Win32 only: Enabling STRICT to fix a VC++ compile warning.
90  *
91  *    Revision 1.23  2002/03/26 22:57:10  jongfoster
92  *    Web server name should begin www.
93  *
94  *    Revision 1.22  2002/03/24 12:48:23  jongfoster
95  *    Fixing doc links
96  *
97  *    Revision 1.21  2002/03/24 12:07:35  jongfoster
98  *    Consistern name for filters file
99  *
100  *    Revision 1.20  2002/03/24 12:03:47  jongfoster
101  *    Name change
102  *
103  *    Revision 1.19  2002/01/17 21:04:17  jongfoster
104  *    Replacing hard references to the URL of the config interface
105  *    with #defines from project.h
106  *
107  *    Revision 1.18  2001/11/30 23:37:24  jongfoster
108  *    Renaming the Win32 config file to config.txt - this is almost the
109  *    same as the corresponding UNIX name "config"
110  *
111  *    Revision 1.17  2001/11/16 00:46:31  jongfoster
112  *    Fixing compiler warnings
113  *
114  *    Revision 1.16  2001/08/01 19:58:12  jongfoster
115  *    Fixing documentation filenames in help menu, and making status
116  *    option work without needing the "Junkbuster Status.URL" file.
117  *
118  *    Revision 1.15  2001/07/30 22:08:36  jongfoster
119  *    Tidying up #defines:
120  *    - All feature #defines are now of the form FEATURE_xxx
121  *    - Permanently turned off WIN_GUI_EDIT
122  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
123  *
124  *    Revision 1.14  2001/07/29 18:47:05  jongfoster
125  *    Adding missing #include "loadcfg.h"
126  *
127  *    Revision 1.13  2001/07/19 19:15:14  haroon
128  *    - Added a FIXME for EditFile but didn't fix :-)
129  *
130  *    Revision 1.12  2001/07/13 14:04:59  oes
131  *    Removed all #ifdef PCRS
132  *
133  *    Revision 1.11  2001/06/07 23:08:12  jongfoster
134  *    Forward and ACL edit options removed.
135  *
136  *    Revision 1.10  2001/05/31 21:37:11  jongfoster
137  *    GUI changes to rename "permissions file" to "actions file".
138  *
139  *    Revision 1.9  2001/05/31 17:33:13  oes
140  *
141  *    CRLF -> LF
142  *
143  *    Revision 1.8  2001/05/29 09:50:24  jongfoster
144  *    Unified blocklist/imagelist/permissionslist.
145  *    File format is still under discussion, but the internal changes
146  *    are (mostly) done.
147  *
148  *    Also modified interceptor behaviour:
149  *    - We now intercept all URLs beginning with one of the following
150  *      prefixes (and *only* these prefixes):
151  *        * http://i.j.b/
152  *        * http://ijbswa.sf.net/config/
153  *        * http://ijbswa.sourceforge.net/config/
154  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
155  *    - Internal changes so that intercepted and fast redirect pages
156  *      are not replaced with an image.
157  *    - Interceptors now have the option to send a binary page direct
158  *      to the client. (i.e. ijb-send-banner uses this)
159  *    - Implemented show-url-info interceptor.  (Which is why I needed
160  *      the above interceptors changes - a typical URL is
161  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
162  *      The previous mechanism would not have intercepted that, and
163  *      if it had been intercepted then it then it would have replaced
164  *      it with an image.)
165  *
166  *    Revision 1.7  2001/05/26 01:26:34  jongfoster
167  *    New #define, WIN_GUI_EDIT, enables the (embryonic) Win32 GUI editor.
168  *    This #define cannot be set from ./configure - there's no point, it
169  *    doesn't work yet.  See feature request # 425722
170  *
171  *    Revision 1.6  2001/05/26 00:31:30  jongfoster
172  *    Fixing compiler warning about comparing signed/unsigned.
173  *
174  *    Revision 1.5  2001/05/26 00:28:36  jongfoster
175  *    Automatic reloading of config file.
176  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
177  *    Most of the global variables have been moved to a new
178  *    struct configuration_spec, accessed through csp->config->globalname
179  *    Most of the globals remaining are used by the Win32 GUI.
180  *
181  *    Revision 1.4  2001/05/22 18:56:28  oes
182  *    CRLF -> LF
183  *
184  *    Revision 1.3  2001/05/20 15:07:54  jongfoster
185  *    File is now ignored if _WIN_CONSOLE is defined.
186  *
187  *    Revision 1.2  2001/05/20 01:21:20  jongfoster
188  *    Version 2.9.4 checkin.
189  *    - Merged popupfile and cookiefile, and added control over PCRS
190  *      filtering, in new "permissionsfile".
191  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
192  *      file error you now get a message box (in the Win32 GUI) rather
193  *      than the program exiting with no explanation.
194  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
195  *      skipping.
196  *    - Removed tabs from "config"
197  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
198  *    - Bumped up version number.
199  *
200  *    Revision 1.1.1.1  2001/05/15 13:59:07  oes
201  *    Initial import of version 2.9.3 source tree
202  *
203  *
204  *********************************************************************/
205 \f
206
207 #include "config.h"
208
209 #include <assert.h>
210 #include <stdio.h>
211
212 #ifndef STRICT
213 #define STRICT
214 #endif
215 #include <windows.h>
216 #include <richedit.h>
217
218 #include "project.h"
219 #include "w32log.h"
220 #include "w32taskbar.h"
221 #include "win32.h"
222 #include "w32res.h"
223 #include "jcc.h"
224 #include "miscutil.h"
225 #include "errlog.h"
226 #include "loadcfg.h"
227
228 const char w32res_h_rcs[] = W32RES_H_VERSION;
229
230 #ifdef __MINGW32__
231 #include "cygwin.h"
232 const char cygwin_h_rcs[] = CYGWIN_H_VERSION;
233 #endif
234
235 const char w32log_h_rcs[] = W32LOG_H_VERSION;
236
237 #ifndef _WIN_CONSOLE /* entire file */
238
239 /*
240  * Timers and the various durations
241  */
242 #define TIMER_ANIM_ID               1
243 #define TIMER_ANIM_TIME             100
244 #define TIMER_ANIMSTOP_ID           2
245 #define TIMER_ANIMSTOP_TIME         1000
246 #define TIMER_CLIPBUFFER_ID         3
247 #define TIMER_CLIPBUFFER_TIME       1000
248 #define TIMER_CLIPBUFFER_FORCE_ID   4
249 #define TIMER_CLIPBUFFER_FORCE_TIME 5000
250
251 /*
252  * Styles of text that can be output
253  */
254 #define STYLE_NONE      0
255 #define STYLE_HIGHLIGHT 1
256 #define STYLE_LINK      2
257 #define STYLE_HEADER    3
258
259 /*
260  * Number of frames of animation in tray activity sequence
261  */
262 #define ANIM_FRAMES 8
263
264 #define DEFAULT_MAX_BUFFER_LINES    200
265 #define DEFAULT_LOG_FONT_NAME       "MS Sans Serif"
266 #define DEFAULT_LOG_FONT_SIZE       8
267
268 /*
269  * These values affect the way the log window behaves, they should be read
270  * from a file but for the moment, they are hardcoded here. Some options are
271  * configurable through the UI.
272  */
273
274 /* Indicates whether task bar shows activity animation */
275 BOOL g_bShowActivityAnimation = 1;
276
277 /* Indicates whether the log window is shown */
278 BOOL g_bShowLogWindow = 1;
279
280 /* Indicates if the log window appears on the task bar */
281 BOOL g_bShowOnTaskBar = 0;
282
283 /* Indicates whether closing the log window really just hides it */
284 BOOL g_bCloseHidesWindow = 1;
285
286 /* Indicates if messages are logged at all */
287 BOOL g_bLogMessages = 1;
288
289 /* Indicates whether log messages are highlighted */
290 BOOL g_bHighlightMessages = 1;
291
292 /* Indicates if buffer is limited in size */
293 BOOL g_bLimitBufferSize = 1;
294
295 /* Maximum number of lines allowed in buffer when limited */
296 int g_nMaxBufferLines = DEFAULT_MAX_BUFFER_LINES;
297
298 /* Font to use */
299 char g_szFontFaceName[32] = DEFAULT_LOG_FONT_NAME;
300
301 /* Size of font to use */
302 int g_nFontSize = DEFAULT_LOG_FONT_SIZE;
303
304
305 /* FIXME: this is a kludge */
306
307 const char * g_default_actions_file = NULL;
308 const char * g_user_actions_file = NULL;
309 const char * g_re_filterfile = NULL;
310 #ifdef FEATURE_TRUST
311 const char * g_trustfile = NULL;
312 #endif /* def FEATURE_TRUST */
313
314 /* FIXME: end kludge */
315
316 /* Regular expression for detected URLs */
317 #define RE_URL "http:[^ \n\r]*"
318
319 /*
320  * Regular expressions that are used to perform highlight in the log window
321  */
322 static struct _Pattern
323 {
324    const char *str;
325    int style;
326    regex_t buffer;
327 } patterns_to_highlight[] =
328 {
329    /* url headers */
330    { RE_URL,                STYLE_LINK },
331 /* { "[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.[^ \n\r]*", STYLE_LINK }, */
332    /* interesting text to highlight */
333    /*   see jcc.c crunch_reason for the full list */
334    { "Crunch: Blocked:",            STYLE_HIGHLIGHT },
335    { "Crunch: Untrusted",           STYLE_HIGHLIGHT },
336    { "Crunch: Redirected:",         STYLE_HIGHLIGHT },
337    { "Crunch: DNS failure",         STYLE_HIGHLIGHT },
338    { "Crunch: Forwarding failed",   STYLE_HIGHLIGHT },
339    { "Crunch: Connection failure",  STYLE_HIGHLIGHT },
340    { "Crunch: Out of memory",       STYLE_HIGHLIGHT },
341    /* what are all the possible error strings?? */
342    { "Error:",                      STYLE_HIGHLIGHT },
343    /* http headers */
344    { "referer:",            STYLE_HEADER },
345    { "proxy-connection:",   STYLE_HEADER },
346    { "proxy-agent:",        STYLE_HEADER },
347    { "user-agent:",         STYLE_HEADER },
348    { "host:",               STYLE_HEADER },
349    { "accept:",             STYLE_HEADER },
350    { "accept-encoding:",    STYLE_HEADER },
351    { "accept-language:",    STYLE_HEADER },
352    { "accept-charset:",     STYLE_HEADER },
353    { "accept-ranges:",      STYLE_HEADER },
354    { "date:",               STYLE_HEADER },
355    { "cache-control:",      STYLE_HEADER },
356    { "cache-last-checked:", STYLE_HEADER },
357    { "connection:",         STYLE_HEADER },
358    { "content-type",        STYLE_HEADER },
359    { "content-length",      STYLE_HEADER },
360    { "cookie",              STYLE_HEADER },
361    { "last-modified:",      STYLE_HEADER },
362    { "pragma:",             STYLE_HEADER },
363    { "server:",             STYLE_HEADER },
364    { "etag:",               STYLE_HEADER },
365    { "expires:",            STYLE_HEADER },
366    { "warning:",            STYLE_HEADER },
367    /* this is the terminator statement - do not delete! */
368    { NULL,                  STYLE_NONE }
369 };
370
371 /*
372  * Public variables
373  */
374 HWND g_hwndLogFrame;
375 HICON g_hiconApp;
376
377 /*
378  * Private variables
379  */
380 static CRITICAL_SECTION g_criticalsection;
381 static HWND g_hwndTray;
382 static HWND g_hwndLogBox;
383 static WNDPROC g_fnLogBox;
384 static HICON g_hiconAnim[ANIM_FRAMES];
385 static HICON g_hiconIdle;
386 static HICON g_hiconOff;
387 static int g_nAnimFrame;
388 static BOOL g_bClipPending = FALSE;
389 static int g_nRichEditVersion = 0;
390
391 /*
392  * Private functions
393  */
394 static HWND CreateLogWindow(HINSTANCE hInstance, int nCmdShow);
395 static HWND CreateHiddenLogOwnerWindow(HINSTANCE hInstance);
396 static LRESULT CALLBACK LogWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
397 static LRESULT CALLBACK LogOwnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
398 static LRESULT CALLBACK LogRichEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
399 static BOOL InitRichEdit(void);
400 static void LogClipBuffer(void);
401 static void LogCreatePatternMatchingBuffers(void);
402 static void LogDestroyPatternMatchingBuffers(void);
403 static int LogPutStringNoMatch(const char *pszText, int style);
404 static void SetIdleIcon(void);
405
406
407 /*********************************************************************
408  *
409  * Function    :  InitLogWindow
410  *
411  * Description :  Initialise the log window.
412  *
413  * Parameters  :  None
414  *
415  * Returns     :  Always TRUE (there should be error checking on the resources).
416  *
417  *********************************************************************/
418 BOOL InitLogWindow(void)
419 {
420    int i;
421
422    /* Load the icons */
423    g_hiconIdle = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_IDLE));
424    g_hiconOff  = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_OFF));
425    for (i = 0; i < ANIM_FRAMES; i++)
426    {
427       g_hiconAnim[i] = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ANIMATED1 + i));
428    }
429    g_hiconApp = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAINICON));
430
431    /* Create the user interface */
432    g_hwndLogFrame = CreateLogWindow(g_hInstance, g_nCmdShow);
433    g_hwndTray = CreateTrayWindow(g_hInstance);
434    TrayAddIcon(g_hwndTray, 1, g_hiconApp, "Privoxy");
435
436    /* Create pattern matching buffers (for highlighting */
437    LogCreatePatternMatchingBuffers();
438
439    /* Create a critical section to protect multi-threaded access to certain things */
440    InitializeCriticalSection(&g_criticalsection);
441
442    return TRUE;
443
444 }
445
446
447 /*********************************************************************
448  *
449  * Function    :  TermLogWindow
450  *
451  * Description :  Cleanup the logwindow.
452  *
453  * Parameters  :  None
454  *
455  * Returns     :  N/A
456  *
457  *********************************************************************/
458 void TermLogWindow(void)
459 {
460    int i;
461
462    LogDestroyPatternMatchingBuffers();
463
464    TrayDeleteIcon(g_hwndTray, 1);
465    DeleteObject(g_hiconApp);
466    DeleteObject(g_hiconIdle);
467    DeleteObject(g_hiconOff);
468    for (i = 0; i < ANIM_FRAMES; i++)
469    {
470       DeleteObject(g_hiconAnim[i]);
471    }
472
473 }
474
475
476 /*********************************************************************
477  *
478  * Function    :  LogCreatePatternMatchingBuffers
479  *
480  * Description :  Compile the pattern matching buffers.
481  *
482  * Parameters  :  None
483  *
484  * Returns     :  N/A
485  *
486  *********************************************************************/
487 void LogCreatePatternMatchingBuffers(void)
488 {
489    int i;
490    for (i = 0; patterns_to_highlight[i].str != NULL; i++)
491    {
492       regcomp(&patterns_to_highlight[i].buffer, patterns_to_highlight[i].str, REG_ICASE);
493    }
494 }
495
496
497 /*********************************************************************
498  *
499  * Function    :  LogDestroyPatternMatchingBuffers
500  *
501  * Description :  Free up the pattern matching buffers.
502  *
503  * Parameters  :  None
504  *
505  * Returns     :  N/A
506  *
507  *********************************************************************/
508 void LogDestroyPatternMatchingBuffers(void)
509 {
510    int i;
511    for (i = 0; patterns_to_highlight[i].str != NULL; i++)
512    {
513       regfree(&patterns_to_highlight[i].buffer);
514    }
515 }
516
517
518 /*********************************************************************
519  *
520  * Function    :  LogGetURLUnderCursor
521  *
522  * Description :  Returns the URL from under the cursor (remember to free it!).
523  *
524  * Parameters  :  None
525  *
526  * Returns     :  NULL or a pointer to an URL string.
527  *
528  *********************************************************************/
529 char *LogGetURLUnderCursor(void)
530 {
531    char *szResult = NULL;
532    regex_t re;
533    POINT ptCursor;
534    POINTL ptl;
535    DWORD nPos;
536    DWORD nWordStart = 0;
537    DWORD nWordEnd = 0;
538
539    regcomp(&re, RE_URL, REG_ICASE);
540
541    /* Get the position of the cursor over the text window */
542    GetCursorPos(&ptCursor);
543    ScreenToClient(g_hwndLogBox, &ptCursor);
544    ptl.x = ptCursor.x;
545    ptl.y = ptCursor.y;
546
547    /* Search backwards and fowards to obtain the word that is highlighted */
548    nPos = LOWORD(SendMessage(g_hwndLogBox, EM_CHARFROMPOS, 0, (LPARAM) &ptl));
549    nWordStart = SendMessage(g_hwndLogBox, EM_FINDWORDBREAK, WB_LEFT, nPos);
550    nWordEnd = SendMessage(g_hwndLogBox, EM_FINDWORDBREAK, WB_RIGHTBREAK, nPos);
551
552    /* Compare the string to the pattern */
553    if (nWordEnd > nWordStart)
554    {
555       TEXTRANGE range;
556       regmatch_t match;
557
558       range.chrg.cpMin = nWordStart;
559       range.chrg.cpMax = nWordEnd;
560       range.lpstrText = (LPSTR)zalloc(nWordEnd - nWordStart + 1);
561       SendMessage(g_hwndLogBox, EM_GETTEXTRANGE, 0, (LPARAM) &range);
562
563       if (regexec(&re, range.lpstrText, 1, &match, 0) == 0)
564       {
565          szResult = range.lpstrText;
566       }
567       else
568       {
569          free(range.lpstrText);
570       }
571
572       regfree(&re);
573    }
574    return szResult;
575
576 }
577
578
579 /*********************************************************************
580  *
581  * Function    :  LogPutString
582  *
583  * Description :  Inserts text into the logging window.  This is really
584  *                a regexp aware wrapper function to `LogPutStringNoMatch'.
585  *
586  * Parameters  :
587  *          1  :  pszText = pointer to string going to the log window
588  *
589  * Returns     :  1 => success, else the return code from `LogPutStringNoMatch'.
590  *                FIXME: this is backwards to the rest of IJB and to common
591  *                programming practice.  Please use 0 => success instead.
592  *
593  *********************************************************************/
594 int LogPutString(const char *pszText)
595 {
596    int i;
597    int result = 0;
598
599    if (pszText == NULL || strlen(pszText) == 0)
600    {
601       return 1;
602    }
603
604    if (!g_bLogMessages)
605    {
606       return 1;
607    }
608
609    /* Critical section stops multiple threads doing nasty interactions that
610     * foul up the highlighting and output.
611     */
612    EnterCriticalSection(&g_criticalsection);
613
614    if (g_bHighlightMessages)
615    {
616       regmatch_t match;
617
618       /* First things first, regexp scan for various things that we would like highlighted */
619       for (i = 0; patterns_to_highlight[i].str != NULL; i++)
620       {
621          if (regexec(&patterns_to_highlight[i].buffer, pszText, 1, &match, 0) == 0)
622          {
623             char *pszBefore = NULL;
624             char *pszMatch = NULL;
625             char *pszAfter = NULL;
626             int nMatchSize;
627
628             /* Split the string up into pieces representing the strings, before
629                at and after the matching pattern
630              */
631             if (match.rm_so > 0)
632             {
633                pszBefore = (char *)malloc((match.rm_so + 1) * sizeof(char));
634                memset(pszBefore, 0, (match.rm_so + 1) * sizeof(char));
635                strncpy(pszBefore, pszText, match.rm_so);
636             }
637             if (match.rm_eo < (regoff_t)strlen(pszText))
638             {
639                pszAfter = strdup(&pszText[match.rm_eo]);
640             }
641             nMatchSize = match.rm_eo - match.rm_so;
642             pszMatch = (char *)malloc(nMatchSize + 1);
643             strncpy(pszMatch, &pszText[match.rm_so], nMatchSize);
644             pszMatch[nMatchSize] = '\0';
645
646             /* Recursively call LogPutString */
647             if (pszBefore)
648             {
649                LogPutString(pszBefore);
650                free(pszBefore);
651             }
652             if (pszMatch)
653             {
654                LogPutStringNoMatch(pszMatch, patterns_to_highlight[i].style);
655                free(pszMatch);
656             }
657             if (pszAfter)
658             {
659                LogPutString(pszAfter);
660                free(pszAfter);
661             }
662
663             result = 1;
664             goto end;
665          }
666       }
667    }
668
669    result = LogPutStringNoMatch(pszText, STYLE_NONE);
670
671 end:
672    LeaveCriticalSection(&g_criticalsection);
673
674    return result;
675
676 }
677
678
679 /*********************************************************************
680  *
681  * Function    :  LogPutStringNoMatch
682  *
683  * Description :  Puts a string into the logging window.
684  *
685  * Parameters  :
686  *          1  :  pszText = pointer to string going to the log window
687  *          2  :  style = STYLE_NONE, STYLE_HEADER, STYLE_HIGHLIGHT, or STYLE_LINK
688  *
689  * Returns     :  Always 1 => success.
690  *                FIXME: this is backwards to the rest of IJB and to common
691  *                programming practice.  Please use 0 => success instead.
692  *
693  *********************************************************************/
694 int LogPutStringNoMatch(const char *pszText, int style)
695 {
696    CHARRANGE range;
697    CHARFORMAT format;
698    int nTextLength;
699
700    assert(g_hwndLogBox);
701    if (g_hwndLogBox == NULL)
702    {
703       return 1;
704    }
705
706    /* TODO preserve existing selection */
707
708    /* Go to the end of the text */
709    nTextLength = GetWindowTextLength(g_hwndLogBox);
710    range.cpMin = nTextLength;
711    range.cpMax = nTextLength;
712    SendMessage(g_hwndLogBox, EM_EXSETSEL, 0, (LPARAM) &range);
713
714    /* Apply a formatting style */
715    memset(&format, 0, sizeof(format));
716    format.cbSize = sizeof(format);
717    format.dwMask = CFM_BOLD | CFM_UNDERLINE | CFM_STRIKEOUT |
718       CFM_ITALIC | CFM_COLOR | CFM_FACE | CFM_SIZE | CFM_CHARSET;
719    format.bCharSet = DEFAULT_CHARSET;
720    format.yHeight = (g_nFontSize * 1440) / 72;
721    strlcpy(format.szFaceName, g_szFontFaceName, sizeof(format.szFaceName));
722    if (style == STYLE_NONE)
723    {
724       /* DO NOTHING */
725       format.dwEffects |= CFE_AUTOCOLOR;
726    }
727    else if (style == STYLE_HEADER)
728    {
729       format.dwEffects |= CFE_AUTOCOLOR | CFE_ITALIC;
730    }
731    else if (style == STYLE_HIGHLIGHT)
732    {
733       format.dwEffects |= CFE_AUTOCOLOR | CFE_BOLD;
734    }
735    else if (style == STYLE_LINK)
736    {
737       format.dwEffects |= CFE_UNDERLINE;
738       format.crTextColor = RGB(0, 0, 255);
739    }
740    SendMessage(g_hwndLogBox, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &format);
741
742    /* Append text to the end */
743    SendMessage(g_hwndLogBox, EM_REPLACESEL, FALSE, (LPARAM) pszText);
744
745    /* TODO Restore the old selection */
746
747    /* Purge buffer */
748    if (strchr(pszText, '\n') != NULL)
749    {
750       SetTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_ID, TIMER_CLIPBUFFER_TIME, NULL);
751       if (!g_bClipPending)
752       {
753          /* Set the force clip timer going. This timer ensures clipping is done
754             intermittently even when there is a sustained burst of logging
755          */
756          SetTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_FORCE_ID, TIMER_CLIPBUFFER_FORCE_TIME, NULL);
757       }
758       g_bClipPending = TRUE;
759    }
760
761    return 1;
762
763 }
764
765
766 /*********************************************************************
767  *
768  * Function    :  LogShowActivity
769  *
770  * Description :  Start the spinner.
771  *
772  * Parameters  :  None
773  *
774  * Returns     :  N/A
775  *
776  *********************************************************************/
777 void LogShowActivity(void)
778 {
779    /* Start some activity timers */
780    if (g_bShowActivityAnimation)
781    {
782       SetTimer(g_hwndLogFrame, TIMER_ANIM_ID, TIMER_ANIM_TIME, NULL);
783       SetTimer(g_hwndLogFrame, TIMER_ANIMSTOP_ID, TIMER_ANIMSTOP_TIME, NULL);
784    }
785
786 }
787
788
789 /*********************************************************************
790  *
791  * Function    :  LogClipBuffer
792  *
793  * Description :  Prunes old lines from the log.
794  *
795  * Parameters  :  None
796  *
797  * Returns     :  N/A
798  *
799  *********************************************************************/
800 void LogClipBuffer(void)
801 {
802    int nLines = SendMessage(g_hwndLogBox, EM_GETLINECOUNT, 0, 0);
803    if (g_bLimitBufferSize && nLines > g_nMaxBufferLines)
804    {
805       /* Compute the range representing the lines to be deleted */
806       LONG nLastLineToDelete = nLines - g_nMaxBufferLines;
807       LONG nLastChar = SendMessage(g_hwndLogBox, EM_LINEINDEX, nLastLineToDelete, 0);
808       CHARRANGE range;
809       range.cpMin = 0;
810       range.cpMax = nLastChar;
811
812       /* TODO get current selection */
813
814       /* TODO adjust and clip old selection against range to be deleted */
815
816       /* Select range and erase it (turning off autoscroll to prevent
817          nasty scrolling) */
818       SendMessage(g_hwndLogBox, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOVSCROLL);
819       SendMessage(g_hwndLogBox, EM_EXSETSEL, 0, (LPARAM) &range);
820       SendMessage(g_hwndLogBox, EM_REPLACESEL, FALSE, (LPARAM) "");
821       SendMessage(g_hwndLogBox, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOVSCROLL);
822
823       /* reposition (back to) the end of the log content */
824       range.cpMin = SendMessage (g_hwndLogBox, WM_GETTEXTLENGTH, 0, 0);
825       range.cpMax = -1;
826       SendMessage(g_hwndLogBox, EM_EXSETSEL, 0, (LPARAM) &range);
827  
828       /* restore vertical ScrollBar stuff (messed up by AUTOVSCROLL) */
829       SendMessage (g_hwndLogBox, EM_SCROLL, SB_LINEDOWN, 0);
830  
831    }
832
833 }                                        
834
835
836 /*********************************************************************
837  *
838  * Function    :  CreateHiddenLogOwnerWindow
839  *
840  * Description :  Creates a hidden owner window that stops the log
841  *                window appearing in the task bar.
842  *
843  * Parameters  :
844  *          1  :  hInstance = application's instance handle
845  *
846  * Returns     :  Handle to newly created window.
847  *
848  *********************************************************************/
849 HWND CreateHiddenLogOwnerWindow(HINSTANCE hInstance)
850 {
851    static const char *szWndName = "PrivoxyLogOwner";
852    WNDCLASS wc;
853    HWND hwnd;
854
855    wc.style          = 0;
856    wc.lpfnWndProc    = LogOwnerWindowProc;
857    wc.cbClsExtra     = 0;
858    wc.cbWndExtra     = 0;
859    wc.hInstance      = hInstance;
860    wc.hIcon          = g_hiconApp;
861    wc.hCursor        = 0;
862    wc.hbrBackground  = 0;
863    wc.lpszMenuName   = 0;
864    wc.lpszClassName  = szWndName;
865
866    RegisterClass(&wc);
867
868    hwnd = CreateWindow(szWndName, szWndName,
869       WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
870       CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
871
872    return hwnd;
873
874 }
875
876
877 /*********************************************************************
878  *
879  * Function    :  LogOwnerWindowProc
880  *
881  * Description :  Dummy procedure that does nothing special.
882  *
883  * Parameters  :
884  *          1  :  hwnd = window handle
885  *          2  :  uMsg = message number
886  *          3  :  wParam = first param for this message
887  *          4  :  lParam = next param for this message
888  *
889  * Returns     :  Same as `DefWindowProc'.
890  *
891  *********************************************************************/
892 LRESULT CALLBACK LogOwnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
893 {
894    return DefWindowProc(hwnd, uMsg, wParam, lParam);
895
896 }
897
898
899 /*********************************************************************
900  *
901  * Function    :  CreateLogWindow
902  *
903  * Description :  Create the logging window.
904  *
905  * Parameters  :
906  *          1  :  hInstance = application's instance handle
907  *          2  :  nCmdShow = window show value (MIN, MAX, NORMAL, etc...)
908  *
909  * Returns     :  Handle to newly created window.
910  *
911  *********************************************************************/
912 HWND CreateLogWindow(HINSTANCE hInstance, int nCmdShow)
913 {
914    static const char *szWndName = "PrivoxyLogWindow";
915    static const char *szWndTitle = "Privoxy";
916
917    HWND hwnd = NULL;
918    HWND hwndOwner = (g_bShowOnTaskBar) ? NULL : CreateHiddenLogOwnerWindow(hInstance);
919    RECT rcClient;
920    WNDCLASSEX wc;
921
922    memset(&wc, 0, sizeof(wc));
923    wc.cbSize         = sizeof(wc);
924    wc.style          = CS_DBLCLKS;
925    wc.lpfnWndProc    = LogWindowProc;
926    wc.cbClsExtra     = 0;
927    wc.cbWndExtra     = 0;
928    wc.hInstance      = hInstance;
929    wc.hIcon          = g_hiconApp;
930    wc.hCursor        = 0;
931    wc.hbrBackground  = 0;
932    wc.lpszMenuName   = MAKEINTRESOURCE(IDR_LOGVIEW);
933    wc.lpszClassName  = szWndName;
934    wc.hbrBackground  = GetStockObject(WHITE_BRUSH);
935    RegisterClassEx(&wc);
936
937    hwnd = CreateWindowEx(WS_EX_APPWINDOW, szWndName, szWndTitle,
938       WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
939       CW_USEDEFAULT, hwndOwner, NULL, hInstance, NULL);
940
941    /* Now create a child list box */
942    GetClientRect(hwnd, &rcClient);
943
944    /* Create a rich edit control */
945    InitRichEdit();
946    g_hwndLogBox = CreateWindowEx(0, (g_nRichEditVersion == 0x0100) ? "RichEdit" : RICHEDIT_CLASS, "",
947       ES_AUTOVSCROLL | ES_MULTILINE | ES_READONLY | ES_NOHIDESEL | WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
948       rcClient.left, rcClient.top, rcClient.right, rcClient.bottom,
949       hwnd, NULL, hInstance, NULL);
950 /* SendMessage(g_hwndLogBox, EM_SETWORDWRAPMODE, 0, 0); */
951
952    /* Subclass the control to catch certain messages */
953    g_fnLogBox = (WNDPROC) GetWindowLong(g_hwndLogBox, GWL_WNDPROC);
954    SetWindowLong(g_hwndLogBox, GWL_WNDPROC, (LONG) LogRichEditProc);
955
956    /* Minimizing looks stupid when the log window is not on the task bar, so hide instead */
957    if (!g_bShowOnTaskBar &&
958          (nCmdShow == SW_SHOWMINIMIZED ||
959           nCmdShow == SW_MINIMIZE ||
960           nCmdShow == SW_SHOWMINNOACTIVE))
961    {
962       g_bShowLogWindow = FALSE;
963       nCmdShow = SW_HIDE;
964    }
965
966    ShowWindow(hwnd, nCmdShow);
967    UpdateWindow(hwnd);
968
969
970    GetClientRect(g_hwndLogFrame, &rcClient);
971    SetWindowPos(g_hwndLogBox, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, SWP_NOZORDER);
972
973    return hwnd;
974
975 }
976
977
978 /*********************************************************************
979  *
980  * Function    :  InitRichEdit
981  *
982  * Description :  Initialise the rich edit control library.
983  *
984  * Parameters  :  None
985  *
986  * Returns     :  TRUE => success, FALSE => failure.
987  *                FIXME: this is backwards to the rest of IJB and to common
988  *                programming practice.  Please use 0 => success instead.
989  *
990  *********************************************************************/
991 BOOL InitRichEdit(void)
992 {
993    static HINSTANCE hInstRichEdit;
994    if (hInstRichEdit == NULL)
995    {
996       g_nRichEditVersion = 0;
997       hInstRichEdit = LoadLibraryA("RICHED20.DLL");
998       if (hInstRichEdit)
999       {
1000          g_nRichEditVersion = _RICHEDIT_VER;
1001       }
1002       else
1003       {
1004          hInstRichEdit = LoadLibraryA("RICHED32.DLL");
1005          if (hInstRichEdit)
1006          {
1007             g_nRichEditVersion = 0x0100;
1008          }
1009       }
1010    }
1011    return (hInstRichEdit != NULL) ? TRUE : FALSE;
1012
1013 }
1014
1015
1016 /*********************************************************************
1017  *
1018  * Function    :  ShowLogWindow
1019  *
1020  * Description :  Shows or hides the log window.  We will also raise the
1021  *                window on a show command in case it is buried.
1022  *
1023  * Parameters  :
1024  *          1  :  bShow = TRUE to show, FALSE to mimize/hide
1025  *
1026  * Returns     :  N/A
1027  *
1028  *********************************************************************/
1029 void ShowLogWindow(BOOL bShow)
1030 {
1031    if (bShow)
1032    {
1033       SetForegroundWindow(g_hwndLogFrame);
1034       SetWindowPos(g_hwndLogFrame, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
1035       
1036    }
1037    else if (g_bShowOnTaskBar)
1038    {
1039       ShowWindow(g_hwndLogFrame, SW_MINIMIZE);
1040    }
1041    else
1042    {
1043       ShowWindow(g_hwndLogFrame, SW_HIDE);
1044    }
1045 }
1046
1047
1048 /*********************************************************************
1049  *
1050  * Function    :  EditFile
1051  *
1052  * Description :  Opens the specified setting file for editing.
1053  * FIXME: What if the file has no associated application. Check for return values
1054 *        from ShellExecute??
1055  *
1056  * Parameters  :
1057  *          1  :  filename = filename from the config (aka config.txt) file.
1058  *
1059  * Returns     :  N/A
1060  *
1061  *********************************************************************/
1062 void EditFile(const char *filename)
1063 {
1064    if (filename)
1065    {
1066       ShellExecute(g_hwndLogFrame, "open", filename, NULL, NULL, SW_SHOWNORMAL);
1067    }
1068
1069 }
1070
1071
1072 /*--------------------------------------------------------------------------*/
1073 /* Windows message handlers                                                 */
1074 /*--------------------------------------------------------------------------*/
1075
1076
1077 /*********************************************************************
1078  *
1079  * Function    :  OnLogRButtonUp
1080  *
1081  * Description :  Handler for WM_RBUTTONUP messages.
1082  *
1083  * Parameters  :
1084  *          1  :  nModifier = wParam from mouse message (unused)
1085  *          2  :  x = x coordinate of the mouse event
1086  *          3  :  y = y coordinate of the mouse event
1087  *
1088  * Returns     :  N/A
1089  *
1090  *********************************************************************/
1091 void OnLogRButtonUp(int nModifier, int x, int y)
1092 {
1093    HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_POPUP_SELECTION));
1094    if (hMenu != NULL)
1095    {
1096       HMENU hMenuPopup = GetSubMenu(hMenu, 0);
1097
1098       /* Check if there is a selection */
1099       CHARRANGE range;
1100       SendMessage(g_hwndLogBox, EM_EXGETSEL, 0, (LPARAM) &range);
1101       if (range.cpMin == range.cpMax)
1102       {
1103          EnableMenuItem(hMenuPopup, ID_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED);
1104       }
1105       else
1106       {
1107          EnableMenuItem(hMenuPopup, ID_EDIT_COPY, MF_BYCOMMAND | MF_ENABLED);
1108       }
1109
1110       /* Display the popup */
1111       TrackPopupMenu(hMenuPopup, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, x, y, 0, g_hwndLogFrame, NULL);
1112       DestroyMenu(hMenu);
1113    }
1114
1115 }
1116
1117
1118 /*********************************************************************
1119  *
1120  * Function    :  OnLogCommand
1121  *
1122  * Description :  Handler for WM_COMMAND messages.
1123  *
1124  * Parameters  :
1125  *          1  :  nCommand = the command portion of the menu selection event
1126  *
1127  * Returns     :  N/A
1128  *
1129  *********************************************************************/
1130 void OnLogCommand(int nCommand)
1131 {
1132    switch (nCommand)
1133    {
1134       case ID_TOGGLE_SHOWWINDOW:
1135          g_bShowLogWindow = !g_bShowLogWindow;
1136
1137          ShowLogWindow(g_bShowLogWindow);
1138          break;
1139
1140       case ID_FILE_EXIT:
1141          PostMessage(g_hwndLogFrame, WM_CLOSE, 0, 0);
1142          break;
1143
1144       case ID_EDIT_COPY:
1145          SendMessage(g_hwndLogBox, WM_COPY, 0, 0);
1146          break;
1147
1148       case ID_VIEW_CLEARLOG:
1149          SendMessage(g_hwndLogBox, WM_SETTEXT, 0, (LPARAM) "");
1150          break;
1151
1152       case ID_VIEW_LOGMESSAGES:
1153          g_bLogMessages = !g_bLogMessages;
1154          /* SaveLogSettings(); */
1155          break;
1156
1157       case ID_VIEW_MESSAGEHIGHLIGHTING:
1158          g_bHighlightMessages = !g_bHighlightMessages;
1159          /* SaveLogSettings(); */
1160          break;
1161
1162       case ID_VIEW_LIMITBUFFERSIZE:
1163          g_bLimitBufferSize = !g_bLimitBufferSize;
1164          /* SaveLogSettings(); */
1165          break;
1166
1167       case ID_VIEW_ACTIVITYANIMATION:
1168          g_bShowActivityAnimation = !g_bShowActivityAnimation;
1169          /* SaveLogSettings(); */
1170          break;
1171
1172 #ifdef FEATURE_TOGGLE
1173       /* by haroon - change toggle to its opposite value */
1174       case ID_TOGGLE_ENABLED:
1175          global_toggle_state = !global_toggle_state;
1176          if (global_toggle_state)
1177          {
1178             log_error(LOG_LEVEL_INFO, "Now toggled ON.");
1179          }
1180          else
1181          {
1182             log_error(LOG_LEVEL_INFO, "Now toggled OFF.");
1183          }
1184          SetIdleIcon();
1185          break;
1186 #endif /* def FEATURE_TOGGLE */
1187
1188       case ID_TOOLS_EDITCONFIG:
1189          EditFile(configfile);
1190          break;
1191
1192       case ID_TOOLS_EDITDEFAULTACTIONS:
1193          EditFile(g_default_actions_file);
1194          break;
1195
1196       case ID_TOOLS_EDITUSERACTIONS:
1197          EditFile(g_user_actions_file);
1198          break;
1199
1200       case ID_TOOLS_EDITFILTERS:
1201          EditFile(g_re_filterfile);
1202          break;
1203
1204 #ifdef FEATURE_TRUST
1205       case ID_TOOLS_EDITTRUST:
1206          EditFile(g_trustfile);
1207          break;
1208 #endif /* def FEATURE_TRUST */
1209
1210       case ID_HELP_GPL:
1211          ShellExecute(g_hwndLogFrame, "open", "LICENSE.txt", NULL, NULL, SW_SHOWNORMAL);
1212          break;
1213
1214       case ID_HELP_FAQ:
1215          ShellExecute(g_hwndLogFrame, "open", "doc\\faq\\index.html", NULL, NULL, SW_SHOWNORMAL);
1216          break;
1217
1218       case ID_HELP_MANUAL:
1219          ShellExecute(g_hwndLogFrame, "open", "doc\\user-manual\\index.html", NULL, NULL, SW_SHOWNORMAL);
1220          break;
1221
1222       case ID_HELP_STATUS:
1223          ShellExecute(g_hwndLogFrame, "open", CGI_PREFIX "show-status", NULL, NULL, SW_SHOWNORMAL);
1224          break;
1225
1226       case ID_HELP_ABOUT:
1227          MessageBox(g_hwndLogFrame, win32_blurb, "About Privoxy", MB_OK);
1228          break;
1229
1230       default:
1231          /* DO NOTHING */
1232          break;
1233    }
1234
1235 }
1236
1237
1238 /*********************************************************************
1239  *
1240  * Function    :  OnLogInitMenu
1241  *
1242  * Description :  Handler for WM_INITMENU messages.  Enable, disable,
1243  *                check, and/or uncheck menu options as apropos.
1244  *
1245  * Parameters  :
1246  *          1  :  hmenu = handle to menu to "make current"
1247  *
1248  * Returns     :  N/A
1249  *
1250  *********************************************************************/
1251 void OnLogInitMenu(HMENU hmenu)
1252 {
1253    /* Only enable editors if there is a file to edit */
1254    EnableMenuItem(hmenu, ID_TOOLS_EDITDEFAULTACTIONS, MF_BYCOMMAND | (g_default_actions_file ? MF_ENABLED : MF_GRAYED));
1255    EnableMenuItem(hmenu, ID_TOOLS_EDITUSERACTIONS, MF_BYCOMMAND | (g_user_actions_file ? MF_ENABLED : MF_GRAYED));
1256    EnableMenuItem(hmenu, ID_TOOLS_EDITFILTERS, MF_BYCOMMAND | (g_re_filterfile ? MF_ENABLED : MF_GRAYED));
1257 #ifdef FEATURE_TRUST
1258    EnableMenuItem(hmenu, ID_TOOLS_EDITTRUST, MF_BYCOMMAND | (g_trustfile ? MF_ENABLED : MF_GRAYED));
1259 #endif /* def FEATURE_TRUST */
1260
1261    /* Check/uncheck options */
1262    CheckMenuItem(hmenu, ID_VIEW_LOGMESSAGES, MF_BYCOMMAND | (g_bLogMessages ? MF_CHECKED : MF_UNCHECKED));
1263    CheckMenuItem(hmenu, ID_VIEW_MESSAGEHIGHLIGHTING, MF_BYCOMMAND | (g_bHighlightMessages ? MF_CHECKED : MF_UNCHECKED));
1264    CheckMenuItem(hmenu, ID_VIEW_LIMITBUFFERSIZE, MF_BYCOMMAND | (g_bLimitBufferSize ? MF_CHECKED : MF_UNCHECKED));
1265    CheckMenuItem(hmenu, ID_VIEW_ACTIVITYANIMATION, MF_BYCOMMAND | (g_bShowActivityAnimation ? MF_CHECKED : MF_UNCHECKED));
1266 #ifdef FEATURE_TOGGLE
1267    /* by haroon - menu item for Enable toggle on/off */
1268    CheckMenuItem(hmenu, ID_TOGGLE_ENABLED, MF_BYCOMMAND | (global_toggle_state ? MF_CHECKED : MF_UNCHECKED));
1269 #endif /* def FEATURE_TOGGLE */
1270    CheckMenuItem(hmenu, ID_TOGGLE_SHOWWINDOW, MF_BYCOMMAND | (g_bShowLogWindow ? MF_CHECKED : MF_UNCHECKED));
1271
1272 }
1273
1274
1275 /*********************************************************************
1276  *
1277  * Function    :  OnLogTimer
1278  *
1279  * Description :  Handler for WM_TIMER messages.
1280  *
1281  * Parameters  :
1282  *          1  :  nTimer = timer id (animation start/stop or clip buffer)
1283  *
1284  * Returns     :  N/A
1285  *
1286  *********************************************************************/
1287 void OnLogTimer(int nTimer)
1288 {
1289    switch (nTimer)
1290    {
1291       case TIMER_ANIM_ID:
1292          TraySetIcon(g_hwndTray, 1, g_hiconAnim[g_nAnimFrame++ % ANIM_FRAMES]);
1293          break;
1294
1295       case TIMER_ANIMSTOP_ID:
1296          g_nAnimFrame = 0;
1297          SetIdleIcon();
1298          KillTimer(g_hwndLogFrame, TIMER_ANIM_ID);
1299          KillTimer(g_hwndLogFrame, TIMER_ANIMSTOP_ID);
1300          break;
1301
1302       case TIMER_CLIPBUFFER_ID:
1303       case TIMER_CLIPBUFFER_FORCE_ID:
1304          LogClipBuffer();
1305          g_bClipPending = FALSE;
1306          KillTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_ID);
1307          KillTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_FORCE_ID);
1308          break;
1309
1310       default:
1311          /* DO NOTHING */
1312          break;
1313    }
1314
1315 }
1316
1317
1318 /*********************************************************************
1319  *
1320  * Function    :  SetIdleIcon
1321  *
1322  * Description :  Sets the tray icon to either idle or off
1323  *
1324  * Parameters  :  none
1325  *
1326  * Returns     :  N/A
1327  *
1328  *********************************************************************/
1329 void SetIdleIcon()
1330 {
1331 #ifdef FEATURE_TOGGLE
1332          if (!global_toggle_state)
1333          {
1334             TraySetIcon(g_hwndTray, 1, g_hiconOff);
1335             /* log_error(LOG_LEVEL_INFO, "Privoxy OFF icon selected."); */
1336          }
1337          else
1338 #endif /* def FEATURE_TOGGLE */
1339          TraySetIcon(g_hwndTray, 1, g_hiconIdle);
1340 }
1341
1342
1343 /*********************************************************************
1344  *
1345  * Function    :  LogRichEditProc
1346  *
1347  * Description :  Window subclass routine handles some events for the rich edit control.
1348  *
1349  * Parameters  :
1350  *          1  :  hwnd = window handle of the rich edit control
1351  *          2  :  uMsg = message number
1352  *          3  :  wParam = first param for this message
1353  *          4  :  lParam = next param for this message
1354  *
1355  * Returns     :  Appropriate M$ window message handler codes.
1356  *
1357  *********************************************************************/
1358 LRESULT CALLBACK LogRichEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1359 {
1360    switch (uMsg)
1361    {
1362       case WM_RBUTTONUP:
1363       {
1364          POINT pt;
1365          pt.x = LOWORD(lParam);
1366          pt.y = HIWORD(lParam);
1367          ClientToScreen(hwnd, &pt);
1368          OnLogRButtonUp(wParam, pt.x, pt.y);
1369          return 0;
1370       }
1371       case WM_CHAR:
1372       {
1373          if ((GetKeyState(VK_CONTROL) != 0) && (wParam == 4)) /* ctrl+d */
1374          {
1375              OnLogCommand(ID_VIEW_CLEARLOG);
1376              return 0;
1377          }
1378       }
1379    }
1380    return CallWindowProc(g_fnLogBox, hwnd, uMsg, wParam, lParam);
1381
1382 }
1383
1384
1385 /*********************************************************************
1386  *
1387  * Function    :  LogWindowProc
1388  *
1389  * Description :  Windows call back routine handles events on the log window.
1390  *
1391  * Parameters  :
1392  *          1  :  hwnd = handle of the logging window
1393  *          2  :  uMsg = message number
1394  *          3  :  wParam = first param for this message
1395  *          4  :  lParam = next param for this message
1396  *
1397  * Returns     :  Appropriate M$ window message handler codes.
1398  *
1399  *********************************************************************/
1400 LRESULT CALLBACK LogWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1401 {
1402    switch (uMsg)
1403    {
1404       case WM_CREATE:
1405          return 0;
1406
1407       case WM_CLOSE:
1408          /* This is the end - beautiful friend - the end */
1409          DestroyWindow(g_hwndLogBox);
1410          DestroyWindow(g_hwndLogFrame);
1411          return 0;
1412
1413       case WM_DESTROY:
1414          PostQuitMessage(0);
1415          return 0;
1416
1417       case WM_SHOWWINDOW:
1418          g_bShowLogWindow = wParam;
1419       case WM_SIZE:
1420          /* Resize the logging window to fit the new frame */
1421          if (g_hwndLogBox)
1422          {
1423             RECT rc;
1424             GetClientRect(g_hwndLogFrame, &rc);
1425             SetWindowPos(g_hwndLogBox, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER);
1426          }
1427          return 0;
1428
1429       case WM_INITMENU:
1430          OnLogInitMenu((HMENU) wParam);
1431          return 0;
1432
1433       case WM_TIMER:
1434          OnLogTimer(wParam);
1435          return 0;
1436
1437       case WM_COMMAND:
1438          OnLogCommand(LOWORD(wParam));
1439          return 0;
1440
1441       case WM_SYSCOMMAND:
1442          switch (wParam)
1443          {
1444             case SC_CLOSE:
1445                if (g_bCloseHidesWindow)
1446                {
1447                   ShowLogWindow(FALSE);
1448                   return 0;
1449                }
1450                break;
1451             case SC_MINIMIZE:
1452                ShowLogWindow(FALSE);
1453                return 0;
1454          }
1455          break;
1456
1457       case WM_CHAR:
1458          if ((GetKeyState(VK_CONTROL) != 0) && (wParam == 4)) /* ctrl+d */
1459          {
1460              OnLogCommand(ID_VIEW_CLEARLOG);
1461              return 0;
1462          }
1463          break;
1464    }
1465
1466    return DefWindowProc(hwnd, uMsg, wParam, lParam);
1467
1468 }
1469
1470 #endif /* ndef _WIN_CONSOLE - entire file */
1471
1472 /*
1473   Local Variables:
1474   tab-width: 3
1475   end:
1476 */