aboutsummaryrefslogtreecommitdiff
path: root/src/listcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/listcache.c')
-rw-r--r--src/listcache.c615
1 files changed, 615 insertions, 0 deletions
diff --git a/src/listcache.c b/src/listcache.c
new file mode 100644
index 0000000..a895ff8
--- /dev/null
+++ b/src/listcache.c
@@ -0,0 +1,615 @@
+/*
+ * listcache.c
+ *
+ * Contact list caching
+ *
+ * (c) 2002-2005 Thomas White <taw27@srcf.ucam.org>
+ * Part of TuxMessenger - GTK+-based MSN Messenger client
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 dated June, 1991.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "contactlist.h"
+#include "debug.h"
+#include "options.h"
+#include "routines.h"
+#include "mainwindow.h"
+#include "xml.h"
+#include "msnprotocol.h"
+#include "addcontact.h"
+#include "error.h"
+
+static char *listcache_tag = NULL;
+static char *listcache_mfn = NULL;
+static char *listcache_ubxdata = NULL;
+static unsigned int listcache_invalid = FALSE;
+
+static char *listcache_file() {
+
+ char *filename;
+ char *done;
+
+ filename = routines_glob("~/.tuxmessenger/");
+ done = malloc(strlen(filename)+11);
+ strcpy(done, filename);
+ free(filename);
+ strcat(done, "list.cache");
+
+ return done;
+
+}
+
+/* Called to record the friendly name for later caching */
+void listcache_setmfn(const char *mfn) {
+
+ if ( listcache_mfn != NULL ) {
+ free(listcache_mfn);
+ }
+
+ listcache_mfn = strdup(mfn);
+
+}
+
+const char *listcache_getmfn() {
+
+ if ( listcache_mfn == NULL ) {
+ return "";
+ }
+
+ return listcache_mfn;
+
+}
+
+void listcache_setcsm(const char *csm) {
+
+ const char *template;
+
+ if ( listcache_ubxdata != NULL ) {
+ free(listcache_ubxdata);
+ }
+
+ template = "<Data><PSM></PSM><CurrentMedia></CurrentMedia></Data>";
+ listcache_ubxdata = xml_setblock(template, strlen(template), "Data", "PSM", csm);
+
+}
+
+static char *listcache_getcsm_internal(int entities) {
+
+ char *result;
+
+ if ( listcache_ubxdata == NULL ) {
+ return strdup("");
+ }
+
+ result = xml_getblock(listcache_ubxdata, strlen(listcache_ubxdata), "Data", "PSM", entities);
+ if ( result == NULL ) {
+ return strdup("");
+ }
+
+ return result;
+
+}
+
+char *listcache_getcsm() {
+ return listcache_getcsm_internal(0);
+}
+
+char *listcache_getcsm_noentities() {
+ return listcache_getcsm_internal(1);
+}
+
+static int listcache_processline(char *line) {
+
+ char *token = routines_lindex(line, 0);
+
+ if ( strcmp(token, "FL") == 0 ) {
+
+ char *username = routines_lindex(line, 1);
+ char *friendlyname = routines_lindex(line, 2);
+ char *guid = routines_lindex(line, 3);
+ if ( username == NULL ) {
+ return -1;
+ }
+ if ( strlen(guid) == 0 ) {
+ free(guid);
+ guid = NULL;
+ }
+ if ( strlen(friendlyname) == 0 ) {
+ /* This would be a bad thing. */
+ free(friendlyname);
+ friendlyname = NULL;
+ }
+ contactlist_fldetails(CONTACT_SOURCE_CACHE, username, friendlyname, 0, NULL, ONLINE_FLN, guid);
+ free(username);
+ free(friendlyname);
+
+ } else if ( strcmp(token, "AL") == 0 ) {
+
+ char *username = routines_lindex(line, 1);
+ char *friendlyname = routines_lindex(line, 2);
+ if ( username == NULL ) {
+ return -1;
+ }
+ if ( strlen(friendlyname) == 0 ) {
+ free(friendlyname);
+ friendlyname = NULL;
+ }
+ contactlist_aldetails(CONTACT_SOURCE_CACHE, username, friendlyname, ONLINE_FLN);
+ free(username);
+ if ( friendlyname != NULL ) {
+ free(friendlyname);
+ }
+
+ } else if ( strcmp(token, "BL") == 0 ) {
+
+ char *username = routines_lindex(line, 1);
+ char *friendlyname = routines_lindex(line, 2);
+ if ( username == NULL ) {
+ return -1;
+ }
+ if ( strlen(friendlyname) == 0 ) {
+ free(friendlyname);
+ friendlyname = NULL;
+ }
+ contactlist_bldetails(CONTACT_SOURCE_CACHE, username, friendlyname, ONLINE_FLN);
+ free(username);
+ if ( friendlyname != NULL ) {
+ free(friendlyname);
+ }
+
+ } else if ( strcmp(token, "RL") == 0 ) {
+
+ char *username = routines_lindex(line, 1);
+ char *friendlyname = routines_lindex(line, 2);
+ if ( username == NULL ) {
+ return -1;
+ }
+ if ( strlen(friendlyname) == 0 ) {
+ free(friendlyname);
+ friendlyname = NULL;
+ }
+ contactlist_rldetails(CONTACT_SOURCE_CACHE, username, friendlyname, ONLINE_FLN);
+ free(username);
+ if ( friendlyname != NULL ) {
+ free(friendlyname);
+ }
+
+ } else if ( strcmp(token, "PL") == 0 ) {
+
+ char *username = routines_lindex(line, 1);
+ char *friendlyname = routines_lindex(line, 2);
+ if ( username == NULL ) {
+ return -1;
+ }
+ if ( strlen(friendlyname) == 0 ) {
+ free(friendlyname);
+ friendlyname = NULL;
+ }
+ contactlist_pldetails(CONTACT_SOURCE_CACHE, username, friendlyname, ONLINE_FLN);
+ addcontact_added(username, friendlyname);
+
+ free(username);
+ if ( friendlyname != NULL ) {
+ free(friendlyname);
+ }
+
+ } else if ( strcmp(token, "BLP") == 0 ) {
+ debug_print("LC: Got BLP from cache.\n");
+ } else if ( strcmp(token, "GTC") == 0 ) {
+ debug_print("LC: Got GTC from cache.\n");
+ } else if ( strcmp(token, "MFN") == 0 ) {
+
+ char *mfn = routines_lindex(line, 1);
+ debug_print("LC: Got MFN from cache.\n");
+ mainwindow_setmfn(mfn);
+ listcache_setmfn(mfn);
+ free(mfn);
+
+ } else if ( strcmp(token, "CSM") == 0 ) {
+
+ /* See also listcache_loadtag_internal() */
+ char *csm_text;
+ char *csm = routines_lindexend(line, 1);
+ msnprotocol_setcsm(csm);
+
+ csm_text = listcache_getcsm();
+ mainwindow_setcsm(csm_text);
+ free(csm_text);
+
+ free(csm);
+ debug_print("LC: Got CSM from cache.\n");
+
+ } else {
+ free(token);
+ return -1;
+ }
+
+ free(token);
+ return 0;
+
+}
+
+static FILE *listcache_loadtag_internal() {
+
+ FILE *fh;
+ char *line;
+ char *rval;
+ char *cachefile;
+ int done = 0;
+
+ cachefile = listcache_file();
+
+ fh = fopen(cachefile, "r");
+ free(cachefile);
+ if ( fh == NULL ) {
+ debug_print("LC: Error opening list cache file.\n");
+ return NULL;
+ }
+
+ line = malloc(1024);
+ assert(line != NULL);
+
+ /* Check this cache file is right for the username. Bin it if not... */
+ rval = fgets(line, 1023, fh);
+ if ( ferror(fh) || (rval == NULL) ) {
+ debug_print("LC: Error retrieving list cache username.\n");
+ return NULL;
+ }
+ if ( line[strlen(line)-1] == '\n' ) {
+ line[strlen(line)-1] = '\0'; /* Cut off trailing newline. */
+ }
+ debug_print("LC: list.cache file is for user '%s' ", line);
+ if ( strcmp(line, options_username()) == 0 ) {
+ debug_print("- good.\n");
+ } else {
+
+ debug_print("- wrong. Deleting...\n");
+ free(line);
+ fclose(fh);
+ cachefile = listcache_file();
+ fh = fopen(listcache_file(), "w");
+ free(cachefile);
+ return NULL;
+
+ }
+
+ /* Get the SYN tag. */
+ rval = fgets(line, 1023, fh);
+ if ( ferror(fh) || (rval == NULL) ) {
+ debug_print("LC: Error retrieving SYN tag.\n");
+ free(line);
+ fclose(fh);
+ return NULL;
+ }
+ if ( line[strlen(line)-1] == '\n' ) {
+ line[strlen(line)-1] = '\0'; /* Cut off trailing newline. */
+ }
+ if ( listcache_tag != NULL ) {
+ free(listcache_tag);
+ }
+ listcache_tag = strdup(line);
+
+ /* Because there doesn't seem to be a way to retrieve the CSM, the CSM also
+ needs to be read from the cache file at this point. Yuk. */
+ while ( rval && !done ) {
+
+ rval = fgets(line, 1023, fh);
+ if ( rval != NULL ) {
+
+ char *token;
+
+ if ( line[strlen(line)-1] == '\n' ) {
+ line[strlen(line)-1] = '\0'; /* Cut off trailing newline. */
+ }
+
+ token = routines_lindex(line, 0);
+
+ if ( strcmp(token, "CSM") == 0 ) {
+
+ /* See also listcache_processline() */
+ char *csm_text;
+ char *csm = routines_lindexend(line, 1);
+ msnprotocol_setcsm(csm);
+
+ csm_text = listcache_getcsm();
+ mainwindow_setcsm(csm_text);
+ free(csm_text);
+
+ free(csm);
+ debug_print("LC: Got CSM from cache.\n");
+ done = 1;
+
+ }
+
+ free(token);
+
+ }
+
+ }
+
+ free(line);
+
+ return fh;
+
+}
+
+char *listcache_loadtag() {
+
+ FILE *fh;
+
+ if ( listcache_invalid ) {
+ debug_print("LC: Cache invalid - not loading.\n");
+ return "0 0";
+ }
+
+ fh = listcache_loadtag_internal();
+ if ( fh != NULL ) {
+ fclose(fh);
+ return listcache_tag;
+ }
+
+ return "0 0";
+
+}
+
+/* Throws the cached contact list at contactlist.c. Returns the tag to send with SYN.
+ (Actually, this return value is never actually used...) */
+char *listcache_load() {
+
+ FILE *fh;
+ char *line;
+ char *rval = "boing";
+ int whoops = 0;
+
+ line = malloc(1024);
+ assert(line != NULL);
+
+ if ( listcache_invalid ) {
+ debug_print("LC: Cache invalid - not loading.\n");
+ return "0 0";
+ }
+
+ fh = listcache_loadtag_internal();
+ if ( fh == NULL ) {
+ return "0 0";
+ }
+
+ while ( rval && !whoops ) {
+ rval = fgets(line, 1023, fh);
+ if ( rval != NULL ) {
+ if ( line[strlen(line)-1] == '\n' ) {
+ line[strlen(line)-1] = '\0'; /* Cut off trailing newline. */
+ }
+ whoops = listcache_processline(line);
+ }
+ }
+ if ( ferror(fh) || whoops ) {
+ debug_print("LC: Error reading list cache file - re-requesting list.\n");
+ contactlist_clear();
+ return "0 0";
+ }
+
+ fclose(fh);
+ free(line);
+
+ return listcache_tag;
+
+}
+
+/* Called to record the most recent tag returned by SYN, to be saved with the list at the next listcache_save */
+void listcache_settag(const char *tag) {
+
+ if ( listcache_tag != NULL ) {
+
+ if ( strcmp(tag, listcache_tag) != 0 ) {
+ /* Tag has changed, so invalidate the lists ready for the new version.*/
+ contactlist_clear();
+ }
+
+ free(listcache_tag);
+
+ }
+
+ listcache_tag = strdup(tag);
+
+}
+
+/* Save the contact data (from contactlist.c) out to disk. */
+void listcache_save() {
+
+ FILE *fh;
+ int rval = 0;
+ char *tag_newline;
+ char *mfn;
+ char *cachefile;
+
+ cachefile = listcache_file();
+
+ fh = fopen(cachefile, "w");
+ if ( chmod(cachefile, S_IRUSR | S_IWUSR) != 0 ) {
+ error_report("Couldn't set permissions on contact list cache file!");
+ }
+ free(cachefile);
+
+ if ( fh == NULL ) {
+ debug_print("LC: Error opening list cache file.\n");
+ return;
+ }
+
+ /* Record the username */
+ tag_newline = malloc(strlen(options_username())+2);
+ assert(tag_newline != NULL);
+ strcpy(tag_newline, options_username());
+ tag_newline[strlen(tag_newline)+1] = '\0';
+ tag_newline[strlen(tag_newline)] = '\n';
+ if ( fputs(tag_newline, fh) == EOF ) {
+ rval = -1;
+ }
+ free(tag_newline);
+
+ /* Record the SYN tag */
+ tag_newline = malloc(strlen(listcache_tag)+2);
+ assert(tag_newline != NULL);
+ strcpy(tag_newline, listcache_tag);
+ tag_newline[strlen(tag_newline)+1] = '\0';
+ tag_newline[strlen(tag_newline)] = '\n';
+ if ( fputs(tag_newline, fh) == EOF ) {
+ rval = -1;
+ }
+ free(tag_newline);
+
+ /* CSM has to be saved before anything else, since listcache_loadtag_internal loads
+ the file as far as the CSM, ignoring everything else, then passes the file
+ handle to the main parser without resetting the pointer. */
+ if ( rval == 0 ) {
+
+ char *csm_text = listcache_getcsm_noentities();
+ if ( csm_text != NULL ) {
+
+ /* Record CSM */
+ char *csm = malloc(strlen(csm_text)+7);
+ strcpy(csm, "CSM ");
+ strcat(csm, csm_text);
+ csm[strlen(csm)+1] = '\0';
+ csm[strlen(csm)] = '\n';
+ if ( fputs(csm, fh) == EOF ) {
+ rval = -1;
+ }
+ free(csm);
+ free(csm_text);
+
+ }
+
+ }
+
+ if ( rval == 0 ) {
+
+ char *blp_newline;
+
+ /* Record the value of BLP */
+ blp_newline = malloc(6+strlen(options_blp()));
+ assert(blp_newline != NULL);
+
+ strcpy(blp_newline, "BLP ");
+ strcat(blp_newline, options_blp());
+ blp_newline[strlen(blp_newline)+1] = '\0';
+ blp_newline[strlen(blp_newline)] = '\n';
+ if ( fputs(blp_newline, fh) == EOF ) {
+ rval = -1;
+ }
+ free(blp_newline);
+
+ }
+
+ if ( rval == 0 ) {
+
+ char *gtc_newline;
+
+ /* Record the value of GTC */
+ gtc_newline = malloc(6+strlen(options_gtc()));
+ assert(gtc_newline != NULL);
+
+ strcpy(gtc_newline, "GTC ");
+ strcat(gtc_newline, options_gtc());
+ gtc_newline[strlen(gtc_newline)+1] = '\0';
+ gtc_newline[strlen(gtc_newline)] = '\n';
+ if ( fputs(gtc_newline, fh) == EOF ) {
+ rval = -1;
+ }
+ free(gtc_newline);
+
+ }
+
+ if ( rval == 0 ) {
+
+ if ( listcache_mfn != NULL ) {
+
+ /* Record friendly name */
+ mfn = malloc(strlen(listcache_mfn)+7);
+ strcpy(mfn, "MFN ");
+ strcat(mfn, listcache_mfn);
+ mfn[strlen(mfn)+1] = '\0';
+ mfn[strlen(mfn)] = '\n';
+ if ( fputs(mfn, fh) == EOF ) {
+ rval = -1;
+ }
+ free(mfn);
+
+ }
+
+ }
+
+ if ( rval == 0 ) {
+ rval = contactlist_dumplist(fh, "FL");
+ }
+ if ( rval == 0 ) {
+ rval = contactlist_dumplist(fh, "RL");
+ }
+ if ( rval == 0 ) {
+ rval = contactlist_dumplist(fh, "AL");
+ }
+ if ( rval == 0 ) {
+ rval = contactlist_dumplist(fh, "BL");
+ }
+ if ( rval == 0 ) {
+ rval = contactlist_dumplist(fh, "PL");
+ }
+
+ if ( rval == 0 ) {
+ debug_print("LC: Saved contacts to cache.\n");
+ } else {
+
+ char *cachefile;
+
+ debug_print("LC: Error saving contacts to cache.\n");
+ fclose(fh);
+ /* Attempt to truncate the cache file for safety next time. */
+ cachefile = listcache_file();
+ fh = fopen(cachefile, "w");
+ free(cachefile);
+
+ }
+
+ fclose(fh);
+ listcache_invalid = FALSE;
+
+}
+
+int listcache_checktag(const char *tag) {
+
+ if ( strcmp(tag, listcache_tag) == 0 ) {
+ return 1;
+ }
+
+ return 0;
+
+}
+
+/* Mark the contents of the cache as invalid, for example, after changing the local username. */
+void listcache_invalidate() {
+ listcache_invalid = TRUE;
+}