// // Copyright 2000 Perforce Software. All rights reserved. // // This file is part of Perforce - the FAST SCM System. // // p4wThread: // Manages a single HTTP request. // ------------------------------------- // Includes // #include <p4wp4.h> #include <msgserver.h> #include "base64.h" #include "p4wThread.h" #include "p4wAboutView.h" #include "p4wAddProcessorView.h" #include "p4wAddSelectView.h" #include "p4wAuthView.h" #include "p4wPathBrowserView.h" #include "p4wBranchEditView.h" #include "p4wBranchView.h" #include "p4wBranchesView.h" #include "p4wChangePendingEditView.h" #include "p4wClientView.h" #include "p4wClientEditView.h" #include "p4wClientsView.h" #include "p4wChangeEditView.h" #include "p4wChangesProcessorView.h" #include "p4wCmdView.h" #include "p4wCmdProcessorView.h" #include "p4wDeleteProcessorView.h" #include "p4wDescribeView.h" #include "p4wDescribeDefaultView.h" #include "p4wEditProcessorView.h" #include "p4wErrorView.h" #include "p4wLabelEditView.h" #include "p4wFileBrowserView.h" #include "p4wFTProcessorView.h" #include "p4wHelpView.h" #include "p4wIconView.h" #include "p4wIntegProcessorView.h" #include "p4wJobEditView.h" #include "p4wJobView.h" #include "p4wJobCmdView.h" #include "p4wJobSpecView.h" #include "p4wJobsView.h" #include "p4wLabelView.h" #include "p4wLabelsView.h" #include "p4wLabSyncProcView.h" #include "p4wLockProcessorView.h" #include "p4wMenuProcessorView.h" #include "p4wMimeContentView.h" #include "p4wPrintView.h" #include "p4wRelocate.h" #include "p4wResolveProcessorView.h" #include "p4wResolveIAProcessorView.h" #include "p4wRevertProcessorView.h" #include "p4wRSSView.h" #include "p4wRSSJobsView.h" #include "p4wRSSJobviewView.h" #include "p4wRSSUserView.h" #include "p4wSyncProcessorView.h" #include "p4wSubmitView.h" #include "p4wEditLocalProcessorView.h" #include "p4wUploadLocalProcessorView.h" #include "p4wThumbnailView.h" #include "p4wUnlockProcessorView.h" #include "p4wUserView.h" #include "p4wUserEditView.h" #include "p4wUsersView.h" #include "p4wWorkspaceFileView.h" #include "p4wPasswdTestView.h" #include "p4wLoginView.h" #include "p4wLogoutStartView.h" #include "p4wLogoutView.h" // // Variable used for cancelling the current server request extern int globalCancel; extern int ignoreBrowserAuth; // // ------------------------------------- // Constructors and destructor. // p4wThread::p4wThread(NetTransport * t, Options * opts, const char *hostPort, const char *progName, int isNTService, int isHTTPS, int securityFlags, ErrorLog *reportLog) : fClient(), fWeb822(t), fBrowseOnly(0), fNoAuth(0), fRequest(NULL), fJavascript(-1), fRestrictLocal(0), fAuthBrowseOnly(0), fNeedsAuth(0), fSetPassword(0), fIsNTService(isNTService), fInitFailed(0), fReportLog(NULL), fIsMultiUser(0) { // // If we are longing, clone the log. if (reportLog) fReportLog = new ErrorLog(reportLog); // // Sets flags based on command-line options fOpts = opts; // // If this is our first time here, we need // authorization. Insure we only do this once at startup. static int firstTimeThru = 1; if (firstTimeThru) { #ifndef _DEBUG // but don't force auth if we are debugging if ((*fOpts)[ 'i' ]) // and don't do it it we are running as inetd #endif firstTimeThru = 0; fNeedsAuth = firstTimeThru ? 1 : 0; firstTimeThru = 0; } fProgName.Set( progName ); // // If we are running as an NT service, we need to get the // client, user, port, editor, & viewer from a special place // in the registry. # ifdef OS_NT if( fIsNTService ) { Enviro enviro; enviro.BeServer( &fProgName ); const char *user; const char *client; const char *port; const char *host; const char *charset; const char *ticketfile; const char *grp; if( port = enviro.Get( "P4PORT" ) ) { fClient.SetPort( port ); } if( user = enviro.Get( "P4USER" ) ) { fClient.SetUser( user ); } if (user && !strcmp(user, "@")) { fIsMultiUser = 1; fClient.SetClient( "(not set)" ); } else if( client = enviro.Get( "P4CLIENT" ) ) { fClient.SetClient( client ); } if( host = enviro.Get( "P4HOST" ) ) { fClient.SetHost( host ); } if( charset = enviro.Get( "P4CHARSET" ) ) { fClient.SetCharset( charset ); } if( ticketfile = enviro.Get( "P4TICKETS" ) ) { fClient.SetTicketFile( ticketfile ); } } # endif // OS_NT // // Get command line overrides of user, client, cwd, port, charset StrPtr *s; if( s = (*opts)[ 'H' ] ) fClient.SetHost( s ); if( s = (*opts)[ 'p' ] ) fClient.SetPort( s ); if((s = (*opts)[ 'M' ]) || fIsMultiUser ) { fClient.SetUser( "@" ); fIsMultiUser = 1; } else if( s = (*opts)[ 'u' ] ) { fClient.SetUser( s ); } if( fIsMultiUser || !strcmp(fClient.GetUser().Text(), "@") ) { fClient.SetClient( "(not set)" ); } else if( s = (*opts)[ 'c' ] ) { fClient.SetClient( s ); } if( s = (*opts)[ 'C' ] ) fClient.SetCharset( s ); if( s = (*opts)[ 'g' ] ) fGroup.Set( s ); if( s = (*opts)[ 'T' ] ) fTabs.Set( s ); // // Set Password only if '-P' was invoked with either // non-authenticated modes if( ( s = (*opts)[ 'P' ] ) && ( (*opts)[ 'b' ] || (*opts)[ 'a' ] ) ) fClient.SetPassword( s ); // Any protocol settings? for( int i = 0; s = opts->GetValue( 'Z', i ); i++ ) fClient.SetProtocolV( s->Text() ); fClient.SetProtocol("specstring", ""); // Browse-only mode, no auth required? if( s = (*opts)[ 'b' ] ) { ++fBrowseOnly; fNoAuth = 1; } // Browse-only mode with authentication? if( s = (*opts)[ 'B' ] ) { ++fBrowseOnly; fAuthBrowseOnly = 1; } // // Check environment variable for browse amd local modes if // they weren't set on the command line if( !fBrowseOnly ) { Enviro enviro; HostEnv h; StrBuf cwd; #ifdef OS_NT if( fIsNTService ) { enviro.BeServer( &fProgName ); } else { h.GetCwd( cwd ); enviro.Config( cwd ); } #else h.GetCwd( cwd ); enviro.Config( cwd ); #endif const char *browse; if( !fBrowseOnly && ( browse = enviro.Get( "P4WEBVIEWER" ) ) ) { if( !strcmp( browse, "-b" ) ) { ++fBrowseOnly; fNoAuth = 1; } else if( !strcmp( browse, "-B" ) ) { ++fBrowseOnly; fAuthBrowseOnly = 1; } } const char *localonly; if( !fRestrictLocal && ( localonly = enviro.Get( "P4WEBLOCALONLY" ) ) ) { if( !strcmp( localonly, "-l" ) ) { ++fRestrictLocal; } } } // Bypass authorization in helper mode? if( s = (*opts)[ 'a' ] ) fNoAuth = 1; // Parse javascript mode entered on command line if( s = (*opts)[ 'J' ] ) { fJavascript = atoi( s->Text() ); if (!fJavascript) { fJavascript = -1; char *p; switch(*(s->Text())) { case 'v': p = strchr(s->Text()+1, '+'); if (p) { *p = '\0'; fJavaScriptViewName.Set(s->Text()+1); *p = '+'; fJavaScriptViewPath.Set(++p); } break; } } } // Host:port used by p4wRequest fHostPort.Set( hostPort ); // security flags used by p4wRequest fIsHTTPS = isHTTPS; fSecurityFlags = securityFlags; // Restrict access to local host? if( s = (*opts)[ 'l' ] ) fRestrictLocal = 1; // Enable streams protocol fClient.SetProtocol( "enableStreams", "yes" ); } p4wThread::~p4wThread() { if (fRequest) delete fRequest; if (fReportLog) delete fReportLog; } int p4wThread::Authenticate() { // // Looks like: "authorization: Basic base64string" StrPtr *auth = fWeb822.GetVar("authorization"); // ignored if ignoreBrowserAuth set StrPtr *cookie = fWeb822.GetVar("cookie"); StrBuf user; StrBuf password; const StrPtr *pw = fRequest->GetDynArg( "pw" ); int bFromCookie = 0; // // Save off defaults from cookie unless this is an icon request char *p; if ( cookie && fRequest->GetCmd() != AC_ICON && (p = strstr(cookie->Text(), "P4WDefaults=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WDefaults=")-1); p = strchr(temp.Text() + 1, '@'); if (p) { *++p = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); if (!strchr(fRequest->GetFullURL().Text(), '@') && fRequest->GetCmd() == AC_USERPSWD) { if( doP4Init() ) { p4wRelocate relocate(*fRequest, fRequest->GetCmd()); if( relocate.DoAddDefaults() ) { fInitFailed = 1; return 0; } } } if (strstr(temp.Text(), "&D=1")) { char *p = NULL; const StrPtr *referer = fWeb822.GetVar( "referer" ); if (referer) { p = strchr(referer->Text(), '@'); if (p) { int len = p-referer->Text(); if (strncmp(referer->Text(), fRequest->GetBase().Text(), len)) p = NULL; } } if( !p && doP4Init() ) { p4wRelocate relocate(*fRequest, fRequest->GetCmd()); if( relocate.DoForceDefaults() ) { fInitFailed = 1; return 0; } } } if ( fIsMultiUser && fRequest->GetCmd() == AC_NONE && (p = strstr(temp.Text(), "&cl=")) ) { char *q = strpbrk(p += 4, "&@#/:\\"); if (q) { *q = '\0'; fClient.SetClient( p ); } } } // AC_USERPSWD comes from login screen // no need to Authenticate it. // Since we've saved the P4WDefaults cookie // we can just return. if (fRequest->GetCmd() == AC_USERPSWD) return 1; // // No auth string means the credentials are in a cookie // or someone is trying to connect from a different browser. // In this case re-prompt for authorization unless we have a cookie. char decoded[128]; if( !auth || ignoreBrowserAuth ) { // Icons don't need authorization if( fRequest->GetCmd() == AC_ICON ) return 1; if( !cookie && !strcmp(fRequest->GetFullURL().Text(), "/favicon.ico") ) { fRequest->SetCmd(AC_ICON); // get the local (internal) version return 1; } if( !cookie && ignoreBrowserAuth && user != "" ) // let secure server do authentication return 1; if ( !cookie ) // if no cookies, re-prompt for auth. { if ( fRequest->GetCmd() == AC_HELP ) // but help is ok { fRequest->SetScreenChunks(SCRN_LOGO + SCRN_BODY + SCRN_COPYRIGHT); return 1; } return 0; } if (pw) // if pw, we must trigger a login box { // so return 0 to re-prompt for auth. if (!(*fOpts)[ 'M' ]) return 0; if (fRequest->GetCmd() != AC_LOGOUT) return 0; } char cookiename[32]; StrBuf temp; temp.Set(cookie); p = temp.Text(); char *q = fRequest->GetHTTPPort().Text(); q = strchr(q, ':'); strcpy(cookiename, COOKIEPREFIX); if (q) strcat(cookiename, q+1); strcat(cookiename, "="); p = strstr(p, cookiename); if (!p) // if no login cookie, re-prompt for auth. { if ( fRequest->GetCmd() == AC_HELP ) // but help is ok { fRequest->SetScreenChunks(SCRN_LOGO + SCRN_BODY + SCRN_COPYRIGHT); return 1; } return 0; } p += strlen(cookiename); if (q = strchr(p, ';')) *q = '\0'; // do not overflow the buffer of decoded and corrupt/crash p4web (job037013) if (strlen(p) >= sizeof(decoded)) return 0; strcpy(decoded, p); // convert from base64 encoding StrBuf bindata; char * src = decoded; char * dest = bindata.Alloc(sizeof(decoded)); int lgth = b64_decode(src, strlen(decoded), dest, sizeof(decoded)-1); if (lgth) { dest[lgth] = '\0'; memmove(decoded, dest, lgth+1); if (!fRequest->isLocalRequest()) fRequest->unHashPswd(decoded, lgth); } if (!strchr(decoded, ':')) { // do not overflow decoded (job037013) if (strlen(decoded) >= sizeof(decoded) - 1) return 0; strcat(decoded, ":"); } bFromCookie = 1; } else { if ( strncmp( auth->Text(), "Basic", 5 ) ) return 0; p = strchr( auth->Text(), ' ' ); if( !p ) return 0; // Now decode base64string into user:password int len = DecodeBase64( p + 1, decoded, sizeof( decoded ) ); // make sure decoded[len] does not exceed the buffer if( !len || len >= sizeof(decoded) ) return 0; decoded[ len ] = 0; } p = strchr( decoded, ':' ); // the first : is what we want since the form is // user:pswdticket and a pswdticket cannot have a : if( p ) { if ( p == decoded ) return 0; // user is empty; redisplay browser's login dialog // user:passwd user.Set( decoded, p - decoded ); if( *( p + 1 ) != 0 ) password.Set( p + 1 ); } else { // user user.Set( decoded ); } // // If this is browse-only mode with authorization, // set the current user to the value in // the auth string. Otherwise restrict access to // the user who started p4web. Use a case-insensitive // match for the username comparison. int su = 1; if( user.CCompare( fClient.GetUser() ) ) su = 0; if( ( !fAuthBrowseOnly && !su ) || ( fAuthBrowseOnly && !user.Length() ) ) { if (!fAuthBrowseOnly && !strcmp(fClient.GetUser().Text(), "@")) { fClient.SetUser( &user ); fRequest->SetMultiUser(1); } else return 0; } else if( fAuthBrowseOnly && !su ) fClient.SetUser( &user ); // // return success if this is just an icon since // any password failure will be detected with the // first real p4 command if( fRequest->GetCmd() == AC_ICON ) return 1; if( fIsMultiUser ) { const StrPtr *cl = fRequest->GetStateArg( "cl" ); const StrPtr *bo = fRequest->GetStateArg( "bo" ); if (!cl && bo) { fIsMultiUser = 0; fBrowseOnly = fAuthBrowseOnly = 1; fRequest->SetAuthBrowseOnly(); Enviro enviro; char *client = enviro.Get( "P4CLIENT" ); if (client) fClient.SetClient( client ); } else if ((!cl || !cl->Length()) && (user.Length() || fRequest->GetCmd() == AC_EDITCLIENT || fRequest->GetCmd() == AC_EDITNEWCLIENT) ) { if( !strcmp(fRequest->GetFullURL().Text(), "/favicon.ico") ) { fRequest->SetCmd(AC_ICON); // get the local (internal) version return 1; } if( fRequest->GetCmd() != AC_CONFIGPROCESSOR && fRequest->GetCmd() != AC_CONFIGURATION && fRequest->GetCmd() != AC_MULTIUSERPROCESSOR && fRequest->GetCmd() != AC_NONE && fRequest->GetCmd() != AC_CLIENTS && fRequest->GetCmd() != AC_CLIENTVIEW && fRequest->GetCmd() != AC_CLIENTSWITCH && fRequest->GetCmd() != AC_EDITCLIENT && fRequest->GetCmd() != AC_EDITNEWCLIENT && fRequest->GetCmd() != AC_CLIENTSPROCESSOR && fRequest->GetCmd() != AC_HELP && fRequest->GetCmd() != AC_LOGOUT && fRequest->GetCmd() != AC_LOGOUT2) fRequest->SetCmd(AC_MULTIUSER); } } // // We need to detect if this is a pre-4.1 server in order // to determine how to handle passwords. int pUnset = 0; if (auth && password.Length()) fClient.SetPassword( &password ); if( !doP4Init() || fRequest->fHadPasswordError ) { if (auth && password.Length()) { password.Clear(); fClient.SetPassword( &password ); } return 0; } p4wPasswdTestView ptestView( *fRequest ); ptestView.fCheckClient = 1; ptestView.Render(); // Did we find that this user is not in the required group? if ( ptestView.HadGroupError() && fIsMultiUser ) { fReportLogMore << "User " << fClient.GetUser() << " in not a member of Group " << fGroup << "."; printf("%s\n", fReportLogMore.Text()); return 0; } // // Make sure we a aurthorized to use this client // (i.e owner of this client is this user // or local connection or fSecurityFlags allows this client) if ( ptestView.HadClientError() && !ptestView.GotError() && !ptestView.HadPasswordError() && fRequest->GetCmd() != AC_NONE ) { char *errcode = "4"; StrBuf errorMsg; errorMsg.Set(ptestView.GetErrorMsg()); if (!errorMsg.Length()) { errorMsg.Set("Only clients owned by '"); errorMsg << fRequest->GetUser().Text(); errorMsg << "' can be used."; errcode = "2"; } else if (strstr(errorMsg.Text(), " host field is not specified ")) errcode = "3"; if( !doP4Init() ) { errorMsg << "<br>Please click "; p4wHtml htm(1); p4wURL urlMaker; StrBuf baseNoPath; fRequest->UseNewBase( baseNoPath, NULL, "path", "//" ); StrBuf url; urlMaker.ConstructURL( url, baseNoPath.Text(), AC_CONFIGURATION, NULL, fRequest->GetUnicode() ); htm.beginLink(url.Text()); htm << "Settings"; htm.endLink(); errorMsg << htm << " to change your client<br>or to log out and then log in as a different user."; p4wErrorView errorView( *fRequest, errorMsg, 0 ); errorView.Render(); } else { fRequest->SetCmd(AC_MULTIUSER); p4wMenuProcessorView menuView(*fRequest, AC_MULTIUSER); menuView.SetErrorMsg(errorMsg.Text()); menuView.Render(); } fInitFailed = 1; return 0; } if (ptestView.GotMiscError()) { StrBuf errorMsg; errorMsg << "Error: "; errorMsg << ptestView.GetErrorMsg(); p4wErrorView errorView( *fRequest, errorMsg, 0 ); errorView.Render(); fInitFailed = 1; return 0; } if (ptestView.GotError() && strstr(ptestView.GetErrorMsg().Text(), " has not been enabled by 'p4 protect'")) { StrBuf errorMsg; errorMsg << "Error: "; errorMsg << ptestView.GetErrorMsg(); errorMsg << "<br>Contact your Perforce administrator or use your browser's Back button to login as a different user."; p4wErrorView errorView( *fRequest, errorMsg, 0 ); errorView.Render(); fInitFailed = 1; return 0; } const StrPtr *server = fRequest->GetProtocol( "server2" ); int secureServer = 0; if( server && server->Atoi() > 17 ) { ++secureServer; if (!fNoAuth) ignoreBrowserAuth = 1; } // if this is an old server, there are no tickets. // so don't try to authorize from a cookie // because cookies don't contain passwords if ( !secureServer && bFromCookie ) return 0; // // Don't pass along a password if this is a secure server // unless this is response to a password failure. // In this case, if we are not browse ony with no auth (-b), // set the password and issue p4 login command. if( secureServer && !pw ) return 1; // // 4.1+, and the user passed in a password: // just set password and issue p4 login if( secureServer ) { fClient.SetPassword( &password ); fSetPassword = 1; p4wLoginView loginView( *fRequest ); loginView.Render(); return (loginView.fPasswordError || pw) ? 0 : 1; } // // If password was not passed in, generate a random password // value ONLY if server is pre-4.1. This insures that // unauthorized users cannot login // to a p4web running in a shell with the authorized password // set correctly in the environment. With 4.1+ server, we can't // do this because the user might have a valid ticket, and sending // a bogus password would not work. if( !password.Length() ) { // // 4.1+ server with no password set: leave it unset if( secureServer ) { ++pUnset; // // Server does not support p4 login: set a bogus // password in case P4PASSWD is set in environment } else { srand( time( NULL ) ); int pword = rand(); char password_str[64]; sprintf( password_str, "%d", pword ); password.Set( (char *)password_str ); } } // // You passed! Now set your password, if appropriate if( !pUnset ) { fClient.SetPassword( &password ); fSetPassword = 1; } return 1; } // ------------------------------------- // Thread entry point. // void p4wThread::Run() { // Temporary vars int logWritten = 0; int gotoCleanup = 0; Error e; StrBuf errorMsg; char *p; AllCommands cmd; // // Load the Web822 header. fWeb822.LoadHeader(); // // Build the log message before p4wRequest messes with the headers StrBuf headers; if ( fReportLog ) { char time_buffer[255 + 1]; time_buffer[0] = '\0'; time_t iTime = time( NULL ); StrBuf time_format; time_format.Append( "%a, %d %b %Y %H:%M:%S %Z" ); strftime( time_buffer, sizeof( time_buffer ), time_format.Text(), localtime( &iTime ) ); headers << time_buffer << crlf; headers << "From: " << fWeb822.GetPeerAddress( 0 ) << crlf; fWeb822.GetRecvHeaders(&headers); char *p = strchr(headers.Text(), '%'); if (p) { StrBuf buf; StrBuf temp; do { *p = '\0'; temp.Set(headers); temp.SetLength(); buf << temp << "%%"; strcpy(headers.Text(), p+1); p = strchr(headers.Text(), '%'); } while (p); buf << headers.Text(); headers.Set(buf); } } // // Create a new request object to handle this connection. fRequest = new p4wRequest(fClient, &fWeb822, fBrowseOnly, fJavascript, fJavaScriptViewName.Text(), fJavaScriptViewPath.Text(), fNoAuth, fAuthBrowseOnly, fHostPort.Text(), fProgName.Text(), fGroup.Text(), fTabs.Text(), fIsNTService, fIsHTTPS, p4debug.GetLevel( DT_NET ) == -2 ? fReportLog : NULL, fSecurityFlags, fOpts ); const StrPtr *pw = fRequest->GetDynArg( "pw" ); if (fRequest->GetXSS()) goto cleanup; switch ( fRequest->GetCmd() ) { case AC_NONE: if (!strcmp(fRequest->GetFullURL().Text(), "/favicon.ico") ) // is /favicon.ico break; case AC_MIMECONTENT: case AC_P4CMD: case AC_P4CMDTAGGED: case AC_P4CMDXML: if ( fRequest->URLHasNoStateInfo() ) { fRequest->RedirectToURLWithReferrerState(); goto cleanup; } break; // // XXX 4.2 diff2 tagged output doesn't show diffs! // Therefore, set the protocol to a client version // which WILL show diffs since tagged output is // always requested. case AC_DIFFCVH: case AC_DIFFRVW: case AC_DIFFSVR: case AC_DIFF2: case AC_DIFF21: case AC_DIFF22: case AC_BRANCHDIFF: fClient.SetProtocol( "api", "56" ); break; default: break; } // // If access is restricted to the local host, enforce it now if( fRestrictLocal && !fRequest->isLocalRequest() ) { errorMsg.Set("Error: This P4Web is restricted to local access from "); errorMsg << fRequest->GetHost() << "."; p4wErrorView errorView(*fRequest, errorMsg, 1); errorView.Render(); goto cleanup; } // // If we haven't done the initial authorization, do it now. Send the // authorization prompt. However, if this is no-auth mode, bypass security // entirely. if( fNeedsAuth && fRequest->GetCmd() == AC_USERPSWD ) fNeedsAuth = 0; else if( !fNoAuth && fNeedsAuth ) { p4wAuthView auth(*fRequest); auth.Render(); goto cleanup; // // Just authorize this request as usual. If browser didn't send authorization, // or sent a request from the wrong user, send the auth prompt again. } else if( !fNoAuth && !Authenticate() ) { if( fInitFailed ) goto cleanup; p4wAuthView newAuth(*fRequest); newAuth.Render(); goto cleanup; // // If previous request yielded a password or login error, the pw // flag was set in the URL. Send a bogus test command to p4 to // see if the password has been set correctly. If a login error was // returned or the command returned no error, issue p4 login // using the current password (if this is a 4.1+ server). // Otherwise if the password is incorrect, // re-issue the authorization prompt. } else if( !fNoAuth && pw ) { if( !doP4Init() ) goto cleanup; p4wPasswdTestView passwdTestView( *fRequest ); p4wLoginView loginView( *fRequest ); passwdTestView.Render(); const StrPtr *server = fRequest->GetProtocol( "server2" ); if( passwdTestView.HadLoginError() && fSetPassword ) { loginView.Render(); } else if( server && server->Atoi() > 17 ) { loginView.Render(); } else if( passwdTestView.HadPasswordError() ) { p4wAuthView pAuth(*fRequest); pAuth.Render(); fRequest->p4Final(&e); gotoCleanup = 1; } } if (gotoCleanup) goto cleanup; if (fNoAuth) // need to init() and get Defaults cookie { if( !doP4Init() ) goto cleanup; StrPtr *cookie = fWeb822.GetVar("cookie"); char *p; if ( cookie && fRequest->GetCmd() != AC_ICON && (p = strstr(cookie->Text(), "P4WDefaults=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WDefaults=")-1); p = strchr(temp.Text() + 1, '@'); if (p) { *++p = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); if (!strchr(fRequest->GetFullURL().Text(), '@')) { p4wRelocate relocate(*fRequest, fRequest->GetCmd()); if( relocate.DoAddDefaults() ) goto cleanup; // added defaults & relocated, so we are done } } } // // Get the command type cmd = fRequest->GetCmd(); // Now that we know the user, add it to the log message // after removing the user/password if ( fReportLog && cmd != AC_ICON ) { char *p = strstr(headers.Text(), "authorization:"); if (p) { char *q = p + sizeof("authorization:")-1; while (*q && *q != '\n' && *q != '\r') q++; while (*q && (*q == '\r' || *q == '\n')) q++; strcpy(p, q); } headers << "User: " << fRequest->GetUser() << "\tClient: " << fRequest->GetClient(); } // // If we are in browse-only mode, don't allow any operations // that modify the client if( fBrowseOnly && !p4wAllCommands::CanBrowse( fRequest->GetCmd() ) ) { errorMsg.Set("Operation not allowed in browse-only mode."); p4wErrorView errorView( *fRequest, errorMsg, 0, "browseonly" ); errorView.Render(); fRequest->p4Final(&e); goto cleanup; } // Now that we are ready to run the cmd, write the log message if ( fReportLog ) { if ( cmd != AC_ICON ) { headers << crlf; writeLog( headers ); } logWritten = 1; } // // Run the desired p4 command doCommand( cmd ); // // Close connection if it is still open. This could // happen if we issued a dummy command to test the password, // and the requested command was NOT a p4 command. cleanup: if ( fReportLog && !logWritten && cmd != AC_ICON ) { headers << "Command not run." << crlf; if (fReportLogMore.Length()) headers << fReportLogMore << crlf; writeLog( headers ); logWritten = 1; } doP4Final(); delete fRequest; fRequest = NULL; return; } void p4wThread::writeLog( StrBuf & headers ) { // // Write the log file record for this request if (strchr( headers.Text(), '%' )) { char temp[2] = { '\0', '\0' }; StrBuf buf; buf.Set(headers); headers.Clear(); char *p = buf.Text(); while (*p) { if (*p == '%') { headers << "%%"; p++; } else { temp[0] = *p++; headers << temp; } } } Error e; e.Set( E_INFO, headers.Text() ); fReportLog->Report( &e ); } void p4wThread::doCommand( AllCommands cmd ) { // // Big switch to run specified command. // // Any deprecated ac codes are handled here if( cmd == AC_CHANGES ) cmd = AC_PENDINGCHANGELISTS; // // Grab the info from the show/hide cookie if ( fRequest->GetCmd() != AC_ICON ) { char *p; StrPtr *cookie = fWeb822.GetVar("cookie"); const StrPtr *swf = fRequest->GetDynArg("swf"); if (swf) // is there an override of the cookie? { char sh[8] = "0"; if (*swf == "0") { ShowHideMasks m = (ShowHideMasks) 0; switch(fRequest->GetCmd()) { case AC_PATHBROWSER: case AC_FILESMATCHING: m = SH_FILES; break; case AC_PENDINGCHANGELISTS: m = SH_PENDING; break; case AC_SUBMITTEDCHANGELISTS: m = SH_SUBMITTED; break; case AC_BRANCHES: m = SH_BRANCHES; break; case AC_LABELS: case AC_LABELSPATH: m = SH_LABELS; break; case AC_CLIENTS: m = SH_CLIENTS; break; case AC_USERS: m = SH_USERS; break; case AC_JOBS: m = SH_JOBS; break; } sprintf(sh, "%d", m); } fRequest->SetShowHide(sh); } else // use the cookie info { if (cookie && (p = strstr(cookie->Text(), "P4WStates=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WStates=")-1); char *q = strstr(temp.Text(), "; "); if (q) { *q = '\0'; temp.SetLength(); } if (!temp.Length()) temp.Set("0"); fRequest->SetShowHide(temp.Text()); } } } switch( cmd ) { // // User hit cancel button to cancel server request case AC_CANCELCMD: { globalCancel = 1; StrBuf errMsg; errMsg.Set( "Operation cancelled by user." ); p4wErrorView errorView( *fRequest, errMsg, 0 ); errorView.Render(); } break; case AC_NONE: if (!strcmp(fRequest->GetFullURL().Text(), "/favicon.ico")) { p4wMimeContentView mimeContent(*fRequest); mimeContent.Render(); return; } case AC_P4CMD: case AC_P4CMDTAGGED: case AC_P4CMDXML: { p4wRelocate relocate(*fRequest, cmd); if( !relocate.DoRelocate() ) { if( !doP4Init() ) return; p4wMimeContentView mimeContent(*fRequest); mimeContent.Render(); } } break; // // p4wFileBrowserView creates the view for these File Browser menu items // so we can build a detailed header case AC_SYNCFILE: case AC_EDITFILE: case AC_ADDFILE: case AC_DELETEFILE: case AC_REMOVEFILEFRM: case AC_LOCKFILEFRM: case AC_UNLOCKFILEFRM: case AC_REVERTUNCHANGEDFILEFRM: { if( !doP4Init() ) return; if (fRequest->GetLastReturnType() == AC_PATHBROWSER) { char *p; AllCommands ac; switch(fRequest->GetCmd()) { case AC_EDITFILE: p = "edit"; break; case AC_ADDFILE: p = "add"; break; case AC_DELETEFILE: p = "delete"; break; default: p = "sync"; break; } p4wCmdView cmdView(*fRequest, p); cmdView.Render(); } else { p4wCmdProcessorView cpView(*fRequest, cmd); cpView.Render(); p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.Render(); } } break; // // p4wMenuProcessorView creates the view for most menu items. // Exceptions include forms to be posted (ie -i) case AC_SYNCFILEFRM: case AC_EDITFILEFRM: case AC_ADDFILEFRM: case AC_DELETEFILEFRM: case AC_FILETYPEFILEFRM: case AC_INTEGRATEFILEFRM: case AC_RESOLVEFILEFRM: case AC_REVERTFILEFRM: case AC_SUBMITFILEFRM: case AC_SYNCFRM: case AC_EDITFRM: case AC_ADDFRM: case AC_DELETEFRM: case AC_FILETYPEFRM: case AC_REMOVEFRM: case AC_INTEGRATEFRM: case AC_RESOLVEFRM: case AC_LOCKFRM: case AC_UNLOCKFRM: case AC_REVERTFRM: case AC_PENDINGINTEGS: case AC_PENDINGCHANGELISTS: case AC_FIXPENDING: case AC_LABELFILES: case AC_LABELFILESTEXT: case AC_DELETELABEL: case AC_REPLACELABEL: case AC_CREATELABEL: case AC_CREATELABELTMP: case AC_DELETEBRANCH: case AC_CREATEBRANCH: case AC_INTEGRATEBRANCH: case AC_BRANCHDIFF: case AC_CREATEJOB: case AC_DELETEJOB: case AC_LABELSELECT: case AC_CONFIGURATION: case AC_MULTIUSER: case AC_SYNCCHANGE: case AC_SYNCCHANGERNG: case AC_SYNCLABEL: case AC_P4CMDPANE: case AC_DIFF2DIRSOUTPUT: { if( !doP4Init() ) return; p4wMenuProcessorView menuView(*fRequest, cmd); menuView.Render(); } break; // // More menuprocessor items, but these don't // need p4 initialization case AC_SUBMITFRM: case AC_FILESMATCHINGFRM: case AC_DELETEJOBCONFIRM: case AC_DELETEBRANCHCONFIRM: case AC_DELETELABELCONFIRM: case AC_REVERTCONFIRM: case AC_SHOWHIDECOLUMNS: { p4wMenuProcessorView menuView(*fRequest, cmd); menuView.Render(); } break; // // PathBrowserView commands case AC_UNSYNCED: case AC_UNRESOLVED: case AC_MISSING: case AC_DEPOT: case AC_CLIENT: case AC_OPENEDUNCHANGED: case AC_CHANGESUNOPENED: case AC_FILESMATCHING: case AC_OPENEDFILESALL: case AC_DIFF2DIRS: case AC_PATHBROWSER: { if( !doP4Init() ) return; p4wPathBrowserView browser(*fRequest, cmd); browser.Render(); } break; case AC_DEPOTVIEW: { p4wRelocate depotviewRelocate(*fRequest, AC_DEPOTVIEW); (void)depotviewRelocate.DoRelocate(); } break; // // File Browser view commands case AC_UPLOADTOLOCALPROCESSOR: { char *pmsg = 0; p4wUploadLocalProcessorView uploadProcessor(*fRequest); if( !fRequest->GetBrowseMode() && fRequest->BypassAuth() ) // -a flag? pmsg = "-a flag incompatible."; else uploadProcessor.Render(); if (pmsg || ((pmsg = uploadProcessor.GetErrorMsg()) != 0)) { StrBuf errorMsg; errorMsg << "Unable to upload the file: " << pmsg; p4wErrorView errorView(*fRequest, errorMsg, 0); errorView.Render(); break; } if( !doP4Init() ) return; p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.Render(); } break; case AC_EDITTEXTLOCALPROCESSOR: { char *pmsg = 0; p4wEditLocalProcessorView editProcessor(*fRequest); if( !fRequest->GetBrowseMode() && fRequest->BypassAuth() ) // -a flag? pmsg = "-a flag incompatible."; else editProcessor.Render(); if (pmsg || ((pmsg = editProcessor.GetErrorMsg()) != 0)) { StrBuf errorMsg; errorMsg << "Unable to save the file: " << pmsg; errorMsg << "<p>Use your browser\'s Back button to return to your edited file;"; errorMsg << "<br>select the entire file, copy the entire file to the clipboard,"; errorMsg << "<br>choose Edit Workspace File in Browser again,"; errorMsg << "<br>when the new form page appears, select the entire file,"; errorMsg << "<br>and paste from the clipboard. Then you can continue working once the"; errorMsg << "<br>problem above is resolved."; p4wErrorView errorView(*fRequest, errorMsg, 0); errorView.Render(); break; } // fall thru } case AC_BROWSEFILE: case AC_EDITTEXTLOCAL: case AC_UPLOADTOLOCAL: case AC_FILETEXTDEPOT: case AC_FILETEXTLOCAL: case AC_DIFFWVC: case AC_DIFFCVH: case AC_DIFFWVH: case AC_DIFFRVW: case AC_DIFF2FILES: case AC_LAUNCHEDITOR: case AC_FILESTATE: case AC_GENERALANNOTATE: case AC_ANNOTATE: case AC_FULLANNOTATE: case AC_CHGLISTANNOTATE: case AC_CHGLISTFULLANNOTATE: case AC_DIFF2: case AC_DIFF22: { p4wRelocate relocate(*fRequest, cmd); // May need to add &cdf= to URL if( relocate.DoRelocate() ) // so MSIE will work with menus; break; // it fails to use the <BASE> if( !doP4Init() ) return; p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.Render(); } break; // // Commands requiring LOCATION to remap url case AC_DIFF21: case AC_DIFFSVR: { p4wRelocate relocate(*fRequest, cmd); if( !relocate.DoRelocate() ) { StrBuf errorMsg; errorMsg << relocate.ErrorMsg; if (!errorMsg.Length()) errorMsg << "Requested URL is invalid in this context"; p4wErrorView errorView(*fRequest, errorMsg, 0, "diff"); errorView.Render(); } } break; case AC_WORKSPACE: { if( !doP4Init() ) return; p4wRelocate relocate(*fRequest, cmd); if( !relocate.DoRelocate() ) { StrBuf errorMsg; errorMsg << "Cannot switch to workspace mode: client root is unset or null."; p4wErrorView errorView(*fRequest, errorMsg, 0, "browsemodes"); errorView.Render(); } } break; case AC_BRANCHESPROCESSOR: case AC_LABELSPROCESSOR: case AC_CLIENTSPROCESSOR: case AC_USERSPROCESSOR: case AC_CHANGESPROCESSOR: { StrPtr *cookie = fWeb822.GetVar("cookie"); char *p; if ( cookie && fRequest->GetCmd() != AC_ICON ) { if ( cmd == AC_CHANGESPROCESSOR && (p = strstr(cookie->Text(), "P4WChgsDefs=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WChgsDefs=")-1); char *q = strstr(temp.Text(), "; "); if (q) { *q = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); } else if ( p = strstr(cookie->Text(), "P4WFilters=") ) { StrBuf temp; temp.Set(p + sizeof("P4WFilters=")-1); char *q = strstr(temp.Text(), "; "); if (q) { *q = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); } } } case AC_CLIENTSWITCH: case AC_MENUPROCESSOR: case AC_FIXSUBPROCESSOR: case AC_JOBSPROCESSOR: case AC_DELETECONFPROC: case AC_SHOWHIDECOLSPROC: case AC_SHOWHIDEFILECOLS: case AC_CHGLISTANNOTATEPROC: case AC_DEPOTPROCESSOR: case AC_GOTO: { p4wRelocate menuRelocate(*fRequest, cmd); if( !menuRelocate.DoRelocate() ) { StrBuf errorMsg; errorMsg << "Requested URL is invalid in this context"; if (menuRelocate.IsError()) errorMsg << "<br>" << menuRelocate.ErrorMsg; if (menuRelocate.IsClose() || menuRelocate.IsLoadUrl()) { errorMsg << crlf; errorMsg << "<script language='JavaScript' type='text/javascript'>" << crlf; errorMsg << "<!--" << crlf; if (menuRelocate.IsLoadUrl()) errorMsg << "opener.location = '" << menuRelocate.GetNewURL() << "';" << crlf; errorMsg << " self.close();" << crlf; errorMsg << "// -->" << crlf; errorMsg << "</script>" << crlf; } p4wErrorView errorView(*fRequest, errorMsg, 0, "roadmap"); errorView.Render(); } } break; case AC_CONFIGPROCESSOR: case AC_MULTIUSERPROCESSOR: { p4wRelocate configRelocate(*fRequest, cmd); if( !configRelocate.DoRelocate() && configRelocate.ErrorMsg.Length() ) { p4wErrorView errorView(*fRequest, configRelocate.ErrorMsg, 0, "settings"); errorView.Render(); } } break; case AC_MATCHPROCESSOR: { p4wRelocate matchingRelocate(*fRequest, AC_FILESMATCHING); (void)matchingRelocate.DoRelocate(); } break; // // Commands using cmdView/cmdPane. These represent simple // commands (ie sync a file), or can be the last step in // a form where the result is simply posted back // (ie client -i ). case AC_SYNCREV: { StrBuf path; path.Set( fRequest->GetPath() ); // // If rev1 is missing we have to bail const StrPtr *rev1 = fRequest->GetDynArg( "rev1" ); if( !rev1 ) { StrBuf errorMsg; errorMsg << "Requested URL is invalid in this context"; p4wErrorView errorView(*fRequest, errorMsg, 0, "roadmap"); errorView.Render(); break;; } path << "#" << rev1; fRequest->SetDepotPath(&path); } case AC_SYNCCMD: { if( !doP4Init() ) return; p4wCmdView cmdView(*fRequest, "sync"); if (fRequest->GetLastReturnType() == AC_BROWSEFILE) { fRequest->fSave4Later = 1; cmdView.RenderContent(); fRequest->fSave4Later = 0; if (cmd == AC_SYNCREV) { StrBuf path; path.Set( fRequest->GetPath() ); char *p = strrchr(path.Text(), '#'); if (p) { *p = '\0'; path.SetLength(); fRequest->SetDepotPath(&path); } } p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.Render(); } else cmdView.Render(); } break; case AC_LOCKCMD: case AC_LOCKFILE: { if( !doP4Init() ) return; p4wCmdView cmdView(*fRequest, "lock"); cmdView.Render(); } break; case AC_UNLOCKCMD: case AC_UNLOCKFILE: { if( !doP4Init() ) return; p4wCmdView cmdView(*fRequest, "unlock"); cmdView.Render(); } break; case AC_REVERTCMD: case AC_REVERTFILE: { if( !doP4Init() ) return; if (fRequest->GetLastReturnType() == AC_BROWSEFILE) { p4wCmdProcessorView cpView(*fRequest, cmd); cpView.Render(); p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.Render(); } else { if (cmd == AC_REVERTCMD && !fRequest->GetCmdFlag()) fRequest->SetCmdFlag("-a"); p4wCmdView cmdView(*fRequest, "revert"); cmdView.Render(); } } break; case AC_EDITEXISTINGCLIENT: { p4wRelocate relocate(*fRequest, cmd); if( !relocate.DoRelocate() ) { p4wErrorView errorView(*fRequest, "Unable to process request", 0); errorView.Render(); } } break; case AC_CLIENTCMD: { if( !doP4Init() ) return; p4wCmdView cmdView(*fRequest, "client"); cmdView.Render(); } break; case AC_USERCMD: { if( !doP4Init() ) return; p4wCmdView cmdView(*fRequest, "user"); cmdView.Render(); } break; case AC_JOBCMD: { if( !doP4Init() ) return; p4wJobCmdView cmdView(*fRequest); cmdView.Render(); } break; case AC_CHANGECMD: case AC_CHANGEORSUBMITCMD: { if( !doP4Init() ) return; p4wCmdView cmdView(*fRequest, "change"); cmdView.Render(); } break; case AC_LABELCMD: { if( !doP4Init() ) return; p4wCmdView cmdView(*fRequest, "label"); cmdView.Render(); } break; case AC_BRANCHCMD: { if( !doP4Init() ) return; p4wCmdView cmdView(*fRequest, "branch" ); cmdView.Render(); } break; case AC_SERVERINFO: { if( !doP4Init() ) return; p4wCmdView cmdView(*fRequest, "info"); cmdView.Render(); } break; // // List commands case AC_SUBMITTEDCHANGELISTSFILE: case AC_SUBMITTEDCHANGELISTS: { StrPtr *cookie = fWeb822.GetVar("cookie"); char *p; if ( cookie && fRequest->GetCmd() != AC_ICON && (p = strstr(cookie->Text(), "P4WChgsDefs=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WChgsDefs=")-1); char *q = strstr(temp.Text(), "; "); if (q) { *q = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); } p4wRelocate relocate(*fRequest, cmd); if( p && relocate.DoRelocate() ) break; } case AC_FIXSUBMITTED: { if( !doP4Init() ) return; p4wChangesProcessorView submittedChanges(*fRequest); submittedChanges.Render(); } break; case AC_CLIENTS: { StrPtr *cookie = fWeb822.GetVar("cookie"); char *p; if ( cookie && fRequest->GetCmd() != AC_ICON && (p = strstr(cookie->Text(), "P4WFilters=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WFilters=")-1); char *q = strstr(temp.Text(), "; "); if (q) { *q = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); } p4wRelocate relocate(*fRequest, cmd); if( !p || !relocate.DoRelocate() ) { if( !doP4Init() ) return; p4wClientsView clients(*fRequest); clients.Render(); } } break; case AC_USERS: { StrPtr *cookie = fWeb822.GetVar("cookie"); char *p; if ( cookie && fRequest->GetCmd() != AC_ICON && (p = strstr(cookie->Text(), "P4WFilters=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WFilters=")-1); char *q = strstr(temp.Text(), "; "); if (q) { *q = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); } p4wRelocate relocate(*fRequest, cmd); if( !p || !relocate.DoRelocate() ) { if( !doP4Init() ) return; p4wUsersView users(*fRequest); users.Render(); } } break; case AC_JOBS: { StrPtr *cookie = fWeb822.GetVar("cookie"); char *p; if ( cookie && fRequest->GetCmd() != AC_ICON && (p = strstr(cookie->Text(), "P4WJobsDefs=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WJobsDefs=")-1); char *q = strstr(temp.Text(), "; "); if (q) { *q = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); } p4wRelocate relocate(*fRequest, cmd); if( !p || !relocate.DoRelocate() ) { if( !doP4Init() ) return; p4wJobsView jobs(*fRequest); jobs.Render(); } } break; case AC_LABELS: case AC_LABELSPATH: { StrPtr *cookie = fWeb822.GetVar("cookie"); char *p; if ( cookie && fRequest->GetCmd() != AC_ICON && (p = strstr(cookie->Text(), "P4WFilters=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WFilters=")-1); char *q = strstr(temp.Text(), "; "); if (q) { *q = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); } p4wRelocate relocate(*fRequest, cmd); if( !p || !relocate.DoRelocate() ) { if( !doP4Init() ) return; p4wLabelsView labels(*fRequest); labels.Render(); } } break; case AC_BRANCHES: { StrPtr *cookie = fWeb822.GetVar("cookie"); char *p; if ( cookie && fRequest->GetCmd() != AC_ICON && (p = strstr(cookie->Text(), "P4WFilters=")) ) { StrBuf temp; temp.Set(p + sizeof("P4WFilters=")-1); char *q = strstr(temp.Text(), "; "); if (q) { *q = '\0'; temp.SetLength(); } fRequest->SetDefaults(temp.Text()); } p4wRelocate relocate(*fRequest, cmd); if( !p || !relocate.DoRelocate() ) { if( !doP4Init() ) return; p4wBranchesView branches(*fRequest); branches.Render(); } } break; // // Commands that display spec data case AC_CLIENTVIEW: { if( !doP4Init() ) return; p4wClientView client(*fRequest, 0); client.Render(); } break; case AC_USERVIEW: { if( !doP4Init() ) return; p4wUserView user(*fRequest); user.Render(); } break; case AC_RSSUSER: { if( !doP4Init() ) return; p4wRSSUserView rssUser(*fRequest); rssUser.Render(); } break; case AC_RSSJOBVIEW: { if( !doP4Init() ) return; p4wRSSJobviewView rssJobview(*fRequest); rssJobview.Render(); } break; case AC_JOBVIEW: case AC_FIXESJOB: { if( !doP4Init() ) return; p4wJobView jobView(*fRequest); jobView.Render(); } break; case AC_LABELVIEW: { if( !doP4Init() ) return; p4wLabelView label(*fRequest); label.Render(); } break; case AC_BRANCHVIEW: { if( !doP4Init() ) return; p4wBranchView branch(*fRequest); branch.Render(); } break; case AC_DESCRIBE: case AC_FIXESCHANGE: case AC_ADDFIX: case AC_ADDFIXPROCESSOR: { if( !doP4Init() ) return; p4wDescribeView describer(*fRequest); describer.Render(); } break; case AC_DESCRIBEDEAFULT: { if( !doP4Init() ) return; p4wDescribeDefaultView describer(*fRequest); describer.Render(); } break; case AC_JOBFIELDS: // obsolete: same as JOBSPEC now case AC_JOBSPEC: { if( !doP4Init() ) return; p4wJobSpecView jobSpec(*fRequest); jobSpec.Render(); } break; // // Commands to edit a spec case AC_CHANGEPENDINGEDIT: case AC_CHANGEEDIT: // obsolete: replaced by CHANGEPENDINGEDIT { if( !doP4Init() ) return; p4wChangePendingEditView changePendingEdit(*fRequest); changePendingEdit.Render(); } break; case AC_SUBMIT: { if( !doP4Init() ) return; p4wSubmitView submit(*fRequest); submit.Render(); } break; case AC_EDITCHANGE: { if( !doP4Init() ) return; p4wChangeEditView changeEdit(*fRequest); changeEdit.Render(); } break; case AC_EDITCLIENT: case AC_EDITNEWCLIENT: { if( !doP4Init() ) return; p4wClientEditView clientEdit(*fRequest); clientEdit.Render(); } break; case AC_EDITUSER: { if( !doP4Init() ) return; p4wUserEditView userEdit(*fRequest); userEdit.Render(); } break; case AC_EDITJOB: { if( !doP4Init() ) return; p4wJobEditView jobEditView(*fRequest); jobEditView.Render(); } break; case AC_EDITBRANCH: { if( !doP4Init() ) return; p4wBranchEditView branchEditView(*fRequest); branchEditView.Render(); } break; case AC_EDITLABEL: { if( !doP4Init() ) return; p4wLabelEditView labelEditView(*fRequest); labelEditView.Render(); } break; // // Some complex actions require more than one form // or require an intermediate processing step. They // go here. case AC_ADDPROCESSOR: { if( !doP4Init() ) return; p4wAddProcessorView addProcessor(*fRequest); if (fRequest->GetLastReturnType() == AC_BROWSEFILE) { fRequest->fSave4Later = 1; addProcessor.RenderContent(); fRequest->fSave4Later = 0; p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.Render(); } else addProcessor.Render(); } break; case AC_ADDSELECTPROCESSOR: { if( !doP4Init() ) return; p4wAddSelectView addSelect(*fRequest); addSelect.Render(); } break; case AC_SYNCPROCESSOR: { if( !doP4Init() ) return; p4wSyncProcessorView syncProcessor(*fRequest); if (fRequest->GetLastReturnType() == AC_BROWSEFILE && !fRequest->GetDynArg("lac")) { fRequest->fSave4Later = 1; syncProcessor.RenderContent(); fRequest->fSave4Later = 0; p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.SetIsPreviewCmd(syncProcessor.IsPreviewCmd()); browsefile.Render(); } else syncProcessor.Render(); } break; case AC_LABSYNCPROCESSOR: { if( !doP4Init() ) return; p4wLabSyncProcView labelSync(*fRequest); labelSync.Render(); } break; case AC_EDITPROCESSOR: { if( !doP4Init() ) return; p4wEditProcessorView editProcessor(*fRequest); if (fRequest->GetLastReturnType() == AC_BROWSEFILE) { fRequest->fSave4Later = 1; editProcessor.RenderContent(); fRequest->fSave4Later = 0; p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.Render(); } else editProcessor.Render(); } break; case AC_DELETEPROCESSOR: { if( !doP4Init() ) return; p4wDeleteProcessorView deleteProcessor(*fRequest); if (fRequest->GetLastReturnType() == AC_BROWSEFILE) { fRequest->fSave4Later = 1; deleteProcessor.RenderContent(); fRequest->fSave4Later = 0; p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.Render(); } else deleteProcessor.Render(); } break; case AC_RESOLVEPROCESSOR: { if( !doP4Init() ) return; p4wResolveProcessorView resolveProcessor(*fRequest, 1); resolveProcessor.Render(); } break; case AC_RESOLVEIAPROCESSOR: { if( !doP4Init() ) return; char *pmsg = 0; p4wResolveIAProcessorView resolveIAProcessor(*fRequest); if( !fRequest->GetBrowseMode() && fRequest->BypassAuth() ) // -a flag? pmsg = "-a flag incompatible."; else resolveIAProcessor.Render(); if (pmsg || ((pmsg = resolveIAProcessor.GetErrorMsg()) != 0)) { StrBuf errorMsg; errorMsg << "<span class=\"title\">Resolve Status:</span><br>"; errorMsg << "<img src=\"/grayPixelIcon?ac=20\" height=\"1\" width=\"100%\" border=\"0\" alt=\"\" title=\"\"><br>"; errorMsg << "<font color=\"#000000\"><b> " << fRequest->GetPath().Text() << "</b><p>"; errorMsg << "<b>Command:</b><br><ul>Resolve "; errorMsg << fRequest->GetPath().Text(); errorMsg << "</ul><p><b>Result:</b></font><br><ul><font color=\"#FF0000\">"; errorMsg << "Unable to resolve the file: " << pmsg << "</font></ul>"; p4wErrorView errorView(*fRequest, errorMsg, 0); errorView.Render(); break; } p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.SetRC(resolveIAProcessor.GetResolveType()); browsefile.Render(); } break; case AC_REVERTPROCESSOR: { if( !doP4Init() ) return; p4wRevertProcessorView revertProcessor(*fRequest); revertProcessor.Render(); } break; case AC_INTEGPROCESSOR: { if ((fRequest->GetSecurityFlags() & FLG_DISALLOW_INTEG) && !fRequest->isLocalRequest()) { StrBuf errorMsg; errorMsg << "Integrations currently are not allowed."; p4wErrorView errorView(*fRequest, errorMsg, 0); errorView.Render(); return; } if( !doP4Init() ) return; p4wIntegProcessorView integProcessor(*fRequest); if (fRequest->GetLastReturnType() == AC_BROWSEFILE && !fRequest->GetDynArg("bv")) { fRequest->fSave4Later = 1; integProcessor.RenderContent(); fRequest->fSave4Later = 0; p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.SetIsPreviewCmd(integProcessor.IsPreviewCmd()); browsefile.Render(); } else integProcessor.Render(); } break; case AC_LOCKPROCESSOR: { if( !doP4Init() ) return; p4wLockProcessorView lockProcessor(*fRequest); lockProcessor.Render(); } break; case AC_UNLOCKPROCESSOR: { if( !doP4Init() ) return; p4wUnlockProcessorView unlockProcessor(*fRequest); unlockProcessor.Render(); } break; case AC_FTYPEPROCESSOR: { if( !doP4Init() ) return; p4wFTProcessorView fTypeProcessor(*fRequest); if (fRequest->GetLastReturnType() == AC_BROWSEFILE) { fRequest->fSave4Later = 1; fTypeProcessor.RenderContent(); fRequest->fSave4Later = 0; p4wFileBrowserView browsefile(*fRequest, cmd); browsefile.Render(); } else fTypeProcessor.Render(); } break; case AC_RESOLVECMD: { if( !doP4Init() ) return; p4wResolveProcessorView resolve(*fRequest, 0); resolve.Render(); } break; // // Miscellaneous requests not belonging to any // of the categories above. // // Switch client command case AC_CLIENTSWITCHRES: { if( !doP4Init() ) return; p4wClientView clientSwitch(*fRequest, 1); clientSwitch.Render(); } break; case AC_PRINT: { if( !doP4Init() ) return; p4wPrintView print(*fRequest); print.Render(); } break; case AC_WORKSPACEFILE: case AC_WORKSPACEFILEPATH: { if( !doP4Init() ) return; p4wWorkspaceFileView localView( *fRequest ); localView.Render(); } break; case AC_TEXTCONTENT: { if( !doP4Init() ) return; p4wMimeContentView mimeContent(*fRequest); mimeContent.Render(); } break; case AC_ICON: { if (!strcmp(fRequest->GetFullURL().Text(), "/favicon.ico")) { if( doP4Init() ) { p4wMimeContentView mimeContent(*fRequest); mimeContent.Render(); return; } } p4wIconView icon(*fRequest); icon.Render(); } break; case AC_HELP: { p4wHelpView help(*fRequest); help.Render(); } break; case AC_ABOUT: { if( !doP4Init() ) return; p4wAboutView about(*fRequest); about.Render(); } break; case AC_RSSCHGS: { if( !doP4Init() ) return; // Show RSS changelists for the given path p4wRSSView rssView(*fRequest); rssView.Render(); } break; case AC_RSSJOBS: { if( !doP4Init() ) return; // Show RSS jobs using the given filter p4wRSSJobsView rssJobsView(*fRequest); rssJobsView.RenderContent(); } break; case AC_LOGIN: { // // Reissue the authenticate screen p4wAuthView auth(*fRequest); auth.Render(); } break; case AC_LOGOUT: { if( !doP4Init() ) return; p4wLogoutStartView logoutstart(*fRequest); logoutstart.Render(); } break; case AC_LOGOUT2: { if( !doP4Init() ) return; p4wLogoutView logout(*fRequest, 1); logout.Render(); } break; case AC_USERPSWD: { if( !doP4Init() ) return; p4wRelocate relocate(*fRequest, cmd); if( !relocate.DoRelocate() ) { // // Reissue the authenticate screen p4wAuthView auth(*fRequest); auth.Render(); } } break; case AC_GETTHUMBNAIL: { if( !doP4Init() ) return; p4wThumbnailView thumbnailView(*fRequest); thumbnailView.Render(); } case AC_ECHOURLAsDATA: { if( !doP4Init() ) return; p4wThumbnailView thumbnailView(*fRequest); thumbnailView.Render(); } case AC_UNSUPPORTED: { StrBuf errorMsg; errorMsg << "Command "; if( fRequest->GetCmdArg() ) errorMsg << fRequest->GetCmdArg(); errorMsg << " currently not supported."; p4wErrorView errorView(*fRequest, errorMsg, 0); errorView.Render(); } break; default: { // // Nothing else matched: process end-user url p4wRelocate relocate(*fRequest, cmd); if( !relocate.DoRelocate() ) { if( cmd == AC_P4CMDPROCESSOR && relocate.fError ) { // must set blankpage=1 or we might crash - buffer overrun perhaps happened p4wErrorView errorView(*fRequest, relocate.ErrorMsg, 1); errorView.Render(); break; } if( !doP4Init() ) return; p4wMimeContentView mimeContent(*fRequest); mimeContent.Render(); } } } } int p4wThread::doP4Init() { if (fRequest->didP4Init()) return 1; // // Issue p4 Init if we haven't already done so. Generate an // error page if the Init fails. Error e; StrBuf errorMsg; fRequest->p4Init( &e ); if( e.Test() ) { e.Fmt( &errorMsg ); p4wErrorView errorView( *fRequest, errorMsg, 0 ); errorView.Render(); fInitFailed = 1; return 0; } // // Issue a dummy command to see if we are connected // to a unicode server. If so, we'll // need to reissue Init() after SetTrans(). If not, then // we're done here. p4wPasswdTestView testUnicode( *fRequest ); testUnicode.Render(); // // had SSL failure? if( testUnicode.HadSSLError() ) { errorMsg.Set( "Failed client connect, server using SSL. Client must add SSL protocol prefix to P4PORT." ); p4wErrorView errView2( *fRequest, errorMsg, 0 ); errView2.Render(); fInitFailed = 1; return 0; } // // had password failure and -b (or -a)? if( testUnicode.HadPasswordError() && fNoAuth ) { StrPtr *pswd = (*fOpts)[ 'P' ]; // grab -P value if( pswd ) { fRequest->SetPassword( pswd ); p4wLoginView loginView( *fRequest ); loginView.Render( 0 ); // login with -P value if (!loginView.fPasswordError) testUnicode.Render(); // retry Unicode test } } // // Is this a "secure" (4.2+) server? const StrPtr *server = fRequest->GetProtocol( "server2" ); int secureServer = 0; if( server && server->Atoi() > 17 ) ++secureServer; // // If we didn't get the error of running a non-unicode client // with a unicode server, we don't have to // start again in unicode mode. if( !testUnicode.GotError() || !testUnicode.HadUnicodeError() ) { if( fNoAuth || !secureServer ) { fRequest->p4Final( &e ); fRequest->p4Init( &e ); if( e.Test() ) { e.Fmt( &errorMsg ); p4wErrorView eView( *fRequest, errorMsg, 0 ); eView.Render(); return 0; } } return 1; } // // We have a unicode server, so see if the P4CHARSET is set. If not, // we need to abort. if( !fClient.GetCharset().Length() ) { errorMsg.Set( "P4CHARSET must be set in order to connect to a unicode server." ); p4wErrorView errView2( *fRequest, errorMsg, 0 ); errView2.Render(); fInitFailed = 1; return 0; } // // Set client to unicode mode and re-issue p4 init fRequest->p4Final( &e ); CharSetCvt::CharSet cs = CharSetCvt::Lookup( fClient.GetCharset().Text() ); if (cs == -1) { errorMsg.Set( "Invalid P4CHARSET name: " ); errorMsg << fClient.GetCharset().Text(); p4wErrorView errView2( *fRequest, errorMsg, 0 ); errView2.Render(); fInitFailed = 1; return 0; } fClient.SetTrans( CharSetCvt::UTF_8, cs, CharSetCvt::UTF_8, CharSetCvt::UTF_8 ); fRequest->p4Init( &e ); if( e.Test() ) { e.Fmt( &errorMsg ); p4wErrorView errView3( *fRequest, errorMsg, 0 ); errView3.Render(); return 0; } // // Tell p4Request that this is a unicode server so that the // rendered page sets the charset correctly in the http header, // and so that text will be rendered correctly. fRequest->SetUnicode ( 1 ); return 1; } void p4wThread::doP4Final() { // // Issue Final to close connection opened by Init. // This is only required if we issued dummy p4 command // to test for correct password, and no subsequent p4 // command was issued to clean/clear the connection. // p4Final will only issue Final() if it believes that // one is required. Error e; StrBuf errorMsg; fRequest->p4Final( &e ); if( e.Test() ) { e.Fmt( &errorMsg ); p4wErrorView errorView( *fRequest, errorMsg, 0 ); errorView.Render(); } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 12234 | Matt Attaway |
Rejigger P4Web project in preparation for official sunsetting The bin directory contains the last official builds of P4Web from the Perforce download site. P4Web is soon to be completely sunsetted; these builds are here for folks who don't want to build their own. To better handle the archived builds the source code has been moved into a separate src directory. |
||
//guest/perforce_software/p4web/Main/p4wThread.cpp | |||||
#1 | 8914 | Matt Attaway | Initial add of the P4Web source code |