// Copyright 1999 (c) by Perforce Software, Inc. All rights reserved. // // p4wResolveProcessorView: // The resolve processor view. #include <stdlib.h> #include <string.h> #include <p4wp4.h> #include "p4wView.h" #include "p4wResolveProcessorView.h" #include "p4wFilelogPane.h" #include "p4wCmdPane.h" #include "p4wPreviewPane.h" #include "p4wResolveIAPane.h" #include "p4wClientRootPane.h" #include "p4wStrBuf.h" #include "p4wHtml.h" #include "p4wI18n.h" #include "p4wStrBuf.h" # ifdef OS_MACOSX # include "macutil.h" # endif # ifdef OS_QNX # define EXECVCAST(x) ((const char * const *)(x)) # else # define EXECVCAST(x) (x) # endif // // p4wResolveHelper is just a class // to process a resolve with to see if any files // need to be resolved. Use it to check if // any files need resolving. // // USE ONLY WHEN DOING A PREVIEW!! // #ifndef __RESOLVEHELPER__ #define __RESOLVEHELPER__ class p4wResolveHelper : public ClientUser { public: p4wResolveHelper() : ClientUser() { needsResolve = 1; }; void InputData( StrBuf *strbuf, Error *e ) {}; void OutputError( const char *errBuf ) {}; void OutputInfo( char level, const char *data ) {}; void OutputBinary( const char *data, int length ) {}; void OutputText( const char *data, int length ) {}; void OutputStat( StrDict *varList ) {}; void Prompt( const StrPtr &msg, StrBuf &rsp, int noEcho, Error *e ) {}; void ErrorPause( char *errBuf, Error *e ) {}; void Edit( FileSys *f1, Error *e ) {}; void Diff( FileSys *f1, FileSys *f2, int doPage, char *diffFlags, Error *e ) {}; void Merge( FileSys *base, FileSys *leg1, FileSys *leg2, FileSys *result, Error *e ) {}; void Help( const char *const *help ) {}; FileSys *File( FileSysType type ) { return NULL; }; void Finished() {}; void HandleError( Error *err ) { StrBuf msg; err->Fmt( &msg ); if ( msg.Contains( StrRef( "no file(s) to resolve" ) ) ) { needsResolve = 0; } else { needsResolve = 1; } }; int NeedsResolving() { return needsResolve; }; private: int needsResolve; }; #endif // __RESOLVEHELPER__ // // ------------------------------------- // Constructors and destructor. // p4wResolveProcessorView::p4wResolveProcessorView( p4wRequest & Request, int fromForm ) : p4wRunView( Request ), fIsFromForm( fromForm ) { if( fIsFromForm ) ProcessFormAction(); fAc = AC_RESOLVEFRM; // // Set the short and the long versions of the title. // If there is no POST data when expected, the title is "Error". if( fIsFromForm && !ProcessForm() ) { fShortTitle.Set( "Error" ); fFullTitle.Set( "Error" ); return; } // If this is not a form determine whether preview or // not by checking flag set in url if( !fIsFromForm ) { const StrPtr *flags = fRequest.GetCmdFlag(); if( flags && *flags == "-n" ) fPreview = 1; else fPreview = 0; } fShortTitle.Set( "Command Result" ); if( fPreview ) fFullTitle.Set( "Resolve Preview Result" ); else fFullTitle.Set( "Resolve Result" ); } p4wResolveProcessorView::~p4wResolveProcessorView() { } // ------------------------------------- // Control item render functions. // void p4wResolveProcessorView::RenderContent() { // // Issue resolve command (passing the results through a single // CmdPane). // Build a spec to parse the sync options if( fIsFromForm && !ProcessForm() ) { RenderError("Requested URL is invalid in this context."); return; } if (!fRequest.isLocalRequest()) { p4wClientRootPane clientRootPane(*this, fRequest); const char *cliArgs[] = { "-o" }; fRequest.p4("client", 1, cliArgs, &clientRootPane); fRequest.p4Wait(); if (clientRootPane.GetIsLockedAway()) { fRequest << "<font color=\"#FF0000\">Locked client "; fRequest << fRequest.GetClient().Text(); fRequest << " can only be used by its owner</font>"; return; } if (!SEC_ALLOW_ALL_CLIENTS) { if (strcmp(clientRootPane.GetOwner().Text(), fRequest.GetUser().Text())) { if (SEC_ALLOW_UNOWNED_CLIENTS && clientRootPane.GetOwner().Length() == 0) ; else { fRequest << "<font color=\"#FF0000\">Client "; fRequest << fRequest.GetClient().Text(); fRequest << " can only be used by its owner</font>"; return; } } if (!clientRootPane.GetHost().Length() && !SEC_ALLOW_NOHOST_CLIENTS) { fRequest << "<font color=\"#FF0000\">Clients whose host field is not specified can not be used."; return; } } } int forceOption = 0; int markOption = 0; int interactive = 0; int multipleFiles = 0; int nonlocal = 0; const StrPtr *resOptionsRes = NULL; const StrPtr *actionFile = NULL; const StrPtr *headType = NULL; p4wHtml err; if( fIsFromForm ) { StrPtr *resOption = specTable.GetVar("Option"); StrPtr *fileChoice = specTable.GetVar("Files"); actionFile = specTable.GetVar( "actionFile" ); headType = specTable.GetVar( "headType" ); if( specTable.GetVar( "OptionFrc" ) ) forceOption = 1; if( specTable.GetVar( "OptionMark" ) ) markOption = 1; if( *resOption == "interactive" ) interactive = 1; else resOptionsRes = specTable.GetVar( "OptionRes" ); if( fileChoice && *fileChoice == "selected" ) multipleFiles = 1; } else { const StrPtr *flags = fRequest.GetCmdFlag(); if( !flags ) interactive = 1; else if( *flags == "-f" ) forceOption = 1; else if( *flags == "-v" ) markOption = 1; else resOptionsRes = flags; } // // Do a resolve request just as a preview that we can check to see if // we should launch an interactive one. // fRequest.p4Arg( "-n" ); if( forceOption ) { fRequest.p4Arg( "-f" ); } if( markOption ) { fRequest.p4Arg( "-v" ); } if ( !interactive ) { fRequest.p4Arg( resOptionsRes->Text() ); } StrBuf fileArg; if( fIsFromForm ) { if( !AddFileArgs() ) return; fileArg.Set( GetFileArg() ); } else { fileArg.Set( fRequest.GetPath() ); fRequest.p4Arg( fileArg ); } p4wResolveHelper helper; fRequest.p4( "resolve", 0, 0, &helper ); fRequest.p4Wait(); int needsResolve = helper.NeedsResolving(); // // The -dw & -db flags are only supported for 2002.2+ // servers. If this flag is set, we need to check the // server protocol. StrBuf dwbFlag; const StrPtr *dw = fRequest.GetStateArg( "rw" ); if( dw && ( *dw =="dw" || *dw == "db" ) ) { const StrPtr *server = fRequest.GetProtocol( "server2" ); if( server && server->Atoi() > 13 ) dwbFlag << "-" << dw; } // // See if we can go for real. // int isText = 0; if ( interactive && !fPreview ) { // need to know if this is a text file since // we can only handle text files non-locally and interactively if( headType && ( strstr( headType->Text(), "text" ) || strstr( headType->Text(), "symlink" ) || strstr( headType->Text(), "unicode" ) ) ) isText = 1; # if defined ( OS_MACOSX ) if ( !getenv( "DISPLAY" ) && !fRequest.isLocalRequest() ) { if ( multipleFiles || !isText ) { err << "To resolve with a remote p4web, "; err << "you must have X-Windows installed."; err.linebreak(); err.linebreak(); err << " You can download a "; err << "version of X-Windows "; err.beginLink( "http://www.apple.com/macosx/features/x11" ); err << "here."; err.endLink(); err.linebreak(); err.linebreak(); RenderErrorLinks( err.Text() ); return; } else nonlocal = 1; } if ( !WindowServicesAvailable() && !getenv( "DISPLAY" ) ) { if ( multipleFiles || !isText ) { err << "No Window Server is available to you. "; err << "This is most likely because you are not "; err << "logged in locally to "; err << fRequest.GetAddress( 0 ); err << ". "; err << "You can either use X-Windows on "; err << fRequest.GetAddress( 0 ); err << " and on your machine or you can log into "; err << fRequest.GetAddress( 0 ); err << " locally."; err.linebreak(); err.linebreak(); err << " You can download a "; err << "version of X-Windows "; err.beginLink( "http://www.xdarwin.org/download" ); err << "here."; err.endLink(); err.linebreak(); err.linebreak(); RenderErrorLinks( err.Text() ); return; } else nonlocal = 1; } # else int envOK = 1; #ifndef OS_NT if( !getenv( "DISPLAY" ) ) envOK = 0; #endif if ( !fRequest.isLocalRequest() || !envOK || fRequest.IsNTService() ) { if ( multipleFiles || !isText ) { if ( multipleFiles ) err << "Multiple "; else err << "Non-text "; err << "files cannot be resolved interactively "; err << "unless the browser and P4Web "; err << "are hosted on the same machine."; err.linebreak(); err.linebreak(); RenderErrorLinks( err.Text() ); return; } else nonlocal = 1; } # endif } // // Now, go for real. // if ( interactive && !fPreview && !nonlocal ) { // // If we are in unicode mode, get the conversion instance // to convert the filenames from UTF-8 to the local // character set since this conversion will be needed for // interactive resolve CharSetCvt *cvt; char *cvtPath = NULL; if( fRequest.GetUnicode() ) { cvt = CharSetCvt::FindCvt( CharSetCvt::UTF_8, CharSetCvt::Lookup( fRequest.GetClientApi().GetCharset().Text() ) ); } // // Launch interactive resolve // StrArray options; StrArray fileArgs; if( fPreview ) options.Put()->Set( "-n" ); if( forceOption ) options.Put()->Set( "-f" ); if( markOption ) options.Put()->Set( "-v" ); if( dwbFlag.Length() ) options.Put()->Set( dwbFlag.Text() ); if( multipleFiles ) { StrPtr *file; StrRef fileVar( "File" ); for( int j = 0; file = specTable.GetVar( fileVar, j ); j++ ) { // // Unicode mode: convert filenames to // local character set for interactive resolve if( fRequest.GetUnicode() ) { cvtPath = p4wI18n::convertText( cvt, file->Text() ); if( !cvtPath ) fileArgs.Put()->Set( file->Text() ); else { fileArgs.Put()->Set( cvtPath ); delete [] cvtPath; } } else { fileArgs.Put()->Set( file->Text() ); } } } else { // // Unicode mode: convert the filename to the local // character set as needed for interactive resolve if( fRequest.GetUnicode() ) { cvtPath = p4wI18n::convertText( cvt, fileArg.Text() ); if( !cvtPath ) fileArgs.Put()->Set( fileArg.Text() ); else { fileArgs.Put()->Set( cvtPath ); delete [] cvtPath; } } else { fileArgs.Put()->Set( fileArg.Text() ); } } if( fRequest.GetUnicode() ) delete cvt; p4wHtml htm; if ( needsResolve ) { int hasSpace = 0; #ifndef OS_NT if ( !multipleFiles && isText && strchr(fileArg.Text(), ' ') ) hasSpace = 1; #endif if (hasSpace || !LaunchInteractiveResolve( options, fRequest, fileArgs )) { htm.paragraph(); htm.text( "Failed to launch local interactive resolve for " ); htm.text( p4wStrBuf().EscapeHTML(fileArg, fRequest.GetUnicode()).Text(), "b" ); #ifndef OS_NT if (!hasSpace) htm.text( " (check environment variable DISPLAY)." ); #endif if (fErrorMsg.Length()) { htm.linebreak(); htm.text(fErrorMsg.Text(), 0, 0, "#FF0000"); } fRequest << htm; if ( !multipleFiles && isText ) { htm.Clear(); htm.linebreak(); htm.text( "You can still resolve this file using the form below." ); fRequest << htm; nonlocal = 1; goto runRemoteResolve; } } else { // // Return generic informational message // htm.endTable(); htm.paragraph(); htm.text( "Interactive resolve was launched for " ); htm.text( p4wStrBuf().EscapeHTML(fileArg, fRequest.GetUnicode()).Text(), "b" ); const StrPtr *mu = fRequest.GetDynArg("mu"); int show = mu ? atoi(mu->Text()) : FM_BROWSEFILE|FM_REVERTCONFIRM|FM_FILETEXTDEPOT |FM_FILETEXTLOCAL|FM_MIMECONTENT|FM_WORKSPACEFILEPATH |FM_LAUNCHEDITOR|FM_EDITTEXTLOCAL|FM_DIFF_WVC_CVH |FM_DIFFWVH|FM_DIFF21; htm.SetRequest(&fRequest); htm.RenderFileMenu(show); htm << "<script language=javascript>" << crlf; htm << "setmushow("; htm << show; htm << ");" << crlf; htm << "</script>" << crlf; fRequest << htm; } } else { htm.paragraph(); htm.text( "No resolve needed for " ); htm.text( p4wStrBuf().EscapeHTML(fileArg, fRequest.GetUnicode()).Text(), "b" ); fRequest << htm; } } else { runRemoteResolve: title = "Resolve "; if( fPreview ) ArgAndTitle( "-n" ); if( forceOption ) ArgAndTitle( "-f" ); if( markOption ) ArgAndTitle( "-v" ); if( !interactive ) ArgAndTitle( resOptionsRes->Text() ); if( dwbFlag.Length() ) ArgAndTitle( dwbFlag.Text() ); // Process the files. If this returned an error // don't issue the command. if( fIsFromForm ) { if( !AddFileArgs() ) return; } else { ArgAndTitle( fileArg.Text() ); } // Run the command. if( fPreview ) { p4wPreviewPane prevPane( *this, fRequest, title.Text() ); fRequest.p4( "resolve", 0, 0, &prevPane ); fRequest.p4Wait(); } else if ( nonlocal ) { if (!actionFile) { p4wHtml htm; htm.paragraph(); htm.text( "Fatal Error: unable to determine file name.", "b" ); fRequest << htm; return; } p4wResolveIAPane resIAPane( *this, fRequest, title.Text() ); resIAPane.fActionFile << actionFile; resIAPane.fForceOption = forceOption; resIAPane.fMarkOption = markOption; if( dwbFlag.Length() ) resIAPane.fdwbFlag << dwbFlag.Text(); fRequest.p4( "resolve", 0, 0, &resIAPane ); fRequest.p4Wait(); } else { p4wCmdPane cmdPane( *this, fRequest, title.Text() ); fRequest.p4( "resolve", 0, 0, &cmdPane ); fRequest.p4Wait(); } } } int p4wResolveProcessorView::LaunchInteractiveResolve( StrArray & options, p4wRequest & request, StrArray & files ) { Error e; RunArgv cmd, tcmd, * pCmd; // NB cmd << adds an argument with spaces, // just raw text. cmd << "p4"; if ( request.GetClient().Length() ) cmd << "-c" << request.GetClient(); if ( request.GetPort().Length() ) cmd << "-p" << request.GetPort(); if ( request.GetPassword().Length() ) cmd << "-P" << request.GetPassword(); if ( request.GetUser().Length() ) cmd << "-u" << request.GetUser(); if ( request.GetUnicode() ) cmd << "-C" << request.GetCharset(); cmd << "resolve"; for ( int i = 0; i < options.Count(); i++ ) cmd.AddArg( *options.Get( i ) ); // // Add the path to the file. for( int j = 0; j < files.Count(); j++ ) cmd.AddArg( *files.Get( j ) ); pCmd = &cmd; // // If p4web is running as an NT service and P4MERGE is // set, set the environment variable for this process only // in a place where "p4 resolve" will find it (LocalSystem's // user environment). This is necessary because the p4 api // doesn't know to look in the service registry area. #ifdef OS_NT if( fRequest.IsNTService() ) { Enviro enviro; StrBuf env; const char *p4m; enviro.BeServer( fRequest.GetSvcName() ); if( p4m = enviro.Get( "P4MERGE" ) ) { env << "P4MERGE=" << p4m; (void)_putenv( env.Text() ); } } #endif // If DISPLAY environment variable is set on a // non-NT OS, we need to launch this from an xterm // window. #ifndef OS_NT if( getenv( "DISPLAY" ) ) { StrBuf tf; tcmd << "xterm" << "-e" << cmd.Text(tf); pCmd = &tcmd; } else { return 0; } #endif // // Save off the command being run if &M=c const StrPtr *M = fRequest.GetStateArg( "M" ); if( M && strchr(M->Text(), 'c') ) { StrBuf buf; (*pCmd).Text(buf); char *p = buf.Text(); while ((p = strchr(p, '\"')) != NULL) strcpy(p, p+1); if ((p = strstr(buf.Text(), "-P ")) != NULL) { int i; p += sizeof("-P ")-1; for (i=0; *p > ' '; i++) { if (i < 5) *p++ = '*'; else strcpy(p, p+1); } } buf.SetLength(); *(fRequest.GetShowP4Cmds()) << buf << "<br>"; } // // Make a new process with the executable. #ifndef OS_NT int fds[2]; RunCommand().RunChild( *pCmd, RCO_AS_SHELL|RCO_USE_STDOUT, fds, &e ); #else RunCommand().RunInWindow( *pCmd, &e ); #endif if ( e.Test() ) { e.Fmt( &fErrorMsg ); char *p = fErrorMsg.Text(); while ((p = strchr(p, '\"')) != NULL) strcpy(p, p+1); if ((p = strstr(fErrorMsg.Text(), "-P ")) != NULL) { int i; p += sizeof("-P ")-1; for (i=0; *p > ' '; i++) { if (i < 5) *p++ = '*'; else strcpy(p, p+1); } } fErrorMsg.SetLength(); return 0; } return 1; }
# | 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/p4wResolveProcessorView.cpp | |||||
#1 | 8914 | Matt Attaway | Initial add of the P4Web source code |