diff --git a/checkin_notes b/checkin_notes index d5ab9b582e..8cb24af79b 100644 --- a/checkin_notes +++ b/checkin_notes @@ -6401,3 +6401,16 @@ Rom 16 Aug 2010 / configure.ac version.h + +David 8 Sept 2010 + - client: support notice feeds from account managers. + Implementation: create a base class PROJ_AM, + from which both PROJECT and ACCT_MGR_INFO are derived, + with basic stuff like name, URL, and RSS feed list + + client/ + acct_mgr.cpp,h + app_start.cpp + client_types.cpp,h + cs_notice.cpp,h + gui_rpc_server_ops.cpp diff --git a/client/acct_mgr.cpp b/client/acct_mgr.cpp index 00fbde7059..00270d96d7 100644 --- a/client/acct_mgr.cpp +++ b/client/acct_mgr.cpp @@ -67,7 +67,7 @@ int ACCT_MGR_OP::do_rpc( // if null URL, detach from current AMS // - if (!strlen(url) && strlen(gstate.acct_mgr_info.acct_mgr_url)) { + if (!strlen(url) && strlen(gstate.acct_mgr_info.master_url)) { msg_printf(NULL, MSG_INFO, "Removing account manager info"); gstate.acct_mgr_info.clear(); boinc_delete_file(ACCT_MGR_URL_FILENAME); @@ -87,8 +87,8 @@ int ACCT_MGR_OP::do_rpc( return 0; } - strlcpy(ami.acct_mgr_url, url, sizeof(ami.acct_mgr_url)); - strlcpy(ami.acct_mgr_name, "", sizeof(ami.acct_mgr_name)); + strlcpy(ami.master_url, url, sizeof(ami.master_url)); + strlcpy(ami.project_name, "", sizeof(ami.project_name)); strlcpy(ami.login_name, name.c_str(), sizeof(ami.login_name)); strlcpy(ami.password_hash, password_hash.c_str(), sizeof(ami.password_hash)); @@ -282,7 +282,7 @@ int ACCT_MGR_OP::parse(FILE* f) { continue; } if (!strcmp(tag, "/acct_mgr_reply")) return 0; - if (xp.parse_str(tag, "name", ami.acct_mgr_name, 256)) continue; + if (xp.parse_str(tag, "name", ami.project_name, 256)) continue; if (xp.parse_int(tag, "error_num", error_num)) continue; if (xp.parse_string(tag, "error", error_str)) continue; if (xp.parse_double(tag, "repeat_sec", repeat_sec)) continue; @@ -369,7 +369,7 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) { if (error_str.size()) { msg_printf(NULL, MSG_USER_ALERT, "%s %s: %s", - gstate.acct_mgr_info.acct_mgr_name, + gstate.acct_mgr_info.project_name, _("error"), error_str.c_str() ); @@ -379,7 +379,7 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) { } else if (error_num) { msg_printf(NULL, MSG_USER_ALERT, "%s %s: %s", - gstate.acct_mgr_info.acct_mgr_name, + gstate.acct_mgr_info.project_name, _("error"), boincerror(error_num) ); @@ -411,8 +411,8 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) { } if (sig_ok) { - strcpy(gstate.acct_mgr_info.acct_mgr_url, ami.acct_mgr_url); - strcpy(gstate.acct_mgr_info.acct_mgr_name, ami.acct_mgr_name); + strcpy(gstate.acct_mgr_info.master_url, ami.master_url); + strcpy(gstate.acct_mgr_info.project_name, ami.project_name); strcpy(gstate.acct_mgr_info.signing_key, ami.signing_key); strcpy(gstate.acct_mgr_info.login_name, ami.login_name); strcpy(gstate.acct_mgr_info.password_hash, ami.password_hash); @@ -517,7 +517,7 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) { // if (global_prefs_xml) { retval = gstate.save_global_prefs( - global_prefs_xml, ami.acct_mgr_url, ami.acct_mgr_url + global_prefs_xml, ami.master_url, ami.master_url ); if (retval) { msg_printf(NULL, MSG_INTERNAL_ERROR, "Can't save global prefs"); @@ -544,15 +544,15 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) { int ACCT_MGR_INFO::write_info() { FILE* p; - if (strlen(acct_mgr_url)) { + if (strlen(master_url)) { p = fopen(ACCT_MGR_URL_FILENAME, "w"); if (p) { fprintf(p, "\n" " %s\n" " %s\n", - acct_mgr_name, - acct_mgr_url + project_name, + master_url ); if (send_gui_rpc_info) fprintf(p," \n"); if (strlen(signing_key)) { @@ -594,8 +594,8 @@ int ACCT_MGR_INFO::write_info() { } void ACCT_MGR_INFO::clear() { - strcpy(acct_mgr_name, ""); - strcpy(acct_mgr_url, ""); + strcpy(project_name, ""); + strcpy(master_url, ""); strcpy(login_name, ""); strcpy(password_hash, ""); strcpy(signing_key, ""); @@ -668,8 +668,8 @@ int ACCT_MGR_INFO::init() { continue; } if (!strcmp(tag, "/acct_mgr")) break; - else if (xp.parse_str(tag, "name", acct_mgr_name, 256)) continue; - else if (xp.parse_str(tag, "url", acct_mgr_url, 256)) continue; + else if (xp.parse_str(tag, "name", project_name, 256)) continue; + else if (xp.parse_str(tag, "url", master_url, 256)) continue; else if (xp.parse_bool(tag, "send_gui_rpc_info", send_gui_rpc_info)) continue; else if (!strcmp(tag, "signing_key")) { retval = xp.element_contents("", signing_key, sizeof(signing_key)); @@ -695,14 +695,13 @@ int ACCT_MGR_INFO::init() { } bool ACCT_MGR_INFO::poll() { + if (!using_am()) return false; if (gstate.gui_http.is_busy()) return false; - if (!strlen(login_name) && !strlen(password_hash)) return false; - if (gstate.now > next_rpc_time) { next_rpc_time = gstate.now + 86400; gstate.acct_mgr_op.do_rpc( - acct_mgr_url, login_name, password_hash, false + master_url, login_name, password_hash, false ); return true; } diff --git a/client/acct_mgr.h b/client/acct_mgr.h index d6c20f96a4..158260fc6b 100644 --- a/client/acct_mgr.h +++ b/client/acct_mgr.h @@ -28,12 +28,10 @@ // represents info stored in acct_mgr_url.xml and acct_mgr_login.xml -struct ACCT_MGR_INFO { +struct ACCT_MGR_INFO : PROJ_AM { // the following used to be std::string but there // were mysterious bugs where setting it to "" didn't work // - char acct_mgr_name[256]; - char acct_mgr_url[256]; char login_name[256]; char password_hash[256]; // md5 of password.lowercase(login_name) @@ -58,6 +56,13 @@ struct ACCT_MGR_INFO { // successfully attached to an account manager bool password_error; + inline bool using_am() { + if (!strlen(master_url)) return false; + if (!strlen(login_name)) return false; + if (!strlen(password_hash)) return false; + return true; + } + ACCT_MGR_INFO(); int parse_login_file(FILE*); int write_info(); @@ -66,6 +71,8 @@ struct ACCT_MGR_INFO { bool poll(); }; +// stuff after here related to RPCs to account managers + struct OPTIONAL_BOOL { bool present; bool value; @@ -80,8 +87,6 @@ struct OPTIONAL_DOUBLE { inline void set(double v) {value=v; present=true;} }; -// stuff after here related to RPCs to account managers - struct AM_ACCOUNT { std::string url; std::string authenticator; diff --git a/client/app_start.cpp b/client/app_start.cpp index 0b8e4cdc85..f384bb453d 100644 --- a/client/app_start.cpp +++ b/client/app_start.cpp @@ -206,7 +206,7 @@ int ACTIVE_TASK::write_app_init_file() { aid.app_version = app_version->version_num; safe_strcpy(aid.app_name, wup->app->name); safe_strcpy(aid.symstore, wup->project->symstore); - safe_strcpy(aid.acct_mgr_url, gstate.acct_mgr_info.acct_mgr_url); + safe_strcpy(aid.acct_mgr_url, gstate.acct_mgr_info.master_url); if (wup->project->project_specific_prefs.length()) { aid.project_preferences = strdup(wup->project->project_specific_prefs.c_str()); } diff --git a/client/client_types.cpp b/client/client_types.cpp index ab0d842b18..fea30fd8af 100644 --- a/client/client_types.cpp +++ b/client/client_types.cpp @@ -460,14 +460,6 @@ int PROJECT::write_statistics(MIOFILE& out, bool /*gui_rpc*/) { return 0; } -char* PROJECT::get_project_name() { - if (strlen(project_name)) { - return project_name; - } else { - return master_url; - } -} - const char* PROJECT::get_scheduler_url(int index, double r) { int n = (int) scheduler_urls.size(); int ir = (int)(r*n); diff --git a/client/client_types.h b/client/client_types.h index a0d301e837..5353c672e3 100644 --- a/client/client_types.h +++ b/client/client_types.h @@ -181,12 +181,26 @@ struct DAILY_STATS { }; bool operator < (const DAILY_STATS&, const DAILY_STATS&); -struct PROJECT { +// base class for PROJECT and ACCT_MGR_INFO +// +struct PROJ_AM { + char master_url[256]; + char project_name[256]; + // descriptive. not unique + std::vector proj_feeds; + inline char *get_project_name() { + if (strlen(project_name)) { + return project_name; + } else { + return master_url; + } + } +}; + +struct PROJECT : PROJ_AM { // the following items come from the account file // They are a function only of the user and the project // - char master_url[256]; - // url of site that contains scheduler tags for this project char authenticator[256]; // user's authenticator on this project std::string project_prefs; @@ -231,8 +245,6 @@ struct PROJECT { // std::vector scheduler_urls; // where to find scheduling servers - char project_name[256]; - // descriptive. not unique char symstore[256]; // URL of symbol server (Windows) char user_name[256]; @@ -405,7 +417,6 @@ struct PROJECT { ~PROJECT(){} void init(); void copy_state_fields(PROJECT&); - char *get_project_name(); int write_account_file(); int parse_account(FILE*); int parse_account_file_venue(); @@ -419,9 +430,6 @@ struct PROJECT { int parse_statistics(FILE*); int write_statistics(MIOFILE&, bool gui_rpc=false); int write_statistics_file(); - - // feed-related - std::vector proj_feeds; }; struct APP { diff --git a/client/cs_notice.cpp b/client/cs_notice.cpp index 340335d79e..b9a242aa83 100644 --- a/client/cs_notice.cpp +++ b/client/cs_notice.cpp @@ -52,7 +52,7 @@ static bool cmp(NOTICE n1, NOTICE n2) { return (strcmp(n1.guid, n2.guid) > 0); } -static void project_feed_list_file_name(PROJECT* p, char* buf) { +static void project_feed_list_file_name(PROJ_AM* p, char* buf) { char url[256]; escape_project_url(p->master_url, url); sprintf(buf, "notices/feeds_%s.xml", url); @@ -97,7 +97,7 @@ static void write_rss_feed_descs(MIOFILE& fout, vector& feeds) { fout.printf("\n"); } -static void write_project_feed_list(PROJECT* p) { +static void write_project_feed_list(PROJ_AM* p) { char buf[256]; project_feed_list_file_name(p, buf); FILE* f = fopen(buf, "w"); @@ -112,7 +112,7 @@ static void write_project_feed_list(PROJECT* p) { // Add new ones to the project's set, // and remove ones from the project's set that aren't in the list. // -void handle_sr_feeds(vector& feeds, PROJECT* p) { +void handle_sr_feeds(vector& feeds, PROJ_AM* p) { unsigned int i, j; bool feed_set_changed = false; @@ -658,25 +658,33 @@ void RSS_FEED_OP::handle_reply(int http_op_retval) { ///////////// RSS_FEEDS //////////////// +static void init_proj_am(PROJ_AM* p) { + FILE* f; + MIOFILE fin; + char path[256]; + + project_feed_list_file_name(p, path); + f = fopen(path, "r"); + if (f) { + fin.init_file(f); + parse_rss_feed_descs(fin, p->proj_feeds); + fclose(f); + } +} + // called on startup. Get list of feeds. Read archives. // void RSS_FEEDS::init() { unsigned int i; - MIOFILE fin; - FILE* f; boinc_mkdir(NOTICES_DIR); for (i=0; iproj_feeds); - fclose(f); - } + init_proj_am(p); + } + if (gstate.acct_mgr_info.using_am()) { + init_proj_am(&gstate.acct_mgr_info); } update_feed_list(); @@ -705,7 +713,7 @@ RSS_FEED* RSS_FEEDS::lookup_url(char* url) { // arrange to fetch the project's feeds // -void RSS_FEEDS::trigger_fetch(PROJECT* p) { +void RSS_FEEDS::trigger_fetch(PROJ_AM* p) { for (unsigned int i=0; iproj_feeds.size(); i++) { RSS_FEED& rf = p->proj_feeds[i]; RSS_FEED* rfp = lookup_url(rf.url); @@ -715,34 +723,42 @@ void RSS_FEEDS::trigger_fetch(PROJECT* p) { } } +void RSS_FEEDS::update_proj_am(PROJ_AM* p) { + unsigned int j; + for (j=0; jproj_feeds.size(); j++) { + RSS_FEED& rf = p->proj_feeds[j]; + RSS_FEED* rfp = lookup_url(rf.url); + if (rfp) { + rfp->found = true; + } else { + rf.found = true; + strcpy(rf.project_name, p->get_project_name()); + feeds.push_back(rf); + if (log_flags.notice_debug) { + msg_printf(0, MSG_INFO, + "[notice] adding feed: %s, %.0f sec", + rf.url, rf.poll_interval + ); + } + } + } +} + // the set of project feeds has changed. // update the master list. // void RSS_FEEDS::update_feed_list() { - unsigned int i, j; + unsigned int i; for (i=0; iproj_feeds.size(); j++) { - RSS_FEED& rf = p->proj_feeds[j]; - RSS_FEED* rfp = lookup_url(rf.url); - if (rfp) { - rfp->found = true; - } else { - rf.found = true; - strcpy(rf.project_name, p->get_project_name()); - feeds.push_back(rf); - if (log_flags.notice_debug) { - msg_printf(0, MSG_INFO, - "[notice] adding feed: %s, %.0f sec", - rf.url, rf.poll_interval - ); - } - } - } + update_proj_am(p); + } + if (gstate.acct_mgr_info.using_am()) { + update_proj_am(&gstate.acct_mgr_info); } vector::iterator iter = feeds.begin(); while (iter != feeds.end()) { diff --git a/client/cs_notice.h b/client/cs_notice.h index badcf08d76..98662db352 100644 --- a/client/cs_notice.h +++ b/client/cs_notice.h @@ -19,7 +19,7 @@ #define _CS_NOTICE_ // Code related to "notices", which come from -// 1) RSS feeds specified by projects +// 1) RSS feeds specified by projects and account managers // 2) Scheduler replies (high-priority messages) // 3) the client (MSG_USER_ALERT messages) // @@ -63,6 +63,7 @@ #include "miofile.h" #include "gui_http.h" +#include "client_types.h" #include "notice.h" @@ -120,16 +121,17 @@ extern RSS_FEED_OP rss_feed_op; struct RSS_FEEDS { std::vector feeds; void init(); - void trigger_fetch(PROJECT*); + void trigger_fetch(struct PROJ_AM*); void update_feed_list(); RSS_FEED* lookup_url(char*); + void update_proj_am(PROJ_AM*); void write_feed_list(); }; extern RSS_FEEDS rss_feeds; int parse_rss_feed_descs(MIOFILE& fin, std::vector&); -void handle_sr_feeds(std::vector&, struct PROJECT*); +void handle_sr_feeds(std::vector&, struct PROJ_AM*); // process the feeds in a scheduler reply #endif diff --git a/client/gui_rpc_server_ops.cpp b/client/gui_rpc_server_ops.cpp index a200a69ce0..b099a4fd4a 100644 --- a/client/gui_rpc_server_ops.cpp +++ b/client/gui_rpc_server_ops.cpp @@ -526,8 +526,8 @@ static void handle_acct_mgr_info(char*, MIOFILE& fout) { "\n" " %s\n" " %s\n", - gstate.acct_mgr_info.acct_mgr_url, - gstate.acct_mgr_info.acct_mgr_name + gstate.acct_mgr_info.master_url, + gstate.acct_mgr_info.project_name ); if (strlen(gstate.acct_mgr_info.login_name)) { @@ -816,13 +816,13 @@ static void handle_acct_mgr_rpc(char* buf, MIOFILE& fout) { } } } else { - if (!strlen(gstate.acct_mgr_info.acct_mgr_url)) { + if (!strlen(gstate.acct_mgr_info.master_url)) { bad_arg = true; msg_printf(NULL, MSG_INTERNAL_ERROR, "Account manager info missing from config file" ); } else { - url = gstate.acct_mgr_info.acct_mgr_url; + url = gstate.acct_mgr_info.master_url; name = gstate.acct_mgr_info.login_name; password_hash = gstate.acct_mgr_info.password_hash; }