Mercurial > pidgin
comparison src/log.c @ 9923:248c3f88ce99
[gaim-migrate @ 10815]
(14:24:22) datallah: LSchiere2:
http://www.butfer.com/gaim-patches/log_filename_escaping.patch deals with
creating logs for screennames that have characters that are not valid for
filenames
(14:25:34) datallah: i may write a conversion script for existing log files
(particularly because it will cause all irc and yahoo chats not to be
found)
(14:25:49) datallah: oh.. not irc chats... only yahoo chats
(14:26:10) LSchiere2: can yahoo chats be found now?
(14:26:35) datallah: yeah... they all have a ':' in them which is not a
valid filename character in win32
(14:26:51) LSchiere2: i see. so they can be found on unix but not on win32
(14:27:51) datallah: LSchiere2: yeah, as far as i know
committer: Tailor Script <tailor@pidgin.im>
| author | Luke Schierer <lschiere@pidgin.im> |
|---|---|
| date | Tue, 31 Aug 2004 18:28:35 +0000 |
| parents | 284a84477ee9 |
| children | b23e70bd1215 |
comparison
equal
deleted
inserted
replaced
| 9922:b03884f4eda6 | 9923:248c3f88ce99 |
|---|---|
| 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) |
