libStatGen Software  1
PhoneHome.cpp
1 /*
2  * Copyright (C) 2013 Regents of the University of Michigan
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "PhoneHome.h"
19 #include "knetfile.h"
20 
21 #include <time.h>
22 #include <iostream>
23 #include <string.h>
24 
25 int PhoneHome::allThinning = 50;
26 int PhoneHome::ourNumber = -1;
27 
28 bool PhoneHome::ourEnableCompletionStatus = false;
29 std::string PhoneHome::ourBaseURL = "http://csgph.sph.umich.edu/ph/";
30 std::string PhoneHome::ourURL = ourBaseURL;
31 char PhoneHome::ourPrefixChar = '?';
32 String PhoneHome::ourReturnString = "";
33 String PhoneHome::ourToolName = "";
34 
35 void PhoneHome::enableCompletionStatus(const char* programName)
36 {
37  if(programName != NULL)
38  {
39  add("pgm", programName);
40  }
41  ourEnableCompletionStatus = true;
42 }
43 
44 
45 void PhoneHome::disableCompletionStatus()
46 {
47  ourEnableCompletionStatus = false;
48 }
49 
50 
51 bool PhoneHome::checkVersion(const char* programName, const char* version,
52  const char* params)
53 {
54  enableCompletionStatus();
55  add("pgm", programName);
56  add("vsn", version);
57  add("args", params);
58 
59  connect();
60 
61  // Look for this program in the returned string.
62  int start = ourReturnString.Find(ourToolName+"\t");
63  if(start < 0)
64  {
65  // Parse the toolName, and check for the program name
66  // just up to a ':'
67  int colStart = ourToolName.FastFindChar(':');
68  if(colStart >= 0)
69  {
70  ourToolName.SetLength(colStart);
71  start = ourReturnString.Find(ourToolName+"\t");
72  }
73  }
74 
75  if(start < 0)
76  {
77  // This program name was not found in the version file,
78  // so it is a program for which version is not tracked,
79  // just return true.
80  return(true);
81  }
82 
83  // Found this program, so extract the version.
84  start += ourToolName.Length();
85  while((start < ourReturnString.Length()) &&
86  isspace(ourReturnString[start]))
87  {
88  // Consume whitespace
89  ++start;
90  }
91 
92  // Start now contains the position of the start of the version
93  String thisVersion = version;
94  String latestVersion;
95  int end = start;
96  while((end < ourReturnString.Length()) &&
97  !isspace(ourReturnString[end]))
98  {
99  latestVersion += ourReturnString[end];
100  ++end;
101  }
102 
103  // std::cerr << "latest version = " << latestVersion << "\nthis version = " << thisVersion.c_str() << "\n";
104 
105  if(latestVersion.FastCompare(thisVersion) > 0)
106  {
107  std::cerr << "\n**************************************************************************************\n"
108  << "A new version, " << latestVersion
109  << ", of " << ourToolName
110  << " is available (currently running "
111  << thisVersion.c_str() << ")"
112  << "\n**************************************************************************************\n\n";
113  return(false);
114  }
115  return(true);
116 }
117 
118 void PhoneHome::completionStatus(const char* status, const char* programName)
119 {
120  if(programName != NULL)
121  {
122  add("pgm", programName);
123  enableCompletionStatus();
124  }
125  if(ourEnableCompletionStatus)
126  {
127  add("status", status);
128  connect();
129  }
130 }
131 
132 
133 void PhoneHome::resetURL()
134 {
135  ourURL = ourBaseURL;
136  ourPrefixChar = '?';
137 }
138 
139 
140 void PhoneHome::add(const char* name, const char* val)
141 {
142  if((name != NULL) && (strlen(name) != 0) &&
143  (val != NULL) && (strlen(val) != 0))
144  {
145  // Check if the value is already set.
146  if(ourURL.find(name) != std::string::npos)
147  {
148  // value already set, so do not set it.
149  return;
150  }
151 
152  // A value was passed in, so add it to the URL.
153  ourURL += ourPrefixChar;
154  ourURL += name;
155  ourURL += '=';
156  // If it is a tool name, trim anything before the last '/'
157  if(strstr(name, "pgm") != NULL)
158  {
159  // toolname, so trim the val.
160  const char* toolVal = strrchr(val, '/');
161  if(toolVal != NULL)
162  {
163  toolVal++;
164  }
165  else
166  {
167  toolVal = val;
168  }
169  ourURL.append(toolVal);
170  ourToolName = toolVal;
171  }
172  else
173  {
174  ourURL += val;
175  }
176  ourPrefixChar = '&';
177  }
178 }
179 
180 
181 bool PhoneHome::connect()
182 {
183  if(ourNumber == -1)
184  {
185  srand (time(NULL));
186  ourNumber = rand();
187  String numString;
188  numString = ourNumber;
189  String thinningString;
190  thinningString = allThinning;
191  add("uniqNum", numString);
192  add("thinning", thinningString);
193  }
194  if((ourNumber % 100) >= allThinning)
195  {
196  // Skip phoneHome.
197  return(true);
198  }
199 
200  // std::cerr << "url = " << ourURL << std::endl;
201  ourReturnString.Clear();
202  // return(true);
203 #ifndef _NO_PHONEHOME
204  knet_silent(1);
205  knetFile *file = knet_open(ourURL.c_str(), "r");
206  if (file == 0) return(false);
207 
208  const int BUF_SIZE = 100;
209  char buf[BUF_SIZE];
210 
211  ssize_t readLen = BUF_SIZE-1;
212  ssize_t numRead = readLen;
213  while(numRead == readLen)
214  {
215  numRead = knet_read(file, buf, readLen);
216  buf[numRead] = '\0';
217  ourReturnString += buf;
218  }
219 
220  knet_close(file);
221  knet_silent(0);
222  // std::cerr << "PhoneHome URL = " << ourReturnString.c_str() << std::endl;
223 #endif
224  return(true);
225 }
String
Definition: StringBasics.h:39
knetFile_s
Definition: knetfile.h:24