source: logging.c @ 8f5afcf

Last change on this file since 8f5afcf was 06af663, checked in by David Benjamin <davidben@mit.edu>, 13 years ago
Use g_build_filename instead of g_strdup_printf to build paths Saves us a duplicate slash in a few places, although most of the time it doesn't do anything. Eh, may as well use it and be more explicit or something. Also change the one existing call to g_build_path to g_build_filename instead. It's much less of a pain to use.
  • Property mode set to 100644
File size: 13.2 KB
Line 
1#include "owl.h"
2#include <stdlib.h>
3#include <string.h>
4#include <ctype.h>
5#include <sys/param.h>
6
7typedef struct _owl_log_entry { /* noproto */
8  char *filename;
9  char *message;
10} owl_log_entry;
11
12
13static GMainContext *log_context;
14static GMainLoop *log_loop;
15static GThread *logging_thread;
16
17/* This is now the one function that should be called to log a
18 * message.  It will do all the work necessary by calling the other
19 * functions in this file as necessary.
20 */
21void owl_log_message(const owl_message *m) {
22  owl_function_debugmsg("owl_log_message: entering");
23
24  if (m == NULL) {
25    owl_function_debugmsg("owl_log_message: passed null message");
26    return;
27  }
28
29  /* should we be logging this message? */
30  if (!owl_log_shouldlog_message(m)) {
31    owl_function_debugmsg("owl_log_message: not logging message");
32    return;
33  }
34
35  /* handle incmoing messages */
36  if (owl_message_is_direction_in(m)) {
37    owl_log_incoming(m);
38    owl_function_debugmsg("owl_log_message: leaving");
39    return;
40  }
41
42  /* handle outgoing messages */
43  owl_log_outgoing(m);
44
45  owl_function_debugmsg("owl_log_message: leaving");
46}
47
48/* Return 1 if we should log the given message, otherwise return 0 */
49int owl_log_shouldlog_message(const owl_message *m) {
50  const owl_filter *f;
51
52  /* If there's a logfilter and this message matches it, log */
53  f=owl_global_get_filter(&g, owl_global_get_logfilter(&g));
54  if (f && owl_filter_message_match(f, m)) return(1);
55
56  /* otherwise we do things based on the logging variables */
57
58  /* skip login/logout messages if appropriate */
59  if (!owl_global_is_loglogins(&g) && owl_message_is_loginout(m)) return(0);
60     
61  /* check direction */
62  if ((owl_global_get_loggingdirection(&g)==OWL_LOGGING_DIRECTION_IN) && owl_message_is_direction_out(m)) {
63    return(0);
64  }
65  if ((owl_global_get_loggingdirection(&g)==OWL_LOGGING_DIRECTION_OUT) && owl_message_is_direction_in(m)) {
66    return(0);
67  }
68
69  if (owl_message_is_type_zephyr(m)) {
70    if (owl_message_is_personal(m) && !owl_global_is_logging(&g)) return(0);
71    if (!owl_message_is_personal(m) && !owl_global_is_classlogging(&g)) return(0);
72  } else {
73    if (owl_message_is_private(m) || owl_message_is_loginout(m)) {
74      if (!owl_global_is_logging(&g)) return(0);
75    } else {
76      if (!owl_global_is_classlogging(&g)) return(0);
77    }
78  }
79  return(1);
80}
81
82CALLER_OWN char *owl_log_zephyr(const owl_message *m)
83{
84    char *tmp = NULL;
85    GString *buffer = NULL;
86    buffer = g_string_new("");
87    tmp = short_zuser(owl_message_get_sender(m));
88    g_string_append_printf(buffer, "Class: %s Instance: %s", 
89                           owl_message_get_class(m), 
90                           owl_message_get_instance(m));
91    if (strcmp(owl_message_get_opcode(m), "")) {
92      g_string_append_printf(buffer, " Opcode: %s", 
93                             owl_message_get_opcode(m));
94    }
95    g_string_append_printf(buffer, "\n");
96    g_string_append_printf(buffer, "Time: %s Host: %s\n", 
97                           owl_message_get_timestr(m), 
98                           owl_message_get_hostname(m));
99    g_string_append_printf(buffer, "From: %s <%s>\n\n", 
100                           owl_message_get_zsig(m), tmp);
101    g_string_append_printf(buffer, "%s\n\n", owl_message_get_body(m));
102    g_free(tmp);
103    return g_string_free(buffer, FALSE);
104}
105
106CALLER_OWN char *owl_log_aim(const owl_message *m)
107{
108    GString *buffer = NULL;
109    buffer = g_string_new("");
110    g_string_append_printf(buffer, "From: <%s> To: <%s>\n", 
111                           owl_message_get_sender(m), owl_message_get_recipient(m));
112    g_string_append_printf(buffer, "Time: %s\n\n", 
113                           owl_message_get_timestr(m));
114    if (owl_message_is_login(m)) {
115        g_string_append_printf(buffer, "LOGIN\n\n");
116    } else if (owl_message_is_logout(m)) {
117        g_string_append_printf(buffer, "LOGOUT\n\n");
118    } else {
119        g_string_append_printf(buffer, "%s\n\n", owl_message_get_body(m));
120    }
121    return g_string_free(buffer, FALSE);
122}
123
124CALLER_OWN char *owl_log_jabber(const owl_message *m)
125{
126    GString *buffer = NULL;
127    buffer = g_string_new("");
128    g_string_append_printf(buffer, "From: <%s> To: <%s>\n",
129                           owl_message_get_sender(m), 
130                           owl_message_get_recipient(m));
131    g_string_append_printf(buffer, "Time: %s\n\n", 
132                           owl_message_get_timestr(m));
133    g_string_append_printf(buffer, "%s\n\n", owl_message_get_body(m));
134    return g_string_free(buffer, FALSE);
135}
136
137CALLER_OWN char *owl_log_generic(const owl_message *m)
138{
139    GString *buffer;
140    buffer = g_string_new("");
141    g_string_append_printf(buffer, "From: <%s> To: <%s>\n", 
142                           owl_message_get_sender(m), 
143                           owl_message_get_recipient(m));
144    g_string_append_printf(buffer, "Time: %s\n\n", 
145                           owl_message_get_timestr(m));
146    g_string_append_printf(buffer, "%s\n\n", 
147                           owl_message_get_body(m));
148    return g_string_free(buffer, FALSE);
149}
150
151static void owl_log_error_main_thread(gpointer data)
152{
153  owl_function_error("%s", (const char*)data);
154}
155
156static void owl_log_error(const char *message)
157{
158  char *data = g_strdup(message);
159  owl_select_post_task(owl_log_error_main_thread,
160                       data, g_free, g_main_context_default());
161}
162
163static void owl_log_write_entry(gpointer data)
164{
165  owl_log_entry *msg = (owl_log_entry*)data;
166  FILE *file = NULL;
167  file = fopen(msg->filename, "a");
168  if (!file) {
169    owl_log_error("Unable to open file for logging");
170    return;
171  }
172  fprintf(file, "%s", msg->message);
173  fclose(file);
174}
175
176static void owl_log_entry_free(void *data)
177{
178  owl_log_entry *msg = (owl_log_entry*)data;
179  if (msg) {
180    g_free(msg->message);
181    g_free(msg->filename);
182    g_free(msg);
183  }
184}
185
186void owl_log_enqueue_message(const char *buffer, const char *filename)
187{
188  owl_log_entry *log_msg = NULL; 
189  log_msg = g_new(owl_log_entry,1);
190  log_msg->message = g_strdup(buffer);
191  log_msg->filename = g_strdup(filename);
192  owl_select_post_task(owl_log_write_entry, log_msg, 
193                       owl_log_entry_free, log_context);
194}
195
196void owl_log_append(const owl_message *m, const char *filename) {
197  char *buffer = NULL;
198  if (owl_message_is_type_zephyr(m)) {
199    buffer = owl_log_zephyr(m);
200  } else if (owl_message_is_type_jabber(m)) {
201    buffer = owl_log_jabber(m);
202  } else if (owl_message_is_type_aim(m)) {
203    buffer = owl_log_aim(m);
204  } else {
205    buffer = owl_log_generic(m);
206  }
207  owl_log_enqueue_message(buffer, filename);
208  g_free(buffer);
209}
210
211void owl_log_outgoing(const owl_message *m)
212{
213  char *filename, *logpath;
214  char *to, *temp;
215  GList *cc;
216
217  /* expand ~ in path names */
218  logpath = owl_util_makepath(owl_global_get_logpath(&g));
219
220  /* Figure out what path to log to */
221  if (owl_message_is_type_zephyr(m)) {
222    /* If this has CC's, do all but the "recipient" which we'll do below */
223    cc = owl_message_get_cc_without_recipient(m);
224    while (cc != NULL) {
225      temp = short_zuser(cc->data);
226      filename = g_build_filename(logpath, temp, NULL);
227      owl_log_append(m, filename);
228
229      g_free(filename);
230      g_free(temp);
231      g_free(cc->data);
232      cc = g_list_delete_link(cc, cc);
233    }
234
235    to = short_zuser(owl_message_get_recipient(m));
236  } else if (owl_message_is_type_jabber(m)) {
237    to = g_strdup_printf("jabber:%s", owl_message_get_recipient(m));
238    g_strdelimit(to, "/", '_');
239  } else if (owl_message_is_type_aim(m)) {
240    char *temp2;
241    temp = owl_aim_normalize_screenname(owl_message_get_recipient(m));
242    temp2 = g_utf8_strdown(temp,-1);
243    to = g_strdup_printf("aim:%s", temp2);
244    g_free(temp2);
245    g_free(temp);
246  } else {
247    to = g_strdup("loopback");
248  }
249
250  filename = g_build_filename(logpath, to, NULL);
251  owl_log_append(m, filename);
252  g_free(to);
253  g_free(filename);
254
255  filename = g_build_filename(logpath, "all", NULL);
256  owl_log_append(m, filename);
257  g_free(logpath);
258  g_free(filename);
259}
260
261
262void owl_log_outgoing_zephyr_error(const owl_zwrite *zw, const char *text)
263{
264  char *filename, *logpath;
265  char *tobuff, *recip;
266  owl_message *m;
267  GString *msgbuf;
268  /* create a present message so we can pass it to
269   * owl_log_shouldlog_message(void)
270   */
271  m = g_new(owl_message, 1);
272  /* recip_index = 0 because there can only be one recipient anyway */
273  owl_message_create_from_zwrite(m, zw, text, 0);
274  if (!owl_log_shouldlog_message(m)) {
275    owl_message_delete(m);
276    return;
277  }
278  owl_message_delete(m);
279
280  /* chop off a local realm */
281  recip = owl_zwrite_get_recip_n_with_realm(zw, 0);
282  tobuff = short_zuser(recip);
283  g_free(recip);
284
285  /* expand ~ in path names */
286  logpath = owl_util_makepath(owl_global_get_logpath(&g));
287  filename = g_build_filename(logpath, tobuff, NULL);
288  msgbuf = g_string_new("");
289  g_string_printf(msgbuf, "ERROR (owl): %s\n%s\n", tobuff, text);
290  if (text[strlen(text)-1] != '\n') {
291    g_string_append_printf(msgbuf, "\n");
292  }
293  owl_log_enqueue_message(msgbuf->str, filename);
294  g_string_free(msgbuf, TRUE);
295
296  filename = g_build_filename(logpath, "all", NULL);
297  g_free(logpath);
298  msgbuf = g_string_new("");
299  g_string_printf(msgbuf, "ERROR (owl): %s\n%s\n", tobuff, text);
300  if (text[strlen(text)-1] != '\n') {
301    g_string_append_printf(msgbuf, "\n");
302  }
303  owl_log_enqueue_message(msgbuf->str, filename);
304  g_string_free(msgbuf, TRUE);
305
306  g_free(tobuff);
307}
308
309void owl_log_incoming(const owl_message *m)
310{
311  char *filename, *allfilename, *logpath;
312  const char *from=NULL;
313  char *frombuff=NULL;
314  int len, ch, i, personal;
315
316  /* figure out if it's a "personal" message or not */
317  if (owl_message_is_type_zephyr(m)) {
318    if (owl_message_is_personal(m)) {
319      personal = 1;
320    } else {
321      personal = 0;
322    }
323  } else if (owl_message_is_type_jabber(m)) {
324    /* This needs to be fixed to handle groupchat */
325    const char* msgtype = owl_message_get_attribute_value(m,"jtype");
326    if (msgtype && !strcmp(msgtype,"groupchat")) {
327      personal = 0;
328    } else {
329      personal = 1;
330    }
331  } else {
332    if (owl_message_is_private(m) || owl_message_is_loginout(m)) {
333      personal = 1;
334    } else {
335      personal = 0;
336    }
337  }
338
339
340  if (owl_message_is_type_zephyr(m)) {
341    if (personal) {
342      from=frombuff=short_zuser(owl_message_get_sender(m));
343    } else {
344      from=frombuff=g_strdup(owl_message_get_class(m));
345    }
346  } else if (owl_message_is_type_aim(m)) {
347    /* we do not yet handle chat rooms */
348    char *normalto, *temp;
349    temp = owl_aim_normalize_screenname(owl_message_get_sender(m));
350    normalto = g_utf8_strdown(temp, -1);
351    from=frombuff=g_strdup_printf("aim:%s", normalto);
352    g_free(normalto);
353    g_free(temp);
354  } else if (owl_message_is_type_loopback(m)) {
355    from=frombuff=g_strdup("loopback");
356  } else if (owl_message_is_type_jabber(m)) {
357    if (personal) {
358      from=frombuff=g_strdup_printf("jabber:%s", 
359                                    owl_message_get_sender(m));
360    } else {
361      from=frombuff=g_strdup_printf("jabber:%s", 
362                                    owl_message_get_recipient(m));
363    }
364  } else {
365    from=frombuff=g_strdup("unknown");
366  }
367 
368  /* check for malicious sender formats */
369  len=strlen(frombuff);
370  if (len<1 || len>35) from="weird";
371  if (strchr(frombuff, '/')) from="weird";
372
373  ch=frombuff[0];
374  if (!g_ascii_isalnum(ch)) from="weird";
375
376  for (i=0; i<len; i++) {
377    if (frombuff[i]<'!' || frombuff[i]>='~') from="weird";
378  }
379
380  if (!strcmp(frombuff, ".") || !strcasecmp(frombuff, "..")) from="weird";
381
382  if (!personal) {
383    if (strcmp(from, "weird")) {
384      char* temp = g_utf8_strdown(frombuff, -1);
385      if (temp) {
386        g_free(frombuff);
387        from = frombuff = temp;
388      }
389    }
390  }
391
392  /* create the filename (expanding ~ in path names) */
393  if (personal) {
394    logpath = owl_util_makepath(owl_global_get_logpath(&g));
395    filename = g_build_filename(logpath, from, NULL);
396    allfilename = g_build_filename(logpath, "all", NULL);
397    owl_log_append(m, allfilename);
398    g_free(allfilename);
399  } else {
400    logpath = owl_util_makepath(owl_global_get_classlogpath(&g));
401    filename = g_build_filename(logpath, from, NULL);
402  }
403
404  owl_log_append(m, filename);
405  g_free(filename);
406
407  if (personal && owl_message_is_type_zephyr(m)) {
408    /* We want to log to all of the CC'd people who were not us, or
409     * the sender, as well.
410     */
411    char *temp;
412    GList *cc;
413    cc = owl_message_get_cc_without_recipient(m);
414    while (cc != NULL) {
415      temp = short_zuser(cc->data);
416      if (strcasecmp(temp, frombuff) != 0) {
417        filename = g_build_filename(logpath, temp, NULL);
418        owl_log_append(m, filename);
419        g_free(filename);
420      }
421
422      g_free(temp);
423      g_free(cc->data);
424      cc = g_list_delete_link(cc, cc);
425    }
426  }
427
428  g_free(frombuff);
429  g_free(logpath);
430}
431
432static gpointer owl_log_thread_func(gpointer data)
433{
434  log_context = g_main_context_new();
435  log_loop = g_main_loop_new(log_context, FALSE);
436  g_main_loop_run(log_loop);
437  return NULL;
438}
439
440void owl_log_init(void) 
441{
442  GError *error = NULL;
443  logging_thread = g_thread_create(owl_log_thread_func,
444                                   NULL,
445                                   TRUE,
446                                   &error);
447  if (error) {
448    endwin();
449    fprintf(stderr, "Error spawning logging thread: %s\n", error->message);
450    fflush(stderr);
451    exit(1);
452  }
453 
454}
455
456static void owl_log_quit_func(gpointer data)
457{
458  g_main_loop_quit(log_loop);
459}
460
461void owl_log_shutdown(void)
462{
463  owl_select_post_task(owl_log_quit_func, NULL,
464                       NULL, log_context);
465  g_thread_join(logging_thread);
466}
Note: See TracBrowser for help on using the repository browser.