libStatGen Software  1
PhoneHome.cpp
00001 /*
00002  *  Copyright (C) 2013  Regents of the University of Michigan
00003  *
00004  *   This program is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #include "PhoneHome.h"
00019 #include "knetfile.h"
00020 
00021 #include <time.h>
00022 #include <iostream>
00023 #include <string.h>
00024 
00025 int PhoneHome::allThinning = 50;
00026 int PhoneHome::ourNumber = -1;
00027 
00028 bool PhoneHome::ourEnableCompletionStatus = false;
00029 std::string PhoneHome::ourBaseURL = "http://csgph.sph.umich.edu/ph/";
00030 std::string PhoneHome::ourURL = ourBaseURL;
00031 char PhoneHome::ourPrefixChar = '?';
00032 String PhoneHome::ourReturnString = "";
00033 String PhoneHome::ourToolName = "";
00034 
00035 void PhoneHome::enableCompletionStatus(const char* programName)
00036 {
00037     if(programName != NULL)
00038     {
00039         add("pgm", programName);
00040     }
00041     ourEnableCompletionStatus = true;
00042 }
00043 
00044 
00045 void PhoneHome::disableCompletionStatus()
00046 {
00047     ourEnableCompletionStatus = false;
00048 }
00049 
00050 
00051 bool PhoneHome::checkVersion(const char* programName, const char* version,
00052                              const char* params)
00053 {
00054     enableCompletionStatus();
00055     add("pgm", programName);
00056     add("vsn", version);
00057     add("args", params);
00058 
00059     connect();
00060 
00061     // Look for this program in the returned string.
00062     int start = ourReturnString.Find(ourToolName+"\t");
00063     if(start < 0)
00064     {
00065         // Parse the toolName, and check for the program name
00066         // just up to a ':'
00067         int colStart = ourToolName.FastFindChar(':');
00068         if(colStart >= 0)
00069         {
00070             ourToolName.SetLength(colStart);
00071             start = ourReturnString.Find(ourToolName+"\t");
00072         }
00073     }
00074 
00075     if(start < 0)
00076     {
00077         // This program name was not found in the version file,
00078         // so it is a program for which version is not tracked,
00079         // just return true.
00080         return(true);
00081     }
00082 
00083     // Found this program, so extract the version.
00084     start += ourToolName.Length();
00085     while((start < ourReturnString.Length()) && 
00086            isspace(ourReturnString[start]))
00087     {
00088         // Consume whitespace
00089         ++start;
00090     }
00091 
00092     // Start now contains the position of the start of the version
00093     String thisVersion = version;
00094     String latestVersion;
00095     int end = start;
00096     while((end < ourReturnString.Length()) && 
00097           !isspace(ourReturnString[end]))
00098     {
00099         latestVersion += ourReturnString[end];
00100         ++end;
00101     }
00102 
00103     //    std::cerr << "latest version = " << latestVersion << "\nthis version = " << thisVersion.c_str() << "\n";
00104 
00105     if(latestVersion.FastCompare(thisVersion) > 0)
00106     {
00107         std::cerr << "\n**************************************************************************************\n"
00108                   << "A new version, " << latestVersion 
00109                   << ", of " << ourToolName
00110                   << " is available (currently running " 
00111                   << thisVersion.c_str() << ")"
00112                   << "\n**************************************************************************************\n\n";
00113         return(false);
00114     }
00115     return(true);
00116 }
00117 
00118 void PhoneHome::completionStatus(const char* status, const char* programName)
00119 {
00120     if(programName != NULL)
00121     {
00122         add("pgm", programName);
00123         enableCompletionStatus();
00124     }
00125     if(ourEnableCompletionStatus)
00126     {
00127         add("status", status);
00128         connect();
00129     }
00130 }
00131 
00132 
00133 void PhoneHome::resetURL()
00134 {
00135     ourURL = ourBaseURL;
00136     ourPrefixChar = '?';
00137 }
00138 
00139 
00140 void PhoneHome::add(const char* name, const char* val)
00141 {
00142     if((name != NULL) && (strlen(name) != 0) &&
00143        (val != NULL) && (strlen(val) != 0))
00144     {
00145         // Check if the value is already set.
00146         if(ourURL.find(name) != std::string::npos)
00147         {
00148             // value already set, so do not set it.
00149             return;
00150         }
00151 
00152         // A value was passed in, so add it to the URL.
00153         ourURL += ourPrefixChar;
00154         ourURL += name;
00155         ourURL += '=';
00156         // If it is a tool name, trim anything before the last '/'
00157         if(strstr(name, "pgm") != NULL)
00158         {
00159             // toolname, so trim the val.
00160             const char* toolVal = strrchr(val, '/');
00161             if(toolVal != NULL)
00162             {
00163                 toolVal++;
00164             }
00165             else
00166             {
00167                 toolVal = val;
00168             }
00169             ourURL.append(toolVal);
00170             ourToolName =  toolVal;
00171         }
00172         else
00173         {
00174             ourURL += val;
00175         }
00176         ourPrefixChar = '&';
00177     }
00178 }
00179 
00180 
00181 bool PhoneHome::connect()
00182 {
00183     if(ourNumber == -1)
00184     {
00185         srand (time(NULL));
00186         ourNumber = rand();
00187         String numString;
00188         numString = ourNumber;
00189         String thinningString;
00190         thinningString = allThinning;
00191         add("uniqNum", numString);
00192         add("thinning", thinningString);
00193     }
00194     if((ourNumber % 100) >= allThinning)
00195     {
00196         // Skip phoneHome.
00197         return(true);
00198     }
00199 
00200     // std::cerr << "url = " << ourURL << std::endl;
00201     ourReturnString.Clear();
00202     //  return(true);
00203 #ifndef _NO_PHONEHOME
00204     knet_silent(1);
00205     knetFile *file = knet_open(ourURL.c_str(), "r");
00206     if (file == 0) return(false);
00207 
00208     const int BUF_SIZE = 100;
00209     char buf[BUF_SIZE];
00210 
00211     ssize_t readLen = BUF_SIZE-1;
00212     ssize_t numRead = readLen;
00213     while(numRead == readLen)
00214     {
00215         numRead = knet_read(file, buf, readLen);
00216         buf[numRead] = '\0';
00217         ourReturnString += buf;
00218     }
00219 
00220     knet_close(file);
00221     knet_silent(0);
00222     // std::cerr << "PhoneHome URL = " << ourReturnString.c_str() << std::endl;
00223 #endif
00224     return(true);
00225 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends