source: logging.c @ e47e1b0

Last change on this file since e47e1b0 was e47e1b0, checked in by Jason Gross <jasongross9@gmail.com>, 7 years ago
Display log file name on failure to open file Also, make owl_log_error be like printf. This will be more useful in the next commit, when we display error codes.
  • Property mode set to 100644
File size: 13.4 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 G_GNUC_PRINTF(1, 2) owl_log_error(const char *fmt, ...)
154{
155  va_list ap;
156  char *data;
157
158  va_start(ap, fmt);
159  data = g_strdup_vprintf(fmt, ap);
160  va_end(ap);
161
162  owl_select_post_task(owl_log_error_main_thread,
163                       data, g_free, g_main_context_default());
164}
165
166static void owl_log_write_entry(gpointer data)
167{
168  owl_log_entry *msg = (owl_log_entry*)data;
169  FILE *file = NULL;
170  file = fopen(msg->filename, "a");
171  if (!file) {
172    owl_log_error("Unable to open file for logging (%s)", msg->filename);
173    return;
174  }
175  fprintf(file, "%s", msg->message);
176  fclose(file);
177}
178
179static void owl_log_entry_free(void *data)
180{
181  owl_log_entry *msg = (owl_log_entry*)data;
182  if (msg) {
183    g_free(msg->message);
184    g_free(msg->filename);
185    g_slice_free(owl_log_entry, msg);
186  }
187}
188
189void owl_log_enqueue_message(const char *buffer, const char *filename)
190{
191  owl_log_entry *log_msg = NULL; 
192  log_msg = g_slice_new(owl_log_entry);
193  log_msg->message = g_strdup(buffer);
194  log_msg->filename = g_strdup(filename);
195  owl_select_post_task(owl_log_write_entry, log_msg, 
196                       owl_log_entry_free, log_context);
197}
198
199void owl_log_append(const owl_message *m, const char *filename) {
200  char *buffer = NULL;
201  if (owl_message_is_type_zephyr(m)) {
202    buffer = owl_log_zephyr(m);
203  } else if (owl_message_is_type_jabber(m)) {
204    buffer = owl_log_jabber(m);
205  } else if (owl_message_is_type_aim(m)) {
206    buffer = owl_log_aim(m);
207  } else {
208    buffer = owl_log_generic(m);
209  }
210  owl_log_enqueue_message(buffer, filename);
211  g_free(buffer);
212}
213
214void owl_log_outgoing(const owl_message *m)
215{
216  char *filename, *logpath;
217  char *to, *temp;
218  GList *cc;
219
220  /* expand ~ in path names */
221  logpath = owl_util_makepath(owl_global_get_logpath(&g));
222
223  /* Figure out what path to log to */
224  if (owl_message_is_type_zephyr(m)) {
225    /* If this has CC's, do all but the "recipient" which we'll do below */
226    cc = owl_message_get_cc_without_recipient(m);
227    while (cc != NULL) {
228      temp = short_zuser(cc->data);
229      filename = g_build_filename(logpath, temp, NULL);
230      owl_log_append(m, filename);
231
232      g_free(filename);
233      g_free(temp);
234      g_free(cc->data);
235      cc = g_list_delete_link(cc, cc);
236    }
237
238    to = short_zuser(owl_message_get_recipient(m));
239  } else if (owl_message_is_type_jabber(m)) {
240    to = g_strdup_printf("jabber:%s", owl_message_get_recipient(m));
241    g_strdelimit(to, "/", '_');
242  } else if (owl_message_is_type_aim(m)) {
243    char *temp2;
244    temp = owl_aim_normalize_screenname(owl_message_get_recipient(m));
245    temp2 = g_utf8_strdown(temp,-1);
246    to = g_strdup_printf("aim:%s", temp2);
247    g_free(temp2);
248    g_free(temp);
249  } else {
250    to = g_strdup("loopback");
251  }
252
253  filename = g_build_filename(logpath, to, NULL);
254  owl_log_append(m, filename);
255  g_free(to);
256  g_free(filename);
257
258  filename = g_build_filename(logpath, "all", NULL);
259  owl_log_append(m, filename);
260  g_free(logpath);
261  g_free(filename);
262}
263
264
265void owl_log_outgoing_zephyr_error(const owl_zwrite *zw, const char *text)
266{
267  char *filename, *logpath;
268  char *tobuff, *recip;
269  owl_message *m;
270  GString *msgbuf;
271  /* create a present message so we can pass it to
272   * owl_log_shouldlog_message(void)
273   */
274  m = g_slice_new(owl_message);
275  /* recip_index = 0 because there can only be one recipient anyway */
276  owl_message_create_from_zwrite(m, zw, text, 0);
277  if (!owl_log_shouldlog_message(m)) {
278    owl_message_delete(m);
279    return;
280  }
281  owl_message_delete(m);
282
283  /* chop off a local realm */
284  recip = owl_zwrite_get_recip_n_with_realm(zw, 0);
285  tobuff = short_zuser(recip);
286  g_free(recip);
287
288  /* expand ~ in path names */
289  logpath = owl_util_makepath(owl_global_get_logpath(&g));
290  filename = g_build_filename(logpath, tobuff, NULL);
291  msgbuf = g_string_new("");
292  g_string_printf(msgbuf, "ERROR (owl): %s\n%s\n", tobuff, text);
293  if (text[strlen(text)-1] != '\n') {
294    g_string_append_printf(msgbuf, "\n");
295  }
296  owl_log_enqueue_message(msgbuf->str, filename);
297  g_string_free(msgbuf, TRUE);
298
299  filename = g_build_filename(logpath, "all", NULL);
300  g_free(logpath);
301  msgbuf = g_string_new("");
302  g_string_printf(msgbuf, "ERROR (owl): %s\n%s\n", tobuff, text);
303  if (text[strlen(text)-1] != '\n') {
304    g_string_append_printf(msgbuf, "\n");
305  }
306  owl_log_enqueue_message(msgbuf->str, filename);
307  g_string_free(msgbuf, TRUE);
308
309  g_free(tobuff);
310}
311
312void owl_log_incoming(const owl_message *m)
313{
314  char *filename, *allfilename, *logpath;
315  const char *from=NULL;
316  char *frombuff=NULL;
317  int len, ch, i, personal;
318
319  /* figure out if it's a "personal" message or not */
320  if (owl_message_is_type_zephyr(m)) {
321    if (owl_message_is_personal(m)) {
322      personal = 1;
323    } else {
324      personal = 0;
325    }
326  } else if (owl_message_is_type_jabber(m)) {
327    /* This needs to be fixed to handle groupchat */
328    const char* msgtype = owl_message_get_attribute_value(m,"jtype");
329    if (msgtype && !strcmp(msgtype,"groupchat")) {
330      personal = 0;
331    } else {
332      personal = 1;
333    }
334  } else {
335    if (owl_message_is_private(m) || owl_message_is_loginout(m)) {
336      personal = 1;
337    } else {
338      personal = 0;
339    }
340  }
341
342
343  if (owl_message_is_type_zephyr(m)) {
344    if (personal) {
345      from=frombuff=short_zuser(owl_message_get_sender(m));
346    } else {
347      from=frombuff=g_strdup(owl_message_get_class(m));
348    }
349  } else if (owl_message_is_type_aim(m)) {
350    /* we do not yet handle chat rooms */
351    char *normalto, *temp;
352    temp = owl_aim_normalize_screenname(owl_message_get_sender(m));
353    normalto = g_utf8_strdown(temp, -1);
354    from=frombuff=g_strdup_printf("aim:%s", normalto);
355    g_free(normalto);
356    g_free(temp);
357  } else if (owl_message_is_type_loopback(m)) {
358    from=frombuff=g_strdup("loopback");
359  } else if (owl_message_is_type_jabber(m)) {
360    if (personal) {
361      from=frombuff=g_strdup_printf("jabber:%s", 
362                                    owl_message_get_sender(m));
363    } else {
364      from=frombuff=g_strdup_printf("jabber:%s", 
365                                    owl_message_get_recipient(m));
366    }
367  } else {
368    from=frombuff=g_strdup("unknown");
369  }
370 
371  /* check for malicious sender formats */
372  len=strlen(frombuff);
373  if (len<1 || len>35) from="weird";
374  if (strchr(frombuff, '/')) from="weird";
375
376  ch=frombuff[0];
377  if (!g_ascii_isalnum(ch)) from="weird";
378
379  for (i=0; i<len; i++) {
380    if (frombuff[i]<'!' || frombuff[i]>='~') from="weird";
381  }
382
383  if (!strcmp(frombuff, ".") || !strcasecmp(frombuff, "..")) from="weird";
384
385  if (!personal) {
386    if (strcmp(from, "weird")) {
387      char* temp = g_utf8_strdown(frombuff, -1);
388      if (temp) {
389        g_free(frombuff);
390        from = frombuff = temp;
391      }
392    }
393  }
394
395  /* create the filename (expanding ~ in path names) */
396  if (personal) {
397    logpath = owl_util_makepath(owl_global_get_logpath(&g));
398    filename = g_build_filename(logpath, from, NULL);
399    allfilename = g_build_filename(logpath, "all", NULL);
400    owl_log_append(m, allfilename);
401    g_free(allfilename);
402  } else {
403    logpath = owl_util_makepath(owl_global_get_classlogpath(&g));
404    filename = g_build_filename(logpath, from, NULL);
405  }
406
407  owl_log_append(m, filename);
408  g_free(filename);
409
410  if (personal && owl_message_is_type_zephyr(m)) {
411    /* We want to log to all of the CC'd people who were not us, or
412     * the sender, as well.
413     */
414    char *temp;
415    GList *cc;
416    cc = owl_message_get_cc_without_recipient(m);
417    while (cc != NULL) {
418      temp = short_zuser(cc->data);
419      if (strcasecmp(temp, frombuff) != 0) {
420        filename = g_build_filename(logpath, temp, NULL);
421        owl_log_append(m, filename);
422        g_free(filename);
423      }
424
425      g_free(temp);
426      g_free(cc->data);
427      cc = g_list_delete_link(cc, cc);
428    }
429  }
430
431  g_free(frombuff);
432  g_free(logpath);
433}
434
435static gpointer owl_log_thread_func(gpointer data)
436{
437  log_loop = g_main_loop_new(log_context, FALSE);
438  g_main_loop_run(log_loop);
439  return NULL;
440}
441
442void owl_log_init(void) 
443{
444  log_context = g_main_context_new();
445#if GLIB_CHECK_VERSION(2, 31, 0)
446  logging_thread = g_thread_new("logging",
447                                owl_log_thread_func,
448                                NULL);
449#else
450  GError *error = NULL;
451  logging_thread = g_thread_create(owl_log_thread_func,
452                                   NULL,
453                                   TRUE,
454                                   &error);
455  if (error) {
456    endwin();
457    fprintf(stderr, "Error spawning logging thread: %s\n", error->message);
458    fflush(stderr);
459    exit(1);
460  }
461#endif
462 
463}
464
465static void owl_log_quit_func(gpointer data)
466{
467  g_main_loop_quit(log_loop);
468}
469
470void owl_log_shutdown(void)
471{
472  owl_select_post_task(owl_log_quit_func, NULL,
473                       NULL, log_context);
474  g_thread_join(logging_thread);
475}
Note: See TracBrowser for help on using the repository browser.