1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23 #include <cstdio>
24 #include <stdlib.h>
25 #include <sys/utsname.h>
26 #include <_version.h>
27 #include <errno.h>
28 #include <string>
29 #include <string.h>
30 #include <assert.h>
31
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include <unistd.h>
35 #include <pwd.h>
36 #include <pthread.h>
37 #include <limits.h>
38
39 #include <hash_map>
40 #include <vector>
41 #include <string>
42
43 #if defined (LINUX) || (FREEBSD)
44 #include <netinet/in.h>
45 #endif
46
47 typedef int SOCKET;
48
49 #define closesocket close
50 #define SOCKET_ERROR -1
51
52 #ifdef SOLARIS
basename(const char * filename)53 const char *basename( const char *filename )
54 {
55 const char *pSlash = strrchr( filename, '/' );
56
57 return pSlash ? pSlash + 1 : pSlash;
58 }
59 #endif
60
61 using namespace std;
62
63 static bool g_bNoUI = false;
64 static bool g_bSendReport = false;
65 static bool g_bLoadReport = false;
66
67 static bool g_bDebugMode = false;
68 static int g_signal = 0;
69
70 static string g_strProductKey;
71 static string g_strReportServer;
72 static unsigned short g_uReportPort = 80;
73 static string g_buildid;
74 static string g_strDefaultLanguage;
75 static string g_strXMLFileName;
76 static string g_strPStackFileName;
77 static string g_strChecksumFileName;
78 static string g_strProgramDir;
79
80 static char g_szStackFile[L_tmpnam] = "";
81 static char g_szDescriptionFile[2048] = "";
82 static char g_szReportFile[2048] = "";
83
84 #define SO_CRASHREPORT_MAIL "so-report@sun.com"
85 #define PSTACK_CMD "pstack %d"
86
87 #ifdef LINUX
88 #define PMAP_CMD "cat /proc/%d/maps"
89 #else
90 #define PMAP_CMD "pmap %d"
91 #endif
92
93 #define REPORT_SERVER (g_strReportServer.c_str())
94 #define REPORT_PORT g_uReportPort
95
getprogramdir()96 static string getprogramdir()
97 {
98 return g_strProgramDir;
99 }
100
getlocale()101 static const char *getlocale()
102 {
103 const char * locale = getenv( "LC_ALL" );
104
105 if( NULL == locale )
106 locale = getenv( "LC_CTYPE" );
107
108 if( NULL == locale )
109 locale = getenv( "LANG" );
110
111 if( NULL == locale )
112 locale = "C";
113
114 return locale;
115 }
116
get_home_dir()117 static const char *get_home_dir()
118 {
119 struct passwd *ppwd = getpwuid( getuid() );
120
121 return ppwd ? (ppwd->pw_dir ? ppwd->pw_dir : "/") : "/";
122 }
123
trim_string(const string & rString)124 static string trim_string( const string& rString )
125 {
126 string temp = rString;
127
128 while ( temp.length() && (temp[0] == ' ' || temp[0] == '\t') )
129 temp.erase( 0, 1 );
130
131 string::size_type len = temp.length();
132
133 while ( len && (temp[len-1] == ' ' || temp[len-1] == '\t') )
134 {
135 temp.erase( len - 1, 1 );
136 len = temp.length();
137 }
138
139 return temp;
140 }
141
xml_encode(const string & rString)142 static string xml_encode( const string &rString )
143 {
144 string temp = rString;
145 string::size_type pos = 0;
146
147 // First replace all occurences of '&' because it may occur in further
148 // encoded chardters too
149
150 for( pos = 0; (pos = temp.find( '&', pos )) != string::npos; pos += 4 )
151 temp.replace( pos, 1, "&" );
152
153 for( pos = 0; (pos = temp.find( '<', pos )) != string::npos; pos += 4 )
154 temp.replace( pos, 1, "<" );
155
156 for( pos = 0; (pos = temp.find( '>', pos )) != string::npos; pos += 4 )
157 temp.replace( pos, 1, ">" );
158
159 return temp;
160 }
161
fcopy(FILE * fpout,FILE * fpin)162 static size_t fcopy( FILE *fpout, FILE *fpin )
163 {
164 char buffer[1024];
165 size_t nBytes;
166 size_t nBytesWritten = 0;
167
168 while ( 0 != (nBytes = fread( buffer, 1, sizeof(buffer), fpin )) )
169 {
170 nBytesWritten += fwrite( buffer, 1, nBytes, fpout );
171 }
172
173 return nBytesWritten;
174 }
175
176 /*
177 writes the report to a temp-file
178 from which it can be reviewed and sent
179 */
180
write_report(const hash_map<string,string> & rSettings)181 bool write_report( const hash_map< string, string >& rSettings )
182 {
183 FILE *fp = fopen( tmpnam( g_szReportFile ), "w" );
184 const char *pszUserType = getenv( "STAROFFICE_USERTYPE" );
185
186 fprintf( fp,
187 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
188 "<!DOCTYPE errormail:errormail PUBLIC \"-//OpenOffice.org//DTD ErrorMail 1.0//EN\" \"errormail.dtd\">\n"
189 "<errormail:errormail xmlns:errormail=\"http://openoffice.org/2002/errormail\" usertype=\"%s\">\n"
190 "<reportmail:mail xmlns:reportmail=\"http://openoffice.org/2002/reportmail\" version=\"1.1\" feedback=\"%s\" email=\"%s\">\n"
191 "<reportmail:title>%s</reportmail:title>\n"
192 "<reportmail:attachment name=\"description.txt\" media-type=\"text/plain\" class=\"UserComment\"/>\n"
193 "<reportmail:attachment name=\"stack.txt\" media-type=\"text/plain\" class=\"pstack output\"/>\n"
194 "</reportmail:mail>\n"
195 "<officeinfo:officeinfo xmlns:officeinfo=\"http://openoffice.org/2002/officeinfo\" build=\"%s\" platform=\"%s\" language=\"%s\" exceptiontype=\"%d\" product=\"%s\" procpath=\"%s\"/>\n"
196 ,
197 pszUserType ? xml_encode( pszUserType ).c_str() : "",
198 xml_encode(rSettings.find( "CONTACT" )->second).c_str(),
199 xml_encode(rSettings.find( "EMAIL" )->second).c_str(),
200 xml_encode(rSettings.find( "TITLE" )->second).c_str(),
201 g_buildid.length() ? xml_encode( g_buildid ).c_str() : "unknown",
202 _INPATH,
203 g_strDefaultLanguage.c_str(),
204 g_signal,
205 g_strProductKey.length() ? xml_encode(g_strProductKey).c_str() : "unknown",
206 xml_encode(getprogramdir()).c_str()
207 );
208
209 struct utsname info;
210
211 memset( &info, 0, sizeof(info) );
212 uname( &info );
213
214 fprintf( fp,
215 "<systeminfo:systeminfo xmlns:systeminfo=\"http://openoffice.org/2002/systeminfo\">\n"
216 "<systeminfo:System name=\"%s\" version=\"%s\" build=\"%s\" locale=\"%s\"/>\n"
217 ,
218 xml_encode( info.sysname ).c_str(),
219 xml_encode( info.version ).c_str(),
220 xml_encode( info.release ).c_str(),
221 xml_encode( getlocale() ).c_str()
222 );
223 fprintf( fp, "<systeminfo:CPU type=\"%s\"/>\n", xml_encode( info.machine ).c_str() );
224 fprintf( fp, "</systeminfo:systeminfo>\n" );
225
226 FILE *fpxml = fopen( g_strXMLFileName.c_str(), "r" );
227 if ( fpxml )
228 {
229 fcopy( fp, fpxml );
230 fclose( fpxml );
231 }
232
233 FILE *fpchk = fopen( g_strChecksumFileName.c_str(), "r" );
234 if ( fpchk )
235 {
236 fcopy( fp, fpchk );
237 fclose( fpchk );
238 }
239
240 fprintf( fp, "</errormail:errormail>\n" );
241
242 fclose( fp );
243
244 return true;
245 }
246
247
write_description(const hash_map<string,string> & rSettings)248 bool write_description( const hash_map< string, string >& rSettings )
249 {
250 bool bSuccess = false;
251 FILE *fp = fopen( tmpnam( g_szDescriptionFile ), "w" );
252
253 if ( fp )
254 {
255 bSuccess = true;
256 fprintf( fp, "\xEF\xBB\xBF" );
257 fprintf( fp, "%s\n", rSettings.find( "DESCRIPTION" )->second.c_str() );
258 fclose( fp );
259 }
260
261 return bSuccess;
262 }
263
264 #if 0
265 // unused
266 static void printSettings( const hash_map<string,string>& rSettings )
267 {
268 printf( "Settings:\n" );
269 for( hash_map<string,string>::const_iterator it = rSettings.begin(); it != rSettings.end(); ++it )
270 {
271 printf( "%s=\"%s\"\n", it->first.c_str(), it->second.c_str() );
272 }
273 }
274 #endif
275
save_crash_report(const string & rFileName,const hash_map<string,string> &)276 bool save_crash_report( const string& rFileName, const hash_map< string, string >& /*rSettings*/ )
277 {
278 bool bSuccess = false;
279 FILE *fpout = fopen( rFileName.c_str(), "w" );
280
281 if ( fpout )
282 {
283 FILE *fpin = fopen( g_szStackFile, "r" );
284
285 if ( fpin )
286 {
287 char buf[1024];
288
289 while (fgets(buf, sizeof(buf), fpin) != NULL)
290 {
291 fputs(buf, fpout);
292 }
293
294 bSuccess = true;
295
296 fclose ( fpin );
297 }
298
299 fclose( fpout );
300 }
301
302 return bSuccess;
303 }
304
SendHTTPRequest(FILE * fp,const char * pszServer,unsigned short uPort=80,const char * pszProxyServer=NULL,unsigned short uProxyPort=8080)305 bool SendHTTPRequest(
306 FILE *fp,
307 const char *pszServer,
308 unsigned short uPort = 80,
309 const char *pszProxyServer = NULL,
310 unsigned short uProxyPort = 8080 )
311 {
312 bool success = false;
313
314 struct hostent *hp;
315
316 if ( pszProxyServer )
317 hp = gethostbyname( pszProxyServer );
318 else
319 hp = gethostbyname( pszServer );
320
321 if ( hp )
322 {
323 SOCKET s = socket( AF_INET, SOCK_STREAM, 0 );
324
325 if ( s )
326 {
327 struct sockaddr_in address;
328
329 memcpy(&(address.sin_addr.s_addr), *(hp->h_addr_list),sizeof(struct in_addr));
330 address.sin_family = AF_INET;
331
332 if ( pszProxyServer )
333 address.sin_port = ntohs( uProxyPort );
334 else
335 address.sin_port = ntohs( uPort );
336
337 if ( 0 == connect( s, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) )
338 {
339 fseek( fp, 0, SEEK_END );
340 size_t length = ftell( fp );
341 fseek( fp, 0, SEEK_SET );
342
343 char buffer[2048];
344
345 if ( pszProxyServer )
346 sprintf( buffer,
347 "POST http://%s:%d/soap/servlet/rpcrouter HTTP/1.0\r\n"
348 "Content-Type: text/xml; charset=\"utf-8\"\r\n"
349 "Content-Length: %d\r\n"
350 "SOAPAction: \"\"\r\n\r\n",
351 pszServer,
352 uPort,
353 static_cast<int>(length)
354 );
355 else
356 sprintf( buffer,
357 "POST /soap/servlet/rpcrouter HTTP/1.0\r\n"
358 "Content-Type: text/xml; charset=\"utf-8\"\r\n"
359 "Content-Length: %d\r\n"
360 "SOAPAction: \"\"\r\n\r\n",
361 static_cast<int>(length)
362 );
363
364 if ( g_bDebugMode )
365 {
366 printf( "*** Sending HTTP request ***\n\n" );
367 printf( buffer );
368 }
369
370 if ( SOCKET_ERROR != send( s, buffer, strlen(buffer), 0 ) )
371 {
372 size_t nBytes;
373
374 do
375 {
376 nBytes = fread( buffer, 1, sizeof(buffer), fp );
377
378 if ( nBytes )
379 {
380 if ( g_bDebugMode )
381 fwrite( buffer, 1, nBytes, stdout );
382 success = SOCKET_ERROR != send( s, buffer, nBytes, 0 );
383 }
384 } while( nBytes && success );
385
386 if ( success )
387 {
388 if ( g_bDebugMode )
389 printf( "*** Receiving HTTP response ***\n\n" );
390
391 memset( buffer, 0, sizeof(buffer) );
392 success = SOCKET_ERROR != recv( s, buffer, sizeof(buffer), 0 );
393 if ( success )
394 {
395 char szHTTPSignature[sizeof(buffer)] = "";
396 unsigned uHTTPReturnCode = 0;
397
398 sscanf( buffer, "%s %d ", szHTTPSignature, &uHTTPReturnCode );
399 success = uHTTPReturnCode == 200;
400 }
401 if ( g_bDebugMode )
402 do
403 {
404 printf( buffer );
405 memset( buffer, 0, sizeof(buffer) );
406 } while ( 0 < recv( s, buffer, sizeof(buffer), 0 ) );
407 }
408 }
409
410 }
411
412 closesocket( s );
413 }
414 }
415
416 return success;
417 }
418
WriteSOAPRequest(FILE * fp)419 static void WriteSOAPRequest( FILE *fp )
420 {
421 fprintf( fp,
422 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
423 "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
424 "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\n"
425 "xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\"\n"
426 "xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"\n"
427 "xmlns:rds=\"urn:ReportDataService\"\n"
428 "xmlns:apache=\"http://xml.apache.org/xml-soap\"\n"
429 "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
430 "<SOAP-ENV:Body>\n"
431 );
432
433 fprintf( fp, "<rds:submitReport>\n" );
434 fprintf( fp, "<body xsi:type=\"xsd:string\">This is an autogenerated crash report mail.</body>\n" );
435 fprintf( fp, "<hash xsi:type=\"apache:Map\">\n" );
436
437 FILE *fpin = fopen( g_szReportFile, "r" );
438 if ( fpin )
439 {
440 fprintf( fp,
441 "<item>\n"
442 "<key xsi:type=\"xsd:string\">reportmail.xml</key>\n"
443 "<value xsi:type=\"xsd:string\"><![CDATA[" );
444 fcopy( fp, fpin );
445 fprintf( fp, "]]></value></item>\n" );
446 fclose( fpin );
447 }
448
449 fpin = fopen( g_szDescriptionFile, "r" );
450 if ( fpin )
451 {
452 fprintf( fp,
453 "<item>\n"
454 "<key xsi:type=\"xsd:string\">description.txt</key>\n"
455 "<value xsi:type=\"xsd:string\"><![CDATA[" );
456 fcopy( fp, fpin );
457 fprintf( fp, "]]></value></item>\n" );
458 fclose( fpin );
459 };
460
461 fpin = fopen( g_szStackFile, "r" );
462 if ( fpin )
463 {
464 fprintf( fp,
465 "<item>\n"
466 "<key xsi:type=\"xsd:string\">stack.txt</key>\n"
467 "<value xsi:type=\"xsd:string\"><![CDATA[" );
468 fcopy( fp, fpin );
469 fprintf( fp, "]]></value></item>\n" );
470 fclose( fpin );
471 };
472
473 fprintf( fp,
474 "</hash>\n"
475 "</rds:submitReport>\n"
476 "</SOAP-ENV:Body>\n"
477 "</SOAP-ENV:Envelope>\n"
478 );
479 }
480
481 struct RequestParams
482 {
483 bool success;
484 FILE *fpin;
485 const char *pServer;
486 unsigned short uPort;
487 const char *pProxyServer;
488 unsigned short uProxyPort;
489 };
490
491
send_crash_report(const hash_map<string,string> & rSettings)492 bool send_crash_report( const hash_map< string, string >& rSettings )
493 {
494 if ( 0 == strcasecmp( rSettings.find( "CONTACT" )->second.c_str(), "true" ) &&
495 !trim_string(rSettings.find( "EMAIL" )->second).length() )
496 {
497 return false;
498 }
499
500 char *endptr = NULL;
501
502 const char *pProxyServer = rSettings.find( "SERVER" )->second.c_str();
503 unsigned short uProxyPort = (unsigned short)strtoul( rSettings.find( "PORT" )->second.c_str(), &endptr, 10 );
504
505 bool bUseProxy = !strcasecmp( "true", rSettings.find( "USEPROXY" )->second.c_str() );
506
507
508 write_description( rSettings );
509 write_report( rSettings );
510
511 bool bSuccess = false;
512
513 FILE *fptemp = tmpfile();
514 if ( fptemp )
515 {
516 WriteSOAPRequest( fptemp );
517 fseek( fptemp, 0, SEEK_SET );
518
519 bSuccess = SendHTTPRequest(
520 fptemp,
521 REPORT_SERVER, REPORT_PORT,
522 bUseProxy ? pProxyServer : NULL,
523 uProxyPort ? uProxyPort : 8080
524 );
525
526 fclose( fptemp );
527
528 }
529
530 unlink( g_szDescriptionFile );
531 unlink( g_szReportFile );
532
533 return bSuccess;
534 }
535
536
append_file(const char * filename,string & rString)537 static bool append_file( const char *filename, string& rString )
538 {
539 char buf[1024];
540 bool bSuccess = false;
541
542 FILE *fp = fopen( filename, "r" );
543 if ( fp )
544 {
545 bSuccess = true;
546 while (fgets(buf, sizeof(buf), fp) != NULL)
547 {
548 rString.append( buf );
549 }
550 fclose( fp );
551 }
552
553 return true;
554 }
555
crash_get_details(const hash_map<string,string> & rSettings)556 string crash_get_details( const hash_map< string, string >& rSettings )
557 {
558 string aRet;
559
560 write_description( rSettings );
561 write_report( rSettings );
562
563 aRet.append( rSettings.find( "TITLE" )->second.c_str() );
564 aRet.append( "\n\n" );
565 append_file( g_szDescriptionFile, aRet );
566 aRet.append( "\n\n-------\n\n" );
567 append_file( g_szReportFile, aRet );
568 aRet.append( "\n\n-------\n\n" );
569 append_file( g_szStackFile, aRet );
570
571 unlink( g_szDescriptionFile );
572 unlink( g_szReportFile );
573
574 return aRet;
575 }
576
577
578 // ensure validity of program relative paths
setup_program_dir(const char * progname)579 static void setup_program_dir( const char* progname )
580 {
581 char szCanonicProgPath[PATH_MAX];
582
583
584 if ( realpath( progname, szCanonicProgPath ) )
585 {
586 string aDir = szCanonicProgPath;
587
588 size_t pos = aDir.rfind( '/' );
589 // FIXME: search PATH if necessary
590 assert( pos != string::npos );
591
592 g_strProgramDir = aDir.substr( 0, pos + 1 );
593 aDir.erase( pos );
594 chdir( aDir.c_str() );
595 }
596 }
597
598 //*************************************************************************
599
setup_commandline_arguments(int argc,char ** argv,int * pSignal)600 static long setup_commandline_arguments( int argc, char** argv, int *pSignal )
601 {
602 long pid = 0;
603 int signal = 0;
604
605 for ( int n = 1; n < argc; n++ )
606 {
607 if ( 0 == strcmp( argv[n], "-p" ) )
608 {
609 if ( ++n < argc )
610 pid = strtol( argv[n], NULL, 0 );
611 }
612 else if ( 0 == strcmp( argv[n], "-s" ) )
613 {
614 if ( ++n < argc )
615 signal = strtol( argv[n], NULL, 0 );
616 }
617 else if ( 0 == strcmp( argv[n], "-debug" ) )
618 {
619 g_bDebugMode = true;
620 }
621 else if ( 0 == strcmp( argv[n], "-xml" ) )
622 {
623 if ( ++n < argc )
624 g_strXMLFileName = argv[n];
625 }
626 else if ( 0 == strcmp( argv[n], "-stack" ) )
627 {
628 if ( ++n < argc )
629 g_strPStackFileName = argv[n];
630 }
631 else if ( 0 == strcmp( argv[n], "-chksum" ) )
632 {
633 if ( ++n < argc )
634 g_strChecksumFileName = argv[n];
635 }
636 else if ( 0 == strcmp( argv[n], "-noui" ) )
637 {
638 g_bNoUI = true;
639 }
640 else if ( 0 == strcmp( argv[n], "-send" ) )
641 {
642 g_bSendReport = true;
643 }
644 else if ( 0 == strcmp( argv[n], "-load" ) )
645 {
646 g_bLoadReport = true;
647 }
648 else if ( argv[n] && strlen(argv[n]) )
649 {
650 printf(
651 "\n%s crash_report %s\n\n" \
652 "/?, -h[elp] %s\n\n" \
653 "%-20s %s\n\n",
654 "%MSG_CMDLINE_USAGE%",
655 "%MSG_PARAM_PROCESSID%",
656 "%MSG_PARAM_HELP_DESCRIPTION%",
657 "%MSG_PARAM_PROCESSID%",
658 "%MSG_PARAM_PROCESSID_DESCRIPTION%"
659 );
660 break;
661 }
662 }
663
664 *pSignal = signal;
665
666 return pid;
667 }
668
669 //*************************************************************************
670
read_line(FILE * fp,string & rLine)671 static bool read_line( FILE *fp, string& rLine )
672 {
673 char szBuffer[1024];
674 bool bSuccess = false;
675 bool bEOL = false;
676 string line;
677
678
679 while ( !bEOL && fgets( szBuffer, sizeof(szBuffer), fp ) )
680 {
681 int len = strlen(szBuffer);
682
683 bSuccess = true;
684
685 while ( len && szBuffer[len - 1] == '\n' )
686 {
687 szBuffer[--len] = 0;
688 bEOL = true;
689 }
690
691 line.append( szBuffer );
692 }
693
694 rLine = line;
695 return bSuccess;
696 }
697
get_script_string(const char * pFileName,const char * pKeyName)698 static string get_script_string( const char *pFileName, const char *pKeyName )
699 {
700 FILE *fp = fopen( pFileName, "r" );
701 string retValue;
702
703 if ( fp )
704 {
705 string line;
706 string section;
707
708 while ( read_line( fp, line ) )
709 {
710 line = trim_string( line );
711
712
713 string::size_type iEqualSign = line.find( '=', 0 );
714
715 if ( iEqualSign != string::npos )
716 {
717 string keyname = line.substr( 0, iEqualSign );
718 keyname = trim_string( keyname );
719
720 string value = line.substr( iEqualSign + 1, string::npos );
721 value = trim_string( value );
722
723 if ( value.length() && '\"' == value[0] )
724 {
725 value.erase( 0, 1 );
726
727 string::size_type iQuotes = value.find( '"', 0 );
728
729 if ( iQuotes != string::npos )
730 value.erase( iQuotes );
731 }
732
733 if ( 0 == strcasecmp( keyname.c_str(), pKeyName ) )
734 {
735 retValue = value;
736 break;
737 }
738 }
739 }
740
741 fclose( fp );
742 }
743
744 return retValue;
745 }
746
get_profile_string(const char * pFileName,const char * pSectionName,const char * pKeyName,const char * pDefault=NULL)747 static string get_profile_string( const char *pFileName, const char *pSectionName, const char *pKeyName, const char *pDefault = NULL )
748 {
749 FILE *fp = fopen( pFileName, "r" );
750 string retValue = pDefault ? pDefault : "";
751
752 if ( fp )
753 {
754 string line;
755 string section;
756
757 while ( read_line( fp, line ) )
758 {
759 line = trim_string( line );
760
761 if ( line.length() && line[0] == '[' )
762 {
763 line.erase( 0, 1 );
764 string::size_type end = line.find( ']', 0 );
765
766 if ( string::npos != end )
767 section = trim_string( line.substr( 0, end ) );
768 }
769 else
770 {
771
772 string::size_type iEqualSign = line.find( '=', 0 );
773
774 if ( iEqualSign != string::npos )
775 {
776 string keyname = line.substr( 0, iEqualSign );
777 keyname = trim_string( keyname );
778
779 string value = line.substr( iEqualSign + 1, string::npos );
780 value = trim_string( value );
781
782 if (
783 0 == strcasecmp( section.c_str(), pSectionName ) &&
784 0 == strcasecmp( keyname.c_str(), pKeyName )
785 )
786 {
787 retValue = value;
788 break;
789 }
790 }
791 }
792 }
793
794 fclose( fp );
795 }
796
797 return retValue;
798 }
799
get_environment_string(const char * pEnvName)800 static string get_environment_string( const char *pEnvName )
801 {
802 const char *pEnvValue = getenv( pEnvName );
803
804 if ( pEnvValue )
805 return pEnvValue;
806 else
807 return "";
808 }
809
read_from_file(const string & rFileName)810 static string read_from_file( const string& rFileName )
811 {
812 string content;
813 FILE *fp = fopen( rFileName.c_str(), "r" );
814
815 if ( fp )
816 {
817 char buffer[256 + 1];
818 size_t nBytesRead;
819
820 while( 0 != ( nBytesRead = fread( buffer, 1, sizeof(buffer) - 1, fp ) ) )
821 {
822 buffer[nBytesRead] = 0;
823 content += buffer;
824 }
825
826 fclose( fp );
827 }
828
829 return content;
830 }
831
832 #define RCFILE ".crash_reportrc"
833 #define XMLFILE ".crash_report_frames"
834 #define CHKFILE ".crash_report_checksum"
835 #define LCKFILE ".crash_report_unsent"
836 #define PRVFILE ".crash_report_preview"
837
load_crash_data()838 static void load_crash_data()
839 {
840 g_strXMLFileName = get_home_dir();
841 g_strXMLFileName += "/";
842 g_strXMLFileName += string(XMLFILE);
843
844 g_strChecksumFileName = get_home_dir();
845 g_strChecksumFileName += "/";
846 g_strChecksumFileName += string(CHKFILE);
847 }
848
write_crash_data()849 static bool write_crash_data()
850 {
851 bool success = true;
852 string sFile = get_home_dir();
853
854 sFile += "/";
855 sFile += string(XMLFILE);
856
857 FILE *fp = fopen( sFile.c_str(), "w" );
858
859 if ( fp )
860 {
861 FILE *fpin = fopen( g_strXMLFileName.c_str(), "r" );
862
863 if ( fpin )
864 {
865 fcopy( fp, fpin );
866 fclose( fpin );
867 }
868
869 fclose( fp );
870 }
871
872 sFile = get_home_dir();
873
874 sFile += "/";
875 sFile += string(CHKFILE);
876
877 fp = fopen( sFile.c_str(), "w" );
878
879 if ( fp )
880 {
881 FILE *fpin = fopen( g_strChecksumFileName.c_str(), "r" );
882
883 if ( fpin )
884 {
885 fcopy( fp, fpin );
886 fclose( fpin );
887 }
888
889 fclose( fp );
890 }
891
892 sFile = get_home_dir();
893
894 sFile += "/";
895 sFile += string(LCKFILE);
896
897 fp = fopen( sFile.c_str(), "w" );
898
899 if ( fp )
900 {
901 fprintf( fp, "Unsent\n" );
902 fclose( fp );
903 }
904
905 return success;
906 }
907
908 #if 0
909 // unused
910 static bool write_settings( const hash_map< string, string >& rSettings )
911 {
912 bool success = false;
913 string sRCFile = get_home_dir();
914
915 sRCFile += "/";
916 sRCFile += string(RCFILE);
917
918 FILE *fp = fopen( sRCFile.c_str(), "w" );
919
920 if ( fp )
921 {
922 fprintf( fp, "[Options]\n" );
923 fprintf( fp, "UseProxy=%s\n", rSettings.find( "USEPROXY" )->second.c_str() );
924 fprintf( fp, "ProxyServer=%s\n", rSettings.find( "SERVER" )->second.c_str() );
925 fprintf( fp, "ProxyPort=%s\n", rSettings.find( "PORT" )->second.c_str() );
926 fprintf( fp, "ReturnAddress=%s\n", rSettings.find( "EMAIL" )->second.c_str() );
927 fprintf( fp, "AllowContact=%s\n", rSettings.find( "CONTACT" )->second.c_str() );
928 fclose( fp );
929 }
930
931 return success;
932 }
933 #endif
934
read_settings(hash_map<string,string> & rSettings)935 static void read_settings( hash_map< string, string >& rSettings )
936 {
937 string sRCFile = get_home_dir();
938
939 sRCFile += "/";
940 sRCFile += string(RCFILE);
941
942 rSettings[ "EMAIL" ] = get_profile_string( sRCFile.c_str(), "Options", "ReturnAddress" );
943 rSettings[ "SERVER" ] = get_profile_string( sRCFile.c_str(), "Options", "ProxyServer" );
944 rSettings[ "PORT" ] = get_profile_string( sRCFile.c_str(), "Options", "ProxyPort" );
945 rSettings[ "USEPROXY" ] = get_profile_string( sRCFile.c_str(), "Options", "UseProxy" );
946 rSettings[ "CONTACT" ] = get_profile_string( sRCFile.c_str(), "Options", "AllowContact" );
947 rSettings[ "DESCRIPTION" ] = "";
948 rSettings[ "TITLE" ] = "";
949 }
950
read_settings_from_environment(hash_map<string,string> & rSettings)951 static void read_settings_from_environment( hash_map< string, string >& rSettings )
952 {
953 string strEnv;
954
955 strEnv = get_environment_string( "ERRORREPORT_RETURNADDRESS" );
956 if ( strEnv.length() )
957 {
958 rSettings[ "EMAIL" ] = strEnv;
959 if ( !(rSettings.find( "CONTACT" )->second).length() )
960 rSettings[ "CONTACT" ] = "true";
961 }
962 else if ( !(rSettings.find( "CONTACT" )->second).length() )
963 rSettings[ "CONTACT" ] = "false";
964
965
966 strEnv = get_environment_string( "ERRORREPORT_HTTPPROXYSERVER" );
967 if ( strEnv.length() )
968 rSettings[ "SERVER" ] = strEnv;
969
970 strEnv = get_environment_string( "ERRORREPORT_HTTPPROXYPORT" );
971 if ( strEnv.length() )
972 rSettings[ "PORT" ] = strEnv;
973
974 strEnv = get_environment_string( "ERRORREPORT_HTTPCONNECTIONTYPE" );
975 if ( strEnv.length() )
976 rSettings[ "USEPROXY" ] = 0 == strcasecmp( strEnv.c_str(), "MANUALPROXY" ) ? "true" : "false";
977
978 strEnv = get_environment_string( "ERRORREPORT_BODYFILE" );
979 if ( strEnv.length() )
980 rSettings[ "DESCRIPTION" ] = read_from_file( strEnv );
981
982 strEnv = get_environment_string( "ERRORREPORT_SUBJECT" );
983 if ( strEnv.length() )
984 rSettings[ "TITLE" ] = strEnv;
985 }
986
setup_version()987 static bool setup_version()
988 {
989 if ( !getenv( "PRODUCTNAME" ) )
990 {
991 string productkey = get_profile_string( "bootstraprc", "Bootstrap", "ProductKey" );
992
993 g_strProductKey = productkey;
994
995 if ( productkey.length() )
996 {
997 static string productname;
998 static string productversion;
999 string::size_type iSpace = productkey.find( ' ', 0 );
1000
1001 if ( string::npos != iSpace )
1002 {
1003 productname = productkey.substr( 0, iSpace );
1004 productversion = productkey.substr( iSpace + 1, string::npos );
1005 }
1006 else
1007 productname = productkey;
1008
1009 productname.insert( 0, "PRODUCTNAME=" );
1010 putenv( (char *)productname.c_str() );
1011
1012 productversion.insert( 0, "PRODUCTVERSION=" );
1013 putenv( (char *)productversion.c_str() );
1014 }
1015 }
1016
1017 g_buildid = get_profile_string( "versionrc", "Version", "BuildId" );
1018 g_strDefaultLanguage = get_script_string( "instdb.ins", "DefaultLanguage" );
1019
1020 g_strReportServer = get_profile_string( "bootstraprc", "ErrorReport", "ErrorReportServer" );
1021
1022 string strReportPort = get_profile_string( "bootstraprc", "ErrorReport", "ErrorReportPort", "80" );
1023 char *endptr = NULL;
1024 unsigned short uReportPort = (unsigned short)strtoul( strReportPort.c_str(), &endptr, 10 );
1025 g_uReportPort = uReportPort ? uReportPort : 80;
1026
1027 return 0 != g_strReportServer.length();
1028 }
1029
1030 #if 0
1031 // Use gconftool-2 to determine if gnome accessiblity is enabled
1032 // unused
1033 static bool get_accessibility_state()
1034 {
1035 bool bAccessible = false;
1036 FILE *fin = popen( "gconftool-2 -g /desktop/gnome/interface/accessibility", "r");
1037
1038 if ( fin )
1039 {
1040 char buffer[sizeof("true")];
1041
1042 bAccessible = fgets( buffer, sizeof(buffer), fin ) && 0 == strcmp( buffer, "true" );
1043
1044 pclose( fin );
1045 }
1046
1047 return bAccessible;
1048 }
1049 #endif
1050
main(int argc,char ** argv)1051 int main( int argc, char** argv )
1052 {
1053 freopen( "/dev/null", "w", stderr );
1054
1055 setup_program_dir( argv[0] );
1056
1057 // Don't start if accessiblity is enabled or report server is not given
1058
1059 if ( setup_version() )
1060 {
1061 /*long pid =*/ setup_commandline_arguments( argc, argv, &g_signal );
1062
1063 if ( g_bLoadReport )
1064 {
1065 load_crash_data();
1066 }
1067
1068 if ( g_bSendReport )
1069 {
1070 hash_map< string, string > aDialogSettings;
1071
1072 read_settings( aDialogSettings );
1073 read_settings_from_environment( aDialogSettings );
1074
1075 send_crash_report( aDialogSettings );
1076 }
1077 else
1078 {
1079 hash_map< string, string > aDialogSettings;
1080
1081 read_settings( aDialogSettings );
1082 read_settings_from_environment( aDialogSettings );
1083
1084 write_crash_data();
1085 write_report( aDialogSettings );
1086
1087 string sPreviewFile = get_home_dir();
1088 sPreviewFile += "/";
1089 sPreviewFile += string(PRVFILE);
1090
1091 FILE *fpout = fopen( sPreviewFile.c_str(), "w+" );
1092 if ( fpout )
1093 {
1094 FILE *fpin = fopen( g_szReportFile, "r" );
1095 if ( fpin )
1096 {
1097 fcopy( fpout, fpin );
1098 fclose( fpin );
1099 }
1100 fclose( fpout );
1101 }
1102
1103 unlink( g_szReportFile );
1104 }
1105
1106 if ( g_bLoadReport )
1107 {
1108 unlink( g_strXMLFileName.c_str() );
1109 unlink( g_strChecksumFileName.c_str() );
1110 }
1111
1112 unlink( g_szStackFile );
1113
1114 return 0;
1115 }
1116
1117 return -1;
1118 }
1119