/* * listcache.c * * Contact list caching * * (c) 2002-2005 Thomas White * 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 #endif #include #include #include #include #include #include #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 = ""; 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; }