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