|
1
|
|
|
#! /usr/bin/env php |
|
2
|
|
|
|
|
|
|
|
|
|
3
|
|
|
<?php |
|
|
|
|
|
|
4
|
|
|
// This file is part of BOINC. |
|
5
|
|
|
// http://boinc.berkeley.edu |
|
6
|
|
|
// Copyright (C) 2008 University of California |
|
7
|
|
|
// |
|
8
|
|
|
// BOINC is free software; you can redistribute it and/or modify it |
|
9
|
|
|
// under the terms of the GNU Lesser General Public License |
|
10
|
|
|
// as published by the Free Software Foundation, |
|
11
|
|
|
// either version 3 of the License, or (at your option) any later version. |
|
12
|
|
|
// |
|
13
|
|
|
// BOINC is distributed in the hope that it will be useful, |
|
14
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
16
|
|
|
// See the GNU Lesser General Public License for more details. |
|
17
|
|
|
// |
|
18
|
|
|
// You should have received a copy of the GNU Lesser General Public License |
|
19
|
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>. |
|
20
|
|
|
|
|
21
|
|
|
// remind.php [--lapsed | --failed] [--show_email] [--userid ID] |
|
22
|
|
|
// |
|
23
|
|
|
// --lapsed |
|
24
|
|
|
// Send emails to lapsed user (see below) |
|
25
|
|
|
// --failed |
|
26
|
|
|
// Send emails to failed user (see below) |
|
27
|
|
|
// --userid |
|
28
|
|
|
// Send both "lapsed" and "failed" emails to the given user, |
|
29
|
|
|
// regardless of whether they are due to be sent. |
|
30
|
|
|
// The --lapsed and --failed options are ignored. |
|
31
|
|
|
// (for testing) |
|
32
|
|
|
// --show_email |
|
33
|
|
|
// Show the text that would be mailed |
|
34
|
|
|
// --explain |
|
35
|
|
|
// Show which users would be sent email and why |
|
36
|
|
|
// --send |
|
37
|
|
|
// Actually send emails (this is an option to encourage |
|
38
|
|
|
// you to do thorough testing before using it) |
|
39
|
|
|
// --count N |
|
40
|
|
|
// By default send to all users that qualify, but if count is |
|
41
|
|
|
// set, only send to N users at a time |
|
42
|
|
|
// |
|
43
|
|
|
// This program sends "reminder" emails to |
|
44
|
|
|
// - failed users: those who |
|
45
|
|
|
// 1) were created at least $start_interval seconds ago, |
|
46
|
|
|
// 2) have zero total credit |
|
47
|
|
|
// 3) haven't been sent an email in at least $email_interval seconds. |
|
48
|
|
|
// These people typically either had a technical glitch, |
|
49
|
|
|
// or their prefs didn't allow sending them work, |
|
50
|
|
|
// or the app crashed on their host. |
|
51
|
|
|
// The email should direct them to a web page that helps |
|
52
|
|
|
// them fix the startup problem. |
|
53
|
|
|
// |
|
54
|
|
|
// Set $start_interval according to your project's delay bounds |
|
55
|
|
|
// e.g. (1 or 2 weeks). |
|
56
|
|
|
/// $email_interval should be roughly 1 month - |
|
57
|
|
|
// we don't want to bother people too often. |
|
58
|
|
|
// |
|
59
|
|
|
// - lapsed users: those who |
|
60
|
|
|
// 1) have positive total credit, |
|
61
|
|
|
// 2) haven't done a scheduler RPC within the past |
|
62
|
|
|
// $lapsed_interval seconds, and |
|
63
|
|
|
// 3) haven't been sent an email in at least $email_interval seconds. |
|
64
|
|
|
// The email should gently prod them to start running the project again. |
|
65
|
|
|
// |
|
66
|
|
|
|
|
67
|
|
|
$cli_only = true; |
|
68
|
|
|
require_once("../inc/util_ops.inc"); |
|
69
|
|
|
require_once("../inc/email.inc"); |
|
70
|
|
|
|
|
71
|
|
|
db_init(); |
|
72
|
|
|
set_time_limit(0); |
|
73
|
|
|
|
|
74
|
|
|
$globals->start_interval = 14*86400; |
|
75
|
|
|
$globals->email_interval = 200*86400; |
|
76
|
|
|
$globals->lapsed_interval = 60*86400; |
|
77
|
|
|
$globals->do_failed = false; |
|
78
|
|
|
$globals->do_lapsed = false; |
|
79
|
|
|
$globals->show_email = false; |
|
80
|
|
|
$globals->send = false; |
|
81
|
|
|
$globals->explain = false; |
|
82
|
|
|
$globals->userid = 0; |
|
83
|
|
|
$globals->count = -1; |
|
84
|
|
|
|
|
85
|
|
|
for ($i=1; $i<$argc; $i++) { |
|
86
|
|
|
if ($argv[$i] == "--failed") { |
|
87
|
|
|
$globals->do_failed = true; |
|
88
|
|
|
} elseif ($argv[$i] == "--lapsed") { |
|
89
|
|
|
$globals->do_lapsed = true; |
|
90
|
|
|
} elseif ($argv[$i] == "--show_email") { |
|
91
|
|
|
$globals->show_email = true; |
|
92
|
|
|
} elseif ($argv[$i] == "--explain") { |
|
93
|
|
|
$globals->explain = true; |
|
94
|
|
|
} elseif ($argv[$i] == "--send") { |
|
95
|
|
|
$globals->send = true; |
|
96
|
|
|
} elseif ($argv[$i] == "--userid") { |
|
97
|
|
|
$i++; |
|
98
|
|
|
$globals->userid = $argv[$i]; |
|
99
|
|
|
} elseif ($argv[$i] == "--count") { |
|
100
|
|
|
$i++; |
|
101
|
|
|
$globals->count = $argv[$i]; |
|
102
|
|
|
} else { |
|
103
|
|
|
echo "unrecognized option $argv[$i]\n"; |
|
104
|
|
|
echo "usage: remind.php [--failed ] [--lapsed] [--userid N] [--show_mail] [--explain] [--send] [--count N]\n"; |
|
105
|
|
|
exit (1); |
|
106
|
|
|
} |
|
107
|
|
|
} |
|
108
|
|
|
|
|
109
|
|
|
// File names for the various mail types. |
|
110
|
|
|
// Change these here if needed. |
|
111
|
|
|
// |
|
112
|
|
|
$dir = "remind_email"; |
|
113
|
|
|
$failed_html = "$dir/reminder_failed_html"; |
|
114
|
|
|
$failed_text = "$dir/reminder_failed_text"; |
|
115
|
|
|
$failed_subject = "$dir/reminder_failed_subject"; |
|
116
|
|
|
$lapsed_html = "$dir/reminder_lapsed_html"; |
|
117
|
|
|
$lapsed_text = "$dir/reminder_lapsed_text"; |
|
118
|
|
|
$lapsed_subject = "$dir/reminder_lapsed_subject"; |
|
119
|
|
|
|
|
120
|
|
|
// return time of last scheduler RPC from this user, |
|
121
|
|
|
// or zero if they're never done one |
|
122
|
|
|
// |
|
123
|
|
|
function last_rpc_time($user) { |
|
124
|
|
|
$x = 0; |
|
125
|
|
|
$result = _mysql_query("select rpc_time from host where userid=$user->id"); |
|
126
|
|
|
while ($host = _mysql_fetch_object($result)) { |
|
127
|
|
|
if ($host->rpc_time > $x) $x = $host->rpc_time; |
|
128
|
|
|
} |
|
129
|
|
|
_mysql_free_result($result); |
|
130
|
|
|
return $x; |
|
131
|
|
|
} |
|
132
|
|
|
|
|
133
|
|
|
function read_files(&$item) { |
|
134
|
|
|
$item['html'] = @file_get_contents($item['html_file']); |
|
135
|
|
|
if (!$item['html']) { |
|
|
|
|
|
|
136
|
|
|
//$x = $item['html_file']; |
|
137
|
|
|
//echo "file missing: $x\n"; |
|
138
|
|
|
//exit(); |
|
139
|
|
|
} |
|
140
|
|
|
$item['text'] = @file_get_contents($item['text_file']); |
|
141
|
|
|
if (!$item['text']) { |
|
142
|
|
|
$x = $item['text_file']; |
|
143
|
|
|
echo "file missing: $x\n"; |
|
144
|
|
|
exit(); |
|
|
|
|
|
|
145
|
|
|
} |
|
146
|
|
|
$item['subject'] = @file_get_contents($item['subject']); |
|
147
|
|
|
if (!$item['subject']) { |
|
148
|
|
|
$x = $item['subject']; |
|
149
|
|
|
echo "file missing: $x\n"; |
|
150
|
|
|
exit(); |
|
|
|
|
|
|
151
|
|
|
} |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
function read_email_files() { |
|
155
|
|
|
global $failed_html; |
|
156
|
|
|
global $failed_text; |
|
157
|
|
|
global $failed_subject; |
|
158
|
|
|
global $lapsed_html; |
|
159
|
|
|
global $lapsed_text; |
|
160
|
|
|
global $lapsed_subject; |
|
161
|
|
|
|
|
162
|
|
|
$failed['html_file'] = $failed_html; |
|
163
|
|
|
$failed['text_file'] = $failed_text; |
|
164
|
|
|
$failed['subject'] = $failed_subject; |
|
165
|
|
|
$lapsed['html_file'] = $lapsed_html; |
|
166
|
|
|
$lapsed['text_file'] = $lapsed_text; |
|
167
|
|
|
$lapsed['subject'] = $lapsed_subject; |
|
168
|
|
|
read_files($failed); |
|
169
|
|
|
read_files($lapsed); |
|
170
|
|
|
$email_files['failed'] = $failed; |
|
171
|
|
|
$email_files['lapsed'] = $lapsed; |
|
172
|
|
|
return $email_files; |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
function replace($user, $template) { |
|
176
|
|
|
$pat = array( |
|
177
|
|
|
'/<name\/>/', |
|
178
|
|
|
'/<email\/>/', |
|
179
|
|
|
'/<create_time\/>/', |
|
180
|
|
|
'/<total_credit\/>/', |
|
181
|
|
|
'/<opt_out_url\/>/', |
|
182
|
|
|
'/<user_id\/>/', |
|
183
|
|
|
'/<lapsed_interval\/>/', |
|
184
|
|
|
); |
|
185
|
|
|
$rep = array( |
|
186
|
|
|
$user->name, |
|
187
|
|
|
$user->email_addr, |
|
188
|
|
|
gmdate('d F Y', $user->create_time), |
|
189
|
|
|
number_format($user->total_credit, 0), |
|
190
|
|
|
opt_out_url($user), |
|
191
|
|
|
$user->id, |
|
192
|
|
|
floor ((time() - last_rpc_time($user)) / 86400), |
|
193
|
|
|
); |
|
194
|
|
|
return preg_replace($pat, $rep, $template); |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
function mail_type($user, $type) { |
|
198
|
|
|
global $globals; |
|
199
|
|
|
global $email_files; |
|
200
|
|
|
|
|
201
|
|
|
$email_file = $email_files[$type]; |
|
202
|
|
|
if ($email_file['html']) { |
|
203
|
|
|
$html = replace($user, $email_file['html']); |
|
204
|
|
|
} else { |
|
205
|
|
|
$html = null; |
|
206
|
|
|
} |
|
207
|
|
|
$text = replace($user, $email_file['text']); |
|
208
|
|
|
if ($globals->show_email) { |
|
209
|
|
|
echo "------- SUBJECT ----------\n"; |
|
210
|
|
|
echo $email_file['subject']; |
|
211
|
|
|
echo "\n------- HTML ----------\n"; |
|
212
|
|
|
echo $html; |
|
213
|
|
|
echo "\n------- TEXT ----------\n"; |
|
214
|
|
|
echo $text; |
|
215
|
|
|
} |
|
216
|
|
|
if ($globals->send) { |
|
217
|
|
|
echo "sending to $user->email_addr\n"; |
|
218
|
|
|
echo send_email( |
|
219
|
|
|
$user, |
|
220
|
|
|
$email_file['subject'], |
|
221
|
|
|
$text, |
|
222
|
|
|
$html |
|
223
|
|
|
); |
|
224
|
|
|
$now = time(); |
|
225
|
|
|
$ntype = 0; |
|
226
|
|
|
if ($type == 'lapsed') $ntype = 2; |
|
227
|
|
|
if ($type == 'failed') $ntype = 3; |
|
228
|
|
|
$query = "insert into sent_email values($user->id, $now, $ntype)"; |
|
229
|
|
|
_mysql_query($query); |
|
230
|
|
|
} |
|
231
|
|
|
$globals->count--; |
|
232
|
|
|
if ($globals->count == 0) { |
|
233
|
|
|
echo "reached limit set by --count - exiting...\n"; |
|
234
|
|
|
exit(); |
|
|
|
|
|
|
235
|
|
|
} |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
function last_reminder_time($user) { |
|
239
|
|
|
$query = "select * from sent_email where userid=$user->id"; |
|
240
|
|
|
$result = _mysql_query($query); |
|
241
|
|
|
$t = 0; |
|
242
|
|
|
while ($r = _mysql_fetch_object($result)) { |
|
243
|
|
|
if ($r->email_type !=2 && $r->email_type != 3) continue; |
|
244
|
|
|
if ($r->time_sent > $t) $t = $r->time_sent; |
|
245
|
|
|
|
|
246
|
|
|
} |
|
247
|
|
|
_mysql_free_result($result); |
|
248
|
|
|
return $t; |
|
249
|
|
|
} |
|
250
|
|
|
|
|
251
|
|
|
function handle_user($user, $do_type) { |
|
252
|
|
|
global $globals; |
|
253
|
|
|
global $email_interval; |
|
254
|
|
|
|
|
255
|
|
|
if ($user->send_email == 0) { |
|
256
|
|
|
if ($globals->explain) { |
|
257
|
|
|
echo "user: $user->id send_email = 0\n"; |
|
258
|
|
|
} |
|
259
|
|
|
return; |
|
260
|
|
|
} |
|
261
|
|
|
$max_email_time = time() - $globals->email_interval; |
|
262
|
|
|
if (last_reminder_time($user) > $max_email_time) { |
|
263
|
|
|
if ($globals->explain) { |
|
264
|
|
|
echo "user: $user->id sent too recently\n"; |
|
265
|
|
|
} |
|
266
|
|
|
return; |
|
267
|
|
|
} |
|
268
|
|
|
if ($globals->explain) { |
|
269
|
|
|
$x = (time() - $user->create_time)/86400; |
|
270
|
|
|
$t = last_rpc_time($user); |
|
271
|
|
|
$show_lapsed_interval = (time()-$t)/86400; |
|
272
|
|
|
echo "user $user->id ($user->email_addr) was created $x days ago\n"; |
|
273
|
|
|
echo " total_credit: $user->total_credit; last RPC $show_lapsed_interval days ago\n"; |
|
274
|
|
|
echo " sending $do_type email\n"; |
|
275
|
|
|
} |
|
276
|
|
|
mail_type($user, $do_type); |
|
277
|
|
|
} |
|
278
|
|
|
|
|
279
|
|
|
function do_failed() { |
|
280
|
|
|
global $globals; |
|
281
|
|
|
|
|
282
|
|
|
$max_create_time = time() - $globals->start_interval; |
|
283
|
|
|
$result = _mysql_query( |
|
284
|
|
|
"select * from user where send_email<>0 and create_time<$max_create_time and total_credit = 0;" |
|
285
|
|
|
); |
|
286
|
|
|
while ($user = _mysql_fetch_object($result)) { |
|
287
|
|
|
handle_user($user, 'failed'); |
|
288
|
|
|
} |
|
289
|
|
|
_mysql_free_result($result); |
|
290
|
|
|
} |
|
291
|
|
|
|
|
292
|
|
|
function do_lapsed() { |
|
293
|
|
|
global $globals; |
|
294
|
|
|
$max_last_rpc_time = time() - $globals->lapsed_interval; |
|
295
|
|
|
|
|
296
|
|
|
// the following is an efficient way of getting the list of |
|
297
|
|
|
// users for which no host has done an RPC recently |
|
298
|
|
|
// |
|
299
|
|
|
$result = _mysql_query( |
|
300
|
|
|
"select userid from host group by userid having max(rpc_time)<$max_last_rpc_time;" |
|
301
|
|
|
); |
|
302
|
|
|
while ($host = _mysql_fetch_object($result)) { |
|
303
|
|
|
$uresult = _mysql_query("select * from user where id = $host->userid;"); |
|
304
|
|
|
$user = _mysql_fetch_object($uresult); |
|
305
|
|
|
_mysql_free_result($uresult); |
|
306
|
|
|
if (!$user) { |
|
307
|
|
|
echo "Can't find user $host->userid\n"; |
|
308
|
|
|
continue; |
|
309
|
|
|
} |
|
310
|
|
|
handle_user($user, 'lapsed'); |
|
311
|
|
|
} |
|
312
|
|
|
_mysql_free_result($result); |
|
313
|
|
|
} |
|
314
|
|
|
|
|
315
|
|
|
if (!function_exists('make_php_mailer')) { |
|
316
|
|
|
echo "You must use PHPMailer (http://phpmailer.sourceforge.net)\n"; |
|
317
|
|
|
exit(); |
|
318
|
|
|
} |
|
319
|
|
|
|
|
320
|
|
|
$email_files = read_email_files(); |
|
321
|
|
|
|
|
322
|
|
|
if ($globals->userid) { |
|
323
|
|
|
$user = BoincUser::lookup_id($globals->userid); |
|
324
|
|
|
if (!$user) { |
|
325
|
|
|
echo "No such user: $globals->userid\n"; |
|
326
|
|
|
exit(); |
|
327
|
|
|
} |
|
328
|
|
|
$user->last_rpc_time = last_rpc_time($user); |
|
329
|
|
|
mail_type($user, 'failed'); |
|
330
|
|
|
mail_type($user, 'lapsed'); |
|
331
|
|
|
} else { |
|
332
|
|
|
if ($globals->do_failed) { |
|
333
|
|
|
do_failed(); |
|
334
|
|
|
} |
|
335
|
|
|
if ($globals->do_lapsed) { |
|
336
|
|
|
do_lapsed(); |
|
337
|
|
|
} |
|
338
|
|
|
} |
|
339
|
|
|
|
|
340
|
|
|
?> |
|
341
|
|
|
|