Mercurial > pidgin
comparison libpurple/plugins/log_reader.c @ 17979:c8d2e131cc37
QIP logger was implemented
| author | Michael Shkutkov <mshkutkov@soc.pidgin.im> |
|---|---|
| date | Wed, 13 Jun 2007 12:26:17 +0000 |
| parents | 21773944db4b |
| children | b5e9a814b711 |
comparison
equal
deleted
inserted
replaced
| 17978:fa4b70c5ea9d | 17979:c8d2e131cc37 |
|---|---|
| 1722 g_free(data->path); | 1722 g_free(data->path); |
| 1723 g_free(data->their_nickname); | 1723 g_free(data->their_nickname); |
| 1724 | 1724 |
| 1725 } | 1725 } |
| 1726 | 1726 |
| 1727 /***************************************************************************** | |
| 1728 * QIP Logger * | |
| 1729 *****************************************************************************/ | |
| 1730 | |
| 1731 /* The QIP logger doesn't write logs, only reads them. This is to include | |
| 1732 * QIP logs in the log viewer transparently. | |
| 1733 */ | |
| 1734 #define QIP_LOG_DELIMITER "--------------------------------------" | |
| 1735 #define QIP_LOG_IN_MESSAGE (QIP_LOG_DELIMITER "<-") | |
| 1736 #define QIP_LOG_OUT_MESSAGE (QIP_LOG_DELIMITER ">-") | |
| 1737 #define QIP_LOG_IN_MESSAGE_ESC (QIP_LOG_DELIMITER "<-") | |
| 1738 #define QIP_LOG_OUT_MESSAGE_ESC (QIP_LOG_DELIMITER ">-") | |
| 1739 | |
| 1740 #define DEBUG_MESSAGE(var, sign, value, title) if(var sign value) \ | |
| 1741 purple_debug(PURPLE_DEBUG_ERROR, title, \ | |
| 1742 #var " " #sign " " #value "\n"); | |
| 1743 | |
| 1744 static PurpleLogLogger *qip_logger; | |
| 1745 static void qip_logger_finalize(PurpleLog *log); | |
| 1746 | |
| 1747 struct qip_logger_data { | |
| 1748 | |
| 1749 char *path; /* FIXME: Change this to use PurpleStringref like log.c:old_logger_list */ | |
| 1750 int offset; | |
| 1751 int length; | |
| 1752 }; | |
| 1753 | |
| 1754 static GList *qip_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account) | |
| 1755 { | |
| 1756 GList *list = NULL; | |
| 1757 const char *logdir; | |
| 1758 PurplePlugin *plugin; | |
| 1759 PurplePluginProtocolInfo *prpl_info; | |
| 1760 const char *buddy_name; | |
| 1761 char *username; | |
| 1762 char *filename; | |
| 1763 char *path; | |
| 1764 GError *error = NULL; | |
| 1765 gchar *contents = NULL; | |
| 1766 gsize length; | |
| 1767 gchar *c; | |
| 1768 | |
| 1769 purple_debug(PURPLE_DEBUG_INFO, "QIP logger list", | |
| 1770 "start\n"); | |
| 1771 | |
| 1772 g_return_val_if_fail(sn != NULL, list); | |
| 1773 g_return_val_if_fail(account != NULL, list); | |
| 1774 | |
| 1775 purple_debug(PURPLE_DEBUG_INFO, "QIP logger list", | |
| 1776 "arguments not NULL\n"); | |
| 1777 | |
| 1778 /* QIP is ICQ messenger. Should we add prpl-aim? */ | |
| 1779 if (strcmp(account->protocol_id, "prpl-icq")) | |
| 1780 return list; | |
| 1781 | |
| 1782 purple_debug(PURPLE_DEBUG_INFO, "QIP logger list", | |
| 1783 "protocol is 'prpl-icq'\n"); | |
| 1784 | |
| 1785 logdir = purple_prefs_get_string("/plugins/core/log_reader/qip/log_directory"); | |
| 1786 | |
| 1787 /* By clearing the log directory path, this logger can be (effectively) disabled. */ | |
| 1788 if (!*logdir) | |
| 1789 return list; | |
| 1790 | |
| 1791 plugin = purple_find_prpl(purple_account_get_protocol_id(account)); | |
| 1792 if (!plugin) | |
| 1793 return NULL; | |
| 1794 | |
| 1795 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); | |
| 1796 if (!prpl_info->list_icon) | |
| 1797 return NULL; | |
| 1798 | |
| 1799 buddy_name = g_strdup(purple_normalize(account, sn)); | |
| 1800 purple_debug(PURPLE_DEBUG_INFO, "QIP logger list", | |
| 1801 "buddy_name %s\n", buddy_name); | |
| 1802 | |
| 1803 username = g_strdup(purple_normalize(account, account->username)); | |
| 1804 purple_debug(PURPLE_DEBUG_INFO, "QIP logger list", | |
| 1805 "username %s\n", username); | |
| 1806 | |
| 1807 purple_debug(PURPLE_DEBUG_INFO, "QIP logger list", | |
| 1808 "sn %s\n", sn); | |
| 1809 | |
| 1810 filename = g_strdup_printf("%s.txt", buddy_name); | |
| 1811 path = g_build_filename( | |
| 1812 logdir, username, "History", filename, NULL); | |
| 1813 purple_debug(PURPLE_DEBUG_INFO, "QIP logger list", | |
| 1814 "Reading %s\n", path); | |
| 1815 if (!g_file_get_contents(path, &contents, &length, &error)) | |
| 1816 if (error) | |
| 1817 g_error_free(error); | |
| 1818 | |
| 1819 if (contents) { | |
| 1820 struct qip_logger_data *data = NULL; | |
| 1821 | |
| 1822 purple_debug(PURPLE_DEBUG_INFO, "QIP logger list", | |
| 1823 "File %s is found\n", filename); | |
| 1824 c = contents; | |
| 1825 if (purple_str_has_prefix(c, QIP_LOG_IN_MESSAGE) || | |
| 1826 purple_str_has_prefix(c, QIP_LOG_OUT_MESSAGE)) { | |
| 1827 | |
| 1828 /* find next line */ | |
| 1829 while(*c && *c != '\n') { | |
| 1830 c++; | |
| 1831 } | |
| 1832 | |
| 1833 if (*c) { | |
| 1834 char *timestamp = c; | |
| 1835 | |
| 1836 while (*timestamp && (*timestamp !='(')) | |
| 1837 timestamp++; | |
| 1838 | |
| 1839 if (*timestamp == '(') { | |
| 1840 struct tm tm; | |
| 1841 | |
| 1842 timestamp++; | |
| 1843 | |
| 1844 /* Parse the time, day, month and year */ | |
| 1845 if (sscanf(timestamp, "%u:%u:%u %u/%u/%u", | |
| 1846 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, | |
| 1847 &tm.tm_mday, &tm.tm_mon, &tm.tm_year) != 6) { | |
| 1848 purple_debug(PURPLE_DEBUG_ERROR, "QIP logger list", | |
| 1849 "Parsing timestamp error\n"); | |
| 1850 } else { | |
| 1851 PurpleLog *log; | |
| 1852 | |
| 1853 | |
| 1854 /* cos month of year in [0,11] */ | |
| 1855 tm.tm_mon -= 1; | |
| 1856 /* cos years since 1900 */ | |
| 1857 tm.tm_year -= 1900; | |
| 1858 | |
| 1859 purple_debug(PURPLE_DEBUG_INFO, | |
| 1860 "QIP logger list", | |
| 1861 "Parsing timestamp: %u/%u/%u %u:%u:%u\n", | |
| 1862 tm.tm_year, tm.tm_mon, tm.tm_mday, | |
| 1863 tm.tm_hour, tm.tm_min, tm.tm_sec); | |
| 1864 | |
| 1865 /* Let the C library deal with | |
| 1866 * daylight savings time. | |
| 1867 */ | |
| 1868 tm.tm_isdst = -1; | |
| 1869 | |
| 1870 data = g_new0( | |
| 1871 struct qip_logger_data, 1); | |
| 1872 data->path = g_strdup(path); | |
| 1873 data->offset = 0; | |
| 1874 data->length = strlen(contents); | |
| 1875 | |
| 1876 /* XXX: Look into this later... Should we pass in a struct tm? */ | |
| 1877 log = purple_log_new(PURPLE_LOG_IM, | |
| 1878 sn, account, NULL, mktime(&tm), NULL); | |
| 1879 | |
| 1880 log->logger = qip_logger; | |
| 1881 log->logger_data = data; | |
| 1882 | |
| 1883 list = g_list_append(list, log); | |
| 1884 } | |
| 1885 } | |
| 1886 } | |
| 1887 } | |
| 1888 | |
| 1889 g_free(contents); | |
| 1890 } | |
| 1891 | |
| 1892 g_free(username); | |
| 1893 g_free(path); | |
| 1894 g_free(filename); | |
| 1895 | |
| 1896 return list; | |
| 1897 } | |
| 1898 | |
| 1899 static char * qip_logger_read (PurpleLog *log, PurpleLogReadFlags *flags) | |
| 1900 { | |
| 1901 struct qip_logger_data *data; | |
| 1902 char *read; | |
| 1903 FILE *file; | |
| 1904 PurpleBuddy *buddy; | |
| 1905 char *escaped; | |
| 1906 GString *formatted; | |
| 1907 char *c; | |
| 1908 const char *line; | |
| 1909 | |
| 1910 purple_debug(PURPLE_DEBUG_INFO, "QIP logger read", | |
| 1911 "start\n"); | |
| 1912 | |
| 1913 DEBUG_MESSAGE(log, ==, NULL, "QIP logger read"); | |
| 1914 g_return_val_if_fail(log != NULL, g_strdup("")); | |
| 1915 | |
| 1916 data = log->logger_data; | |
| 1917 | |
| 1918 DEBUG_MESSAGE(data->path, ==, NULL, "QIP logger read"); | |
| 1919 g_return_val_if_fail(data->path != NULL, g_strdup("")); | |
| 1920 | |
| 1921 DEBUG_MESSAGE(data->length, <=, 0, "QIP logger read"); | |
| 1922 g_return_val_if_fail(data->length > 0, g_strdup("")); | |
| 1923 | |
| 1924 | |
| 1925 purple_debug(PURPLE_DEBUG_INFO, "QIP logger read", | |
| 1926 "Reading %s\n", data->path); | |
| 1927 | |
| 1928 read = g_malloc(data->length + 2); | |
| 1929 | |
| 1930 file = g_fopen(data->path, "rb"); | |
| 1931 fseek(file, data->offset, SEEK_SET); | |
| 1932 fread(read, data->length, 1, file); | |
| 1933 fclose(file); | |
| 1934 | |
| 1935 if (read[data->length-1] == '\n') { | |
| 1936 read[data->length] = '\0'; | |
| 1937 } else { | |
| 1938 read[data->length] = '\n'; | |
| 1939 read[data->length+1] = '\0'; | |
| 1940 } | |
| 1941 | |
| 1942 /* Load miscellaneous data. */ | |
| 1943 buddy = purple_find_buddy(log->account, log->name); | |
| 1944 | |
| 1945 escaped = g_markup_escape_text(read, -1); | |
| 1946 g_free(read); | |
| 1947 read = escaped; | |
| 1948 | |
| 1949 /* Apply formatting... */ | |
| 1950 formatted = g_string_sized_new(strlen(read)); | |
| 1951 c = read; | |
| 1952 line = read; | |
| 1953 | |
| 1954 while (*c) | |
| 1955 { | |
| 1956 gboolean is_in_message = FALSE; | |
| 1957 | |
| 1958 if (purple_str_has_prefix(line, QIP_LOG_IN_MESSAGE_ESC) || | |
| 1959 purple_str_has_prefix(line, QIP_LOG_OUT_MESSAGE_ESC)) { | |
| 1960 const char *buddy_name; | |
| 1961 is_in_message = purple_str_has_prefix(line, QIP_LOG_IN_MESSAGE_ESC); | |
| 1962 | |
| 1963 purple_debug(PURPLE_DEBUG_INFO, "QIP loggger read", | |
| 1964 "%s message\n", (is_in_message) ? "incoming" : "Outgoing"); | |
| 1965 | |
| 1966 /* find next line */ | |
| 1967 while(*c && *c!= '\n') | |
| 1968 c++; | |
| 1969 /* XXX: Do we need buddy_name when we have buddy->alias? */ | |
| 1970 buddy_name = c; | |
| 1971 | |
| 1972 /* we hope that nickname hasn't '(' symbol */ | |
| 1973 while (*c && *c != '(') | |
| 1974 c++; | |
| 1975 | |
| 1976 if (*c == '(') { | |
| 1977 const char *timestamp = c; | |
| 1978 int hour; | |
| 1979 int min; | |
| 1980 int sec; | |
| 1981 | |
| 1982 timestamp++; | |
| 1983 | |
| 1984 /* Parse the time, day, month and year */ | |
| 1985 if (sscanf(timestamp, "%u:%u:%u", | |
| 1986 &hour, &min, &sec) != 3) | |
| 1987 purple_debug(PURPLE_DEBUG_ERROR, "QIP logger read", | |
| 1988 "Parsing timestamp error\n"); | |
| 1989 else { | |
| 1990 g_string_append(formatted, "<font size=\"2\">"); | |
| 1991 g_string_append_printf(formatted, | |
| 1992 "(%u:%02u:%02u) %cM ", hour % 12, | |
| 1993 min, sec, (hour >= 12) ? 'P': 'A'); | |
| 1994 g_string_append(formatted, "</font> "); | |
| 1995 | |
| 1996 if (is_in_message) { | |
| 1997 if (buddy_name != NULL && buddy->alias) { | |
| 1998 g_string_append_printf(formatted, | |
| 1999 "<span style=\"color: #A82F2F;\">" | |
| 2000 "<b>%s</b></span>: ", buddy->alias); | |
| 2001 } | |
| 2002 } else { | |
| 2003 const char *acct_name; | |
| 2004 acct_name = purple_account_get_alias(log->account); | |
| 2005 if (!acct_name) | |
| 2006 acct_name = purple_account_get_username(log->account); | |
| 2007 | |
| 2008 g_string_append_printf(formatted, | |
| 2009 "<span style=\"color: #16569E;\">" | |
| 2010 "<b>%s</b></span>: ", acct_name); | |
| 2011 } | |
| 2012 | |
| 2013 /* find next line */ | |
| 2014 while(c && *c != '\n') | |
| 2015 c++; | |
| 2016 | |
| 2017 line = ++c; | |
| 2018 | |
| 2019 if ((c = strstr(c, "\n"))) | |
| 2020 *c = '\0'; | |
| 2021 | |
| 2022 purple_debug(PURPLE_DEBUG_INFO, "QIP logger read", | |
| 2023 "writing message: \"%s\"\n", line); | |
| 2024 | |
| 2025 g_string_append(formatted, line); | |
| 2026 line = ++c; | |
| 2027 g_string_append_c(formatted, '\n'); | |
| 2028 } | |
| 2029 } | |
| 2030 } else { | |
| 2031 if ((c = strchr(c, '\n'))) | |
| 2032 *c = '\0'; | |
| 2033 | |
| 2034 if (line[0] != '\n' && line[0] != '\r') { | |
| 2035 purple_debug(PURPLE_DEBUG_INFO, "QIP logger read", | |
| 2036 "line is not delimiter \"%s\"\n", line); | |
| 2037 | |
| 2038 g_string_append(formatted, line); | |
| 2039 g_string_append_c(formatted, '\n'); | |
| 2040 } | |
| 2041 line = ++c; | |
| 2042 } | |
| 2043 } | |
| 2044 g_free(read); | |
| 2045 /* XXX: TODO: Avoid this g_strchomp() */ | |
| 2046 return g_strchomp(g_string_free(formatted, FALSE)); | |
| 2047 } | |
| 2048 | |
| 2049 static int qip_logger_size (PurpleLog *log) | |
| 2050 { | |
| 2051 struct qip_logger_data *data; | |
| 2052 char *text; | |
| 2053 size_t size; | |
| 2054 | |
| 2055 g_return_val_if_fail(log != NULL, 0); | |
| 2056 | |
| 2057 data = log->logger_data; | |
| 2058 | |
| 2059 if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) { | |
| 2060 return data ? data->length : 0; | |
| 2061 } | |
| 2062 | |
| 2063 text = qip_logger_read(log, NULL); | |
| 2064 size = strlen(text); | |
| 2065 g_free(text); | |
| 2066 | |
| 2067 return size; | |
| 2068 } | |
| 2069 | |
| 2070 static void qip_logger_finalize(PurpleLog *log) | |
| 2071 { | |
| 2072 struct qip_logger_data *data; | |
| 2073 | |
| 2074 g_return_if_fail(log != NULL); | |
| 2075 | |
| 2076 data = log->logger_data; | |
| 2077 | |
| 2078 g_free(data->path); | |
| 2079 } | |
| 1727 | 2080 |
| 1728 /***************************************************************************** | 2081 /***************************************************************************** |
| 1729 * Plugin Code * | 2082 * Plugin Code * |
| 1730 *****************************************************************************/ | 2083 *****************************************************************************/ |
| 1731 | 2084 |
| 1968 g_free(folder); | 2321 g_free(folder); |
| 1969 } else /* !folder */ | 2322 } else /* !folder */ |
| 1970 path = g_strdup(""); | 2323 path = g_strdup(""); |
| 1971 #endif | 2324 #endif |
| 1972 | 2325 |
| 1973 purple_prefs_add_string("/plugins/core/log_reader/trillian/log_directory", path); | |
| 1974 g_free(path); | |
| 1975 | |
| 1976 #ifdef _WIN32 | 2326 #ifdef _WIN32 |
| 1977 } /* !found */ | 2327 } /* !found */ |
| 1978 #endif | 2328 #endif |
| 2329 | |
| 2330 /* Add QIP log directory preference. */ | |
| 2331 purple_prefs_add_none("/plugins/core/log_reader/qip"); | |
| 2332 | |
| 2333 #ifdef _WIN32 | |
| 2334 /* Calculate default Messenger Plus! log directory. */ | |
| 2335 folder = wpurple_get_special_folder(CSIDL_PROGRAM_FILES); | |
| 2336 if (folder) { | |
| 2337 #endif | |
| 2338 path = g_build_filename( | |
| 2339 #ifdef _WIN32 | |
| 2340 folder, | |
| 2341 #else | |
| 2342 PURPLE_LOG_READER_WINDOWS_MOUNT_POINT, "Program Files", | |
| 2343 #endif | |
| 2344 "QIP", "Users", NULL); | |
| 2345 #ifdef _WIN32 | |
| 2346 g_free(folder); | |
| 2347 } else /* !folder */ | |
| 2348 path = g_strdup(""); | |
| 2349 #endif | |
| 2350 | |
| 2351 purple_debug(PURPLE_DEBUG_INFO, "QIP log reader", "QIP log directory %s\n", path); | |
| 2352 | |
| 2353 purple_prefs_add_string("/plugins/core/log_reader/qip/log_directory", path); | |
| 2354 g_free(path); | |
| 1979 } | 2355 } |
| 1980 | 2356 |
| 1981 static gboolean | 2357 static gboolean |
| 1982 plugin_load(PurplePlugin *plugin) | 2358 plugin_load(PurplePlugin *plugin) |
| 1983 { | 2359 { |
| 2017 messenger_plus_logger_finalize, | 2393 messenger_plus_logger_finalize, |
| 2018 messenger_plus_logger_list, | 2394 messenger_plus_logger_list, |
| 2019 messenger_plus_logger_read, | 2395 messenger_plus_logger_read, |
| 2020 messenger_plus_logger_size); | 2396 messenger_plus_logger_size); |
| 2021 purple_log_logger_add(messenger_plus_logger); | 2397 purple_log_logger_add(messenger_plus_logger); |
| 2022 #endif | 2398 |
| 2023 | 2399 #endif |
| 2400 | |
| 2401 /* The names of IM clients are marked for translation at the request of | |
| 2402 translators who wanted to transliterate them. Many translators | |
| 2403 choose to leave them alone. Choose what's best for your language. */ | |
| 2404 qip_logger = purple_log_logger_new("qip", _("QIP"), 6, | |
| 2405 NULL, | |
| 2406 NULL, | |
| 2407 qip_logger_finalize, | |
| 2408 qip_logger_list, | |
| 2409 qip_logger_read, | |
| 2410 qip_logger_size); | |
| 2411 purple_log_logger_add(qip_logger); | |
| 2412 | |
| 2024 /* The names of IM clients are marked for translation at the request of | 2413 /* The names of IM clients are marked for translation at the request of |
| 2025 translators who wanted to transliterate them. Many translators | 2414 translators who wanted to transliterate them. Many translators |
| 2026 choose to leave them alone. Choose what's best for your language. */ | 2415 choose to leave them alone. Choose what's best for your language. */ |
| 2027 msn_logger = purple_log_logger_new("msn", _("MSN Messenger"), 6, | 2416 msn_logger = purple_log_logger_new("msn", _("MSN Messenger"), 6, |
| 2028 NULL, | 2417 NULL, |
| 2058 purple_log_logger_remove(fire_logger); | 2447 purple_log_logger_remove(fire_logger); |
| 2059 purple_log_logger_remove(messenger_plus_logger); | 2448 purple_log_logger_remove(messenger_plus_logger); |
| 2060 #endif | 2449 #endif |
| 2061 purple_log_logger_remove(msn_logger); | 2450 purple_log_logger_remove(msn_logger); |
| 2062 purple_log_logger_remove(trillian_logger); | 2451 purple_log_logger_remove(trillian_logger); |
| 2452 purple_log_logger_remove(qip_logger); | |
| 2063 | 2453 |
| 2064 return TRUE; | 2454 return TRUE; |
| 2065 } | 2455 } |
| 2066 | 2456 |
| 2067 static PurplePluginPrefFrame * | 2457 static PurplePluginPrefFrame * |
| 2105 | 2495 |
| 2106 ppref = purple_plugin_pref_new_with_name_and_label( | 2496 ppref = purple_plugin_pref_new_with_name_and_label( |
| 2107 "/plugins/core/log_reader/messenger_plus/log_directory", _("Messenger Plus!")); | 2497 "/plugins/core/log_reader/messenger_plus/log_directory", _("Messenger Plus!")); |
| 2108 purple_plugin_pref_frame_add(frame, ppref); | 2498 purple_plugin_pref_frame_add(frame, ppref); |
| 2109 #endif | 2499 #endif |
| 2500 | |
| 2501 ppref = purple_plugin_pref_new_with_name_and_label( | |
| 2502 "/plugins/core/log_reader/qip/log_directory", _("QIP")); | |
| 2503 purple_plugin_pref_frame_add(frame, ppref); | |
| 2504 purple_debug(PURPLE_DEBUG_INFO, "QIP log reader", "QIP creating directory\n"); | |
| 2110 | 2505 |
| 2111 ppref = purple_plugin_pref_new_with_name_and_label( | 2506 ppref = purple_plugin_pref_new_with_name_and_label( |
| 2112 "/plugins/core/log_reader/msn/log_directory", _("MSN Messenger")); | 2507 "/plugins/core/log_reader/msn/log_directory", _("MSN Messenger")); |
| 2113 purple_plugin_pref_frame_add(frame, ppref); | 2508 purple_plugin_pref_frame_add(frame, ppref); |
| 2114 | 2509 |
