source: logging.c

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