comparison src/log.c @ 7431:643cbc9a6035

[gaim-migrate @ 8036] This is good enough for CVS. This is new logging. It centers around the highly modular "GaimLogLogger," which controls how to write the log. Currently I only have the plain text logger. I wrote the beginning of an XML logger, but decided I didn't think it was that great an idea. Plugins can implement loggers themselves, so you can have, like, an SQL logger or something. The default logger writes to a file unique to the conversation, and they're saved on disk in a heirarchical fashion: ~/.gaim/logs/aim/seanegn/robflynn-date.log would be a conversation I had with Rob on date. What doesn't work: System logging The search button in the log viewer. Oh, chats probably don't log either, I didn't test. You can only log in plain text right now. Obviously, it's not done yet. But you can play around with it, and give it some love. I'll get back to it tomorrow after school, maybe. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Wed, 05 Nov 2003 06:15:49 +0000
parents ab828b8c3f22
children 7cdbd2eb7546
comparison
equal deleted inserted replaced
7430:783eea64614c 7431:643cbc9a6035
1 /* --------------------------------------------------- 1 /**
2 * Function to remove a log file entry 2 * @file log.c Logging API
3 * --------------------------------------------------- 3 * @ingroup core
4 *
5 * gaim
6 *
7 * Copyright (C) 2003 Buzz Lightyear
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4 */ 22 */
23
24 #include "account.h"
25 #include "debug.h"
5 #include "internal.h" 26 #include "internal.h"
6
7 #include "conversation.h"
8 #include "debug.h"
9 #include "log.h" 27 #include "log.h"
10 #include "multi.h"
11 #include "notify.h"
12 #include "prefs.h" 28 #include "prefs.h"
13 #include "prpl.h"
14 #include "util.h" 29 #include "util.h"
15 30
16 /* XXX CORE/UI */ 31 static GaimLogLogger txt_logger;
17 #include "gtkinternal.h" 32 static GaimLogLogger old_logger;
18 #include "gtkconv.h" 33
19 #include "ui.h" 34 /**************************************************************************
20 35 * PUBLIC LOGGING FUNCTIONS ***********************************************
21 GList *log_conversations = NULL; 36 **************************************************************************/
22 37
23 void rm_log(struct log_conversation *a) 38 GaimLog *gaim_log_new(GaimLogType type, const char *name, GaimAccount *account, time_t time)
24 { 39 {
25 GaimConversation *cnv = gaim_find_conversation(a->name); 40 GaimLog *log = g_new0(GaimLog, 1);
26 41 log->name = g_strdup(name);
27 /* Added the following if statements for sanity check */ 42 log->account = account;
28 if (!a) 43 log->time = time;
29 { 44 log->logger = gaim_log_logger_get();
30 gaim_notify_error (NULL, NULL, _("Error in specifying buddy conversation."), NULL); 45 if (log->logger && log->logger->new)
46 log->logger->new(log);
47 return log;
48 }
49
50 void gaim_log_free(GaimLog *log)
51 {
52 g_return_if_fail(log);
53 if (log->logger && log->logger->finalize)
54 log->logger->finalize(log);
55 g_free(log->name);
56 g_free(log);
57 }
58
59
60 void gaim_log_write(GaimLog *log, GaimMessageFlags type,
61 const char *from, time_t time, const char *message)
62 {
63 g_return_if_fail(log);
64 g_return_if_fail(log->logger);
65 g_return_if_fail(log->logger->write);
66
67 log->logger->write(log, type, from, time, message);
68 }
69
70 char *gaim_log_read(GaimLog *log, GaimLogReadFlags *flags)
71 {
72 g_return_val_if_fail(log && log->logger, NULL);
73 if (log->logger->read)
74 return log->logger->read(log, flags);
75 return (_("<b><font color\"=red\">The logger has no read function</font></b>"));
76 }
77
78 /****************************************************************************
79 * LOGGER FUNCTIONS *********************************************************
80 ****************************************************************************/
81
82 static GaimLogLogger *current_logger = NULL;
83 static GSList *loggers = NULL;
84
85 static void logger_pref_cb(const char *name, GaimPrefType type,
86 gpointer value, gpointer data)
87 {
88 GaimLogLogger *logger;
89 GSList *l = loggers;
90 while (l) {
91 logger = l->data;
92 if (!strcmp(logger->id, value)) {
93 gaim_log_logger_set(logger);
94 return;
95 }
96 l = l->next;
97 }
98 gaim_log_logger_set(&txt_logger);
99 }
100
101
102 GaimLogLogger *gaim_log_logger_new(void(*new)(GaimLog *),
103 void(*write)(GaimLog *, GaimMessageFlags, const char *,
104 time_t, const char *),
105 void(*finalize)(GaimLog *), GList*(*list)(const char*, GaimAccount*),
106 char*(*read)(GaimLog*, GaimLogReadFlags*))
107 {
108 GaimLogLogger *logger = g_new0(GaimLogLogger, 1);
109 logger->new = new;
110 logger->write = write;
111 logger->finalize = finalize;
112 logger->list = list;
113 logger->read = read;
114 return logger;
115 }
116
117 void gaim_log_logger_free(GaimLogLogger *logger)
118 {
119 g_free(logger);
120 }
121
122 void gaim_log_logger_add (GaimLogLogger *logger)
123 {
124 g_return_if_fail(logger);
125 if (g_slist_find(loggers, logger))
31 return; 126 return;
32 } 127 loggers = g_slist_append(loggers, logger);
33 cnv = gaim_find_conversation(a->name); 128 }
34 if (!cnv) 129
35 { 130 void gaim_log_logger_remove (GaimLogLogger *logger)
36 gaim_notify_error (NULL, NULL, _("Unable to find conversation log"), NULL); 131 {
37 return; 132 g_return_if_fail(logger);
38 } 133 g_slist_remove(loggers, logger);
39 134 }
40 log_conversations = g_list_remove(log_conversations, a); 135
41 } 136 void gaim_log_logger_set (GaimLogLogger *logger)
42 137 {
43 struct log_conversation *find_log_info(const char *name) 138 g_return_if_fail(logger);
44 { 139 current_logger = logger;
45 char *pname = g_malloc(BUF_LEN); 140 }
46 GList *lc = log_conversations; 141
47 struct log_conversation *l; 142 GaimLogLogger *gaim_log_logger_get()
48 143 {
49 144 return current_logger;
50 strcpy(pname, gaim_normalize(NULL, name)); 145 }
51 146
52 while (lc) { 147 GList *gaim_log_logger_get_options(void)
53 l = (struct log_conversation *)lc->data; 148 {
54 if (!gaim_utf8_strcasecmp(pname, gaim_normalize(NULL, l->name))) { 149 GSList *n;
55 g_free(pname); 150 GList *list = NULL;
56 return l; 151 GaimLogLogger *data;
152
153 for (n = loggers; n; n = n->next) {
154 data = n->data;
155 if (!data->write)
156 continue;
157 list = g_list_append(list, data->name);
158 list = g_list_append(list, data->id);
159 }
160
161 return list;
162 }
163
164 static gint log_compare(GaimLog *a, GaimLog *b)
165 {
166 return b->time - a->time;
167 }
168
169 GList *gaim_log_get_logs(const char *name, GaimAccount *account)
170 {
171 GList *logs = NULL;
172 GSList *n;
173 for (n = loggers; n; n = n->next) {
174 GaimLogLogger *logger = n->data;
175 if (!logger->list)
176 continue;
177 logs = g_list_concat(logs, logger->list(name, account));
178 }
179
180 return g_list_sort(logs, log_compare);
181 }
182
183 void gaim_log_init(void)
184 {
185 gaim_prefs_add_none("/core/logging");
186 gaim_prefs_add_string("/core/logging/format", "txt");
187 gaim_log_logger_add(&txt_logger);
188 gaim_log_logger_add(&old_logger);
189 gaim_prefs_connect_callback("/core/logging/format",
190 logger_pref_cb, NULL);
191 gaim_prefs_trigger_callback("/core/logging/format");
192 }
193
194 /****************************************************************************
195 * LOGGERS ******************************************************************
196 ****************************************************************************/
197
198 static GList *log_lister_common(const char *screenname, GaimAccount *account, const char *ext, GaimLogLogger *logger)
199 {
200 GDir *dir;
201 GList *list = NULL;
202 const char *filename;
203 char *me = g_strdup(gaim_normalize(account, gaim_account_get_username(account)));
204
205 const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO
206 (gaim_find_prpl(gaim_account_get_protocol(account)))->list_icon(account, NULL);
207 char *path = g_build_filename(gaim_user_dir(), "logs", prpl, me, gaim_normalize(account, screenname), NULL);
208
209 if (!(dir = g_dir_open(path, 0, NULL))) {
210 g_free(path);
211 g_free(me);
212 return NULL;
213 }
214 while ((filename = g_dir_read_name(dir))) {
215 if (g_str_has_suffix(filename, ext)) {
216 const char *l = filename;
217 struct tm time;
218 GaimLog *log;
219 char d[5];
220
221 strncpy(d, l, 4);
222 d[4] = '\0';
223 time.tm_year = atoi(d) - 1900;
224 l = l + 5;
225
226 strncpy(d, l, 2);
227 d[2] = '\0';
228 time.tm_mon = atoi(d) - 1;
229 l = l + 3;
230
231 strncpy(d, l, 2);
232 time.tm_mday = atoi(d);
233 l = l + 3;
234
235 strncpy(d, l, 2);
236 time.tm_hour = atoi(d);
237 l = l + 2;
238
239 strncpy(d, l, 2);
240 time.tm_min = atoi(d);
241 l = l + 2;
242
243 strncpy(d, l, 2);
244 time.tm_sec = atoi(d);
245 l = l + 2;
246 log = gaim_log_new(GAIM_LOG_IM, screenname, account, mktime(&time));
247 log->logger = logger;
248 log->logger_data = g_build_filename(path, filename, NULL);
249 list = g_list_append(list, log);
57 } 250 }
58 lc = lc->next; 251 }
59 } 252 g_dir_close(dir);
60 g_free(pname); 253 return list;
61 return NULL; 254 }
62 } 255
63 256 #if 0 /* Maybe some other time. */
64 void update_log_convs() 257 /****************
65 { 258 ** XML LOGGER **
66 GList *cnv; 259 ****************/
67 GaimConversation *c; 260
68 GaimGtkConversation *gtkconv; 261 static const char *str_from_msg_type (GaimMessageFlags type)
69 262 {
70 for (cnv = gaim_get_conversations(); cnv != NULL; cnv = cnv->next) { 263
71 264 return "";
72 c = (GaimConversation *)cnv->data; 265
73 266 }
74 if (!GAIM_IS_GTK_CONVERSATION(c)) 267
75 continue; 268 static void xml_logger_write(GaimLog *log,
76 269 GaimMessageFlags type,
77 gtkconv = GAIM_GTK_CONVERSATION(c); 270 const char *from, time_t time, const char *message)
78 271 {
79 if (gtkconv->toolbar.log) { 272 char date[64];
80 if (gaim_conversation_get_type(c) == GAIM_CONV_CHAT) 273 char *xhtml = NULL;
81 gtk_widget_set_sensitive(GTK_WIDGET(gtkconv->toolbar.log), 274 if (!log->logger_data) {
82 !gaim_prefs_get_bool("/gaim/gtk/logging/log_chats")); 275 /* This log is new. We could use the loggers 'new' function, but
83 else 276 * creating a new file there would result in empty files in the case
84 gtk_widget_set_sensitive(GTK_WIDGET(gtkconv->toolbar.log), 277 * that you open a convo with someone, but don't say anything.
85 !gaim_prefs_get_bool("/gaim/gtk/logging/log_ims")); 278 */
279 char *ud = gaim_user_dir();
280 char *guy = g_strdup(gaim_normalize(log->account, gaim_account_get_username(log->account)));
281 const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO
282 (gaim_find_prpl(gaim_account_get_protocol(log->account)))->list_icon(log->account, NULL);
283 char *dir;
284 FILE *file;
285
286 strftime(date, sizeof(date), "%F.%H%M%S.xml", localtime(&log->time));
287
288 dir = g_build_filename(ud, "logs", NULL);
289 mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
290 g_free(dir);
291 dir = g_build_filename(ud, "logs",
292 prpl, NULL);
293 mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
294 g_free(dir);
295 dir = g_build_filename(ud, "logs",
296 prpl, guy, NULL);
297 mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
298 g_free(dir);
299 dir = g_build_filename(ud, "logs",
300 prpl, guy, gaim_normalize(log->account, log->name), NULL);
301 mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
302
303 char *filename = g_build_filename(dir, date, NULL);
304 g_free(dir);
305
306 file = fopen(dir, "r");
307 if(!file)
308 mkdir(dir, S_IRUSR | S_IWUSR | S_IXUSR);
309 else
310 fclose(file);
311
312 log->logger_data = fopen(filename, "a");
313 if (!log->logger_data) {
314 gaim_debug(GAIM_DEBUG_ERROR, "log", "Could not create log file %s\n", filename);
315 return;
86 } 316 }
87 } 317 fprintf(log->logger_data, "<?xml version='1.0' encoding='UTF-8' ?>\n"
88 } 318 "<?xml-stylesheet href='file:///usr/src/web/htdocs/log-stylesheet.xsl' type='text/xml' ?>\n");
89 319
90 static FILE *open_gaim_log_file(const char *name, int *flag) 320 strftime(date, sizeof(date), "%F %T", localtime(&log->time));
91 { 321 fprintf(log->logger_data, "<conversation time='%s' screenname='%s' protocol='%s'>\n",
92 char *buf; 322 date, log->name, prpl);
93 char *buf2; 323 }
94 char log_all_file[256]; 324
95 struct stat st; 325 strftime(date, sizeof(date), "%T", localtime(&time));
96 FILE *fd; 326 gaim_markup_html_to_xhtml(message, &xhtml, NULL);
97 #ifndef _WIN32 327 if (from)
98 int res; 328 fprintf(log->logger_data, "<message %s %s from='%s' time='%s'>%s</message>\n",
329 str_from_msg_type(type),
330 type & GAIM_MESSAGE_SEND ? "direction='sent'" :
331 type & GAIM_MESSAGE_RECV ? "direction='received'" : "",
332 from, date, xhtml);
333 else
334 fprintf(log->logger_data, "<message %s %s time='%s'>%s</message>\n",
335 str_from_msg_type(type),
336 type & GAIM_MESSAGE_SEND ? "direction='sent'" :
337 type & GAIM_MESSAGE_RECV ? "direction='received'" : "",
338 date, xhtml);
339 fflush(log->logger_data);
340 g_free(xhtml);
341 }
342
343 static void xml_logger_finalize(GaimLog *log)
344 {
345 if (log->logger_data) {
346 fprintf(log->logger_data, "</conversation>\n");
347 fclose(log->logger_data);
348 log->logger_data = NULL;
349 }
350 }
351
352 static GList *xml_logger_list(const char *sn, GaimAccount *account)
353 {
354 return log_lister_common(sn, account, ".xml", &xml_logger);
355 }
356
357 static GaimLogLogger xml_logger = {
358 N_("XML"), "xml",
359 NULL,
360 xml_logger_write,
361 xml_logger_finalize,
362 xml_logger_list,
363 NULL
364 };
99 #endif 365 #endif
100 gchar *gaim_dir; 366
101 367 /****************************
102 buf = g_malloc(BUF_LONG); 368 ** PLAIN TEXT LOGGER *******
103 buf2 = g_malloc(BUF_LONG); 369 ****************************/
104 gaim_dir = gaim_user_dir(); 370
105 371 static void txt_logger_write(GaimLog *log,
106 /* Dont log yourself */ 372 GaimMessageFlags type,
107 strncpy(log_all_file, gaim_dir, 256); 373 const char *from, time_t time, const char *message)
108 374 {
109 #ifndef _WIN32 375 char date[64];
110 stat(log_all_file, &st); 376 char *stripped = NULL;
111 if (!S_ISDIR(st.st_mode)) 377 if (!log->logger_data) {
112 unlink(log_all_file); 378 /* This log is new. We could use the loggers 'new' function, but
113 379 * creating a new file there would result in empty files in the case
114 fd = fopen(log_all_file, "r"); 380 * that you open a convo with someone, but don't say anything.
115 381 */
116 if (!fd) { 382 char *ud = gaim_user_dir();
117 res = mkdir(log_all_file, S_IRUSR | S_IWUSR | S_IXUSR); 383 char *guy = g_strdup(gaim_normalize(log->account, gaim_account_get_username(log->account)));
118 if (res < 0) { 384 const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO
119 g_snprintf(buf, BUF_LONG, _("Unable to make directory %s for logging"), 385 (gaim_find_prpl(gaim_account_get_protocol(log->account)))->list_icon(log->account, NULL);
120 log_all_file); 386 char *dir;
121 gaim_notify_error(NULL, NULL, buf, NULL); 387 FILE *file;
122 g_free(buf); 388
123 g_free(buf2); 389 strftime(date, sizeof(date), "%F.%H%M%S.txt", localtime(&log->time));
124 return NULL; 390
391 dir = g_build_filename(ud, "logs", NULL);
392 mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
393 g_free(dir);
394 dir = g_build_filename(ud, "logs",
395 prpl, NULL);
396 mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
397 g_free(dir);
398 dir = g_build_filename(ud, "logs",
399 prpl, guy, NULL);
400 mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
401 g_free(dir);
402 dir = g_build_filename(ud, "logs",
403 prpl, guy, gaim_normalize(log->account, log->name), NULL);
404 mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
405
406 char *filename = g_build_filename(dir, date, NULL);
407 g_free(dir);
408
409 file = fopen(dir, "r");
410 if(!file)
411 mkdir(dir, S_IRUSR | S_IWUSR | S_IXUSR);
412 else
413 fclose(file);
414
415 log->logger_data = fopen(filename, "a");
416 if (!log->logger_data) {
417 gaim_debug(GAIM_DEBUG_ERROR, "log", "Could not create log file %s\n", filename);
418 return;
125 } 419 }
126 } else 420 strftime(date, sizeof(date), "%F %T", localtime(&log->time));
127 fclose(fd); 421 fprintf(log->logger_data, "Conversation with %s at %s on %s (%s)\n",
128 422 log->name, date, gaim_account_get_username(log->account), prpl);
129 g_snprintf(log_all_file, 256, "%s" G_DIR_SEPARATOR_S "logs", gaim_dir); 423 }
130 424
131 if (stat(log_all_file, &st) < 0) 425 strftime(date, sizeof(date), "%T", localtime(&time));
132 *flag = 1; 426 stripped = gaim_markup_strip_html(message);
133 if (!S_ISDIR(st.st_mode)) 427 fprintf(log->logger_data, "(%s) %s%s %s\n", date, from ? from : "", from ? ":" : "", stripped);
134 unlink(log_all_file); 428 fflush(log->logger_data);
135 429 g_free(stripped);
136 fd = fopen(log_all_file, "r"); 430 }
137 if (!fd) { 431
138 res = mkdir(log_all_file, S_IRUSR | S_IWUSR | S_IXUSR); 432 static void txt_logger_finalize(GaimLog *log)
139 if (res < 0) { 433 {
140 g_snprintf(buf, BUF_LONG, _("Unable to make directory %s for logging"), 434 if (log->logger_data)
141 log_all_file); 435 fclose(log->logger_data);
142 gaim_notify_error(NULL, NULL, buf, NULL); 436 }
143 g_free(buf); 437
144 g_free(buf2); 438 static GList *txt_logger_list(const char *sn, GaimAccount *account)
145 return NULL; 439 {
440 return log_lister_common(sn, account, ".txt", &txt_logger);
441 }
442
443 static char *txt_logger_read(GaimLog *log, GaimLogReadFlags *flags)
444 {
445 char *read, *minus_header;
446 if (!log->logger_data)
447 return g_strdup("<font color='red'><b>log->logger_data was NULL!</b></font>");
448 if (g_file_get_contents((char *)log->logger_data, &read, NULL, NULL)) {
449 minus_header = strchr(read, '\n');
450 if (!minus_header)
451 minus_header = g_strdup(read);
452 else
453 minus_header = g_strdup(minus_header + 1);
454 g_free(read);
455 return minus_header;
456 }
457 return g_strdup(_("<font color='red'><b>Could not read file: %s</b></font>"));
458 }
459
460 static GaimLogLogger txt_logger = {
461 N_("Plain text"), "txt",
462 NULL,
463 txt_logger_write,
464 txt_logger_finalize,
465 txt_logger_list,
466 txt_logger_read
467 };
468
469 /****************
470 * OLD LOGGER ***
471 ****************/
472
473 /* The old logger doesn't write logs, only reads them. This is to include
474 * old logs in the log viewer transparently.
475 */
476
477 struct old_logger_data {
478 char *path;
479 int offset;
480 int length;
481 };
482
483 static GList *old_logger_list(const char *sn, GaimAccount *account)
484 {
485 FILE *file;
486 char buf[BUF_LONG];
487 struct tm tm;
488 struct old_logger_data *data = NULL;
489 char day[4], month[4], year[5];
490 char *logfile = g_strdup_printf("%s.log", gaim_normalize(account, sn));
491 char *date;
492 char *path = g_build_filename(gaim_user_dir(), "logs", logfile, NULL);
493 char *newlog;
494
495 GaimLog *log = NULL;
496 GList *list = NULL;
497
498 if (!(file = fopen(path, "r")))
499 return NULL;
500
501 while (fgets(buf, BUF_LONG, file)) {
502 if ((newlog = strstr(buf, "---- New C"))) {
503 int length;
504 int offset;
505 GDate gdate;
506 char convostart[32];
507 char *temp = strchr(buf, '@');
508
509 if (temp == NULL || strlen(temp) < 2)
510 continue;
511
512 temp++;
513 length = strcspn(temp, "-");
514 if (length > 31) length = 31;
515
516 offset = ftell(file);
517
518 if (data) {
519 data->length = offset - data->offset - length -
520 strlen("<HR><BR><H3 Align=Center> ---- New Conversation @ ") -
521 strlen("----</H3><BR>");
522 if (data->length != 0)
523 list = g_list_append(list, log);
524 else
525 gaim_log_free(log);
526 }
527
528 log = gaim_log_new(GAIM_LOG_IM, sn, account, -1);
529 log->logger = &old_logger;
530
531 data = g_malloc(sizeof(struct old_logger_data));
532 data->offset = offset;
533 data->path = path;
534 log->logger_data = data;
535
536
537 g_snprintf(convostart, length, "%s", temp);
538 sscanf(convostart, "%*s %s %s %d:%d:%d %s",
539 month, day, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, year);
540 date = g_strdup_printf("%s %s %s", month, day, year);
541 g_date_set_parse(&gdate, date);
542 tm.tm_mday = g_date_get_day(&gdate);
543 tm.tm_mon = g_date_get_month(&gdate) - 1;
544 tm.tm_year = g_date_get_year(&gdate) - 1900;
545 log->time = mktime(&tm);
546
146 } 547 }
147 } else 548 }
148 fclose(fd); 549 fclose(file);
149 #else /* _WIN32 */ 550 return list;
150 g_snprintf(log_all_file, 256, "%s" G_DIR_SEPARATOR_S "logs", gaim_dir); 551 }
151 552
152 if( _mkdir(log_all_file) < 0 && errno != EEXIST ) { 553 char * old_logger_read (GaimLog *log, GaimLogReadFlags *flags)
153 g_snprintf(buf, BUF_LONG, _("Unable to make directory %s for logging"), log_all_file); 554 {
154 gaim_notify_error(NULL, NULL, buf, NULL); 555 *flags = GAIM_LOG_READ_NO_NEWLINE;
155 g_free(buf); 556 struct old_logger_data *data = log->logger_data;
156 g_free(buf2); 557 FILE *file = fopen(data->path, "r");
157 return NULL; 558 char *read = g_malloc(data->length + 1);
158 } 559 fseek(file, data->offset, SEEK_SET);
159 #endif 560 fread(read, data->length, 1, file);
160 561 read[data->length] = '\0';
161 g_snprintf(log_all_file, 256, "%s" G_DIR_SEPARATOR_S "logs" G_DIR_SEPARATOR_S "%s", gaim_dir, name); 562 return read;
162 if (stat(log_all_file, &st) < 0) 563 }
163 *flag = 1; 564
164 565 static GaimLogLogger old_logger = {
165 gaim_debug(GAIM_DEBUG_INFO, "log", "Logging to: \"%s\"\n", log_all_file); 566 "old logger", "old",
166 567 NULL, NULL, NULL,
167 fd = fopen(log_all_file, "a"); 568 old_logger_list,
168 569 old_logger_read
169 g_free(buf); 570 };
170 g_free(buf2);
171 return fd;
172 }
173
174 static FILE *open_system_log_file(const char *name)
175 {
176 int x;
177
178 if (name)
179 return open_log_file(name, 2);
180 else
181 return open_gaim_log_file("system", &x);
182 }
183
184 FILE *open_log_file(const char *name, int is_chat)
185 {
186 struct stat st;
187 char realname[256];
188 struct log_conversation *l;
189 FILE *fd;
190 int flag = 0;
191
192 if (((is_chat == 2) && !gaim_prefs_get_bool("/gaim/gtk/logging/individual_logs"))
193 || ((is_chat == 1) && !gaim_prefs_get_bool("/gaim/gtk/logging/log_chats"))
194 || ((is_chat == 0) && !gaim_prefs_get_bool("/gaim/gtk/logging/log_ims"))) {
195
196 l = find_log_info(name);
197 if (!l)
198 return NULL;
199
200 if (stat(l->filename, &st) < 0)
201 flag = 1;
202
203 fd = fopen(l->filename, "a");
204
205 if (flag) { /* is a new file */
206 if (gaim_prefs_get_bool("/gaim/gtk/logging/strip_html")) {
207 fprintf(fd, _("IM Sessions with %s\n"), name);
208 } else {
209 fprintf(fd, "<HTML><HEAD><TITLE>");
210 fprintf(fd, _("IM Sessions with %s"), name);
211 fprintf(fd, "</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n");
212 }
213 }
214
215 return fd;
216 }
217
218 g_snprintf(realname, sizeof(realname), "%s.log", name);
219 fd = open_gaim_log_file(realname, &flag);
220
221 if (fd && flag) { /* is a new file */
222 if (gaim_prefs_get_bool("/gaim/gtk/logging/strip_html")) {
223 fprintf(fd, _("IM Sessions with %s\n"), name);
224 } else {
225 fprintf(fd, "<HTML><HEAD><TITLE>");
226 fprintf(fd, _("IM Sessions with %s"), name);
227 fprintf(fd, "</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n");
228 }
229 }
230
231 return fd;
232 }
233
234 void system_log(enum log_event what, GaimConnection *gc,
235 GaimBuddy *who, int why)
236 {
237 GaimAccount *account = NULL;
238 FILE *fd;
239 char text[256], html[256];
240
241 if (gc != NULL)
242 account = gaim_connection_get_account(gc);
243
244 if ((why & OPT_LOG_MY_SIGNON &&
245 !gaim_prefs_get_bool("/gaim/gtk/logging/log_own_states")) ||
246 (why & OPT_LOG_BUDDY_SIGNON &&
247 !gaim_prefs_get_bool("/gaim/gtk/logging/log_signon_signoff")) ||
248 (why & OPT_LOG_BUDDY_IDLE &&
249 !gaim_prefs_get_bool("/gaim/gtk/logging/log_idle_state")) ||
250 (why & OPT_LOG_BUDDY_AWAY &&
251 !gaim_prefs_get_bool("/gaim/gtk/logging/log_away_state"))) {
252
253 return;
254 }
255
256 if (gaim_prefs_get_bool("/gaim/gtk/logging/individual_logs")) {
257 if (why & OPT_LOG_MY_SIGNON)
258 fd = open_system_log_file(gc ? gaim_account_get_username(account) : NULL);
259 else
260 fd = open_system_log_file(who->name);
261 } else
262 fd = open_system_log_file(NULL);
263
264 if (!fd)
265 return;
266
267 if (why & OPT_LOG_MY_SIGNON) {
268 switch (what) {
269 case log_signon:
270 g_snprintf(text, sizeof(text), _("+++ %s (%s) signed on @ %s"),
271 gaim_account_get_username(account), gc->prpl->info->name, gaim_date_full());
272 g_snprintf(html, sizeof(html), "<B>%s</B>", text);
273 break;
274 case log_signoff:
275 g_snprintf(text, sizeof(text), _("+++ %s (%s) signed off @ %s"),
276 gaim_account_get_username(account), gc->prpl->info->name, gaim_date_full());
277 g_snprintf(html, sizeof(html), "<I><FONT COLOR=GRAY>%s</FONT></I>", text);
278 break;
279 case log_away:
280 g_snprintf(text, sizeof(text), _("+++ %s (%s) changed away state @ %s"),
281 gaim_account_get_username(account), gc->prpl->info->name, gaim_date_full());
282 g_snprintf(html, sizeof(html), "<FONT COLOR=OLIVE>%s</FONT>", text);
283 break;
284 case log_back:
285 g_snprintf(text, sizeof(text), _("+++ %s (%s) came back @ %s"),
286 gaim_account_get_username(account), gc->prpl->info->name, gaim_date_full());
287 g_snprintf(html, sizeof(html), "%s", text);
288 break;
289 case log_idle:
290 g_snprintf(text, sizeof(text), _("+++ %s (%s) became idle @ %s"),
291 gaim_account_get_username(account), gc->prpl->info->name, gaim_date_full());
292 g_snprintf(html, sizeof(html), "<FONT COLOR=GRAY>%s</FONT>", text);
293 break;
294 case log_unidle:
295 g_snprintf(text, sizeof(text), _("+++ %s (%s) returned from idle @ %s"),
296 gaim_account_get_username(account), gc->prpl->info->name, gaim_date_full());
297 g_snprintf(html, sizeof(html), "%s", text);
298 break;
299 case log_quit:
300 g_snprintf(text, sizeof(text), _("+++ Program exit @ %s"), gaim_date_full());
301 g_snprintf(html, sizeof(html), "<I><FONT COLOR=GRAY>%s</FONT></I>", text);
302 break;
303 }
304 } else if (gaim_get_buddy_alias_only(who)) {
305 switch (what) {
306 case log_signon:
307 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) signed on @ %s"),
308 gaim_account_get_username(account), gc->prpl->info->name, gaim_get_buddy_alias(who), who->name, gaim_date_full());
309 g_snprintf(html, sizeof(html), "<B>%s</B>", text);
310 break;
311 case log_signoff:
312 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) signed off @ %s"),
313 gaim_account_get_username(account), gc->prpl->info->name, gaim_get_buddy_alias(who), who->name, gaim_date_full());
314 g_snprintf(html, sizeof(html), "<I><FONT COLOR=GRAY>%s</FONT></I>", text);
315 break;
316 case log_away:
317 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) went away @ %s"),
318 gaim_account_get_username(account), gc->prpl->info->name, gaim_get_buddy_alias(who), who->name, gaim_date_full());
319 g_snprintf(html, sizeof(html), "<FONT COLOR=OLIVE>%s</FONT>", text);
320 break;
321 case log_back:
322 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) came back @ %s"),
323 gaim_account_get_username(account), gc->prpl->info->name, gaim_get_buddy_alias(who), who->name, gaim_date_full());
324 g_snprintf(html, sizeof(html), "%s", text);
325 break;
326 case log_idle:
327 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s (%s) became idle @ %s"),
328 gaim_account_get_username(account), gc->prpl->info->name, gaim_get_buddy_alias(who), who->name, gaim_date_full());
329 g_snprintf(html, sizeof(html), "<FONT COLOR=GRAY>%s</FONT>", text);
330 break;
331 case log_unidle:
332 g_snprintf(text, sizeof(text),
333 _("%s (%s) reported that %s (%s) returned from idle @ %s"), gaim_account_get_username(account),
334 gc->prpl->info->name, gaim_get_buddy_alias(who), who->name, gaim_date_full());
335 g_snprintf(html, sizeof(html), "%s", text);
336 break;
337 default:
338 fclose(fd);
339 return;
340 break;
341 }
342 } else {
343 switch (what) {
344 case log_signon:
345 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s signed on @ %s"),
346 gaim_account_get_username(account), gc->prpl->info->name, who->name, gaim_date_full());
347 g_snprintf(html, sizeof(html), "<B>%s</B>", text);
348 break;
349 case log_signoff:
350 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s signed off @ %s"),
351 gaim_account_get_username(account), gc->prpl->info->name, who->name, gaim_date_full());
352 g_snprintf(html, sizeof(html), "<I><FONT COLOR=GRAY>%s</FONT></I>", text);
353 break;
354 case log_away:
355 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s went away @ %s"),
356 gaim_account_get_username(account), gc->prpl->info->name, who->name, gaim_date_full());
357 g_snprintf(html, sizeof(html), "<FONT COLOR=OLIVE>%s</FONT>", text);
358 break;
359 case log_back:
360 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s came back @ %s"),
361 gaim_account_get_username(account), gc->prpl->info->name, who->name, gaim_date_full());
362 g_snprintf(html, sizeof(html), "%s", text);
363 break;
364 case log_idle:
365 g_snprintf(text, sizeof(text), _("%s (%s) reported that %s became idle @ %s"),
366 gaim_account_get_username(account), gc->prpl->info->name, who->name, gaim_date_full());
367 g_snprintf(html, sizeof(html), "<FONT COLOR=GRAY>%s</FONT>", text);
368 break;
369 case log_unidle:
370 g_snprintf(text, sizeof(text),
371 _("%s (%s) reported that %s returned from idle @ %s"), gaim_account_get_username(account),
372 gc->prpl->info->name, who->name, gaim_date_full());
373 g_snprintf(html, sizeof(html), "%s", text);
374 break;
375 default:
376 fclose(fd);
377 return;
378 break;
379 }
380 }
381
382 if (gaim_prefs_get_bool("/gaim/gtk/logging/strip_html"))
383 fprintf(fd, "---- %s ----\n", text);
384 else if (gaim_prefs_get_bool("/gaim/gtk/logging/individual_logs"))
385 fprintf(fd, "<HR>%s<BR><HR><BR>\n", html);
386 else
387 fprintf(fd, "%s<BR>\n", html);
388
389 fclose(fd);
390 }
391
392 char *html_logize(const char *p)
393 {
394 const char *temp_p;
395 char *buffer_p;
396 char *buffer_start;
397 int num_cr = 0;
398 int char_len = 0;
399
400 for (temp_p = p; *temp_p != '\0'; temp_p++) {
401 char_len++;
402
403 if ((*temp_p == '\n') || ((*temp_p == '<') && (*(temp_p + 1) == '!')))
404 num_cr++;
405 }
406
407 buffer_p = g_malloc(char_len + (4 * num_cr) + 1);
408
409 for (temp_p = p, buffer_start = buffer_p;
410 *temp_p != '\0';
411 temp_p++) {
412
413 if (*temp_p == '\n') {
414 *buffer_p++ = '<';
415 *buffer_p++ = 'B';
416 *buffer_p++ = 'R';
417 *buffer_p++ = '>';
418 *buffer_p++ = '\n';
419
420 } else if ((*temp_p == '<') && (*(temp_p + 1) == '!')) {
421 *buffer_p++ = '&';
422 *buffer_p++ = 'l';
423 *buffer_p++ = 't';
424 *buffer_p++ = ';';
425
426 } else
427 *buffer_p++ = *temp_p;
428 }
429
430 *buffer_p = '\0';
431
432 return buffer_start;
433 }