diff --git a/client/acct_mgr.h b/client/acct_mgr.h
index ebbd921d693..7ac771601e3 100644
--- a/client/acct_mgr.h
+++ b/client/acct_mgr.h
@@ -52,6 +52,8 @@ struct ACCT_MGR_INFO : PROJ_AM {
// in AM RPCs (used for "farm management")
bool no_project_notices;
// if set, don't show notices from projects
+
+ // TODO: get rid of the following
bool cookie_required;
// use of cookies are required during initial signup
// NOTE: This bool gets dropped after the client has
@@ -60,6 +62,7 @@ struct ACCT_MGR_INFO : PROJ_AM {
// if the cookies could not be detected, provide a
// link to a website to go to so the user can find
// what login name and password they have been assigned
+
bool password_error;
bool send_rec;
// send REC in AM RPCs
diff --git a/client/acct_setup.cpp b/client/acct_setup.cpp
index b730cdf6b0d..9ce7ff483eb 100644
--- a/client/acct_setup.cpp
+++ b/client/acct_setup.cpp
@@ -220,6 +220,7 @@ int GET_PROJECT_LIST_OP::do_rpc() {
void GET_PROJECT_LIST_OP::handle_reply(int http_op_retval) {
bool error = false;
+ error_num = 0;
if (http_op_retval) {
error_num = http_op_retval;
error = true;
@@ -232,6 +233,7 @@ void GET_PROJECT_LIST_OP::handle_reply(int http_op_retval) {
);
gstate.all_projects_list_check_time = gstate.now;
} else {
+ error_num = ERR_XML_PARSE;
error = true;
}
}
@@ -241,10 +243,17 @@ void GET_PROJECT_LIST_OP::handle_reply(int http_op_retval) {
gstate.all_projects_list_check_time =
gstate.now - ALL_PROJECTS_LIST_CHECK_PERIOD + SECONDS_PER_DAY;
}
+
+ // were we initiated by autologin?
+ //
+ if (gstate.autologin_fetching_project_list) {
+ gstate.process_autologin(false);
+ }
}
void CLIENT_STATE::all_projects_list_check() {
if (cc_config.dont_contact_ref_site) return;
+ if (get_project_list_op.gui_http->gui_http_state == GUI_HTTP_STATE_BUSY) return;
if (all_projects_list_check_time) {
if (now - all_projects_list_check_time < ALL_PROJECTS_LIST_CHECK_PERIOD) {
return;
@@ -253,36 +262,55 @@ void CLIENT_STATE::all_projects_list_check() {
get_project_list_op.do_rpc();
}
-// called at startup.
+// called at startup (first=true)
+// or on completion of get project list RPC (first=false).
// check for installer filename file.
// If present, parse project ID and login token,
// and initiate RPC to look up token.
//
-void CLIENT_STATE::process_autologin() {
- int project_id, user_id, n, retval;
- char buf[256], login_token[256], *p;
+void CLIENT_STATE::process_autologin(bool first) {
+ static int project_id, user_id;
+ static char login_token[256];
- // read and parse installer filename
- //
- FILE* f = boinc_fopen(ACCOUNT_DATA_FILENAME, "r");
- if (!f) return;
- fgets(buf, 256, f);
- fclose(f);
- p = strstr(buf, "__");
- if (!p) {
- boinc_delete_file(ACCOUNT_DATA_FILENAME);
- return;
- }
- msg_printf(NULL, MSG_INFO, "Read installer filename file");
- p += 2;
- n = sscanf(p, "%d_%d_%[^. ]", &project_id, &user_id, login_token);
- // don't include the ".exe" or the " (1)"
- if (n != 3) {
- msg_printf(NULL, MSG_INFO, "bad account data: %s", buf);
- boinc_delete_file(ACCOUNT_DATA_FILENAME);
- return;
+ int n, retval;
+ char buf[256], *p;
+
+ if (first) {
+ // read and parse autologin file
+ //
+ FILE* f = boinc_fopen(ACCOUNT_DATA_FILENAME, "r");
+ if (!f) return;
+ fgets(buf, 256, f);
+ fclose(f);
+ p = strstr(buf, "__");
+ if (!p) {
+ boinc_delete_file(ACCOUNT_DATA_FILENAME);
+ return;
+ }
+ msg_printf(NULL, MSG_INFO, "Read account data file");
+ p += 2;
+ n = sscanf(p, "%d_%d_%[^. ]", &project_id, &user_id, login_token);
+ // don't include the ".exe" or the " (1)"
+ if (n != 3) {
+ msg_printf(NULL, MSG_INFO, "bad account data: %s", buf);
+ boinc_delete_file(ACCOUNT_DATA_FILENAME);
+ return;
+ }
+ strip_whitespace(login_token);
+ } else {
+ // here the get project list RPC finished.
+ // check whether it failed.
+ //
+ autologin_in_progress = false;
+ if (get_project_list_op.error_num) {
+ msg_printf(NULL, MSG_INFO,
+ "get project list RPC failed: %s",
+ boincerror(get_project_list_op.error_num)
+ );
+ boinc_delete_file(ACCOUNT_DATA_FILENAME);
+ return;
+ }
}
- strip_whitespace(login_token);
// check that project ID is valid, get URL
//
@@ -296,9 +324,29 @@ void CLIENT_STATE::process_autologin() {
}
PROJECT_LIST_ITEM *pli = project_list.lookup(project_id);
if (!pli) {
- msg_printf(NULL, MSG_INFO, "Unknown project ID: %d", project_id);
- boinc_delete_file(ACCOUNT_DATA_FILENAME);
- return;
+ if (first) {
+ // we may have an outdated project list.
+ // Initiate RPC to get newest version
+ //
+ retval = get_project_list_op.do_rpc();
+ if (retval) {
+ msg_printf(NULL, MSG_INFO,
+ "Get project list RPC failed: %s",
+ boincerror(retval)
+ );
+ boinc_delete_file(ACCOUNT_DATA_FILENAME);
+ return;
+ }
+ autologin_in_progress = true;
+ // defer GUI RPCs
+ autologin_fetching_project_list = true;
+ // tell RPC handler to call us when done
+ return;
+ } else {
+ msg_printf(NULL, MSG_INFO, "Unknown project ID: %d", project_id);
+ boinc_delete_file(ACCOUNT_DATA_FILENAME);
+ return;
+ }
}
if (!pli->is_account_manager) {
@@ -320,14 +368,14 @@ void CLIENT_STATE::process_autologin() {
retval = lookup_login_token_op.do_rpc(pli, user_id, login_token);
if (retval) {
msg_printf(NULL, MSG_INFO,
- "lookup token RPC failed: %s", boincerror(retval)
+ "token lookup RPC failed: %s", boincerror(retval)
);
boinc_delete_file(ACCOUNT_DATA_FILENAME);
}
// disable GUI RPCs until we get an RPC reply
//
- gstate.enable_gui_rpcs = false;
+ gstate.autologin_in_progress = true;
}
int LOOKUP_LOGIN_TOKEN_OP::do_rpc(
@@ -345,16 +393,19 @@ int LOOKUP_LOGIN_TOKEN_OP::do_rpc(
// If everything checks out, attach to account manager or project.
//
void LOOKUP_LOGIN_TOKEN_OP::handle_reply(int http_op_retval) {
- string user_name, team_name, weak_auth;
+ string user_name;
+ string team_name, weak_auth; // returned by projects
+ string login_name, passwd_hash; // returned by AMs
- gstate.enable_gui_rpcs = true;
+ gstate.autologin_in_progress = false;
if (http_op_retval) {
+ msg_printf(NULL, MSG_INFO, "token lookup RPC failed: %s", boincerror(http_op_retval));
return;
}
FILE* f = boinc_fopen(LOGIN_TOKEN_LOOKUP_REPLY, "r");
if (!f) {
- msg_printf(NULL, MSG_INFO, "lookup token: no reply file");
+ msg_printf(NULL, MSG_INFO, "token lookup RPC: no reply file");
boinc_delete_file(ACCOUNT_DATA_FILENAME);
return;
}
@@ -368,21 +419,33 @@ void LOOKUP_LOGIN_TOKEN_OP::handle_reply(int http_op_retval) {
continue;
} else if (xp.parse_string("weak_auth", weak_auth)) {
continue;
+ } else if (xp.parse_string("login_name", login_name)) {
+ continue;
+ } else if (xp.parse_string("passwd_hash", passwd_hash)) {
+ continue;
}
}
fclose(f);
- if (!user_name.size() || !weak_auth.size()) {
- msg_printf(NULL, MSG_INFO, "lookup token: missing info");
- boinc_delete_file(ACCOUNT_DATA_FILENAME);
- return;
- }
if (pli->is_account_manager) {
+ if (!login_name.size() || !passwd_hash.size()) {
+ msg_printf(NULL, MSG_INFO, "token lookup RPC: missing info");
+ boinc_delete_file(ACCOUNT_DATA_FILENAME);
+ return;
+ }
+ msg_printf(NULL, MSG_INFO, "Using account manager %s", pli->name.c_str());
strcpy(gstate.acct_mgr_info.master_url, pli->master_url.c_str());
+ strcpy(gstate.acct_mgr_info.login_name, login_name.c_str());
strcpy(gstate.acct_mgr_info.user_name, user_name.c_str());
- strcpy(gstate.acct_mgr_info.password_hash, weak_auth.c_str());
+ strcpy(gstate.acct_mgr_info.password_hash, passwd_hash.c_str());
} else {
+ if (!user_name.size() || !weak_auth.size()) {
+ msg_printf(NULL, MSG_INFO, "token lookup RPC: missing info");
+ boinc_delete_file(ACCOUNT_DATA_FILENAME);
+ return;
+ }
+ msg_printf(NULL, MSG_INFO, "Attaching to project %s", pli->name.c_str());
gstate.add_project(
pli->master_url.c_str(), weak_auth.c_str(), pli->name.c_str(), false
);
diff --git a/client/client_state.cpp b/client/client_state.cpp
index cc90bb362f1..f71e39687c9 100644
--- a/client/client_state.cpp
+++ b/client/client_state.cpp
@@ -175,7 +175,8 @@ CLIENT_STATE::CLIENT_STATE()
must_check_work_fetch = true;
retry_shmem_time = 0;
no_gui_rpc = false;
- enable_gui_rpcs = true;
+ autologin_in_progress = false;
+ autologin_fetching_project_list = false;
gui_rpc_unix_domain = false;
new_version_check_time = 0;
all_projects_list_check_time = 0;
@@ -731,7 +732,7 @@ int CLIENT_STATE::init() {
// check for initialization files
//
- process_autologin();
+ process_autologin(true);
acct_mgr_info.init();
project_init.init();
@@ -787,13 +788,12 @@ int CLIENT_STATE::init() {
//
proxy_info_startup();
- if (gstate.projects.size() == 0) {
- msg_printf(NULL, MSG_INFO,
- "This computer is not attached to any projects"
- );
- msg_printf(NULL, MSG_INFO,
- "Visit https://boinc.berkeley.edu for instructions"
- );
+ if (!autologin_in_progress) {
+ if (gstate.projects.size() == 0) {
+ msg_printf(NULL, MSG_INFO,
+ "This computer is not attached to any projects"
+ );
+ }
}
// get list of BOINC projects occasionally,
@@ -843,7 +843,7 @@ void CLIENT_STATE::do_io_or_sleep(double max_time) {
gui_rpc_fds.zero();
http_ops->get_fdset(curl_fds);
all_fds = curl_fds;
- if (enable_gui_rpcs) {
+ if (!autologin_in_progress) {
gui_rpcs.get_fdset(gui_rpc_fds, all_fds);
}
diff --git a/client/client_state.h b/client/client_state.h
index a769694f553..6fcfcb50eb5 100644
--- a/client/client_state.h
+++ b/client/client_state.h
@@ -92,7 +92,6 @@ struct CLIENT_STATE {
FILE_XFER_SET* file_xfers;
#ifndef SIM
GUI_RPC_CONN_SET gui_rpcs;
- bool enable_gui_rpcs;
#endif
GUI_HTTP gui_http;
#ifdef ENABLE_AUTO_UPDATE
@@ -247,8 +246,10 @@ struct CLIENT_STATE {
double all_projects_list_check_time;
// the time we last successfully fetched the project list
string newer_version;
+ bool autologin_in_progress;
+ bool autologin_fetching_project_list;
PROJECT_LIST project_list;
- void process_autologin();
+ void process_autologin(bool first);
// --------------- client_state.cpp:
CLIENT_STATE();
diff --git a/client/project_list.cpp b/client/project_list.cpp
index 33c2eeee390..7e798957978 100644
--- a/client/project_list.cpp
+++ b/client/project_list.cpp
@@ -46,6 +46,7 @@ int PROJECT_LIST_ITEM::parse(XML_PARSER& xp, bool is_am) {
}
int PROJECT_LIST::read_file() {
+ items.clear();
FILE* f = fopen(ALL_PROJECTS_LIST_FILENAME, "r");
if (!f) return ERR_FOPEN;
MIOFILE mf;
@@ -56,6 +57,7 @@ int PROJECT_LIST::read_file() {
msg_printf(NULL, MSG_INTERNAL_ERROR,
"missing start tag in project list file"
);
+ fclose(f);
return ERR_XML_PARSE;
}
while (!xp.get_tag()) {
diff --git a/clientgui/AdvancedFrame.cpp b/clientgui/AdvancedFrame.cpp
index 1e2035b8de6..74d71aac045 100644
--- a/clientgui/AdvancedFrame.cpp
+++ b/clientgui/AdvancedFrame.cpp
@@ -1884,7 +1884,7 @@ void CAdvancedFrame::OnConnect(CFrameEvent& WXUNUSED(event)) {
//
m_pNotebook->SetSelection(ID_ADVNOTICESVIEW - ID_ADVVIEWBASE);
}
- } else if ((0 >= pDoc->GetProjectCount()) && !status.disallow_attach && !autoattach_in_progress()) {
+ } else if ((0 >= pDoc->GetProjectCount()) && !status.disallow_attach) {
// client isn't attached to any projects.
// Look for an account to attach to, either in project_init.xml
// or in browser cookies
diff --git a/clientgui/AsyncRPC.cpp b/clientgui/AsyncRPC.cpp
index 47de6a9430a..ee946e79d6f 100644
--- a/clientgui/AsyncRPC.cpp
+++ b/clientgui/AsyncRPC.cpp
@@ -36,7 +36,9 @@
extern bool s_bSkipExitConfirmation;
-// Delay in milliseconds before showing AsyncRPCDlg
+// Delay in milliseconds before showing AsyncRPCDlg during auto-attach to project
+#define RPC_WAIT_DLG_DELAY_DURING_AUTOATTACH 60000
+// Delay in milliseconds before showing AsyncRPCDlg normally
#define RPC_WAIT_DLG_DELAY 1500
// How often to check for events when minimized and waiting for Demand RPC
#define DELAY_WHEN_MINIMIZED 500
@@ -474,7 +476,7 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) {
int retval = 0;
int response = wxID_OK;
wxMutexError mutexErr = wxMUTEX_NO_ERROR;
- long delayTimeRemaining, timeToSleep;
+ long timeToDelay, delayTimeRemaining, timeToSleep;
bool shown = false;
if (!m_RPCThread) return -1;
@@ -544,18 +546,29 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) {
return -1;
}
// Don't show dialog if RPC completes before RPC_WAIT_DLG_DELAY
- // or while BOINC is minimized
+ // or while BOINC is minimized or during auto-attach to project
CBOINCBaseFrame* pFrame = wxGetApp().GetFrame();
wxStopWatch Dlgdelay = wxStopWatch();
m_RPCWaitDlg = new AsyncRPCDlg();
m_bWaitingForRPC = true;
+ if (m_bAutoAttaching) {
+ // client may auto-attach only when first launched
+ // so don't keep checking once it is false
+ m_bAutoAttaching = autoattach_in_progress();
+ }
// Allow RPC_WAIT_DLG_DELAY seconds for Demand RPC to complete before
// displaying "Please Wait" dialog, but keep checking for completion.
- delayTimeRemaining = RPC_WAIT_DLG_DELAY;
+ if (m_bAutoAttaching) {
+ timeToDelay = RPC_WAIT_DLG_DELAY_DURING_AUTOATTACH;
+ } else {
+ timeToDelay = RPC_WAIT_DLG_DELAY;
+ }
+
+ delayTimeRemaining = timeToDelay;
while (true) {
if (delayTimeRemaining >= 0) { // Prevent overflow if minimized for a very long time
- delayTimeRemaining = RPC_WAIT_DLG_DELAY - Dlgdelay.Time();
+ delayTimeRemaining = timeToDelay - Dlgdelay.Time();
}
if (pFrame) {
@@ -583,7 +596,7 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) {
wxSafeYield(NULL, true);
}
- // OnRPCComplete() clears m_bWaitingForRPC if RPC completed
+ // OnRPCComplete() clears m_bWaitingForRPC and deletes m_RPCWaitDlg if RPC completed
if (! m_bWaitingForRPC) {
return retval;
}
@@ -748,8 +761,8 @@ void CMainDocument::HandleCompletedRPC() {
if (m_RPCWaitDlg->IsShown()) {
m_RPCWaitDlg->EndModal(wxID_OK);
}
- m_RPCWaitDlg->Destroy();
- m_RPCWaitDlg = NULL;
+ m_RPCWaitDlg->Destroy();
+ m_RPCWaitDlg = NULL;
}
m_bWaitingForRPC = false;
}
diff --git a/clientgui/MainDocument.cpp b/clientgui/MainDocument.cpp
index 765b67d22aa..12abdfed934 100644
--- a/clientgui/MainDocument.cpp
+++ b/clientgui/MainDocument.cpp
@@ -477,6 +477,9 @@ int CMainDocument::OnInit() {
m_pClientManager = new CBOINCClientManager();
wxASSERT(m_pClientManager);
+ // client may auto-attach only when first launched
+ m_bAutoAttaching = autoattach_in_progress();
+
m_RPCWaitDlg = NULL;
m_bWaitingForRPC = false;
m_bNeedRefresh = false;
diff --git a/clientgui/MainDocument.h b/clientgui/MainDocument.h
index f64cc9ca051..17151c375ab 100644
--- a/clientgui/MainDocument.h
+++ b/clientgui/MainDocument.h
@@ -214,6 +214,7 @@ class CMainDocument : public wxObject {
BOINC_Condition* m_pRPC_Request_Condition;
wxDateTime m_dtLasAsyncRPCDlgTime;
wxDateTime m_dtLastFrameViewRefreshRPCTime;
+ bool m_bAutoAttaching;
//
// Projects Tab
diff --git a/clientgui/sg_BoincSimpleFrame.cpp b/clientgui/sg_BoincSimpleFrame.cpp
index 0dd01f2220f..58f7319f36f 100644
--- a/clientgui/sg_BoincSimpleFrame.cpp
+++ b/clientgui/sg_BoincSimpleFrame.cpp
@@ -832,7 +832,7 @@ void CSimpleFrame::OnConnect(CFrameEvent& WXUNUSED(event)) {
}
#endif
}
- } else if ((0 >= pDoc->GetProjectCount()) && !status.disallow_attach && !autoattach_in_progress()) {
+ } else if ((0 >= pDoc->GetProjectCount()) && !status.disallow_attach) {
if (pis.url.size() > 0) {
strProjectName = pis.name.c_str();
diff --git a/html/user/login_token_lookup.php b/html/user/login_token_lookup.php
index ad2b1d978d6..b0c828b2fec 100644
--- a/html/user/login_token_lookup.php
+++ b/html/user/login_token_lookup.php
@@ -23,6 +23,7 @@
require_once("../inc/xml.inc");
function main() {
+ global $config;
$user_id = get_str("user_id");
$token = get_str("token");
$user = BoincUser::lookup_id($user_id);
@@ -35,18 +36,22 @@ function main() {
if (time() - $user->login_token_time > 86400) {
xml_error("token timed out");
}
- $name = htmlentities($user->name);
- $auth = weak_auth($user);
- echo "