Fix endless loop in the logging system when -d=5. Reported by _static_.
[jelmer/ctrlproxy.git] / src / log.c
1 /*
2         ctrlproxy: A modular IRC proxy
3         (c) 2002-2005 Jelmer Vernooij <jelmer@nl.linux.org>
4
5         This program is free software; you can redistribute it and/or modify
6         it under the terms of the GNU General Public License as published by
7         the Free Software Foundation; either version 2 of the License, or
8         (at your option) any later version.
9
10         This program is distributed in the hope that it will be useful,
11         but WITHOUT ANY WARRANTY; without even the implied warranty of
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13         GNU General Public License for more details.
14
15         You should have received a copy of the GNU General Public License
16         along with this program; if not, write to the Free Software
17         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "internals.h"
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 static const char *get_date(void)
28 {
29         static char ret[40];
30         time_t t = time(NULL);
31         strftime(ret, sizeof(ret), "%F %H:%M:%S", localtime(&t));
32         return ret;
33 }
34
35 gboolean no_log_timestamp = FALSE;
36 enum log_level current_log_level = LOG_INFO;
37 FILE *flog = NULL;
38
39 static void log_entry(enum log_level level, const struct network *n, const struct client *c, const char *data)
40 {
41         if (flog == NULL)
42                 return;
43
44         if (level > current_log_level)
45                 return;
46
47         if (level < LOG_DATA)
48                 admin_log(level, n, c, data);
49         
50         if (!no_log_timestamp)
51                 fprintf(flog, "[%s] ", get_date());
52         
53         g_assert(strchr(data, '\n') == NULL);
54         fprintf(flog, "%s", data);
55
56         if (n) {
57                 fprintf(flog, " (%s", n->name);
58
59                 if (c)
60                         fprintf(flog, "/%s", c->description);
61
62                 fprintf(flog, ")");
63         }
64
65         fprintf(flog, "\n");
66         fflush(flog);
67 }
68
69 void log_network_line(const struct network *n, const struct line *l, gboolean incoming)
70 {
71         char *raw;
72         if (current_log_level < LOG_DATA)
73                 return;
74
75         raw = irc_line_string(l);
76         log_network(LOG_DATA, n, "%c %s", incoming?'<':'>', raw);
77         g_free(raw);
78 }
79
80 void log_client_line(const struct client *n, const struct line *l, gboolean incoming)
81 {
82         char *raw;
83         if (current_log_level < LOG_DATA)
84                 return;
85
86         raw = irc_line_string(l);
87         log_client(LOG_DATA, n, "%c %s", incoming?'<':'>', raw);
88         g_free(raw);
89 }
90
91 void log_network(enum log_level level, const struct network *n, const char *fmt, ...)
92 {
93         va_list ap;     
94         char *tmp; 
95         va_start(ap, fmt);
96         tmp = g_strdup_vprintf(fmt, ap);
97         log_entry(level, n, NULL, tmp);
98         va_end(ap);
99         g_free(tmp);
100 }
101
102 void log_client(enum log_level level, const struct client *c, const char *fmt, ...)
103 {
104         va_list ap;     
105         char *tmp; 
106         va_start(ap, fmt);
107         tmp = g_strdup_vprintf(fmt, ap);
108         va_end(ap);
109         log_entry(level, c->network, c, tmp);
110         g_free(tmp);
111 }
112
113 void log_global(enum log_level level, const char *fmt, ...)
114 {
115         va_list ap;     
116         char *tmp; 
117         va_start(ap, fmt);
118         tmp = g_strdup_vprintf(fmt, ap);
119         va_end(ap);
120         log_entry(level, NULL, NULL, tmp);
121         g_free(tmp);
122 }
123
124
125
126 static void log_handler(const gchar *log_domain, GLogLevelFlags flags, const gchar *message, gpointer user_data) {
127         log_global(LOG_ERROR, "[%s] %s", log_domain, message);
128 }
129
130 static void fini_log(void)
131 {
132         log_global(LOG_INFO, "Closing log file");
133         if (flog != stderr) {
134                 fclose(flog);
135         }
136         flog = NULL;
137 }
138
139 gboolean init_log(const char *lf)
140 {
141         g_log_set_handler ("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, log_handler, NULL);
142
143         if (!lf) {
144                 flog = stderr;
145                 return TRUE;
146         }
147
148         flog = fopen(lf, "a+");
149         if (!flog) {
150                 perror("Opening log file");
151                 return FALSE;
152         }
153
154         atexit(fini_log);
155
156         log_global(LOG_INFO, "Opening log file");
157         return TRUE;
158 }