| 176 g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(size)); |
176 g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(size)); |
| 177 } |
177 } |
| 178 return size; |
178 return size; |
| 179 } |
179 } |
| 180 |
180 |
| |
181 #if 0 |
| |
182 static char* unescape_filename(const char *escaped) { |
| |
183 const char *c = escaped; |
| |
184 GString *ret; |
| |
185 |
| |
186 if (escaped == NULL) |
| |
187 return NULL; |
| |
188 |
| |
189 ret = g_string_new(""); |
| |
190 |
| |
191 /** |
| |
192 * <>:"/\ |?*'&$ |
| |
193 * The above chars are "taboo" for gaim log names and are URL escaped |
| |
194 * % is also escaped so we can convert back easily |
| |
195 */ |
| |
196 |
| |
197 while (*c) { |
| |
198 if (*c == '%') { |
| |
199 if (*(c + 1) && *(c + 2)) { |
| |
200 char hex[2]; |
| |
201 hex[0] = *(c + 1); |
| |
202 hex[1] = *(c + 2); |
| |
203 unsigned char *nonhex; |
| |
204 gaim_base16_decode(hex, &nonhex); |
| |
205 ret = g_string_append_c(ret, *nonhex); |
| |
206 g_free(nonhex); |
| |
207 c += 2; |
| |
208 } |
| |
209 } else { |
| |
210 ret = g_string_append_c(ret, *c); |
| |
211 } |
| |
212 c++; |
| |
213 } |
| |
214 |
| |
215 return g_string_free(ret, FALSE); |
| |
216 } |
| |
217 #endif |
| |
218 |
| |
219 static char* escape_filename(const char *unescaped) { |
| |
220 const char *c = unescaped; |
| |
221 char *hex; |
| |
222 GString *ret; |
| |
223 |
| |
224 if (unescaped == NULL) |
| |
225 return NULL; |
| |
226 |
| |
227 ret = g_string_new(""); |
| |
228 |
| |
229 /** |
| |
230 * <>:"/\ |?*'&$ |
| |
231 * The above chars are "taboo" for gaim log names and are URL escaped |
| |
232 * % is also escaped so we can convert back easily |
| |
233 */ |
| |
234 |
| |
235 while (*c) { |
| |
236 switch (*c) { |
| |
237 case '<': |
| |
238 case '>': |
| |
239 case ':': |
| |
240 case '"': |
| |
241 case '/': |
| |
242 case '\\': |
| |
243 case ' ': |
| |
244 case '|': |
| |
245 case '?': |
| |
246 case '*': |
| |
247 case '\'': |
| |
248 case '&': |
| |
249 case '$': |
| |
250 case '%': |
| |
251 hex = g_strdup_printf ("%%%X", (int) *c); |
| |
252 ret = g_string_append(ret, hex); |
| |
253 g_free(hex); |
| |
254 break; |
| |
255 default: |
| |
256 ret = g_string_append_c(ret, *c); |
| |
257 } |
| |
258 c++; |
| |
259 } |
| |
260 |
| |
261 return g_string_free(ret, FALSE); |
| |
262 } |
| |
263 |
| |
264 static char* gaim_log_get_log_dir(GaimLogType type, const char *name, GaimAccount *account) { |
| |
265 char *acct_name = escape_filename(gaim_normalize(account, |
| |
266 gaim_account_get_username(account))); |
| |
267 char *target; |
| |
268 /* does this seem like a bad way to get this component of the path to anyone else? --Nathan */ |
| |
269 const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO( |
| |
270 gaim_find_prpl(gaim_account_get_protocol_id(account)) |
| |
271 )->list_icon(account, NULL); |
| |
272 |
| |
273 char *dir; |
| |
274 |
| |
275 if (type == GAIM_LOG_CHAT) { |
| |
276 char *temp = g_strdup_printf("%s.chat", gaim_normalize(account, name)); |
| |
277 target = escape_filename(temp); |
| |
278 g_free(temp); |
| |
279 } else if(type == GAIM_LOG_SYSTEM) { |
| |
280 target = g_strdup(".system"); |
| |
281 } else { |
| |
282 target = escape_filename(gaim_normalize(account, name)); |
| |
283 } |
| |
284 |
| |
285 |
| |
286 dir = g_build_filename(gaim_user_dir(), "logs", prpl, acct_name, target, NULL); |
| |
287 g_free(target); |
| |
288 g_free(acct_name); |
| |
289 |
| |
290 return dir; |
| |
291 } |
| |
292 |
| 181 /**************************************************************************** |
293 /**************************************************************************** |
| 182 * LOGGER FUNCTIONS ********************************************************* |
294 * LOGGER FUNCTIONS ********************************************************* |
| 183 ****************************************************************************/ |
295 ****************************************************************************/ |
| 184 |
296 |
| 185 static GaimLogLogger *current_logger = NULL; |
297 static GaimLogLogger *current_logger = NULL; |
| 334 char *path; |
446 char *path; |
| 335 FILE *file; |
447 FILE *file; |
| 336 }; |
448 }; |
| 337 |
449 |
| 338 static void log_writer_common(GaimLog *log, GaimMessageFlags type, |
450 static void log_writer_common(GaimLog *log, GaimMessageFlags type, |
| 339 const char *prpl, time_t time, |
451 time_t time, const char *ext) |
| 340 const char *ext) |
|
| 341 { |
452 { |
| 342 char date[64]; |
453 char date[64]; |
| 343 struct generic_logger_data *data = log->logger_data; |
454 struct generic_logger_data *data = log->logger_data; |
| 344 |
455 |
| 345 if(!data) { |
456 if(!data) { |
| 346 /* This log is new */ |
457 /* This log is new */ |
| 347 char *ud = gaim_user_dir(); |
458 char *dir, *filename, *path; |
| 348 char *acct_name = g_strdup(gaim_normalize(log->account, |
459 |
| 349 gaim_account_get_username(log->account))); |
460 dir = gaim_log_get_log_dir(log->type, log->name, log->account); |
| 350 char *target; |
461 gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR); |
| 351 char *dir; |
|
| 352 char *filename, *path; |
|
| 353 |
|
| 354 if (log->type == GAIM_LOG_CHAT) { |
|
| 355 target = g_strdup_printf("%s.chat", gaim_normalize(log->account, |
|
| 356 log->name)); |
|
| 357 } else if(log->type == GAIM_LOG_SYSTEM) { |
|
| 358 target = g_strdup(".system"); |
|
| 359 } else { |
|
| 360 target = g_strdup(gaim_normalize(log->account, log->name)); |
|
| 361 } |
|
| 362 |
462 |
| 363 strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S", localtime(&log->time)); |
463 strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S", localtime(&log->time)); |
| 364 |
|
| 365 dir = g_build_filename(ud, "logs", |
|
| 366 prpl, acct_name, target, NULL); |
|
| 367 gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR); |
|
| 368 g_free(target); |
|
| 369 g_free(acct_name); |
|
| 370 |
464 |
| 371 filename = g_strdup_printf("%s%s", date, ext ? ext : ""); |
465 filename = g_strdup_printf("%s%s", date, ext ? ext : ""); |
| 372 |
466 |
| 373 path = g_build_filename(dir, filename, NULL); |
467 path = g_build_filename(dir, filename, NULL); |
| 374 g_free(dir); |
468 g_free(dir); |
| 390 static GList *log_lister_common(GaimLogType type, const char *name, GaimAccount *account, const char *ext, GaimLogLogger *logger) |
484 static GList *log_lister_common(GaimLogType type, const char *name, GaimAccount *account, const char *ext, GaimLogLogger *logger) |
| 391 { |
485 { |
| 392 GDir *dir; |
486 GDir *dir; |
| 393 GList *list = NULL; |
487 GList *list = NULL; |
| 394 const char *filename; |
488 const char *filename; |
| 395 char *me; |
|
| 396 const char *prpl; |
|
| 397 char *path; |
489 char *path; |
| 398 |
490 |
| 399 if(!account) |
491 if(!account) |
| 400 return NULL; |
492 return NULL; |
| 401 |
493 |
| 402 if (type == GAIM_LOG_CHAT) |
494 path = gaim_log_get_log_dir(type, name, account); |
| 403 me = g_strdup_printf("%s.chat", gaim_normalize(account, gaim_account_get_username(account))); |
|
| 404 else |
|
| 405 me = g_strdup(gaim_normalize(account, gaim_account_get_username(account))); |
|
| 406 |
|
| 407 /* does this seem like a bad way to get this component of the path to anyone else? --Nathan */ |
|
| 408 prpl = GAIM_PLUGIN_PROTOCOL_INFO |
|
| 409 (gaim_find_prpl(gaim_account_get_protocol_id(account)))->list_icon(account, NULL); |
|
| 410 if(type == GAIM_LOG_SYSTEM) |
|
| 411 path = g_build_filename(gaim_user_dir(),"logs", prpl, me, name, NULL); |
|
| 412 else |
|
| 413 path = g_build_filename(gaim_user_dir(),"logs", prpl, me, gaim_normalize(account, name), NULL); |
|
| 414 g_free(me); |
|
| 415 |
495 |
| 416 if (!(dir = g_dir_open(path, 0, NULL))) { |
496 if (!(dir = g_dir_open(path, 0, NULL))) { |
| 417 g_free(path); |
497 g_free(path); |
| 418 return NULL; |
498 return NULL; |
| 419 } |
499 } |
| 470 if (!log->logger_data) { |
550 if (!log->logger_data) { |
| 471 /* This log is new. We could use the loggers 'new' function, but |
551 /* This log is new. We could use the loggers 'new' function, but |
| 472 * creating a new file there would result in empty files in the case |
552 * creating a new file there would result in empty files in the case |
| 473 * that you open a convo with someone, but don't say anything. |
553 * that you open a convo with someone, but don't say anything. |
| 474 */ |
554 */ |
| 475 char *ud = gaim_user_dir(); |
555 char *dir = gaim_log_get_log_dir(log->type, log->name, log->account); |
| 476 char *guy = g_strdup(gaim_normalize(log->account, gaim_account_get_username(log->account))); |
|
| 477 const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO |
|
| 478 (gaim_find_prpl(gaim_account_get_protocol(log->account)))->list_icon(log->account, NULL); |
|
| 479 char *dir; |
|
| 480 FILE *file; |
556 FILE *file; |
| 481 |
|
| 482 if (log->type == GAIM_LOG_CHAT) { |
|
| 483 char *chat = g_strdup_printf("%s.chat", guy); |
|
| 484 g_free(guy); |
|
| 485 guy = chat; |
|
| 486 } |
|
| 487 |
|
| 488 strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S.xml", localtime(&log->time)); |
557 strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S.xml", localtime(&log->time)); |
| 489 |
558 |
| 490 dir = g_build_filename(ud, "logs", |
|
| 491 prpl, guy, gaim_normalize(log->account, log->name), NULL); |
|
| 492 gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR); |
559 gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR); |
| 493 g_free(guy); |
|
| 494 |
560 |
| 495 char *filename = g_build_filename(dir, date, NULL); |
561 char *filename = g_build_filename(dir, date, NULL); |
| 496 g_free(dir); |
562 g_free(dir); |
| 497 |
563 |
| 498 log->logger_data = fopen(filename, "a"); |
564 log->logger_data = fopen(filename, "a"); |
| 507 |
573 |
| 508 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&log->time)); |
574 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&log->time)); |
| 509 fprintf(log->logger_data, "<conversation time='%s' screenname='%s' protocol='%s'>\n", |
575 fprintf(log->logger_data, "<conversation time='%s' screenname='%s' protocol='%s'>\n", |
| 510 date, log->name, prpl); |
576 date, log->name, prpl); |
| 511 } |
577 } |
| |
578 |
| |
579 /* if we can't write to the file, give up before we hurt ourselves */ |
| |
580 if(!data->file) |
| |
581 return; |
| 512 |
582 |
| 513 strftime(date, sizeof(date), "%H:%M:%S", localtime(&time)); |
583 strftime(date, sizeof(date), "%H:%M:%S", localtime(&time)); |
| 514 gaim_markup_html_to_xhtml(message, &xhtml, NULL); |
584 gaim_markup_html_to_xhtml(message, &xhtml, NULL); |
| 515 if (from) |
585 if (from) |
| 516 fprintf(log->logger_data, "<message %s %s from='%s' time='%s'>%s</message>\n", |
586 fprintf(log->logger_data, "<message %s %s from='%s' time='%s'>%s</message>\n", |
| 567 struct generic_logger_data *data = log->logger_data; |
637 struct generic_logger_data *data = log->logger_data; |
| 568 |
638 |
| 569 if(!data) { |
639 if(!data) { |
| 570 const char *prpl = |
640 const char *prpl = |
| 571 GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL); |
641 GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL); |
| 572 log_writer_common(log, type, prpl, time, ".html"); |
642 log_writer_common(log, type, time, ".html"); |
| 573 |
643 |
| 574 data = log->logger_data; |
644 data = log->logger_data; |
| 575 |
645 |
| 576 /* if we can't write to the file, give up before we hurt ourselves */ |
646 /* if we can't write to the file, give up before we hurt ourselves */ |
| 577 if(!data->file) |
647 if(!data->file) |
| 705 * creating a new file there would result in empty files in the case |
775 * creating a new file there would result in empty files in the case |
| 706 * that you open a convo with someone, but don't say anything. |
776 * that you open a convo with someone, but don't say anything. |
| 707 */ |
777 */ |
| 708 const char *prpl = |
778 const char *prpl = |
| 709 GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL); |
779 GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL); |
| 710 log_writer_common(log, type, prpl, time, ".txt"); |
780 log_writer_common(log, type, time, ".txt"); |
| 711 |
781 |
| 712 data = log->logger_data; |
782 data = log->logger_data; |
| 713 |
783 |
| 714 /* if we can't write to the file, give up before we hurt ourselves */ |
784 /* if we can't write to the file, give up before we hurt ourselves */ |
| 715 if(!data->file) |
785 if(!data->file) |