// // Copyright 2001 Perforce Software. All rights reserved. // // This file is part of Perforce - the FAST SCM System. // // p4wCmdView: // Issues a command and passes result to a result pane (cmdPane). // Command is either generated directly from the url, or in the // case of spec forms, it is generated with only the -i flag.. #include <stdlib.h> #include <string.h> #include <p4wp4.h> #include "p4wMenuPane.h" #include "p4wClientRootPane.h" #include "p4wCmdView.h" #include "p4wCmdPane.h" p4wCmdView::p4wCmdView(p4wRequest & Request, const char * cmd) : p4wRunView(Request), fFiles(0), fHasFormData(0), fReplaceField(0), fSpecHasFlags(0) { // // Set the command, command flags and args (if any). // Also set flags specifying whether this is a form, // and whether form data was found. const StrPtr *flags = fRequest.GetCmdFlag(); const StrPtr *args = fRequest.GetCmdArg(); if( flags ) fFlags.Put()->Set( *flags ); if( args ) fArgs.Set( *args ); if( cmd ) fCmd.Set( cmd ); switch( fRequest.GetCmd() ) { case AC_CLIENTCMD: case AC_USERCMD: case AC_JOBCMD: case AC_CHANGECMD: case AC_CHANGEORSUBMITCMD: case AC_LABELCMD: case AC_BRANCHCMD: fIsSpec = 1; break; default: fIsSpec = 0; break; } if( fRequest.GetPostData() ) fHasFormData = 1; // // Handle special cases: client command when in // workspace mode, Edit Pending Changelist form // that has several command options, and create // label which can result in replacing the View // field in cmdPane. if( fRequest.GetViewMode() == VM_WORKSPACE && fRequest.GetCmd() == AC_CLIENTCMD ) { SetClientWSOpts(); } else if( fRequest.GetCmd() == AC_CHANGEORSUBMITCMD ) { SetPendingChgOpts(); } else if( fRequest.GetCmd() == AC_LABELCMD ) { SetLabelCreateOpts(); } else if( fRequest.GetCmd() == AC_CHANGECMD ) { SetSubmittedChgOpts(); } // // Set the short and the long versions of the title fShortTitle.Set( "Command Result" ); if( !fCmd.Length() ) { fFullTitle.Set( "Command Result" ); } else { fFullTitle << fCmd; for( int i = 0; i < fFlags.Count(); i++ ) fFullTitle << " " << fFlags.Get( i ); // // If the path component of the url is not // empty, use it in the title. If this is a form, // GetURL() gives the argument to the command; // otherwise use GetPath() since the argument is // the path or file. if( fRequest.GetURL().Length() ) { if( fIsSpec ) { fFullTitle << " " << fRequest.GetURL(); } else { fFullTitle << " " << fRequest.GetPath(); } } if( fArgs.Length() ) fFullTitle << " " << fArgs; fFullTitle << " Result"; } } p4wCmdView::~p4wCmdView() { } void p4wCmdView::RenderContent() { // // Generate and send the command via the status pane. // // If fCmd is unset, we have to bail. We assume the user typed an // invalid URL. Similarly, if this is a form command and there // is no form data, we have to bail. if( !fCmd.Length() || ( fIsSpec && !fHasFormData ) ) { RenderError( "Requested URL is invalid in this context." ); return; } // // If this is a client edit from a remote browser // make sure the Owner, Root and AltRoots are unchanged if (fRequest.GetCmd() == AC_CLIENTCMD && !fRequest.isLocalRequest()) { p4wClientRootPane clientRootPane(*this, fRequest); int lgthMaster = fRequest.GetMasterRoot()->Length(); if (!SEC_ALLOW_EDIT_CLIENTROOT || lgthMaster) { const char *cliArgs[] = { "-o" }; fRequest.p4("client", 1, cliArgs, &clientRootPane); fRequest.p4Wait(); spec.Add( "Client" ); spec.Add( "Owner" ); spec.Add( "Root" ); spec.Add( "AltRoots" ); spec.Add( "Accessed" ); spec.Add( "Updated" ); if( !ProcessForm() ) { securityError(); return; } } if (!SEC_ALLOW_EDIT_CLIENTROOT && (specTable.GetVar( "Accessed" ) || specTable.GetVar( "Updated" ))) { StrPtr *c = specTable.GetVar( "Client" ); StrPtr *o = specTable.GetVar( "Owner" ); StrPtr *r = specTable.GetVar( "Root" ); if( !c || strcmp(c->Text(), clientRootPane.GetClient().Text()) || !o || strcmp(o->Text(), clientRootPane.GetOwner().Text()) || !r || strcmp(r->Text(), clientRootPane.GetRoot().Text()) ) { securityError(); return; } StrPtr *a = specTable.GetVar( "AltRoots" ); if (a || clientRootPane.GetAltRoots().Length()) { StrBuf ar; if ( a ) { ar.Set(a); char *p = ar.Text(); char *q = p; for (p = p + strlen(p); --p >= q; ) // remove trailing \n's { if (*p == '\n') *p = '\0'; else break; } ar.SetLength(); } if ( !a || strcmp(ar.Text(), clientRootPane.GetAltRoots().Text()) ) { securityError(); return; } } } else if (lgthMaster) { StrPtr *root = specTable.GetVar( "Root" ); #ifdef OS_NT if (!root || strnicmp(root->Text(), fRequest.GetMasterRoot()->Text(), lgthMaster)) #else if (!root || strncmp(root->Text(), fRequest.GetMasterRoot()->Text(), lgthMaster)) #endif { StrBuf buf; buf << "The Client must begin with "; buf << fRequest.GetMasterRoot(); buf << ". Use your browser's Back button and correct the Root field."; RenderError(buf.Text()); return; } } } // // Generate the title and set the arguments. if( fIsSpec ) DoSpecArgAndTitle(); else DoCmdArgAndTitle(); // // Make the request. If we need to replace a field in // a spec (ie as in the label create form), use the // special cmdPane constructor for that purpose. if( fReplaceField ) { p4wCmdPane cmdPane( *this, fRequest, title.Text(), fNewField.Text(), fNewVal.Text() ); fRequest.p4( fCmd.Text(), 0, 0, &cmdPane ); fRequest.p4Wait(); } else { p4wCmdPane cmdPane( *this, fRequest, title.Text() ); fRequest.p4( fCmd.Text(), 0, 0, &cmdPane ); fRequest.p4Wait(); } } void p4wCmdView::securityError() { RenderError( "The Client spec was corrupt when received by P4Web. Use your browser's Back button to retry."); } void p4wCmdView::SetClientWSOpts() { // // If this was an edit client command and we are in // workspace mode, and the client root changed, // reset the cd and wr state parameters so that // we don't get dozens of "file is not under client root" // errors. spec.Add( "Root" ); if( !ProcessForm() ) return; // // Get the current root value so we can compare it to // the old root. If this server supports multiple roots, // only perform this check if only one root is specified // on this form, since we don't know which of these roots // is currently in use. StrPtr *r = specTable.GetVar( "Root" ); if( !r ) return; // // Bail if we detect more than 1 client root on form char *end = strstr( r->Text(), "\n" ); if( end ) { ++end; if( *end != '\0' && *end != '\n' ) return; } // // Strip newline from root value StrBuf root; if( end = strstr( r->Text(), "\n" ) ) root.Set( r->Text(), end - r->Text() ); else root.Set( r ); // // Normalize the workspace root so that we can // compare it with the existing root, and reset state // variables if different. StrBuf wr; char pd; p4wURL urlMaker; (void)urlMaker.GetSysDirDelim( &pd ); wr.Set( root ); if( *( root.Text() + root.Length() - 1 ) != pd ) wr << urlMaker.GetSysDirDelim( NULL ); if( wr != fRequest.GetStateArg( "wr" )->Text() ) { fRequest.ReplaceBase( "wr", wr.Text() ); fRequest.ReplaceBase( "cd", wr.Text() ); } } void p4wCmdView::SetLabelCreateOpts() { // // Parse the Create Label form to see if the // View field needs to be replaced spec.Add( "ViewOpt" ); if( !ProcessForm() ) return; const StrPtr *viewOpt = specTable.GetVar( "ViewOpt" ); const StrPtr *view = specTable.GetVar( "dirVal" ); if( viewOpt && *viewOpt == "in" ) { fReplaceField = 1; fNewField.Set( "View" ); fNewVal.Set( view->Text() ); } } void p4wCmdView::SetSubmittedChgOpts() { ++fSpecHasFlags; fFlags.Put()->Set( "-u" ); } void p4wCmdView::SetPendingChgOpts() { fAddJobFix = 0; // // Parse the form to see which command and flags // to issue based on which button was pushed. // This is used only for the Edit Pending // Changelist form. StrPtr *formAction = NULL; StrPtr *action = NULL; // // If this was not from a form, we will have to bail spec.Add( "formActions" )->type = SDT_LLIST; spec.Add( "changelistVal" ); spec.Add( "revertOpt" ); spec.Add( "unchgOption" ); spec.Add( "openOpt" ); spec.Add( "submitOptions" ); if( !ProcessForm() ) return; // // Get the name of the button that was selected for( int curAction = 0; (action = specTable.GetVar(StrRef("formActions"), curAction)) != NULL; curAction++ ) { // See if this action is the one that was selected. Spec actionItemSpec; StrBufDict actionItemTable; actionItemSpec.Add(*action); (void)fRequest.ProcessForm(actionItemSpec, &actionItemTable); formAction = actionItemTable.GetVar(action->Text()); if( formAction != NULL ) { formAction = action; break; } } // // Handle "delete", "reopen" and "revert" from the pending change form. // They don't post back a form, and use flags not specified in url. if( formAction && *formAction == "delete" ) { fIsSpec = 0; fCmd.Set( "change" ); fFlags.Put()->Set( "-d" ); StrPtr *changelistval = specTable.GetVar( "Change" ); if( changelistval ) fArgs.Set( *changelistval ); } else if( formAction && *formAction == "reopen" ) { fIsSpec = 0; fCmd.Set( "reopen" ); fFlags.Put()->Set( "-c" ); StrPtr *changelistval = specTable.GetVar( "changelistVal" ); if( changelistval ) { char *p = strchr(changelistval->Text(), ' '); if (p) { *p = '\0'; changelistval->SetLength(); } fArgs.Set( *changelistval ); } fFiles = 1; } else if( formAction && *formAction == "revert" ) { fIsSpec = 0; fCmd.Set( "revert" ); StrPtr *changelistval = specTable.GetVar( "Change" ); StrPtr *revertOpt = specTable.GetVar( "revertOpt" ); if( revertOpt && *revertOpt == "unchanged" ) fFlags.Put()->Set( "-a" ); fFlags.Put()->Set( "-c" ); if( changelistval ) { if( *changelistval == "new" ) fArgs.Set( "default" ); else fArgs.Set( *changelistval ); } fFiles = 1; } else if( formAction && *formAction == "redisplay" ) { fIsSpec = 0; fRedisplay = 1; fAc = AC_CHANGEPENDINGEDIT; // // Change or submit just post the form back (-i ). // Submit may take -r flag. } else if( formAction && *formAction == "submit" ) { const StrPtr *server = fRequest.GetProtocol( "server2" ); if( server && server->Atoi() >= 22 ) // pass -f for 2006.2+ servers { StrPtr *submitOptions = specTable.GetVar( "submitOptions" ); if (submitOptions && !strstr(submitOptions->Text(), "client")) { ++fSpecHasFlags; fFlags.Put()->Set( "-f" ); if(strstr(submitOptions->Text(), "Revert " )) { fFlags.Put()->Set( strstr(submitOptions->Text(), "reopen") ? "revertunchanged+reopen" : "revertunchanged" ); } else if(strstr(submitOptions->Text(), "Leave " )) { fFlags.Put()->Set( strstr(submitOptions->Text(), "reopen") ? "leaveunchanged+reopen" : "leaveunchanged" ); } else { fFlags.Put()->Set( strstr(submitOptions->Text(), "reopen") ? "submitunchanged+reopen" : "submitunchanged" ); } } } else { StrPtr *openOpt = specTable.GetVar( "openOpt" ); if( openOpt && *openOpt == "y" ) { ++fSpecHasFlags; fFlags.Put()->Set( "-r" ); } StrPtr *uch = specTable.GetVar( "unchgOption" ); if( uch && *uch == "revert" ) { ++fSpecHasFlags; fFlags.Put()->Set( "-R" ); } } fCmd.Set( *formAction ); } else if( formAction && *formAction == "addjobfix" ) { fRedisplay = fIsSpec = 0; fAddJobFix = 1; fAc = AC_JOBS; } else { if( formAction ) fCmd.Set( *formAction ); } } void p4wCmdView::DoSpecArgAndTitle() { // // Generate the title and argument list for a // spec form. Generally this only needs -i option. title.Set( fCmd ); title << " "; fRequest.p4Arg( "-i" ); // Submit -i may have flags, like submit -i -r if( fSpecHasFlags ) { for( int i = 0; i < fFlags.Count(); i++ ) ArgAndTitle( fFlags.Get( i )->Text() ); } // // If the path part of the url isn't empty, use the // argument in the title. if( fRequest.GetURL().Length() ) title << fRequest.GetURL(); } void p4wCmdView::DoCmdArgAndTitle() { // // Generate the title and argument list for commands // that are not simple spec forms needing only the -i // option. // title.Set( fCmd ); title << " "; // // Command-line flags for( int i = 0; i < fFlags.Count(); i++ ) ArgAndTitle( fFlags.Get( i )->Text() ); // // Non-empty URL signals that path is part of // the command. if( fRequest.GetURL().Length() ) ArgAndTitle( fRequest.GetPath().Text() ); else if (fRequest.GetLastReturnType() == AC_PATHBROWSER && (fRequest.GetCmd() == AC_SYNCCMD // special hack for sync folder || fRequest.GetCmd() == AC_REVERTCMD)) // special hack for revert unchged in folder { StrBuf buf; buf << fRequest.GetDepotPath() << "..."; ArgAndTitle( buf.Text() ); } // // Append command arguments if( fArgs.Length() ) ArgAndTitle( fArgs.Text() ); // // Some commands need to pass file arguments that // have been passed in the form. if( fFiles ) { Spec s; StrBufDict st; s.Add( "Files" )->type = SDT_LLIST; StrPtr *file; if( fRequest.ProcessForm( s, &st ) ) { for( int j = 0; file = st.GetVar( StrRef("Files"), j ); j++ ) ArgAndTitle( file->Text() ); } } }
# | 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/Views/p4wCmdView.cpp | |||||
#1 | 8914 | Matt Attaway | Initial add of the P4Web source code |