log_reader.c
来自「Linux下的多协议即时通讯程序源代码」· C语言 代码 · 共 2,177 行 · 第 1/4 页
C
2,177 行
} else if (hour == 12) { /* 12 AM = 00 hr */ hour = 0; } str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec); t = purple_str_to_time(str, TRUE, &tm, NULL, NULL); if (stamp > t) diff = stamp - t; else diff = t - stamp; if (diff > (14 * 60 * 60)) { if (day <= 12) { /* Swap day & month variables, to see if it's a non-US date. */ g_free(str); str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec); t = purple_str_to_time(str, TRUE, &tm, NULL, NULL); if (stamp > t) diff = stamp - t; else diff = t - stamp; if (diff > (14 * 60 * 60)) { /* We got a time, it's not impossible, but * the diff is too large. Display the UTC time. */ g_free(str); *tm_out = &tm2; return stamp; } else { /* Legal time */ /* Fall out */ } } else { /* We got a time, it's not impossible, but * the diff is too large. Display the UTC time. */ g_free(str); *tm_out = &tm2; return stamp; } } /* If we got here, the time is legal with a reasonable offset. * Let's find out if it's in our TZ. */ if (purple_str_to_time(str, FALSE, &tm, NULL, NULL) == stamp) { g_free(str); *tm_out = &tm; return stamp; } g_free(str); /* The time isn't in our TZ, but it's reasonable. */#ifdef HAVE_STRUCT_TM_TM_ZONE tm.tm_zone = " ";#endif *tm_out = &tm; return stamp;}static GList *msn_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account){ GList *list = NULL; char *username; PurpleBuddy *buddy; const char *logdir; const char *savedfilename = NULL; char *logfile; char *path; GError *error = NULL; gchar *contents = NULL; gsize length; xmlnode *root; xmlnode *message; const char *old_session_id = ""; struct msn_logger_data *data = NULL; g_return_val_if_fail(sn != NULL, list); g_return_val_if_fail(account != NULL, list); if (strcmp(account->protocol_id, "prpl-msn")) return list; logdir = purple_prefs_get_string("/plugins/core/log_reader/msn/log_directory"); /* By clearing the log directory path, this logger can be (effectively) disabled. */ if (!*logdir) return list; buddy = purple_find_buddy(account, sn); if ((username = g_strdup(purple_account_get_string( account, "log_reader_msn_log_folder", NULL)))) { /* As a special case, we allow the null string to kill the parsing * straight away. This would allow the user to deal with the case * when two account have the same username at different domains and * only one has logs stored. */ if (!*username) { g_free(username); return list; } } else { username = g_strdup(purple_normalize(account, account->username)); } if (buddy) savedfilename = purple_blist_node_get_string(&buddy->node, "log_reader_msn_log_filename"); if (savedfilename) { /* As a special case, we allow the null string to kill the parsing * straight away. This would allow the user to deal with the case * when two buddies have the same username at different domains and * only one has logs stored. */ if (!*savedfilename) { g_free(username); return list; } logfile = g_strdup(savedfilename); } else { logfile = g_strdup_printf("%s.xml", purple_normalize(account, sn)); } path = g_build_filename(logdir, username, "History", logfile, NULL); if (!g_file_test(path, G_FILE_TEST_EXISTS)) { gboolean found = FALSE; char *at_sign; GDir *dir; g_free(path); if (savedfilename) { /* We had a saved filename, but it doesn't exist. * Returning now is the right course of action because we don't * want to detect another file incorrectly. */ g_free(username); g_free(logfile); return list; } /* Perhaps we're using a new version of MSN with the weird numbered folders. * I don't know how the numbers are calculated, so I'm going to attempt to * find logs by pattern matching... */ at_sign = g_strrstr(username, "@"); if (at_sign) *at_sign = '\0'; dir = g_dir_open(logdir, 0, NULL); if (dir) { const gchar *name; while ((name = g_dir_read_name(dir))) { const char *c = name; if (!purple_str_has_prefix(c, username)) continue; c += strlen(username); while (*c) { if (!g_ascii_isdigit(*c)) break; c++; } path = g_build_filename(logdir, name, NULL); /* The !c makes sure we got to the end of the while loop above. */ if (!*c && g_file_test(path, G_FILE_TEST_IS_DIR)) { char *history_path = g_build_filename( path, "History", NULL); if (g_file_test(history_path, G_FILE_TEST_IS_DIR)) { purple_account_set_string(account, "log_reader_msn_log_folder", name); g_free(path); path = history_path; found = TRUE; break; } g_free(path); g_free(history_path); } else g_free(path); } g_dir_close(dir); } g_free(username); if (!found) { g_free(logfile); return list; } /* If we've reached this point, we've found a History folder. */ username = g_strdup(purple_normalize(account, sn)); at_sign = g_strrstr(username, "@"); if (at_sign) *at_sign = '\0'; found = FALSE; dir = g_dir_open(path, 0, NULL); if (dir) { const gchar *name; while ((name = g_dir_read_name(dir))) { const char *c = name; if (!purple_str_has_prefix(c, username)) continue; c += strlen(username); while (*c) { if (!g_ascii_isdigit(*c)) break; c++; } path = g_build_filename(path, name, NULL); if (!strcmp(c, ".xml") && g_file_test(path, G_FILE_TEST_EXISTS)) { found = TRUE; g_free(logfile); logfile = g_strdup(name); break; } else g_free(path); } g_dir_close(dir); } g_free(username); if (!found) { g_free(logfile); return list; } } else { g_free(username); g_free(logfile); logfile = NULL; /* No sense saving the obvious buddy@domain.com. */ } purple_debug(PURPLE_DEBUG_INFO, "MSN log read", "Reading %s\n", path); if (!g_file_get_contents(path, &contents, &length, &error)) { g_free(path); purple_debug(PURPLE_DEBUG_ERROR, "MSN log read", "Error reading log\n"); if (error) g_error_free(error); return list; } g_free(path); /* Reading the file was successful... * Save its name if it involves the crazy numbers. The idea here is that you could * then tweak the blist.xml file by hand if need be. This would be the case if two * buddies have the same username at different domains. One set of logs would get * detected for both buddies. */ if (buddy && logfile) { purple_blist_node_set_string(&buddy->node, "log_reader_msn_log_filename", logfile); g_free(logfile); } root = xmlnode_from_str(contents, length); g_free(contents); if (!root) return list; for (message = xmlnode_get_child(root, "Message"); message; message = xmlnode_get_next_twin(message)) { const char *session_id; session_id = xmlnode_get_attrib(message, "SessionID"); if (!session_id) { purple_debug(PURPLE_DEBUG_ERROR, "MSN log parse", "Error parsing message: %s\n", "SessionID missing"); continue; } if (strcmp(session_id, old_session_id)) { /* * The session ID differs from the last message. * Thus, this is the start of a new conversation. */ struct tm *tm; time_t stamp; PurpleLog *log; data = g_new0(struct msn_logger_data, 1); data->root = root; data->message = message; data->session_id = session_id; data->text = NULL; data->last_log = FALSE; stamp = msn_logger_parse_timestamp(message, &tm); log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, stamp, tm); log->logger = msn_logger; log->logger_data = data; list = g_list_append(list, log); } old_session_id = session_id; } if (data) data->last_log = TRUE; return list;}static char * msn_logger_read (PurpleLog *log, PurpleLogReadFlags *flags){ struct msn_logger_data *data; GString *text = NULL; xmlnode *message; g_return_val_if_fail(log != NULL, g_strdup("")); data = log->logger_data; if (data->text) { /* The GTK code which displays the logs g_free()s whatever is * returned from this function. Thus, we can't reuse the str * part of the GString. The only solution is to free it and * start over. */ g_string_free(data->text, FALSE); } text = g_string_new(""); if (!data->root || !data->message || !data->session_id) { /* Something isn't allocated correctly. */ purple_debug(PURPLE_DEBUG_ERROR, "MSN log parse", "Error parsing message: %s\n", "Internal variables inconsistent"); data->text = text; return text->str; } for (message = data->message; message; message = xmlnode_get_next_twin(message)) { const char *new_session_id; xmlnode *text_node; const char *from_name = NULL; const char *to_name = NULL; xmlnode *from; xmlnode *to; enum name_guesses name_guessed = NAME_GUESS_UNKNOWN; const char *their_name; time_t time_unix; struct tm *tm; char *timestamp; char *tmp; const char *style; new_session_id = xmlnode_get_attrib(message, "SessionID"); /* If this triggers, something is wrong with the XML. */ if (!new_session_id) { purple_debug(PURPLE_DEBUG_ERROR, "MSN log parse", "Error parsing message: %s\n", "New SessionID missing"); break; } if (strcmp(new_session_id, data->session_id)) { /* The session ID differs from the first message. * Thus, this is the start of a new conversation. */ break; } text_node = xmlnode_get_child(message, "Text"); if (!text_node) continue; from = xmlnode_get_child(message, "From"); if (from) { xmlnode *user = xmlnode_get_child(from, "User"); if (user) { from_name = xmlnode_get_attrib(user, "FriendlyName"); /* This saves a check later. */ if (!*from_name) from_name = NULL; } } to = xmlnode_get_child(message, "To"); if (to) { xmlnode *user = xmlnode_get_child(to, "User"); if (user) { to_name = xmlnode_get_attrib(user, "FriendlyName"); /* This saves a check later. */ if (!*to_name) to_name = NULL; } } their_name = from_name; if (from_name && purple_prefs_get_bool("/plugins/core/log_reader/use_name_heuristics")) { const char *friendly_name = purple_connection_get_display_name(log->account->gc); if (friendly_name != NULL) { int friendly_name_length = strlen(friendly_name); const char *alias; int alias_length; PurpleBuddy *buddy = purple_find_buddy(log->account, log->name); gboolean from_name_matches; gboolean to_name_matches; if (buddy && buddy->alias) their_name = buddy->alias; if (log->account->alias) { alias = log->account->alias; alias_length = strlen(alias); } else { alias = ""; alias_length = 0; } /* Try to guess which user is me. * The first step is to determine if either of the names matches either my * friendly name or alias. For this test, "match" is defined as: * ^(friendly_name|alias)([^a-zA-Z0-9].*)?$ */ from_name_matches = (purple_str_has_prefix(from_name, friendly_name) && !isalnum(*(from_name + friendly_name_length))) || (purple_str_has_prefix(from_name, alias) && !isalnum(*(from_name + alias_length))); to_name_matches = to_name != NULL && ( (purple_str_has_prefix(to_name, friendly_name) && !isalnum(*(to_name + friendly_name_length))) || (purple_str_has_prefix(to_name, alias) && !isalnum(*(to_name + alias_length)))); if (from_name_matches) { if (!to_name_matches) { name_guessed = NAME_GUESS_ME; } } else if (to_name_matches) { name_guessed = NAME_GUESS_THEM; } else { if (buddy && buddy->alias) { char *alias = g_strdup(buddy->alias); /* "Truncate" the string at the first non-alphanumeric * character. The idea is to relax the comparison. */ char *temp; for (temp = alias; *temp ; temp++) { if (!isalnum(*temp)) { *temp = '\0'; break; } } alias_length = strlen(alias); /* Try to guess which user is them. * The first step is to determine if either of the names * matches their alias. For this test, "match" is * defined as: ^alias([^a-zA-Z0-9].*)?$ */ from_name_matches = (purple_str_has_prefix( from_name, alias) && !isalnum(*(from_name + alias_length))); to_name_matches = to_name && (purple_str_has_prefix( to_name, alias) && !isalnum(*(to_name + alias_length))); g_free(alias); if (from_name_matches) { if (!to_name_matches) { name_guessed = NAME_GUESS_THEM; } } else if (to_name_matches) { name_guessed = NAME_GUESS_ME; } else if (buddy->server_alias) { friendly_name_length = strlen(buddy->server_alias); /* Try to guess which user is them. * The first step is to determine if either of * the names matches their friendly name. For * this test, "match" is defined as: * ^friendly_name([^a-zA-Z0-9].*)?$ */ from_name_matches = (purple_str_has_prefix( from_name, buddy->server_alias) && !isalnum(*(from_name + friendly_name_length))); to_name_matches = to_name && ( (purple_str_has_prefix( to_name, buddy->server_alias) && !isalnum(*(to_name + friendly_name_length)))); if (from_name_matches) { if (!to_name_matches) { name_guessed = NAME_GUESS_THEM; } } else if (to_name_matches) { name_guessed = NAME_GUESS_ME; } } } } } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?