// // Copyright 2003 Perforce Software. All rights reserved. // // This file is part of Perforce - the FAST SCM System. // // p4wView: // A view (single HTML page) in the p4w interface. #include <stdio.h> #include <string.h> #include <p4wp4.h> #include "p4wView.h" #include "p4wStrBuf.h" #include "p4wHtml.h" #include "p4wInfoPane.h" #include "p4wMenuPane.h" #include "changeshelper.h" #include "p4wP4CmdPane.h" #include "p4wGoPane.h" #include "p4wUpdatePane.h" #include "base64.h" extern int ignoreBrowserAuth; p4wView::p4wView( p4wRequest & Request ) : fRequest(Request), fIsFromFileBrowser(0), fIsErrorPage(0), fPreview(0), fP4CharsProtected(0) { } p4wView::~p4wView() { } // ------------------------------------- // Render this entire html page // void p4wView::Render() { // // Build up the page and render it p4wHtml htm; const char *charset = NULL; if( fRequest.GetUnicode() ) charset = "utf-8"; htm.httpHeader( 200 ); htm.serverId(); htm.contentType( "text/html", 0, charset ); const StrPtr *server = fRequest.GetProtocol( "server2" ); int protocol; if( server ) protocol = server->Atoi(); // point p to the port char *p = fRequest.GetHTTPPort().Text(); if (p) p = strchr(p, ':'); if (fRequest.GetCmd() != AC_HELP) { StrBuf userpswd; userpswd << fRequest.GetUser(); if (*(userpswd.Text()) != '@') { StrPtr pswd = fRequest.GetPassword(); if (protocol > 17) { ignoreBrowserAuth = 1; if (pswd.Length()) { userpswd << ":" << pswd; if (!fRequest.isLocalRequest()) fRequest.doHashPswd(userpswd.Text(), userpswd.Length()); } } // conver 'userpswd' to Base64 encoding StrBuf b64data; int ln64; int len; int lgth = userpswd.Length(); char *q = b64data.Alloc(len = ((lgth + 2)/ 3 * 4) + 8); memset(q, '\0', len); ln64 = b64_encode(userpswd.Text(), lgth, q, len); if (ln64) userpswd.Set(q); // write the cookie if (fRequest.isLocalRequest() || protocol > 17) htm.setCookie( p ? p+1 : "", fRequest.BypassAuth() ? "" : userpswd.Text(), fRequest.BypassAuth(), 1, !fRequest.isLocalRequest() ); else htm.setCookie( p ? p+1 : "", "", 1, 1, 1 ); } else htm.setCookie( p ? p+1 : "", "", 1, 1, 1 ); } else htm << "\r\n"; // end the header htm.beginHeader( charset ); StrBuf title; title << "P4Web - " << fFullTitle << " - " << fRequest.GetHTTPPort().Text(); htm.title( title.Text() ); if (fRequest.GetViewMode() == VM_WORKSPACE && !fRequest.isLocalRequest() && !SEC_ALLOW_CR8CHG_SYMLINKS) { StrBuf path; path << fRequest.GetPath(); char *p = path.Text(); p += strlen(p) - 1; if (*p == '/' || *p == '\\') { *p = '\0'; path.SetLength(); } FileSys *f = FileSys::Create( FST_BINARY ); f->Set( StrRef( path ) ); if ((f->Stat() & FSF_SYMLINK)) { delete f; htm << "A Symlink may not be viewed by a remote browser."; fRequest << htm; return; } delete f; } htm.styleSheet(&fRequest); htm.base( p4wStrBuf().NormalizeBase( fRequest.GetBase(), fRequest.GetUnicode() ).Text(), fRequest.IsHTTPS() ); RenderRssHdrLink(&htm); htm.endHeader( fRequest.GetHTTPPort().Text(), fRequest.IsHTTPS() ); char *jshandler = NULL; char *jsaction = NULL; const StrPtr *thx = fRequest.GetStateArg( "thx" ); if (!thx && (fRequest.GetLastReturnType() == AC_BROWSEFILE || fRequest.GetLastReturnType() == AC_PATHBROWSER)) { jshandler = "onClick"; jsaction = "hideMenu()"; } htm.beginBody( "#ffffff", NULL, NULL, "0", "0", "0", "0", jshandler, jsaction ); // // Write out the header & start of body fRequest << htm; // // Create and send the info pane (doesn't issue any requests). RenderInfo(); // // Generate the navigation & subnavigation menus RenderMenu(); // // Generate the raw p4 commands pane if we're configured to view this if( !fRequest.HideRawP4Cmds() && (!SEC_DISALLOW_RAW_CMDS || fRequest.isLocalRequest()) ) { p4wP4CmdPane p4cmdPane(*this, fRequest); p4cmdPane.DrawPane(); } // // Generate the goto pane if we're configured to view this if( !fRequest.HideGoTo() && p4wAllCommands::ShowRecentActivity( fRequest.GetCmd() ) == 1 ) { p4wGoPane goPane(*this, fRequest); goPane.DrawPane(); } // // Generate the recent activity pane if we're configured to view this if( !fRequest.HideRecentChanges() && p4wAllCommands::ShowRecentActivity( fRequest.GetCmd() ) == 1 ) (void) RenderUpdateOK(); // // Prepare to generate the content StartContent(); // // Render the content of the page RenderContent(); // // Spit out any lingering p4 errors RenderFinalErrors(); // // Render the copyright message RenderCopyright(); // // End the page htm.Clear(); htm.endTable(); switch (fRequest.GetCmd()) { case AC_PATHBROWSER: case AC_FILESMATCHING: { int i = 9; while (i--) htm.linebreak(); break; } } htm.endBody(); fRequest << htm; } void p4wView::RenderMenu() { // // Draw the menu bar p4wMenuPane menuPane( *this, fRequest, "pathbrowser" ); menuPane.Render( NULL ); } void p4wView::RenderInfo() { // // Generate the info pane with the logo bar p4wInfoPane infoPane( *this, fRequest ); infoPane.Render( NULL ); } void p4wView::RenderCopyright() { // // Generate the copyright message // p4wHtml htm; p4wURL urlMaker; StrBuf clearIcon; StrBuf grayIcon; urlMaker.ConstructURL( clearIcon, "/clearpixelIcon", AC_ICON, NULL ); urlMaker.ConstructURL( grayIcon, "/grayPixelIcon", AC_ICON, NULL ); htm.endTable(); htm.endCol(); htm.beginCol( NULL, NULL, NULL, NULL, NULL, "9" ); htm.icon( clearIcon.Text(), "1", "9", "", 1 ); htm.endCol(); htm.endTRow(); htm.endTable(); htm.endCol(); htm.endTRow(); htm.endTable(); htm.endTable(); htm.endTable(); if (!(fRequest.GetScreenChunks() & SCRN_COPYRIGHT)) { fRequest << htm; return; } const StrPtr *M = fRequest.GetStateArg("M"); if (M && strchr(M->Text(), 'c') && fRequest.GetScreenChunks() == -1) { htm.beginTable(0, "100%", "2", "0"); htm.beginTRow(); htm.beginCol(0,0,"100%"); htm.icon( clearIcon.Text(), fRequest.GetCmd() == AC_BROWSEFILE ? "1" : "10", "1", "", 1 ); htm.endCol(); htm.endTRow(); htm.beginTRow(); htm.beginCol(); htm.icon( clearIcon.Text(), "1", "20", "", 1 ); htm.endCol(); htm.beginCol(0,0,0,0,0,"100%"); htm.beginTable(0, "100%", "1", "0", "#d9dad9"); htm.beginTRow(); htm.beginCol(0,0,0,0,0,"100%"); htm.beginTable(0, "100%", "7", "0", "#fbfbfb"); htm.beginTRow(); const StrPtr *X = fRequest.GetStateArg("X"); int allowshowhide = (X && strchr(X->Text(), 'h')) ? 0 : 1; // 0->always show; 1->allow show hide if (allowshowhide) { htm.beginCol(0,0,0,0,0,"100%"); fRequest << htm; htm.Clear(); fRequest.doShowHideBlock(SH_P4CMDS, "command block", "P4 Command Log", 0, 9); htm << "<script language=javascript>" << crlf; htm << "document.write(\"<div id='showhideBlock9'>\")" << crlf; htm << "</script>" << crlf; htm.beginTable(0, "100%", "7", "0"); htm.beginTRow(); htm.beginCol(); htm.endCol(); } htm.beginCol(0,0,0,0,0,"100%",0,1); htm << fRequest.fShowP4Cmds; htm.icon( clearIcon.Text(), "1", "100%", "", 1 ); if (allowshowhide) { htm.endCol(); htm.endTRow(); htm.endTable(); htm << "<script language=javascript>" << crlf; htm << "document.write(\"</div>\")" << crlf; htm << "</script>" << crlf; } htm.endCol(); htm.endTRow(); htm.endTable(); htm.endCol(); htm.endTRow(); htm.endTable(); htm.endCol(); htm.beginCol(); htm.icon( clearIcon.Text(), "1", "20", "", 1 ); htm.endCol(); htm.endTRow(); htm.endTable(); } htm.beginTable(0, "100%", "2", "0"); htm.beginTRow(); htm.beginCol(); htm.icon( clearIcon.Text(), "10", "1", "", 1 ); htm.endCol(); htm.endTRow(); // // Generate custom footer if there is one const StrPtr *ptr = fRequest.GetCustFooter(); if (ptr && ptr->Length()) { fRequest << htm; fRequest.WriteCustHTML(ptr->Text(), 1); htm.Clear(); } htm.beginTRow(); htm.beginCol( NULL, NULL, NULL, NULL, NULL, "5" ); htm.icon( clearIcon.Text(), "1", "5", "", 1 ); htm.endCol(); htm.beginCol(0,0, "100%"); htm.icon( grayIcon.Text(), "1", "100%", "", 1, "0", "0" ); htm.endCol(); htm.beginCol( NULL, NULL, NULL, NULL, NULL, "5" ); htm.icon( clearIcon.Text(), "1", "5", "", 1 ); htm.endCol(); htm.endTRow(); htm.endTable(); htm.beginTable(0, "100%", "2", "0"); htm.beginTRow(); htm.beginCol( NULL, NULL, NULL, NULL, NULL, "5" ); htm.icon( clearIcon.Text(), "1", "5", "", 1 ); htm.endCol(); htm.beginCol(0, 0, 0, 0,0,0,0,1); htm.beginSpan( "copyright" ); htm << "Copyright 2008 Perforce Software. All rights reserved."; htm.endSpan(); htm.endCol(); AllCommands ac = fRequest.GetCmd(); if (p4wAllCommands::CanBrowse(ac) || fPermalink.Length() || ac == AC_DIFFWVC || ac == AC_DIFFCVH || ac == AC_DIFFWVH || ac == AC_DIFF21 || ac == AC_DIFFRVW || ac == AC_DIFF22 || ac == AC_FILETEXTLOCAL || ac == AC_EDITTEXTLOCAL || ac == AC_PENDINGCHANGELISTS || ac == AC_CHANGEPENDINGEDIT || ac == AC_EDITCHANGE || ac == AC_EDITCLIENT || ac == AC_EDITUSER) { fRequest << htm; htm.Clear(); GeneratePermalink(ac); } htm.endTRow(); fRequest << htm; } void p4wView::StartContent() { // // Start the tables which will show the content // p4wHtml htm; p4wURL urlMaker; StrBuf clearIcon; urlMaker.ConstructURL( clearIcon, "/clearpixelIcon", AC_ICON, NULL ); htm.endTable(); htm.endCol(); htm.endTRow(); htm.beginTRow(); htm.beginCol(); htm.beginTable( "0", "100%", "0", "0" ); htm.beginTRow(); htm.beginCol( NULL, NULL, NULL, NULL, NULL, "10" ); htm.icon( clearIcon.Text(), "1", "10", "", 1 ); htm.endCol(); htm.beginCol( 0, 0, 0, 0, 0, "100%" ); htm.beginTable( "0", "100%", "0", "0" ); htm.beginTRow(); htm.beginCol(); htm.icon( clearIcon.Text(), "5", "0", "", 1 ); htm.endCol(); htm.endTRow(); fRequest << htm; } void p4wView::RenderError( char *data ) { // // Generate the error message while escaping any special // html characters. p4wHtml htm; htm.text( p4wStrBuf().EscapeHTML( StrRef(data), fRequest.GetUnicode() ).Text(), NULL, NULL, "red" ); fRequest << htm; } void p4wView::RenderErrorLinks( char *data ) { // // Generate the error message without escaping any special // html characters. This allows error messages to be displayed // using html & links. p4wHtml htm; htm.text( data, NULL, NULL, "red" ); fRequest << htm; } int p4wView::HasDirPattern( const char *path ) { // // Returns 1 only if path contains // pattern matching characters resulting in a directory path if( strchr( path, '*' ) ) return 1; else if( strstr( path, "..." ) ) return 1; return 0; } void p4wView::RenderFinalErrors() { // // Assuming we've issued p4 Init, // issue p4 Final and spit out any last errors Error e; StrBuf errorMsg; fRequest.p4Final( &e ); if( e.Test() ) { e.Fmt( &errorMsg ); RenderError( errorMsg.Text() ); } } void p4wView::RenderTitle( int shortenTitle ) { // // Render either the short or long version of the title if( shortenTitle ) fRequest << fShortTitle; else fRequest << fFullTitle; } int p4wView::RenderUpdateOK() { // // Default is to draw an update pane. StrBuf path; AllCommands ac = fRequest.GetLastReturnType(); path.Set( fRequest.GetReturnURL( ac ).Text() ); int isFileBrowser = ac != AC_PATHBROWSER; if ( !fIsFromFileBrowser ) { path << "..."; } p4wUpdatePane updatePane(*this, fRequest, path); updatePane.DrawPane(); return 1; } void p4wView::GeneratePermalink(AllCommands ac) { if (ac == AC_SHOWHIDECOLUMNS) return; char *p; p4wHtml htm; htm.beginCol("top", "right", 0,0,0,0,0,0, "permalink"); if (!fPermalink.Length()) { fPermalink.Set( fRequest.IsHTTPS() ? "https://" : "http://" ); if (!strncmp(fRequest.GetHTTPPort().Text(), "localhost", sizeof("localhost")-1)) { // convert localhost to real host StrBuf temp; temp << fRequest.GetHTTPPort(); char *col = strchr(temp.Text(), ':'); if (col) fPermalink << fRequest.GetHost() << col; else fPermalink << temp; fPermalink << fRequest.GetFullURL(); } else fPermalink << fRequest.GetHTTPPort() << fRequest.GetFullURL(); if ((p = strchr(fPermalink.Text(), '@')) != NULL) { char *q = strchr(p+1, '@'); if (q) { int b = (strstr(p, "&cl=") || strstr(p, "&pat=")) ? 1 : 0; if (!b) b = CantSimplifyPermalink(ac, p, q); if (!b) { strcpy(p, q+1); while (*p == '/') strcpy(p, p+1); fPermalink.SetLength(); } else { RemoveStateArg("c", p, q); RemoveStateArg("cd", p, q); RemoveStateArg("cdf", p, q); } } } } if ((p = strstr(fPermalink.Text(), "&mu=")) != NULL) { strcpy(p, p+4); while (*p && *p != '&' && *p != '@') strcpy(p, p+1); fPermalink.SetLength(); } htm.beginLink(fPermalink.Text()); htm << "Permalink"; htm.endLink(); htm.endCol(); p4wURL urlMaker; StrBuf clearIcon; urlMaker.ConstructURL( clearIcon, "/clearpixelIcon", AC_ICON, NULL ); htm.beginCol( NULL, NULL, NULL, NULL, NULL, "5" ); htm.icon( clearIcon.Text(), "1", "5", "", 1 ); htm.endCol(); fRequest << htm; } // // Check to see if the Base of the URL can be simplified. // Base looks something like /@md=c&rt=s&dw=c&thv=d&jf=y@/ // ac is current command // p points to initial @ // q points to training @ // Return 1 if it CANNOT be simplified. int p4wView::CantSimplifyPermalink(AllCommands ac, char *p, char *q) { if (fRequest.GetLastReturnType() == AC_BROWSEFILE && !strncmp(p, "@md=w", sizeof("@md=w")-1)) return 1; if (strstr(p, "&thx=") || strstr(p, "&pc=")) return 1; switch(ac) { case AC_PATHBROWSER: if (!strncmp(p, "@md=w", sizeof("@md=w")-1)) return 1; case AC_BROWSEFILE: if( fRequest.GetBITBRev().Length() > 0 ) return 1; if (fRequest.GetBrowseMode()) { if (!strncmp(p, "@md=c", sizeof("@md=c")-1)) return 1; } else { if (!strncmp(p, "@md=d", sizeof("@md=d")-1) || strstr(p, "&po=")) return 1; } return (strstr(p, "&rt=s") || strstr(p, "&pb=") || strstr(p, "&df=") || strstr(p, "&cf=")) ? 1 : 0; case AC_FILETEXTDEPOT: case AC_FILETEXTLOCAL: if (!strstr(p, "lno=y")) return 0; strcpy(p+1, "lno=y"); if (!*q) *q = '@'; else strcat(p+1, q); fPermalink.SetLength(); return 1; case AC_JOBVIEW: if (!strstr(p, "jf=y")) return 0; strcpy(p+1, "jf=y"); if (!*q) *q = '@'; else strcat(p+1, q); fPermalink.SetLength(); return 1; case AC_LABELSPATH: p = strstr(q, "&lfl=2"); if (p) { strcpy(p, p + sizeof("&lfl=2")-1); fPermalink.SetLength(); } return 0; case AC_BRANCHDIFF: if (!strstr(p, "dw=")) // only dw applies to branch diffs return 0; case AC_DIFF2: case AC_DIFF21: case AC_DIFF22: case AC_DIFFWVC: case AC_DIFFCVH: case AC_DIFFWVH: case AC_DIFFRVW: case AC_DIFF2FILES: case AC_DIFF2DIRS: { if (!strstr(p, "dw=") && !strstr(p, "dc=") && !strstr(p, "dl=")) return 0; char *d = strstr(p, "@d"); if (!d) { d = strstr(p, "&d"); if (!d) return 0; strcpy(p+1, d+1); } p = strchr(p+3, '&'); if (!p || p > q) { fPermalink.SetLength(); return 1; } while (d = strstr(p, "&d")) { strcpy(p, d); p = strchr(p+3, '&'); if (!p || p > q) { fPermalink.SetLength(); return 1; } } strcpy(p, q); fPermalink.SetLength(); return 1; } } return 0; } void p4wView::RemoveStateArg(char *arg, char *p, char *q) { char str[16] = "&"; strcpy(&str[1], arg); strcat(&str[1], "="); char *a = strstr(p, str); if (a && a < q) { p = strchr(a+3, '&'); if (!p || p > q) p = q; strcpy(a, p); fPermalink.SetLength(); } }
# | 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/p4wView.cpp | |||||
#2 | 10416 | Lester Cheung | Using HTTPS for favicon when option -ss (HTTPS mode) is used. | ||
#1 | 8914 | Matt Attaway | Initial add of the P4Web source code |