comparison libpurple/plugins/log_reader.c @ 20921:b2b16843851b

A patch from QuLogic to eliminate some duplication in the aMSN code, also from QuLogic. Fixes #3497 (again).
author Richard Laager <rlaager@wiktel.com>
date Sat, 13 Oct 2007 21:55:41 +0000
parents 54d232b52607
children d0fdf2f95277
comparison
equal deleted inserted replaced
20920:ef44eb0859fe 20921:b2b16843851b
2093 2093
2094 #define AMSN_LOG_CONV_START "|\"LRED[Conversation started on " 2094 #define AMSN_LOG_CONV_START "|\"LRED[Conversation started on "
2095 #define AMSN_LOG_CONV_END "|\"LRED[You have closed the window on " 2095 #define AMSN_LOG_CONV_END "|\"LRED[You have closed the window on "
2096 #define AMSN_LOG_CONV_EXTRA "01 Aug 2001 00:00:00]" 2096 #define AMSN_LOG_CONV_EXTRA "01 Aug 2001 00:00:00]"
2097 2097
2098 /* `log_dir`/username@hotmail.com/logs/buddyname@hotmail.com.log */ 2098 static GList *amsn_logger_parse_file(char *filename, const char *sn, PurpleAccount *account)
2099 /* `log_dir`/username@hotmail.com/logs/Month Year/buddyname@hotmail.com.log */
2100 static GList *amsn_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
2101 { 2099 {
2102 GList *list = NULL; 2100 GList *list = NULL;
2103 struct amsn_logger_data *data;
2104 const char *logdir;
2105 char *username;
2106 char *log_path;
2107 char *buddy_log;
2108 char *filename;
2109 GDir *dir;
2110 const char *name;
2111 GError *error; 2101 GError *error;
2112 char *contents; 2102 char *contents;
2103 struct amsn_logger_data *data;
2113 PurpleLog *log; 2104 PurpleLog *log;
2114 GList *files = NULL; 2105
2115 GList *f; 2106 purple_debug_info("aMSN logger", "Reading %s\n", filename);
2116 2107 error = NULL;
2117 logdir = purple_prefs_get_string("/plugins/core/log_reader/amsn/log_directory"); 2108 if (!g_file_get_contents(filename, &contents, NULL, &error)) {
2118 2109 purple_debug_error("aMSN logger",
2119 /* By clearing the log directory path, this logger can be (effectively) disabled. */ 2110 "Couldn't read file %s: %s \n", filename,
2120 if (!logdir || !*logdir) 2111 (error && error->message) ?
2121 return NULL; 2112 error->message : "Unknown error");
2122 2113 if (error)
2123 /* aMSN only works with MSN/WLM */ 2114 g_error_free(error);
2124 if (strcmp(account->protocol_id, "prpl-msn")) 2115 } else {
2125 return NULL; 2116 char *c = contents;
2126 2117 gboolean found_start = FALSE;
2127 username = g_strdup(purple_normalize(account, account->username)); 2118 char *start_log = c;
2128 buddy_log = g_strdup_printf("%s.log", purple_normalize(account, sn)); 2119 int offset = 0;
2129 log_path = g_build_filename(logdir, username, "logs", NULL); 2120 struct tm tm;
2130 2121 while (c && *c) {
2131 /* First check in the top-level */ 2122 if (purple_str_has_prefix(c, AMSN_LOG_CONV_START)) {
2132 filename = g_build_filename(log_path, buddy_log, NULL); 2123 char month[4];
2133 if (g_file_test(filename, G_FILE_TEST_EXISTS)) 2124 if (sscanf(c + strlen(AMSN_LOG_CONV_START),
2134 files = g_list_prepend(files, filename); 2125 "%u %3s %u %u:%u:%u",
2135 else 2126 &tm.tm_mday, (char*)&month, &tm.tm_year,
2136 g_free(filename); 2127 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
2137
2138 /* Check in previous months */
2139 dir = g_dir_open(log_path, 0, NULL);
2140 if (dir) {
2141 while ((name = g_dir_read_name(dir)) != NULL) {
2142 filename = g_build_filename(log_path, name, buddy_log, NULL);
2143 if (g_file_test(filename, G_FILE_TEST_EXISTS))
2144 files = g_list_prepend(files, filename);
2145 else
2146 g_free(filename);
2147 }
2148 g_dir_close(dir);
2149 }
2150
2151 g_free(log_path);
2152
2153 /* New versions use 'friendlier' directory names */
2154 purple_util_chrreplace(username, '@', '_');
2155 purple_util_chrreplace(username, '.', '_');
2156
2157 log_path = g_build_filename(logdir, username, "logs", NULL);
2158
2159 /* First check in the top-level */
2160 filename = g_build_filename(log_path, buddy_log, NULL);
2161 if (g_file_test(filename, G_FILE_TEST_EXISTS))
2162 files = g_list_prepend(files, filename);
2163 else
2164 g_free(filename);
2165
2166 /* Check in previous months */
2167 dir = g_dir_open(log_path, 0, NULL);
2168 if (dir) {
2169 while ((name = g_dir_read_name(dir)) != NULL) {
2170 filename = g_build_filename(log_path, name, buddy_log, NULL);
2171 if (g_file_test(filename, G_FILE_TEST_EXISTS))
2172 files = g_list_prepend(files, filename);
2173 else
2174 g_free(filename);
2175 }
2176 g_dir_close(dir);
2177 }
2178
2179 g_free(log_path);
2180 g_free(username);
2181 g_free(buddy_log);
2182
2183 /* Loop through files looking for logs */
2184 for(f = g_list_first(files); f; f = g_list_next(f)) {
2185 filename = f->data;
2186 purple_debug_info("aMSN logger", "Reading %s\n", filename);
2187 error = NULL;
2188 if (!g_file_get_contents(filename, &contents, NULL, &error)) {
2189 purple_debug_error("aMSN logger",
2190 "Couldn't read file %s: %s \n", filename,
2191 (error && error->message) ?
2192 error->message : "Unknown error");
2193 if (error)
2194 g_error_free(error);
2195 } else {
2196 char *c = contents;
2197 gboolean found_start = FALSE;
2198 char *start_log = c;
2199 int offset = 0;
2200 struct tm tm;
2201 while (c && *c) {
2202 if (purple_str_has_prefix(c, AMSN_LOG_CONV_START)) {
2203 char month[4];
2204 if (sscanf(c + strlen(AMSN_LOG_CONV_START),
2205 "%u %3s %u %u:%u:%u",
2206 &tm.tm_mday, (char*)&month, &tm.tm_year,
2207 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
2208 found_start = FALSE;
2209 purple_debug_error("aMSN logger",
2210 "Error parsing start date for %s\n",
2211 filename);
2212 } else {
2213 tm.tm_year -= 1900;
2214
2215 /* Let the C library deal with
2216 * daylight savings time.
2217 */
2218 tm.tm_isdst = -1;
2219 tm.tm_mon = get_month(month);
2220
2221 found_start = TRUE;
2222 offset = c - contents;
2223 start_log = c;
2224 }
2225 } else if (purple_str_has_prefix(c, AMSN_LOG_CONV_END) && found_start) {
2226 data = g_new0(struct amsn_logger_data, 1);
2227 data->path = g_strdup(filename);
2228 data->offset = offset;
2229 data->length = c - start_log
2230 + strlen(AMSN_LOG_CONV_END)
2231 + strlen(AMSN_LOG_CONV_EXTRA);
2232 log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
2233 log->logger = amsn_logger;
2234 log->logger_data = data;
2235 list = g_list_prepend(list, log);
2236 found_start = FALSE; 2128 found_start = FALSE;
2237 2129 purple_debug_error("aMSN logger",
2238 purple_debug_info("aMSN logger", 2130 "Error parsing start date for %s\n",
2239 "Found log for %s:" 2131 filename);
2240 " path = (%s)," 2132 } else {
2241 " offset = (%d)," 2133 tm.tm_year -= 1900;
2242 " length = (%d)\n", 2134
2243 sn, data->path, data->offset, data->length); 2135 /* Let the C library deal with
2136 * daylight savings time.
2137 */
2138 tm.tm_isdst = -1;
2139 tm.tm_mon = get_month(month);
2140
2141 found_start = TRUE;
2142 offset = c - contents;
2143 start_log = c;
2244 } 2144 }
2245 c = strstr(c, "\n"); 2145 } else if (purple_str_has_prefix(c, AMSN_LOG_CONV_END) && found_start) {
2246 c++;
2247 }
2248
2249 /* I've seen the file end without the AMSN_LOG_CONV_END bit */
2250 if (found_start) {
2251 data = g_new0(struct amsn_logger_data, 1); 2146 data = g_new0(struct amsn_logger_data, 1);
2252 data->path = g_strdup(filename); 2147 data->path = g_strdup(filename);
2253 data->offset = offset; 2148 data->offset = offset;
2254 data->length = c - start_log 2149 data->length = c - start_log
2255 + strlen(AMSN_LOG_CONV_END) 2150 + strlen(AMSN_LOG_CONV_END)
2265 " path = (%s)," 2160 " path = (%s),"
2266 " offset = (%d)," 2161 " offset = (%d),"
2267 " length = (%d)\n", 2162 " length = (%d)\n",
2268 sn, data->path, data->offset, data->length); 2163 sn, data->path, data->offset, data->length);
2269 } 2164 }
2270 g_free(contents); 2165 c = strstr(c, "\n");
2271 } 2166 c++;
2167 }
2168
2169 /* I've seen the file end without the AMSN_LOG_CONV_END bit */
2170 if (found_start) {
2171 data = g_new0(struct amsn_logger_data, 1);
2172 data->path = g_strdup(filename);
2173 data->offset = offset;
2174 data->length = c - start_log
2175 + strlen(AMSN_LOG_CONV_END)
2176 + strlen(AMSN_LOG_CONV_EXTRA);
2177 log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
2178 log->logger = amsn_logger;
2179 log->logger_data = data;
2180 list = g_list_prepend(list, log);
2181 found_start = FALSE;
2182
2183 purple_debug_info("aMSN logger",
2184 "Found log for %s:"
2185 " path = (%s),"
2186 " offset = (%d),"
2187 " length = (%d)\n",
2188 sn, data->path, data->offset, data->length);
2189 }
2190 g_free(contents);
2191 }
2192
2193 return list;
2194 }
2195
2196 /* `log_dir`/username@hotmail.com/logs/buddyname@hotmail.com.log */
2197 /* `log_dir`/username@hotmail.com/logs/Month Year/buddyname@hotmail.com.log */
2198 static GList *amsn_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
2199 {
2200 GList *list = NULL;
2201 const char *logdir;
2202 char *username;
2203 char *log_path;
2204 char *buddy_log;
2205 char *filename;
2206 GDir *dir;
2207 const char *name;
2208
2209 logdir = purple_prefs_get_string("/plugins/core/log_reader/amsn/log_directory");
2210
2211 /* By clearing the log directory path, this logger can be (effectively) disabled. */
2212 if (!logdir || !*logdir)
2213 return NULL;
2214
2215 /* aMSN only works with MSN/WLM */
2216 if (strcmp(account->protocol_id, "prpl-msn"))
2217 return NULL;
2218
2219 username = g_strdup(purple_normalize(account, account->username));
2220 buddy_log = g_strdup_printf("%s.log", purple_normalize(account, sn));
2221 log_path = g_build_filename(logdir, username, "logs", NULL);
2222
2223 /* First check in the top-level */
2224 filename = g_build_filename(log_path, buddy_log, NULL);
2225 if (g_file_test(filename, G_FILE_TEST_EXISTS))
2226 list = amsn_logger_parse_file(filename, sn, account);
2227 else
2272 g_free(filename); 2228 g_free(filename);
2273 } 2229
2274 2230 /* Check in previous months */
2275 g_list_free(files); 2231 dir = g_dir_open(log_path, 0, NULL);
2232 if (dir) {
2233 while ((name = g_dir_read_name(dir)) != NULL) {
2234 filename = g_build_filename(log_path, name, buddy_log, NULL);
2235 if (g_file_test(filename, G_FILE_TEST_EXISTS))
2236 list = g_list_concat(list, amsn_logger_parse_file(filename, sn, account));
2237 g_free(filename);
2238 }
2239 g_dir_close(dir);
2240 }
2241
2242 g_free(log_path);
2243
2244 /* New versions use 'friendlier' directory names */
2245 purple_util_chrreplace(username, '@', '_');
2246 purple_util_chrreplace(username, '.', '_');
2247
2248 log_path = g_build_filename(logdir, username, "logs", NULL);
2249
2250 /* First check in the top-level */
2251 filename = g_build_filename(log_path, buddy_log, NULL);
2252 if (g_file_test(filename, G_FILE_TEST_EXISTS))
2253 list = g_list_concat(list, amsn_logger_parse_file(filename, sn, account));
2254 g_free(filename);
2255
2256 /* Check in previous months */
2257 dir = g_dir_open(log_path, 0, NULL);
2258 if (dir) {
2259 while ((name = g_dir_read_name(dir)) != NULL) {
2260 filename = g_build_filename(log_path, name, buddy_log, NULL);
2261 if (g_file_test(filename, G_FILE_TEST_EXISTS))
2262 list = g_list_concat(list, amsn_logger_parse_file(filename, sn, account));
2263 g_free(filename);
2264 }
2265 g_dir_close(dir);
2266 }
2267
2268 g_free(log_path);
2269 g_free(username);
2270 g_free(buddy_log);
2276 2271
2277 return list; 2272 return list;
2278 } 2273 }
2279 2274
2280 /* Really it's |"L, but the string's been escaped */ 2275 /* Really it's |"L, but the string's been escaped */