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