TZIVI-254: IVI needs a newer version of cmake
[profile/ivi/cmake.git] / Source / CTest / cmCTestSubmitHandler.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc.
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmCTestSubmitHandler.h"
13
14 #include "cmSystemTools.h"
15 #include "cmVersion.h"
16 #include "cmGeneratedFileStream.h"
17 #include "cmCTest.h"
18 #include "cmXMLParser.h"
19
20 #include <cmsys/Process.h>
21 #include <cmsys/Base64.h>
22
23 // For XML-RPC submission
24 #include "cm_xmlrpc.h"
25
26 // For curl submission
27 #include "cm_curl.h"
28
29 #include <sys/stat.h>
30
31 #define SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT 120
32
33 typedef std::vector<char> cmCTestSubmitHandlerVectorOfChar;
34
35 //----------------------------------------------------------------------------
36 class cmCTestSubmitHandler::ResponseParser: public cmXMLParser
37 {
38 public:
39   ResponseParser() { this->Status = STATUS_OK; }
40   ~ResponseParser() {}
41
42 public:
43
44   enum StatusType
45     {
46     STATUS_OK,
47     STATUS_WARNING,
48     STATUS_ERROR
49     };
50
51   StatusType Status;
52   std::string CDashVersion;
53   std::string Filename;
54   std::string MD5;
55   std::string Message;
56
57 private:
58
59   std::vector<char> CurrentValue;
60
61   std::string GetCurrentValue()
62     {
63     std::string val;
64     if(this->CurrentValue.size())
65       {
66       val.assign(&this->CurrentValue[0], this->CurrentValue.size());
67       }
68     return val;
69     }
70
71   virtual void StartElement(const char* name, const char** atts)
72     {
73     this->CurrentValue.clear();
74     if(strcmp(name, "cdash") == 0)
75       {
76       this->CDashVersion = this->FindAttribute(atts, "version");
77       }
78     }
79
80   virtual void CharacterDataHandler(const char* data, int length)
81     {
82     this->CurrentValue.insert(this->CurrentValue.end(), data, data+length);
83     }
84
85   virtual void EndElement(const char* name)
86     {
87     if(strcmp(name, "status") == 0)
88       {
89       std::string status = cmSystemTools::UpperCase(this->GetCurrentValue());
90       if(status == "OK" || status == "SUCCESS")
91         {
92         this->Status = STATUS_OK;
93         }
94       else if(status == "WARNING")
95         {
96         this->Status = STATUS_WARNING;
97         }
98       else
99         {
100         this->Status = STATUS_ERROR;
101         }
102       }
103     else if(strcmp(name, "filename") == 0)
104       {
105       this->Filename = this->GetCurrentValue();
106       }
107     else if(strcmp(name, "md5") == 0)
108       {
109       this->MD5 = this->GetCurrentValue();
110       }
111     else if(strcmp(name, "message") == 0)
112       {
113       this->Message = this->GetCurrentValue();
114       }
115     }
116 };
117
118
119 static size_t
120 cmCTestSubmitHandlerWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
121   void *data)
122 {
123   register int realsize = (int)(size * nmemb);
124
125   cmCTestSubmitHandlerVectorOfChar *vec
126     = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
127   const char* chPtr = static_cast<char*>(ptr);
128   vec->insert(vec->end(), chPtr, chPtr + realsize);
129
130   return realsize;
131 }
132
133 static size_t
134 cmCTestSubmitHandlerCurlDebugCallback(CURL *, curl_infotype, char *chPtr,
135   size_t size, void *data)
136 {
137   cmCTestSubmitHandlerVectorOfChar *vec
138     = static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
139   vec->insert(vec->end(), chPtr, chPtr + size);
140
141   return size;
142 }
143
144 //----------------------------------------------------------------------------
145 cmCTestSubmitHandler::cmCTestSubmitHandler() : HTTPProxy(), FTPProxy()
146 {
147   this->Initialize();
148 }
149
150 //----------------------------------------------------------------------------
151 void cmCTestSubmitHandler::Initialize()
152 {
153   // We submit all available parts by default.
154   for(cmCTest::Part p = cmCTest::PartStart;
155       p != cmCTest::PartCount; p = cmCTest::Part(p+1))
156     {
157     this->SubmitPart[p] = true;
158     }
159   this->CDash = false;
160   this->HasWarnings = false;
161   this->HasErrors = false;
162   this->Superclass::Initialize();
163   this->HTTPProxy = "";
164   this->HTTPProxyType = 0;
165   this->HTTPProxyAuth = "";
166   this->FTPProxy = "";
167   this->FTPProxyType = 0;
168   this->LogFile = 0;
169   this->Files.clear();
170 }
171
172 //----------------------------------------------------------------------------
173 bool cmCTestSubmitHandler::SubmitUsingFTP(const cmStdString& localprefix,
174   const std::set<cmStdString>& files,
175   const cmStdString& remoteprefix,
176   const cmStdString& url)
177 {
178   CURL *curl;
179   CURLcode res;
180   FILE* ftpfile;
181   char error_buffer[1024];
182
183   /* In windows, this will init the winsock stuff */
184   ::curl_global_init(CURL_GLOBAL_ALL);
185
186   cmCTest::SetOfStrings::const_iterator file;
187   for ( file = files.begin(); file != files.end(); ++file )
188     {
189     /* get a curl handle */
190     curl = curl_easy_init();
191     if(curl)
192       {
193       // Using proxy
194       if ( this->FTPProxyType > 0 )
195         {
196         curl_easy_setopt(curl, CURLOPT_PROXY, this->FTPProxy.c_str());
197         switch (this->FTPProxyType)
198           {
199         case 2:
200           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
201           break;
202         case 3:
203           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
204           break;
205         default:
206           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
207           }
208         }
209
210       // enable uploading
211       ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
212
213       // if there is little to no activity for too long stop submitting
214       ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
215       ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
216         SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
217
218       ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
219
220       cmStdString local_file = *file;
221       if ( !cmSystemTools::FileExists(local_file.c_str()) )
222         {
223         local_file = localprefix + "/" + *file;
224         }
225       cmStdString upload_as
226         = url + "/" + remoteprefix + cmSystemTools::GetFilenameName(*file);
227
228       struct stat st;
229       if ( ::stat(local_file.c_str(), &st) )
230         {
231         cmCTestLog(this->CTest, ERROR_MESSAGE, "   Cannot find file: "
232           << local_file.c_str() << std::endl);
233         ::curl_easy_cleanup(curl);
234         ::curl_global_cleanup();
235         return false;
236         }
237
238       ftpfile = ::fopen(local_file.c_str(), "rb");
239       *this->LogFile << "\tUpload file: " << local_file.c_str() << " to "
240           << upload_as.c_str() << std::endl;
241       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "   Upload file: "
242         << local_file.c_str() << " to "
243         << upload_as.c_str() << std::endl);
244
245       ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
246
247       // specify target
248       ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
249
250       // now specify which file to upload
251       ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
252
253       // and give the size of the upload (optional)
254       ::curl_easy_setopt(curl, CURLOPT_INFILESIZE,
255         static_cast<long>(st.st_size));
256
257       // and give curl the buffer for errors
258       ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
259
260       // specify handler for output
261       ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
262         cmCTestSubmitHandlerWriteMemoryCallback);
263       ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
264         cmCTestSubmitHandlerCurlDebugCallback);
265
266       /* we pass our 'chunk' struct to the callback function */
267       cmCTestSubmitHandlerVectorOfChar chunk;
268       cmCTestSubmitHandlerVectorOfChar chunkDebug;
269       ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
270       ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
271
272       // Now run off and do what you've been told!
273       res = ::curl_easy_perform(curl);
274
275       if ( chunk.size() > 0 )
276         {
277         cmCTestLog(this->CTest, DEBUG, "CURL output: ["
278           << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
279           << std::endl);
280         }
281       if ( chunkDebug.size() > 0 )
282         {
283         cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
284           << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
285           << std::endl);
286         }
287
288       fclose(ftpfile);
289       if ( res )
290         {
291         cmCTestLog(this->CTest, ERROR_MESSAGE,
292           "   Error when uploading file: "
293           << local_file.c_str() << std::endl);
294         cmCTestLog(this->CTest, ERROR_MESSAGE, "   Error message was: "
295           << error_buffer << std::endl);
296         *this->LogFile << "   Error when uploading file: "
297                        << local_file.c_str()
298                        << std::endl
299                        << "   Error message was: "
300                        << error_buffer << std::endl
301                        << "   Curl output was: ";
302         // avoid dereference of empty vector
303         if(chunk.size())
304           {
305           *this->LogFile << cmCTestLogWrite(&*chunk.begin(), chunk.size());
306           cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
307                      << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
308                      << std::endl);
309           }
310         *this->LogFile << std::endl;
311         ::curl_easy_cleanup(curl);
312         ::curl_global_cleanup();
313         return false;
314         }
315       // always cleanup
316       ::curl_easy_cleanup(curl);
317       cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Uploaded: " + local_file
318         << std::endl);
319       }
320     }
321   ::curl_global_cleanup();
322   return true;
323 }
324
325 //----------------------------------------------------------------------------
326 // Uploading files is simpler
327 bool cmCTestSubmitHandler::SubmitUsingHTTP(const cmStdString& localprefix,
328   const std::set<cmStdString>& files,
329   const cmStdString& remoteprefix,
330   const cmStdString& url)
331 {
332   CURL *curl;
333   CURLcode res;
334   FILE* ftpfile;
335   char error_buffer[1024];
336
337   /* In windows, this will init the winsock stuff */
338   ::curl_global_init(CURL_GLOBAL_ALL);
339   cmStdString dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
340   cmStdString curlopt(this->CTest->GetCTestConfiguration("CurlOptions"));
341   std::vector<std::string> args;
342   cmSystemTools::ExpandListArgument(curlopt.c_str(), args);
343   bool verifyPeerOff = false;
344   bool verifyHostOff = false;
345   for( std::vector<std::string>::iterator i = args.begin();
346        i != args.end(); ++i)
347     {
348     if(*i == "CURLOPT_SSL_VERIFYPEER_OFF")
349       {
350       verifyPeerOff = true;
351       }
352     if(*i == "CURLOPT_SSL_VERIFYHOST_OFF")
353       {
354       verifyHostOff = true;
355       }
356     }
357   cmStdString::size_type kk;
358   cmCTest::SetOfStrings::const_iterator file;
359   for ( file = files.begin(); file != files.end(); ++file )
360     {
361     /* get a curl handle */
362     curl = curl_easy_init();
363     if(curl)
364       {
365       if(verifyPeerOff)
366         {
367         cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
368                    "  Set CURLOPT_SSL_VERIFYPEER to off\n");
369         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
370         }
371       if(verifyHostOff)
372         {
373         cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
374                    "  Set CURLOPT_SSL_VERIFYHOST to off\n");
375         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
376         }
377
378       // Using proxy
379       if ( this->HTTPProxyType > 0 )
380         {
381         curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
382         switch (this->HTTPProxyType)
383           {
384         case 2:
385           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
386           break;
387         case 3:
388           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
389           break;
390         default:
391           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
392           if (this->HTTPProxyAuth.size() > 0)
393             {
394             curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
395               this->HTTPProxyAuth.c_str());
396             }
397           }
398         }
399       if(this->CTest->ShouldUseHTTP10())
400         {
401         curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
402         }
403       // enable HTTP ERROR parsing
404       curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
405       /* enable uploading */
406       curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
407
408       // if there is little to no activity for too long stop submitting
409       ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1);
410       ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME,
411         SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
412
413       /* HTTP PUT please */
414       ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
415       ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
416
417       cmStdString local_file = *file;
418       if ( !cmSystemTools::FileExists(local_file.c_str()) )
419         {
420         local_file = localprefix + "/" + *file;
421         }
422       cmStdString remote_file
423         = remoteprefix + cmSystemTools::GetFilenameName(*file);
424
425       *this->LogFile << "\tUpload file: " << local_file.c_str() << " to "
426           << remote_file.c_str() << std::endl;
427
428       cmStdString ofile = "";
429       for ( kk = 0; kk < remote_file.size(); kk ++ )
430         {
431         char c = remote_file[kk];
432         char hexCh[4] = { 0, 0, 0, 0 };
433         hexCh[0] = c;
434         switch ( c )
435           {
436         case '+':
437         case '?':
438         case '/':
439         case '\\':
440         case '&':
441         case ' ':
442         case '=':
443         case '%':
444           sprintf(hexCh, "%%%02X", (int)c);
445           ofile.append(hexCh);
446           break;
447         default:
448           ofile.append(hexCh);
449           }
450         }
451       cmStdString upload_as
452         = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
453         + "FileName=" + ofile;
454
455       upload_as += "&MD5=";
456
457       if(cmSystemTools::IsOn(this->GetOption("InternalTest")))
458         {
459         upload_as += "bad_md5sum";
460         }
461       else
462         {
463         char md5[33];
464         cmSystemTools::ComputeFileMD5(local_file.c_str(), md5);
465         md5[32] = 0;
466         upload_as += md5;
467         }
468
469       struct stat st;
470       if ( ::stat(local_file.c_str(), &st) )
471         {
472         cmCTestLog(this->CTest, ERROR_MESSAGE, "   Cannot find file: "
473           << local_file.c_str() << std::endl);
474         ::curl_easy_cleanup(curl);
475         ::curl_global_cleanup();
476         return false;
477         }
478
479       ftpfile = ::fopen(local_file.c_str(), "rb");
480       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "   Upload file: "
481         << local_file.c_str() << " to "
482         << upload_as.c_str() << " Size: " << st.st_size << std::endl);
483
484       // specify target
485       ::curl_easy_setopt(curl,CURLOPT_URL, upload_as.c_str());
486
487       // now specify which file to upload
488       ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
489
490       // and give the size of the upload (optional)
491       ::curl_easy_setopt(curl, CURLOPT_INFILESIZE,
492         static_cast<long>(st.st_size));
493
494       // and give curl the buffer for errors
495       ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
496
497       // specify handler for output
498       ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
499         cmCTestSubmitHandlerWriteMemoryCallback);
500       ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
501         cmCTestSubmitHandlerCurlDebugCallback);
502
503       /* we pass our 'chunk' struct to the callback function */
504       cmCTestSubmitHandlerVectorOfChar chunk;
505       cmCTestSubmitHandlerVectorOfChar chunkDebug;
506       ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
507       ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
508
509       // Now run off and do what you've been told!
510       res = ::curl_easy_perform(curl);
511
512       if(cmSystemTools::IsOn(this->GetOption("InternalTest")) &&
513          cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
514          this->CTest->GetCDashVersion().c_str(), "1.7"))
515         {
516         // mock failure output for internal test case
517         std::string mock_output = "<cdash version=\"1.7.0\">\n"
518           "  <status>ERROR</status>\n"
519           "  <message>Checksum failed for file.</message>\n"
520           "</cdash>\n";
521         chunk.clear();
522         chunk.assign(mock_output.begin(), mock_output.end());
523         }
524
525       if ( chunk.size() > 0 )
526         {
527         cmCTestLog(this->CTest, DEBUG, "CURL output: ["
528           << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
529           << std::endl);
530         this->ParseResponse(chunk);
531         }
532       if ( chunkDebug.size() > 0 )
533         {
534         cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
535           << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
536           << std::endl);
537         }
538
539       // If curl failed for any reason, or checksum fails, wait and retry
540       //
541       if(res != CURLE_OK || this->HasErrors)
542         {
543         std::string retryDelay = this->GetOption("RetryDelay") == NULL ?
544           "" : this->GetOption("RetryDelay");
545         std::string retryCount = this->GetOption("RetryCount") == NULL ?
546           "" : this->GetOption("RetryCount");
547
548         int delay = retryDelay == "" ? atoi(this->CTest->GetCTestConfiguration(
549           "CTestSubmitRetryDelay").c_str()) : atoi(retryDelay.c_str());
550         int count = retryCount == "" ? atoi(this->CTest->GetCTestConfiguration(
551           "CTestSubmitRetryCount").c_str()) : atoi(retryCount.c_str());
552
553         for(int i = 0; i < count; i++)
554           {
555           cmCTestLog(this->CTest, HANDLER_OUTPUT,
556             "   Submit failed, waiting " << delay << " seconds...\n");
557
558           double stop = cmSystemTools::GetTime() + delay;
559           while(cmSystemTools::GetTime() < stop)
560             {
561             cmSystemTools::Delay(100);
562             }
563
564           cmCTestLog(this->CTest, HANDLER_OUTPUT,
565             "   Retry submission: Attempt " << (i + 1) << " of "
566             << count << std::endl);
567
568           ::fclose(ftpfile);
569           ftpfile = ::fopen(local_file.c_str(), "rb");
570           ::curl_easy_setopt(curl, CURLOPT_INFILE, ftpfile);
571
572           chunk.clear();
573           chunkDebug.clear();
574           this->HasErrors = false;
575
576           res = ::curl_easy_perform(curl);
577
578           if ( chunk.size() > 0 )
579             {
580             cmCTestLog(this->CTest, DEBUG, "CURL output: ["
581               << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
582               << std::endl);
583             this->ParseResponse(chunk);
584             }
585
586           if(res == CURLE_OK && !this->HasErrors)
587             {
588             break;
589             }
590           }
591         }
592
593       fclose(ftpfile);
594       if ( res )
595         {
596         cmCTestLog(this->CTest, ERROR_MESSAGE,
597           "   Error when uploading file: "
598           << local_file.c_str() << std::endl);
599         cmCTestLog(this->CTest, ERROR_MESSAGE, "   Error message was: "
600           << error_buffer << std::endl);
601         *this->LogFile << "   Error when uploading file: "
602                        << local_file.c_str()
603                        << std::endl
604                        << "   Error message was: " << error_buffer
605                        << std::endl;
606         // avoid deref of begin for zero size array
607         if(chunk.size())
608           {
609           *this->LogFile << "   Curl output was: "
610                          << cmCTestLogWrite(&*chunk.begin(), chunk.size())
611                          << std::endl;
612           cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
613                      << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
614                      << std::endl);
615           }
616         ::curl_easy_cleanup(curl);
617         ::curl_global_cleanup();
618         return false;
619         }
620       // always cleanup
621       ::curl_easy_cleanup(curl);
622       cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Uploaded: " + local_file
623         << std::endl);
624       }
625     }
626   ::curl_global_cleanup();
627   return true;
628 }
629
630 //----------------------------------------------------------------------------
631 void cmCTestSubmitHandler
632 ::ParseResponse(cmCTestSubmitHandlerVectorOfChar chunk)
633 {
634   std::string output = "";
635   output.append(chunk.begin(), chunk.end());
636
637   if(output.find("<cdash") != output.npos)
638     {
639     ResponseParser parser;
640     parser.Parse(output.c_str());
641
642     if(parser.Status != ResponseParser::STATUS_OK)
643       {
644       this->HasErrors = true;
645       cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Submission failed: " <<
646         parser.Message << std::endl);
647       return;
648       }
649     }
650   output = cmSystemTools::UpperCase(output);
651   if(output.find("WARNING") != std::string::npos)
652     {
653     this->HasWarnings = true;
654     }
655   if(output.find("ERROR") != std::string::npos)
656     {
657     this->HasErrors = true;
658     }
659
660   if(this->HasWarnings || this->HasErrors)
661     {
662     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Server Response:\n" <<
663           cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
664     }
665 }
666
667 //----------------------------------------------------------------------------
668 bool cmCTestSubmitHandler::TriggerUsingHTTP(
669   const std::set<cmStdString>& files,
670   const cmStdString& remoteprefix,
671   const cmStdString& url)
672 {
673   CURL *curl;
674   char error_buffer[1024];
675   /* In windows, this will init the winsock stuff */
676   ::curl_global_init(CURL_GLOBAL_ALL);
677
678   cmCTest::SetOfStrings::const_iterator file;
679   for ( file = files.begin(); file != files.end(); ++file )
680     {
681     /* get a curl handle */
682     curl = curl_easy_init();
683     if(curl)
684       {
685       // Using proxy
686       if ( this->HTTPProxyType > 0 )
687         {
688         curl_easy_setopt(curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
689         switch (this->HTTPProxyType)
690           {
691         case 2:
692           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
693           break;
694         case 3:
695           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
696           break;
697         default:
698           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
699           if (this->HTTPProxyAuth.size() > 0)
700             {
701             curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD,
702               this->HTTPProxyAuth.c_str());
703             }
704           }
705         }
706
707       ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
708
709       // and give curl the buffer for errors
710       ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer);
711
712       // specify handler for output
713       ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
714         cmCTestSubmitHandlerWriteMemoryCallback);
715       ::curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
716         cmCTestSubmitHandlerCurlDebugCallback);
717
718       /* we pass our 'chunk' struct to the callback function */
719       cmCTestSubmitHandlerVectorOfChar chunk;
720       cmCTestSubmitHandlerVectorOfChar chunkDebug;
721       ::curl_easy_setopt(curl, CURLOPT_FILE, (void *)&chunk);
722       ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)&chunkDebug);
723
724       cmStdString rfile
725         = remoteprefix + cmSystemTools::GetFilenameName(*file);
726       cmStdString ofile = "";
727       cmStdString::iterator kk;
728       for ( kk = rfile.begin(); kk < rfile.end(); ++ kk)
729         {
730         char c = *kk;
731         char hexCh[4] = { 0, 0, 0, 0 };
732         hexCh[0] = c;
733         switch ( c )
734           {
735         case '+':
736         case '?':
737         case '/':
738         case '\\':
739         case '&':
740         case ' ':
741         case '=':
742         case '%':
743           sprintf(hexCh, "%%%02X", (int)c);
744           ofile.append(hexCh);
745           break;
746         default:
747           ofile.append(hexCh);
748           }
749         }
750       cmStdString turl
751         = url + ((url.find("?",0) == cmStdString::npos) ? "?" : "&")
752         + "xmlfile=" + ofile;
753       *this->LogFile << "Trigger url: " << turl.c_str() << std::endl;
754       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "   Trigger url: "
755         << turl.c_str() << std::endl);
756       curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
757       curl_easy_setopt(curl, CURLOPT_URL, turl.c_str());
758       if ( curl_easy_perform(curl) )
759         {
760         cmCTestLog(this->CTest, ERROR_MESSAGE, "   Error when triggering: "
761           << turl.c_str() << std::endl);
762         cmCTestLog(this->CTest, ERROR_MESSAGE, "   Error message was: "
763           << error_buffer << std::endl);
764         *this->LogFile << "\tTriggering failed with error: " << error_buffer
765                        << std::endl
766                        << "   Error message was: " << error_buffer
767                        << std::endl;
768         if(chunk.size())
769           {
770           *this->LogFile
771             << "   Curl output was: "
772             << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << std::endl;
773           cmCTestLog(this->CTest, ERROR_MESSAGE, "CURL output: ["
774                      << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
775                      << std::endl);
776           }
777         ::curl_easy_cleanup(curl);
778         ::curl_global_cleanup();
779         return false;
780         }
781
782       if ( chunk.size() > 0 )
783         {
784         cmCTestLog(this->CTest, DEBUG, "CURL output: ["
785           << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
786           << std::endl);
787         }
788       if ( chunkDebug.size() > 0 )
789         {
790         cmCTestLog(this->CTest, DEBUG, "CURL debug output: ["
791           << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size())
792           << "]" << std::endl);
793         }
794
795       // always cleanup
796       ::curl_easy_cleanup(curl);
797       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, std::endl);
798       }
799     }
800   ::curl_global_cleanup();
801   cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Dart server triggered..."
802     << std::endl);
803   return true;
804 }
805
806 //----------------------------------------------------------------------------
807 bool cmCTestSubmitHandler::SubmitUsingSCP(
808   const cmStdString& scp_command,
809   const cmStdString& localprefix,
810   const std::set<cmStdString>& files,
811   const cmStdString& remoteprefix,
812   const cmStdString& url)
813 {
814   if ( !scp_command.size() || !localprefix.size() ||
815     !files.size() || !remoteprefix.size() || !url.size() )
816     {
817     return 0;
818     }
819   std::vector<const char*> argv;
820   argv.push_back(scp_command.c_str()); // Scp command
821   argv.push_back(scp_command.c_str()); // Dummy string for file
822   argv.push_back(scp_command.c_str()); // Dummy string for remote url
823   argv.push_back(0);
824
825   cmsysProcess* cp = cmsysProcess_New();
826   cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
827   //cmsysProcess_SetTimeout(cp, timeout);
828
829   int problems = 0;
830
831   cmCTest::SetOfStrings::const_iterator file;
832   for ( file = files.begin(); file != files.end(); ++file )
833     {
834     int retVal;
835
836     std::string lfname = localprefix;
837     cmSystemTools::ConvertToUnixSlashes(lfname);
838     lfname += "/" + *file;
839     lfname = cmSystemTools::ConvertToOutputPath(lfname.c_str());
840     argv[1] = lfname.c_str();
841     std::string rfname = url + "/" + remoteprefix + *file;
842     argv[2] = rfname.c_str();
843     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Execute \"" << argv[0]
844       << "\" \"" << argv[1] << "\" \""
845       << argv[2] << "\"" << std::endl);
846     *this->LogFile << "Execute \"" << argv[0] << "\" \"" << argv[1] << "\" \""
847       << argv[2] << "\"" << std::endl;
848
849     cmsysProcess_SetCommand(cp, &*argv.begin());
850     cmsysProcess_Execute(cp);
851     char* data;
852     int length;
853
854     while(cmsysProcess_WaitForData(cp, &data, &length, 0))
855       {
856       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
857         cmCTestLogWrite(data, length));
858       }
859
860     cmsysProcess_WaitForExit(cp, 0);
861
862     int result = cmsysProcess_GetState(cp);
863
864     if(result == cmsysProcess_State_Exited)
865       {
866       retVal = cmsysProcess_GetExitValue(cp);
867       if ( retVal != 0 )
868         {
869         cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "\tSCP returned: "
870           << retVal << std::endl);
871         *this->LogFile << "\tSCP returned: " << retVal << std::endl;
872         problems ++;
873         }
874       }
875     else if(result == cmsysProcess_State_Exception)
876       {
877       retVal = cmsysProcess_GetExitException(cp);
878       cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was an exception: "
879         << retVal << std::endl);
880       *this->LogFile << "\tThere was an exception: " << retVal << std::endl;
881       problems ++;
882       }
883     else if(result == cmsysProcess_State_Expired)
884       {
885       cmCTestLog(this->CTest, ERROR_MESSAGE, "\tThere was a timeout"
886         << std::endl);
887       *this->LogFile << "\tThere was a timeout" << std::endl;
888       problems ++;
889       }
890     else if(result == cmsysProcess_State_Error)
891       {
892       cmCTestLog(this->CTest, ERROR_MESSAGE, "\tError executing SCP: "
893         << cmsysProcess_GetErrorString(cp) << std::endl);
894       *this->LogFile << "\tError executing SCP: "
895         << cmsysProcess_GetErrorString(cp) << std::endl;
896       problems ++;
897       }
898     }
899   cmsysProcess_Delete(cp);
900   if ( problems )
901     {
902     return false;
903     }
904   return true;
905 }
906
907 //----------------------------------------------------------------------------
908 bool cmCTestSubmitHandler::SubmitUsingCP(
909   const cmStdString& localprefix,
910   const std::set<cmStdString>& files,
911   const cmStdString& remoteprefix,
912   const cmStdString& destination)
913 {
914   if ( !localprefix.size() ||
915     !files.size() || !remoteprefix.size() || !destination.size() )
916     {
917     cmCTestLog(this->CTest, ERROR_MESSAGE,
918                "Missing arguments for submit via cp:\n"
919                << "\tlocalprefix: " << localprefix << "\n"
920                << "\tNumber of files: " << files.size() << "\n"
921                << "\tremoteprefix: " << remoteprefix << "\n"
922                << "\tdestination: " << destination << std::endl);
923     return 0;
924     }
925   cmCTest::SetOfStrings::const_iterator file;
926   bool problems = false;
927   for ( file = files.begin(); file != files.end(); ++file )
928     {
929     std::string lfname = localprefix;
930     cmSystemTools::ConvertToUnixSlashes(lfname);
931     lfname += "/" + *file;
932     std::string rfname = destination + "/" + remoteprefix + *file;
933     cmSystemTools::CopyFileAlways(lfname.c_str(), rfname.c_str());
934     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "   Copy file: "
935         << lfname.c_str() << " to "
936         << rfname.c_str() << std::endl);
937     }
938   std::string tagDoneFile = destination + "/" + remoteprefix + "DONE";
939   cmSystemTools::Touch(tagDoneFile.c_str(), true);
940   if ( problems )
941     {
942     return false;
943     }
944   return true;
945 }
946
947
948 //----------------------------------------------------------------------------
949 #if defined(CTEST_USE_XMLRPC)
950 bool cmCTestSubmitHandler::SubmitUsingXMLRPC(const cmStdString& localprefix,
951   const std::set<cmStdString>& files,
952   const cmStdString& remoteprefix,
953   const cmStdString& url)
954 {
955   xmlrpc_env env;
956   char ctestString[] = "CTest";
957   std::string ctestVersionString = cmVersion::GetCMakeVersion();
958   char* ctestVersion = const_cast<char*>(ctestVersionString.c_str());
959
960   cmStdString realURL = url + "/" + remoteprefix + "/Command/";
961
962   /* Start up our XML-RPC client library. */
963   xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, ctestString, ctestVersion);
964
965   /* Initialize our error-handling environment. */
966   xmlrpc_env_init(&env);
967
968   /* Call the famous server at UserLand. */
969   cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Submitting to: "
970     << realURL.c_str() << " (" << remoteprefix.c_str() << ")" << std::endl);
971   cmCTest::SetOfStrings::const_iterator file;
972   for ( file = files.begin(); file != files.end(); ++file )
973     {
974     xmlrpc_value *result;
975
976     cmStdString local_file = *file;
977     if ( !cmSystemTools::FileExists(local_file.c_str()) )
978       {
979       local_file = localprefix + "/" + *file;
980       }
981     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Submit file: "
982       << local_file.c_str() << std::endl);
983     struct stat st;
984     if ( ::stat(local_file.c_str(), &st) )
985       {
986       cmCTestLog(this->CTest, ERROR_MESSAGE, "  Cannot find file: "
987         << local_file.c_str() << std::endl);
988       return false;
989       }
990
991     // off_t can be bigger than size_t.  fread takes size_t.
992     // make sure the file is not too big.
993     if(static_cast<off_t>(static_cast<size_t>(st.st_size)) !=
994        static_cast<off_t>(st.st_size))
995       {
996       cmCTestLog(this->CTest, ERROR_MESSAGE, "  File too big: "
997         << local_file.c_str() << std::endl);
998       return false;
999       }
1000     size_t fileSize = static_cast<size_t>(st.st_size);
1001     FILE* fp = fopen(local_file.c_str(), "rb");
1002     if ( !fp )
1003       {
1004       cmCTestLog(this->CTest, ERROR_MESSAGE, "  Cannot open file: "
1005         << local_file.c_str() << std::endl);
1006       return false;
1007       }
1008
1009     unsigned char *fileBuffer = new unsigned char[fileSize];
1010     if ( fread(fileBuffer, 1, fileSize, fp) != fileSize )
1011       {
1012       delete [] fileBuffer;
1013       fclose(fp);
1014       cmCTestLog(this->CTest, ERROR_MESSAGE, "  Cannot read file: "
1015         << local_file.c_str() << std::endl);
1016       return false;
1017       }
1018     fclose(fp);
1019
1020     char remoteCommand[] = "Submit.put";
1021     char* pRealURL = const_cast<char*>(realURL.c_str());
1022     result = xmlrpc_client_call(&env, pRealURL, remoteCommand,
1023       "(6)", fileBuffer, (xmlrpc_int32)fileSize );
1024
1025     delete [] fileBuffer;
1026
1027     if ( env.fault_occurred )
1028       {
1029       cmCTestLog(this->CTest, ERROR_MESSAGE, " Submission problem: "
1030         << env.fault_string << " (" << env.fault_code << ")" << std::endl);
1031       xmlrpc_env_clean(&env);
1032       xmlrpc_client_cleanup();
1033       return false;
1034       }
1035
1036     /* Dispose of our result value. */
1037     xmlrpc_DECREF(result);
1038     }
1039
1040   /* Clean up our error-handling environment. */
1041   xmlrpc_env_clean(&env);
1042
1043   /* Shutdown our XML-RPC client library. */
1044   xmlrpc_client_cleanup();
1045   return true;
1046 }
1047 #else
1048 bool cmCTestSubmitHandler::SubmitUsingXMLRPC(cmStdString const&,
1049                                              std::set<cmStdString> const&,
1050                                              cmStdString const&,
1051                                              cmStdString const&)
1052 {
1053   return false;
1054 }
1055 #endif
1056
1057 //----------------------------------------------------------------------------
1058 int cmCTestSubmitHandler::ProcessHandler()
1059 {
1060   std::string iscdash = this->CTest->GetCTestConfiguration("IsCDash");
1061   // cdash does not need to trigger so just return true
1062   if(iscdash.size())
1063     {
1064     this->CDash = true;
1065     }
1066
1067   const std::string &buildDirectory
1068     = this->CTest->GetCTestConfiguration("BuildDirectory");
1069   if ( buildDirectory.size() == 0 )
1070     {
1071     cmCTestLog(this->CTest, ERROR_MESSAGE,
1072       "Cannot find BuildDirectory  key in the DartConfiguration.tcl"
1073       << std::endl);
1074     return -1;
1075     }
1076
1077   if ( getenv("HTTP_PROXY") )
1078     {
1079     this->HTTPProxyType = 1;
1080     this->HTTPProxy = getenv("HTTP_PROXY");
1081     if ( getenv("HTTP_PROXY_PORT") )
1082       {
1083       this->HTTPProxy += ":";
1084       this->HTTPProxy += getenv("HTTP_PROXY_PORT");
1085       }
1086     if ( getenv("HTTP_PROXY_TYPE") )
1087       {
1088       cmStdString type = getenv("HTTP_PROXY_TYPE");
1089       // HTTP/SOCKS4/SOCKS5
1090       if ( type == "HTTP" )
1091         {
1092         this->HTTPProxyType = 1;
1093         }
1094       else if ( type == "SOCKS4" )
1095         {
1096         this->HTTPProxyType = 2;
1097         }
1098       else if ( type == "SOCKS5" )
1099         {
1100         this->HTTPProxyType = 3;
1101         }
1102       }
1103     if ( getenv("HTTP_PROXY_USER") )
1104       {
1105       this->HTTPProxyAuth = getenv("HTTP_PROXY_USER");
1106       }
1107     if ( getenv("HTTP_PROXY_PASSWD") )
1108       {
1109       this->HTTPProxyAuth += ":";
1110       this->HTTPProxyAuth += getenv("HTTP_PROXY_PASSWD");
1111       }
1112     }
1113
1114   if ( getenv("FTP_PROXY") )
1115     {
1116     this->FTPProxyType = 1;
1117     this->FTPProxy = getenv("FTP_PROXY");
1118     if ( getenv("FTP_PROXY_PORT") )
1119       {
1120       this->FTPProxy += ":";
1121       this->FTPProxy += getenv("FTP_PROXY_PORT");
1122       }
1123     if ( getenv("FTP_PROXY_TYPE") )
1124       {
1125       cmStdString type = getenv("FTP_PROXY_TYPE");
1126       // HTTP/SOCKS4/SOCKS5
1127       if ( type == "HTTP" )
1128         {
1129         this->FTPProxyType = 1;
1130         }
1131       else if ( type == "SOCKS4" )
1132         {
1133         this->FTPProxyType = 2;
1134         }
1135       else if ( type == "SOCKS5" )
1136         {
1137         this->FTPProxyType = 3;
1138         }
1139       }
1140     }
1141
1142   if ( this->HTTPProxy.size() > 0 )
1143     {
1144     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Use HTTP Proxy: "
1145       << this->HTTPProxy << std::endl);
1146     }
1147   if ( this->FTPProxy.size() > 0 )
1148     {
1149     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Use FTP Proxy: "
1150       << this->FTPProxy << std::endl);
1151     }
1152   cmGeneratedFileStream ofs;
1153   this->StartLogFile("Submit", ofs);
1154
1155   cmCTest::SetOfStrings files;
1156   std::string prefix = this->GetSubmitResultsPrefix();
1157
1158   if (!this->Files.empty())
1159     {
1160     // Submit the explicitly selected files:
1161     //
1162     cmCTest::SetOfStrings::const_iterator it;
1163     for (it = this->Files.begin(); it != this->Files.end(); ++it)
1164       {
1165       files.insert(*it);
1166       }
1167     }
1168
1169   // Add to the list of files to submit from any selected, existing parts:
1170   //
1171
1172   // TODO:
1173   // Check if test is enabled
1174
1175   this->CTest->AddIfExists(cmCTest::PartUpdate, "Update.xml");
1176   this->CTest->AddIfExists(cmCTest::PartConfigure, "Configure.xml");
1177   this->CTest->AddIfExists(cmCTest::PartBuild, "Build.xml");
1178   this->CTest->AddIfExists(cmCTest::PartTest, "Test.xml");
1179   if(this->CTest->AddIfExists(cmCTest::PartCoverage, "Coverage.xml"))
1180     {
1181     cmCTest::VectorOfStrings gfiles;
1182     std::string gpath
1183       = buildDirectory + "/Testing/" + this->CTest->GetCurrentTag();
1184     std::string::size_type glen = gpath.size() + 1;
1185     gpath = gpath + "/CoverageLog*";
1186     cmCTestLog(this->CTest, DEBUG, "Globbing for: " << gpath.c_str()
1187       << std::endl);
1188     if ( cmSystemTools::SimpleGlob(gpath, gfiles, 1) )
1189       {
1190       size_t cc;
1191       for ( cc = 0; cc < gfiles.size(); cc ++ )
1192         {
1193         gfiles[cc] = gfiles[cc].substr(glen);
1194         cmCTestLog(this->CTest, DEBUG, "Glob file: " << gfiles[cc].c_str()
1195           << std::endl);
1196         this->CTest->AddSubmitFile(cmCTest::PartCoverage, gfiles[cc].c_str());
1197         }
1198       }
1199     else
1200       {
1201       cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem globbing" << std::endl);
1202       }
1203     }
1204   this->CTest->AddIfExists(cmCTest::PartMemCheck, "DynamicAnalysis.xml");
1205   this->CTest->AddIfExists(cmCTest::PartMemCheck, "Purify.xml");
1206   this->CTest->AddIfExists(cmCTest::PartNotes, "Notes.xml");
1207   this->CTest->AddIfExists(cmCTest::PartUpload, "Upload.xml");
1208
1209   // Query parts for files to submit.
1210   for(cmCTest::Part p = cmCTest::PartStart;
1211       p != cmCTest::PartCount; p = cmCTest::Part(p+1))
1212     {
1213     // Skip parts we are not submitting.
1214     if(!this->SubmitPart[p])
1215       {
1216       continue;
1217       }
1218
1219     // Submit files from this part.
1220     std::vector<std::string> const& pfiles = this->CTest->GetSubmitFiles(p);
1221     for(std::vector<std::string>::const_iterator pi = pfiles.begin();
1222         pi != pfiles.end(); ++pi)
1223       {
1224       files.insert(*pi);
1225       }
1226     }
1227
1228   if ( ofs )
1229     {
1230     ofs << "Upload files:" << std::endl;
1231     int cnt = 0;
1232     cmCTest::SetOfStrings::iterator it;
1233     for ( it = files.begin(); it != files.end(); ++ it )
1234       {
1235       ofs << cnt << "\t" << it->c_str() << std::endl;
1236       cnt ++;
1237       }
1238     }
1239   cmCTestLog(this->CTest, HANDLER_OUTPUT, "Submit files (using "
1240     << this->CTest->GetCTestConfiguration("DropMethod") << ")"
1241     << std::endl);
1242   const char* specificTrack = this->CTest->GetSpecificTrack();
1243   if ( specificTrack )
1244     {
1245     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Send to track: "
1246       << specificTrack << std::endl);
1247     }
1248   this->SetLogFile(&ofs);
1249
1250   cmStdString dropMethod(this->CTest->GetCTestConfiguration("DropMethod"));
1251
1252   if ( dropMethod == "" || dropMethod == "ftp" )
1253     {
1254     ofs << "Using drop method: FTP" << std::endl;
1255     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Using FTP submit method"
1256       << std::endl
1257       << "   Drop site: ftp://");
1258     std::string url = "ftp://";
1259     url += cmCTest::MakeURLSafe(
1260       this->CTest->GetCTestConfiguration("DropSiteUser")) + ":" +
1261       cmCTest::MakeURLSafe(this->CTest->GetCTestConfiguration(
1262           "DropSitePassword")) + "@" +
1263       this->CTest->GetCTestConfiguration("DropSite") +
1264       cmCTest::MakeURLSafe(
1265         this->CTest->GetCTestConfiguration("DropLocation"));
1266     if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
1267       {
1268       cmCTestLog(this->CTest, HANDLER_OUTPUT,
1269         this->CTest->GetCTestConfiguration(
1270           "DropSiteUser").c_str());
1271       if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
1272         {
1273         cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
1274         }
1275       cmCTestLog(this->CTest, HANDLER_OUTPUT, "@");
1276       }
1277     cmCTestLog(this->CTest, HANDLER_OUTPUT,
1278       this->CTest->GetCTestConfiguration("DropSite")
1279       << this->CTest->GetCTestConfiguration("DropLocation") << std::endl);
1280     if ( !this->SubmitUsingFTP(buildDirectory + "/Testing/"
1281         + this->CTest->GetCurrentTag(),
1282         files, prefix, url) )
1283       {
1284       cmCTestLog(this->CTest, ERROR_MESSAGE,
1285         "   Problems when submitting via FTP"
1286         << std::endl);
1287       ofs << "   Problems when submitting via FTP" << std::endl;
1288       return -1;
1289       }
1290     if(!this->CDash)
1291       {
1292       cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Using HTTP trigger method"
1293                  << std::endl
1294                  << "   Trigger site: "
1295                  << this->CTest->GetCTestConfiguration("TriggerSite")
1296                  << std::endl);
1297       if ( !this->
1298            TriggerUsingHTTP(files, prefix,
1299                             this->CTest->GetCTestConfiguration("TriggerSite")))
1300         {
1301         cmCTestLog(this->CTest, ERROR_MESSAGE,
1302                    "   Problems when triggering via HTTP" << std::endl);
1303         ofs << "   Problems when triggering via HTTP" << std::endl;
1304         return -1;
1305         }
1306       cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Submission successful"
1307                  << std::endl);
1308       ofs << "   Submission successful" << std::endl;
1309       return 0;
1310       }
1311     }
1312   else if ( dropMethod == "http" || dropMethod == "https" )
1313     {
1314     std::string url = dropMethod;
1315     url += "://";
1316     ofs << "Using drop method: " << dropMethod << std::endl;
1317     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Using HTTP submit method"
1318       << std::endl
1319       << "   Drop site:" << url);
1320      if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
1321       {
1322       url += this->CTest->GetCTestConfiguration("DropSiteUser");
1323       cmCTestLog(this->CTest, HANDLER_OUTPUT,
1324         this->CTest->GetCTestConfiguration("DropSiteUser").c_str());
1325       if ( this->CTest->GetCTestConfiguration("DropSitePassword").size() > 0 )
1326         {
1327         url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword");
1328         cmCTestLog(this->CTest, HANDLER_OUTPUT, ":******");
1329         }
1330       url += "@";
1331       cmCTestLog(this->CTest, HANDLER_OUTPUT, "@");
1332       }
1333     url += this->CTest->GetCTestConfiguration("DropSite") +
1334       this->CTest->GetCTestConfiguration("DropLocation");
1335     cmCTestLog(this->CTest, HANDLER_OUTPUT,
1336       this->CTest->GetCTestConfiguration("DropSite")
1337       << this->CTest->GetCTestConfiguration("DropLocation") << std::endl);
1338     if ( !this->SubmitUsingHTTP(buildDirectory + "/Testing/" +
1339         this->CTest->GetCurrentTag(), files, prefix, url) )
1340       {
1341       cmCTestLog(this->CTest, ERROR_MESSAGE,
1342         "   Problems when submitting via HTTP" << std::endl);
1343       ofs << "   Problems when submitting via HTTP" << std::endl;
1344       return -1;
1345       }
1346     if(!this->CDash)
1347       {
1348       cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Using HTTP trigger method"
1349                  << std::endl
1350                  << "   Trigger site: "
1351                  << this->CTest->GetCTestConfiguration("TriggerSite")
1352                  << std::endl);
1353       if ( !this->
1354            TriggerUsingHTTP(files, prefix,
1355                             this->CTest->GetCTestConfiguration("TriggerSite")))
1356         {
1357         cmCTestLog(this->CTest, ERROR_MESSAGE,
1358                    "   Problems when triggering via HTTP" << std::endl);
1359         ofs << "   Problems when triggering via HTTP" << std::endl;
1360         return -1;
1361         }
1362       }
1363     if(this->HasErrors)
1364       {
1365       cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Errors occurred during "
1366         "submission." << std::endl);
1367       ofs << "   Errors occurred during submission. " << std::endl;
1368       }
1369     else
1370       {
1371       cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Submission successful" <<
1372         (this->HasWarnings ? ", with warnings." : "") << std::endl);
1373       ofs << "   Submission successful" <<
1374         (this->HasWarnings ? ", with warnings." : "") << std::endl;
1375       }
1376
1377     return 0;
1378     }
1379   else if ( dropMethod == "xmlrpc" )
1380     {
1381 #if defined(CTEST_USE_XMLRPC)
1382     ofs << "Using drop method: XML-RPC" << std::endl;
1383     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Using XML-RPC submit method"
1384       << std::endl);
1385     std::string url = this->CTest->GetCTestConfiguration("DropSite");
1386     prefix = this->CTest->GetCTestConfiguration("DropLocation");
1387     if ( !this->SubmitUsingXMLRPC(buildDirectory + "/Testing/" +
1388         this->CTest->GetCurrentTag(), files, prefix, url) )
1389       {
1390       cmCTestLog(this->CTest, ERROR_MESSAGE,
1391         "   Problems when submitting via XML-RPC" << std::endl);
1392       ofs << "   Problems when submitting via XML-RPC" << std::endl;
1393       return -1;
1394       }
1395     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Submission successful"
1396       << std::endl);
1397     ofs << "   Submission successful" << std::endl;
1398     return 0;
1399 #else
1400     cmCTestLog(this->CTest, ERROR_MESSAGE,
1401                "   Submission method \"xmlrpc\" not compiled into CTest!"
1402                << std::endl);
1403     return -1;
1404 #endif
1405     }
1406   else if ( dropMethod == "scp" )
1407     {
1408     std::string url;
1409     std::string oldWorkingDirectory;
1410     if ( this->CTest->GetCTestConfiguration("DropSiteUser").size() > 0 )
1411       {
1412       url += this->CTest->GetCTestConfiguration("DropSiteUser") + "@";
1413       }
1414     url += this->CTest->GetCTestConfiguration("DropSite") + ":" +
1415       this->CTest->GetCTestConfiguration("DropLocation");
1416
1417     // change to the build directory so that we can uses a relative path
1418     // on windows since scp dosn't support "c:" a drive in the path
1419     oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
1420     cmSystemTools::ChangeDirectory(buildDirectory.c_str());
1421
1422     if ( !this->SubmitUsingSCP(
1423         this->CTest->GetCTestConfiguration("ScpCommand"),
1424         "Testing/"+this->CTest->GetCurrentTag(), files, prefix, url) )
1425       {
1426       cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
1427       cmCTestLog(this->CTest, ERROR_MESSAGE,
1428         "   Problems when submitting via SCP"
1429         << std::endl);
1430       ofs << "   Problems when submitting via SCP" << std::endl;
1431       return -1;
1432       }
1433     cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
1434     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Submission successful"
1435       << std::endl);
1436     ofs << "   Submission successful" << std::endl;
1437     return 0;
1438     }
1439   else if ( dropMethod == "cp" )
1440     {
1441     std::string location
1442       = this->CTest->GetCTestConfiguration("DropLocation");
1443
1444
1445     // change to the build directory so that we can uses a relative path
1446     // on windows since scp dosn't support "c:" a drive in the path
1447     std::string
1448       oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
1449     cmSystemTools::ChangeDirectory(buildDirectory.c_str());
1450     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "   Change directory: "
1451                << buildDirectory.c_str() << std::endl);
1452
1453     if ( !this->SubmitUsingCP(
1454            "Testing/"+this->CTest->GetCurrentTag(),
1455            files,
1456            prefix,
1457            location) )
1458       {
1459       cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
1460       cmCTestLog(this->CTest, ERROR_MESSAGE,
1461         "   Problems when submitting via CP"
1462         << std::endl);
1463       ofs << "   Problems when submitting via cp" << std::endl;
1464       return -1;
1465       }
1466     cmSystemTools::ChangeDirectory(oldWorkingDirectory.c_str());
1467     cmCTestLog(this->CTest, HANDLER_OUTPUT, "   Submission successful"
1468       << std::endl);
1469     ofs << "   Submission successful" << std::endl;
1470     return 0;
1471     }
1472
1473   cmCTestLog(this->CTest, ERROR_MESSAGE, "   Unknown submission method: \""
1474     << dropMethod << "\"" << std::endl);
1475   return -1;
1476 }
1477
1478 //----------------------------------------------------------------------------
1479 std::string cmCTestSubmitHandler::GetSubmitResultsPrefix()
1480 {
1481   std::string name = this->CTest->GetCTestConfiguration("Site") +
1482     "___" + this->CTest->GetCTestConfiguration("BuildName") +
1483     "___" + this->CTest->GetCurrentTag() + "-" +
1484     this->CTest->GetTestModelString() + "___XML___";
1485   return name;
1486 }
1487
1488 //----------------------------------------------------------------------------
1489 void cmCTestSubmitHandler::SelectParts(std::set<cmCTest::Part> const& parts)
1490 {
1491   // Check whether each part is selected.
1492   for(cmCTest::Part p = cmCTest::PartStart;
1493       p != cmCTest::PartCount; p = cmCTest::Part(p+1))
1494     {
1495     this->SubmitPart[p] =
1496       (std::set<cmCTest::Part>::const_iterator(parts.find(p)) != parts.end());
1497     }
1498 }
1499
1500 //----------------------------------------------------------------------------
1501 void cmCTestSubmitHandler::SelectFiles(cmCTest::SetOfStrings const& files)
1502 {
1503   cmCTest::SetOfStrings::const_iterator it;
1504   for (it = files.begin(); it != files.end(); ++it)
1505     {
1506     this->Files.insert(*it);
1507     }
1508 }