diff --git a/checkin_notes b/checkin_notes
index c814b86f31..fa2b87a666 100755
--- a/checkin_notes
+++ b/checkin_notes
@@ -10173,4 +10173,32 @@ Kevin 12 Sept 2006
clientgui/
sg_SkinClass.cpp
-
\ No newline at end of file
+David 12 Sept 2006
+ - Core client and account manager protocol:
+ account manager replies can include a
+
+ ...
+
+ element. It is stored in the acct_mgr_login.xml file,
+ and returned verbatim in subsequent account manager RPCs.
+ This is intended to allow account managers to send a
+ string analogous to BOINC's account key,
+ identifying the user and/or host on subsequent RPCs.
+ This overrides the name/password, and allows RPCs to
+ continue working even if the user changes name/password
+ on the AMS site.
+
+ NOTE: the contents of are arbitrary XML.
+ Can contain other elements, and can have newlines.
+ Doing this required switching all AMS-related XML parsing
+ to use the new XML parser.
+ So now AMS replies don't have any XML formatting restrictions.
+ Woo-hoo!
+ - XML_PARSER: added element_contents() method to parse
+ stuff that may contain tags (like )
+
+ client/
+ acct_mgr.C,h
+ lib/
+ parse.C,h
+
diff --git a/client/acct_mgr.C b/client/acct_mgr.C
index 1061c07f5b..3dd9646da3 100644
--- a/client/acct_mgr.C
+++ b/client/acct_mgr.C
@@ -161,6 +161,13 @@ int ACCT_MGR_OP::do_rpc(
fclose(fprefs);
}
}
+ if (strlen(gstate.acct_mgr_info.opaque)) {
+ fprintf(f,
+ " \n%s\n"
+ " \n",
+ gstate.acct_mgr_info.opaque
+ );
+ }
fprintf(f, "\n");
fclose(f);
sprintf(buf, "%srpc.php", url.c_str());
@@ -176,9 +183,10 @@ int ACCT_MGR_OP::do_rpc(
return 0;
}
-int AM_ACCOUNT::parse(FILE* f) {
- char buf[256];
- int retval;
+int AM_ACCOUNT::parse(XML_PARSER& xp) {
+ char tag[256];
+ bool is_tag;
+ int retval;
detach = false;
update = false;
@@ -186,66 +194,80 @@ int AM_ACCOUNT::parse(FILE* f) {
strcpy(url_signature, "");
authenticator = "";
- while (fgets(buf, sizeof(buf), f)) {
- if (match_tag(buf, "")) {
+ while (!xp.get(tag, sizeof(tag), is_tag)) {
+ if (!is_tag) {
+ if (log_flags.unparsed_xml) {
+ msg_printf(0, MSG_ERROR, "AM_ACCOUNT::parse: unexpected text %s", tag);
+ }
+ continue;
+ }
+ if (!strcmp(tag, "/account")) {
if (url.length() && authenticator.length()) return 0;
return ERR_XML_PARSE;
}
- if (parse_str(buf, "", url)) continue;
- if (match_tag(buf, "")) {
- retval = copy_element_contents(
- f,
- "",
- url_signature,
- sizeof(url_signature)
- );
+ if (xp.parse_string(tag, "url", url)) continue;
+ if (!strcmp(tag, "url_signature")) {
+ retval = xp.element_contents("", url_signature, sizeof(url_signature));
if (retval) return retval;
+ strcat(url_signature, "\n");
continue;
}
- if (parse_str(buf, "", authenticator)) continue;
- if (parse_bool(buf, "detach", detach)) continue;
- if (parse_bool(buf, "update", update)) continue;
+ if (xp.parse_string(tag, "authenticator", authenticator)) continue;
+ if (xp.parse_bool(tag, "detach", detach)) continue;
+ if (xp.parse_bool(tag, "update", update)) continue;
}
return ERR_XML_PARSE;
}
int ACCT_MGR_OP::parse(FILE* f) {
- char buf[256];
+ char tag[1024];
+ bool is_tag;
string message;
int retval;
+ MIOFILE mf;
+ mf.init_file(f);
+ XML_PARSER xp(&mf);
accounts.clear();
error_str = "";
error_num = 0;
repeat_sec = 0;
strcpy(host_venue, "");
- while (fgets(buf, sizeof(buf), f)) {
- if (match_tag(buf, "")) return 0;
- if (parse_str(buf, "", ami.acct_mgr_name, 256)) continue;
- if (parse_int(buf, "", error_num)) continue;
- if (parse_str(buf, "", error_str)) continue;
- if (parse_double(buf, "", repeat_sec)) continue;
- if (parse_str(buf, "", message)) {
+ strcpy(ami.opaque, "");
+ if (!xp.parse_start("acct_mgr_reply")) return ERR_XML_PARSE;
+ while (!xp.get(tag, sizeof(tag), is_tag)) {
+ if (!is_tag) {
+ if (log_flags.unparsed_xml) {
+ msg_printf(0, MSG_ERROR, "ACCT_MGR_OP::parse: unexpected text %s", tag);
+ }
+ continue;
+ }
+ if (!strcmp(tag, "/acct_mgr_reply")) return 0;
+ if (xp.parse_str(tag, "name", ami.acct_mgr_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;
+ if (xp.parse_string(tag, "message", message)) {
msg_printf(NULL, MSG_INFO, "Account manager: %s", message.c_str());
continue;
}
- if (match_tag(buf, "")) {
- retval = copy_element_contents(
- f,
- "",
- ami.signing_key,
- sizeof(ami.signing_key)
- );
+ if (!strcmp(tag, "opaque")) {
+ retval = xp.element_contents("", ami.opaque, sizeof(ami.opaque));
+ if (retval) return retval;
+ continue;
+ }
+ if (!strcmp(tag, "signing_key")) {
+ retval = xp.element_contents("", ami.signing_key, sizeof(ami.signing_key));
if (retval) return retval;
continue;
}
- if (match_tag(buf, "")) {
+ if (!strcmp(tag, "")) {
AM_ACCOUNT account;
- retval = account.parse(f);
+ retval = account.parse(xp);
if (!retval) accounts.push_back(account);
continue;
}
- if (match_tag(buf, "")) {
+ if (!strcmp(tag, "")) {
retval = dup_element_contents(
f,
"",
@@ -260,7 +282,7 @@ int ACCT_MGR_OP::parse(FILE* f) {
}
continue;
}
- if (parse_str(buf, "", host_venue, sizeof(host_venue))) continue;
+ if (xp.parse_str(tag, "", host_venue, sizeof(host_venue))) continue;
}
return ERR_XML_PARSE;
}
@@ -328,6 +350,7 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
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);
+ strcpy(gstate.acct_mgr_info.opaque, ami.opaque);
// process projects
//
@@ -421,7 +444,7 @@ int ACCT_MGR_INFO::write_info() {
if (send_gui_rpc_info) fprintf(p," \n");
if (strlen(signing_key)) {
fprintf(p,
- " \n%s\n",
+ " \n%s\n\n",
signing_key
);
}
@@ -442,11 +465,14 @@ int ACCT_MGR_INFO::write_info() {
" %s\n"
" %s\n"
" %f\n"
+ " \n%s\n"
+ " \n"
"\n",
login_name,
password_hash,
previous_host_cpid,
- next_rpc_time
+ next_rpc_time,
+ opaque
);
fclose(p);
}
@@ -461,6 +487,7 @@ void ACCT_MGR_INFO::clear() {
strcpy(password_hash, "");
strcpy(signing_key, "");
strcpy(previous_host_cpid, "");
+ strcpy(opaque, "");
next_rpc_time = 0;
send_gui_rpc_info = false;
password_error = false;
@@ -471,7 +498,8 @@ ACCT_MGR_INFO::ACCT_MGR_INFO() {
}
int ACCT_MGR_INFO::init() {
- char buf[256];
+ char tag[1024];
+ bool is_tag;
MIOFILE mf;
FILE* p;
int retval;
@@ -480,19 +508,22 @@ int ACCT_MGR_INFO::init() {
p = fopen(ACCT_MGR_URL_FILENAME, "r");
if (!p) return 0;
mf.init_file(p);
- while(mf.fgets(buf, sizeof(buf))) {
- if (match_tag(buf, "")) break;
- else if (parse_str(buf, "", acct_mgr_name, 256)) continue;
- else if (parse_str(buf, "", acct_mgr_url, 256)) continue;
- else if (parse_bool(buf, "send_gui_rpc_info", send_gui_rpc_info)) continue;
- else if (match_tag(buf, "")) {
- retval = copy_element_contents(
- p,
- "",
- signing_key,
- sizeof(signing_key)
- );
- if (retval) return retval;
+ XML_PARSER xp(&mf);
+ if (!xp.parse_start("acct_mgr_login")) {
+ //
+ }
+ while (!xp.get(tag, sizeof(tag), is_tag)) {
+ if (!is_tag) {
+ printf("unexpected text: %s\n", tag);
+ 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_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));
+ continue;
}
}
fclose(p);
@@ -500,12 +531,24 @@ int ACCT_MGR_INFO::init() {
p = fopen(ACCT_MGR_LOGIN_FILENAME, "r");
if (p) {
mf.init_file(p);
- while(mf.fgets(buf, sizeof(buf))) {
- if (match_tag(buf, "")) break;
- else if (parse_str(buf, "", login_name, 256)) continue;
- else if (parse_str(buf, "", password_hash, 256)) continue;
- else if (parse_str(buf, "", previous_host_cpid, sizeof(previous_host_cpid))) continue;
- else if (parse_double(buf, "", next_rpc_time)) continue;
+ XML_PARSER xp(&mf);
+ if (!xp.parse_start("acct_mgr_login")) {
+ //
+ }
+ while (!xp.get(tag, sizeof(tag), is_tag)) {
+ if (!is_tag) {
+ printf("unexpected text: %s\n", tag);
+ continue;
+ }
+ if (!strcmp(tag, "/acct_mgr_login")) break;
+ else if (xp.parse_str(tag, "login", login_name, 256)) continue;
+ else if (xp.parse_str(tag, "password_hash", password_hash, 256)) continue;
+ else if (xp.parse_str(tag, "previous_host_cpid", previous_host_cpid, sizeof(previous_host_cpid))) continue;
+ else if (xp.parse_double(tag, "next_rpc_time", next_rpc_time)) continue;
+ else if (!strcmp(tag, "opaque")) {
+ retval = xp.element_contents("", opaque, sizeof(opaque));
+ continue;
+ }
}
fclose(p);
}
diff --git a/client/acct_mgr.h b/client/acct_mgr.h
index 2e9b1af685..9fbc4a80e5 100644
--- a/client/acct_mgr.h
+++ b/client/acct_mgr.h
@@ -24,6 +24,7 @@
#include
#include "miofile.h"
+#include "parse.h"
#include "gui_http.h"
#include "client_types.h"
@@ -38,6 +39,8 @@ struct ACCT_MGR_INFO {
char login_name[256];
char password_hash[256];
// md5 of password.lowercase(login_name)
+ char opaque[256];
+ // whatever the AMS sends us
char signing_key[MAX_KEY_LEN];
char previous_host_cpid[64];
// the host CPID sent in last RPC
@@ -65,7 +68,7 @@ struct AM_ACCOUNT {
bool detach;
bool update;
- int parse(FILE*);
+ int parse(XML_PARSER&);
AM_ACCOUNT() {}
~AM_ACCOUNT() {}
};
diff --git a/lib/parse.C b/lib/parse.C
index e2c77f56ad..ec4205dc7d 100644
--- a/lib/parse.C
+++ b/lib/parse.C
@@ -638,6 +638,36 @@ bool XML_PARSER::parse_start(char* start_tag) {
return true;
}
+// copy everything up to (but not including) the given end tag.
+// The copied text may include XML tags.
+// strips whitespace.
+//
+int XML_PARSER::element_contents(const char* end_tag, char* buf, int buflen) {
+ int n=0;
+ int retval=0;
+ while (1) {
+ if (n == buflen-1) {
+ retval = ERR_XML_PARSE;
+ break;
+ }
+ int c = f->getc();
+ if (c == EOF) {
+ retval = ERR_XML_PARSE;
+ break;
+ }
+ buf[n++] = c;
+ buf[n] = 0;
+ char* p = strstr(buf, end_tag);
+ if (p) {
+ *p = 0;
+ break;
+ }
+ }
+ buf[n] = 0;
+ strip_whitespace(buf);
+ return retval;
+}
+
// sample use is shown below
#if 0
diff --git a/lib/parse.h b/lib/parse.h
index fb1b23e500..efd3b37d16 100644
--- a/lib/parse.h
+++ b/lib/parse.h
@@ -49,6 +49,7 @@ public:
bool parse_int(char*, char*, int&);
bool parse_double(char*, char*, double&);
bool parse_bool(char*, char*, bool&);
+ int element_contents(const char*, char*, int);
};
/////////////// START DEPRECATED XML PARSER