// // Copyright 2003 Perforce Software. All rights reserved. // // This file is part of Perforce - the FAST SCM System. // // p4wRSSView: // A view (single HTML page) in the p4w interface. #include <stdio.h> #include <string.h> #include <p4wp4.h> #include "p4wRSSView.h" #include "p4wRSSPane.h" #include "p4wStrBuf.h" #include "p4wPasswdTestPane.h" p4wRSSView::p4wRSSView( p4wRequest & Request ) : p4wView(Request) { } p4wRSSView::~p4wRSSView() { } // ------------------------------------- // Render this entire html page // void p4wRSSView::Render() { // // Issue changes command to get the subset of submitted changes // and options as chosen from options passed in the URL. StrBuf pathArg; int newServer = 0; const StrPtr *rev1 = fRequest.GetDynArg( "rev1" ); const StrPtr *rev2 = fRequest.GetDynArg( "rev2" ); const StrPtr *sr1 = fRequest.GetDynArg( "sr" ); const StrPtr *sr2 = fRequest.GetDynArg( "sr2" ); const StrPtr *pat = fRequest.GetStateArg( "pat" ); const StrPtr *is = fRequest.GetStateArg( "is" ); const StrPtr *mx = fRequest.GetDynArg( "mx" ); const StrPtr *fl = fRequest.GetDynArg( "fl" ); const StrPtr *u = fRequest.GetDynArg( "u" ); const StrPtr *cl = fRequest.GetDynArg( "cl" ); const StrPtr *srevState = fRequest.GetStateArg( "sr" ); const StrPtr *all = fRequest.GetDynArg( "al" ); int maxResults = 0; // // -c & -u arguments are only supported for servers // with protocol version 12 or above. Issue dummy // cmd to get the server protocol version. if( u || cl ) { const StrPtr *server = fRequest.GetProtocol( "server2" ); if (!server) { p4wPasswdTestPane dummyCmd( *this, fRequest ); fRequest.p4( "info", 0, 0, &dummyCmd ); fRequest.p4Wait(); server = fRequest.GetProtocol( "server2" ); } if( server && server->Atoi() > 11 ) ++newServer; } ChangesHelper * ch; StrBuf mxBuf; if(!mx || mx->Atoi() < 0) { mxBuf.Set("125"); mx = &mxBuf; } if( mx ) { maxResults = mx->Atoi(); } // // Generate the path argument unless "all" submitted // changelists have been requested if( !all ) pathArg.Set( fRequest.GetPath() ); else pathArg.Set( "//" ); if( !fIsFromFileBrowser || all ) { if( pat ) { if( is && strncmp( pat->Text(), "...", 3 ) ) pathArg << ".../"; if ((strncmp( pat->Text(), "//", 2 ) == 0) && (strcmp( pathArg.Text(), "//" ) == 0)) pathArg.Clear(); pathArg << pat; } else { pathArg << "..."; } } StrBuf feedPath(pathArg); // // If both state and dynamic sr parameters are // set, dynamic gets preference. if( !sr1 && srevState ) sr1 = srevState; if( rev1 ) { pathArg << "#" << rev1; if( rev2) pathArg << "," << rev2; } else if( sr1 ) { pathArg << "@" << sr1; if( sr2 ) pathArg << "," << sr2; } // // Generate fee title StrBuf feedTitle(pathArg); feedTitle << " - ("; if ( mx ) feedTitle << "Last " << mx->Text(); else feedTitle << "All"; feedTitle << " Changes"; if( u && cl && newServer ) { feedTitle << " for " << u->Text() << "@" << cl->Text(); } if( cl && !u && newServer ) { feedTitle << " using client '" << cl->Text() << "'"; } if( u && !cl && newServer ) { feedTitle << " for " << u->Text(); } feedTitle << ")"; // Run the command. if ( newServer ) ch = new ChangesHelper( fRequest.GetClientApi(), pathArg, maxResults, u, cl ); else ch = new ChangesHelper( fRequest.GetClientApi(), pathArg, maxResults ); RenderWithChgsHelper(ch, pat, mx, fl, newServer, feedTitle); delete ch; } void p4wRSSView::RenderWithChgsHelper(ChangesHelper * ch, const StrPtr *pat, const StrPtr *mx, const StrPtr *fl, int newServer, StrBuf feedTitle) { p4wHtml htm; const char *charset = NULL; if( fRequest.GetUnicode() ) charset = "utf-8"; htm.httpHeader( 200 ); htm.serverId(); htm.contentType( "application/rss+xml", 1, charset ); fRequest << htm; StrBuf feedDesc; feedDesc << "Perforce Submitted Changelists"; fRequest << "<?xml version=\"1.0\" encoding=\""; fRequest << (fRequest.GetUnicode() ? "UTF-8" : "ISO-8859-1") << "\"?>\n"; fRequest << "<rss version=\"2.0\">\n"; fRequest << " <channel>\n"; fRequest << " <title>" << feedTitle << "</title>\n"; StrBuf changeURL; p4wURL urlMaker; p4wStrBuf changeURLFormatted; if ( pat ) { StrBuf newBase; fRequest.UseNewBaseDoCache( newBase, NULL, "cd", "//" ); fRequest.UseNewBaseDoCache( newBase, newBase.Text(), "md", "c" ); fRequest.UseNewBaseDoCache( newBase, newBase.Text(), "pat", pat->Text() ); urlMaker.ConstructURL( changeURL, newBase.Text(), AC_SUBMITTEDCHANGELISTS, fRequest.GetDynArgs() ); if (fRequest.IsHTTPS()) changeURLFormatted << "https://"; else changeURLFormatted << "http://"; changeURLFormatted << fRequest.GetHTTPPort().Text(); } else { urlMaker.ConstructURL( changeURL, fRequest.GetBase().Text(), AC_SUBMITTEDCHANGELISTS, fRequest.GetDynArgs() ); } if (mx && mx->Length() && !fRequest.GetDynArg( "mx" )) changeURL << "&mx=" << mx->Text(); changeURLFormatted.EscapeHTML(changeURL); fRequest << " <link>" << changeURLFormatted.Text() << "</link>\n"; fRequest << " <description>" << feedDesc << "</description>\n"; fRequest << " <generator>" << "P4Web" "/" ID_OS "/" ID_REL "/" ID_PATCH " (" ID_Y "/" ID_M "/" ID_D ")" << "</generator>\n"; // // Prepare to sort the changelists if there are multiple paths int i; int totResults; int *sort = new int [ (totResults = ch->TotalResults()) + 1 ]; for ( i = 0; i < totResults; i++ ) sort[i] = i; const StrPtr fullURL = fRequest.GetFullURL(); const char * fullURLtxt = fullURL.Text(); if( strstr( fullURLtxt, "%20%7C%20" ) ) // are there multiple paths? { int eq = 0; int b = 1; while (b) // until sorted, do bubble sort { int e = 1; for ( i=totResults, b=0; --i >= e; ) { StrDict * varList1 = ch->GetResult( sort[i-1] ); StrDict * varList2 = ch->GetResult( sort[i] ); StrPtr *time1 = varList1->GetVar("time"); StrPtr *time2 = varList2->GetVar("time"); unsigned int t1 = atoi(time1->Text()); unsigned int t2 = atoi(time2->Text()); if (t1 < t2) { int k = sort[i-1]; sort[i-1] = sort[i]; sort[i] = k; b = e = i; } else if (t1 == t2) eq = 1; // remeber that there are duplicate chg#s } } // end of bubble sort if (eq) // were there duplicates? { for (i = 0; ++i < totResults; ) { int j; for (j=1; sort[i-j] == -1; j++) ; StrDict * varList1 = ch->GetResult( sort[i-j] ); StrDict * varList2 = ch->GetResult( sort[i] ); StrPtr *time1 = varList1->GetVar("change"); StrPtr *time2 = varList2->GetVar("change"); unsigned int t1 = atoi(time1->Text()); unsigned int t2 = atoi(time2->Text()); if (t1 == t2) sort[i] = -1; // -1 ==> ignore } } } // // Now process each changelist for ( i = 0; i < totResults; i++ ) { if (sort[i] == -1) continue; // ignore; it's a duplicate StrDict * varList = ch->GetResult( sort[i] ); const char * user = varList->GetVar("user")->Text(); const char * client = varList->GetVar("client")->Text(); StrPtr *changeNo = varList->GetVar("change"); StrPtr *chgtime = varList->GetVar("time"); if (!i) // first time thru? { char time_buffer[255 + 1]; // Do our own strftime time_buffer[0] = '\0'; DateTime t; Error e; t.Set( chgtime->Text(), &e ); time_t iTime = (time_t) t.Value(); StrBuf time_format; time_format.Append( "%a, %d %b %Y %H:%M:%S" ); strftime( time_buffer, sizeof( time_buffer ), time_format.Text(), gmtime( &iTime ) ); fRequest << " <lastBuildDate>" << time_buffer << " GMT</lastBuildDate>\n"; } fRequest << " <item>\n"; p4wStrBuf title; title.Expand(StrRef("%desc%"), *varList).Text(); char *p = title.End(); int lgth = title.Length(); while (*--p <= ' ' && p > title.Text()) lgth--; title.SetLength(lgth); fRequest << " <title>Change - " << changeNo << ": " << title << "</title>\n"; char time_buffer[255 + 1]; // Do our own strftime time_buffer[0] = '\0'; DateTime t; Error e; t.Set( chgtime->Text(), &e ); time_t iTime = (time_t) t.Value(); StrBuf time_format; time_format.Append( "%a, %d %b %Y %H:%M:%S" ); strftime( time_buffer, sizeof( time_buffer ), time_format.Text(), gmtime( &iTime ) ); fRequest << " <pubDate>" << time_buffer << " GMT</pubDate>\n"; StrBuf changeURL; StrBuf newBase; fRequest.ReplaceBase( "pgc", "y" ); fRequest.ReplaceBase( "pat", NULL ); fRequest.UseNewBase( newBase, NULL, "path", NULL ); newBase << changeNo; urlMaker.ConstructURL( changeURL, newBase.Text(), AC_DESCRIBE, NULL ); p4wStrBuf changeURLFormatted; if (fRequest.IsHTTPS()) changeURLFormatted << "https://"; else changeURLFormatted << "http://"; changeURLFormatted << fRequest.GetHTTPPort().Text(); changeURLFormatted.EscapeHTML(changeURL); fRequest << " <link>" << changeURLFormatted.Text() << "</link>\n"; char * p4webrssauthor = getenv( "P4WEBRSSAUTHOR" ); if ( p4webrssauthor ) fRequest << " <author>" << p4webrssauthor << "</author>\n"; else fRequest << " <author>" << user << "@" << client << ".eml</author>\n"; fRequest << " <description>"; // // Check for flags if( fl ) fRequest.p4Arg( fl->Text() ); fRequest.p4Arg( "-s" ); fRequest.p4Arg( changeNo->Text() ); p4wRSSChangeDetailPane cmdPane( *this, fRequest ); fRequest.p4( "describe", 0, 0, &cmdPane ); fRequest.p4Wait(); fRequest << " </description>\n"; fRequest << " </item>\n"; } delete sort; fRequest << " </channel>\n"; fRequest << "</rss>\n"; }
# | 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/p4wRSSView.cpp | |||||
#1 | 8914 | Matt Attaway | Initial add of the P4Web source code |