Issues (1839)

modules/boincwork/includes/boincwork.forms.inc (41 issues)

1
<?php
2
// $Id$
3
4
/**
5
 * Form submission handlers and data processing functions are contained
6
 * herein to prevent littering of the main module file.
7
 */
8
9
10
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
11
 * General preferences form handlers and functions
12
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
13
14
/**
15
 * The structure of the general preferences form
16
 */
17
function boincwork_generalprefs_form(&$form_state, $venue, $prefs_preset = null, $advanced = FALSE) {
18
  $form = array();
19
  $prefs = null;
20
  $established = TRUE;
21
22
  // Enable AHAH form support for dynamically updating content based on preset
23
  ahah_helper_register($form, $form_state);
24
25
  if (!$prefs_preset) {
26
    if (isset($form_state['storage']['prefs']['preset'])) {
27
      $prefs_preset = $form_state['storage']['prefs']['preset'];
28
    }
29
30
    // Load preferences from BOINC account
31
    $prefs = boincwork_load_prefs('general', $venue);
32
33
    // Take note if this is not an established preference set on the account
34
    if (isset($prefs['@attributes']['cleared'])) {
35
      $established = FALSE;
36
    }
37
38
    // Determine if a preset is selected or if these are custom settings
39
    // transform old way to store the preset into new way
40
    if (isset($prefs['@attributes']['preset'])) {
41
        $prefs['preset'] = $prefs['@attributes']['preset'];
42
        unset($prefs['@attributes']['preset']);
43
    }
44
    // Set $prefs_preset if preset tag is present in database.
45
    if (!$prefs_preset) {
46
        if (isset($prefs['preset'])) {
47
            $prefs_preset = $prefs['preset']['@value'];
48
        }
49
    }// if !$prefs_preset
50
  }
51
  // Extract mod_time tag if present, because it will be erased with
52
  // boincwork_get_preset_prefs() below.
53
  $mod_time = null;
54
  if (isset($prefs['mod_time']['@value'])) {
55
      $mod_time = $prefs['mod_time']['@value'];
56
  }
57
58
  if (isset($form_state['storage']['wip'])) {
59
      switch ($prefs_preset) {
60
      case 'standard':
61
      case 'maximum':
62
      case 'green':
63
      case 'minimum':
64
          $prefs = boincwork_get_preset_prefs($prefs_preset);
65
          break;
66
      case 'custom':
67
      default:
0 ignored issues
show
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
68
          // Just keeps prefs as they are
69
          unset($prefs['preset']);
70
          break;
71
      }// switch
72
  } else {
73
      $form_state['storage']['wip'] = TRUE;
74
      if ( !in_array($prefs_preset, array('standard','maximum','green','minimum','custom')) ) {
75
          if ($established) {
76
              $prefs_preset = 'custom';
77
          } else {
78
              $prefs_preset = 'standard';
79
              $prefs = boincwork_get_preset_prefs($prefs_preset);
80
          }// if $established
81
      }// if $prefs_preset
82
  }// if WIP
83
84
  // This set of preferences is used in the form if no preferences
85
  // have been set above, in variable $prefs.
86
  require_boinc(array('db', 'prefs'));
87
  $disk_space_config = get_disk_space_config();
88
  $default = array(
89
    'preset' => $prefs_preset,
90
    // Processing...
91
    'run_on_batteries' => 0,
92
    'run_if_user_active' => 0,
93
    'run_gpu_if_user_active' => 1,
94
    'idle_time_to_run' => 3,
95
    'suspend_if_no_recent_input' => 0,
96
    'suspend_cpu_usage' => 0,
97
    'start_hour' => 0,
98
    'end_hour' => 0,
99
    'leave_apps_in_memory' => 0,
100
    'cpu_scheduling_period_minutes' => 60,
101
    'max_ncpus_pct' => 100,
102
    'cpu_usage_limit' => 100,
103
    // Storage...
104
    'disk_max_used_gb' => $disk_space_config->disk_max_used_gb,
105
    'disk_min_free_gb' => $disk_space_config->disk_min_free_gb,
106
    'disk_max_used_pct' => $disk_space_config->disk_max_used_pct,
107
    'disk_interval' => 60,
108
    'vm_max_used_pct' => 75,
109
    'ram_max_used_busy_pct' => 50,
110
    'ram_max_used_idle_pct' => 90,
111
    // Network...
112
    'work_buf_min_days' => 0,
113
    'work_buf_additional_days' => 0.25,
114
    'confirm_before_connecting' => 0,
115
    'hangup_if_dialed' => 0,
116
    'max_bytes_sec_down' => 0,
117
    'max_bytes_sec_up' => 0,
118
    'net_start_hour' => 0,
119
    'net_end_hour' => 0,
120
    'daily_xfer_limit_mb' => 0,
121
    'daily_xfer_period_days' => 0,
122
    'dont_verify_images' => 0
123
  );
124
  foreach ($default as $name => $value) {
125
    if (isset($prefs[$name])) {
126
      if (is_array($prefs[$name])) {
127
        if (isset($prefs[$name]['@value'])) {
128
          $default[$name] = $prefs[$name]['@value'];
129
        }
130
      }
131
      else {
132
        $default[$name] = $prefs[$name];
133
      }
134
    }
135
  }
136
137
  // Standard option sets
138
  $form['boolean_options'] = array(
139
    '#type' => 'value',
140
    '#value' => array(1 => bts('yes', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-no'), 0 => bts('no', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-yes'))
141
  );
142
  $form['hour_options'] = array(
143
    '#type' => 'value',
144
    '#value' => array('0:00','1:00','2:00','3:00','4:00',
0 ignored issues
show
The first value in a multi-value array must be on a new line
Loading history...
Each value in a multi-line array must be on a new line
Loading history...
145
     '5:00','6:00','7:00','8:00','9:00','10:00','11:00',
0 ignored issues
show
Each value in a multi-line array must be on a new line
Loading history...
146
     '12:00','13:00','14:00','15:00','16:00','17:00',
0 ignored issues
show
Each value in a multi-line array must be on a new line
Loading history...
147
     '18:00','19:00','20:00','21:00','22:00','23:00')
0 ignored issues
show
Each value in a multi-line array must be on a new line
Loading history...
There should be a trailing comma after the last value of an array declaration.
Loading history...
The closing parenthesis of an array declaration should be on a new line.
Loading history...
148
  );
149
150
  // Identify preference sets that are established to distinguish what has been
151
  // saved to the database from what is just showing default values
152
  $form['#established'] = $established;
153
154
  // Set up the preference container for AHAH
155
  $form['prefs'] = array(
156
    '#title' => '',
157
    '#type' => 'fieldset',
158
    '#prefix' => '<div id="prefs-wrapper">', // This is our wrapper div.
159
    '#attributes' => array('class' => 'ahah-container'),
160
    '#suffix' => '</div>',
161
    '#tree'   => TRUE
162
  );
163
  //$form['prefs']['debug'] = array('#value' => '<pre>' . print_r($form_state, true) . '</pre>');
164
165
  // Hidden elements
166
  $form['prefs']['modified'] = array(
167
    '#type' => 'hidden',
168
    '#value' => $mod_time
169
  );
170
  $form['prefs']['venue'] = array(
171
    '#type' => 'hidden',
172
    '#value' => $venue
173
  );
174
175
  $form['prefs']['separator_top'] = array(
176
    '#value' => '<div class="separator"></div>'
177
  );
178
179
  // Simplified selectors
180
  $form['prefs']['preset'] = array(
181
      '#title' => bts('Presets', array(), NULL, 'boinc:account-preferences-preset:-1:for a user to choose a computing or project preference preset.'),
182
    '#type' => 'radios',
183
    '#description' => ' ',
184
    '#options' => array(
185
      'standard' => bts('Standard', array(), NULL, 'boinc:account-preferences-preset'),
186
      'maximum' => bts('Maximum', array(), NULL, 'boinc:account-preferences-preset'),
187
      'green' => bts('Green', array(), NULL, 'boinc:account-preferences-preset'),
188
      'minimum' => bts('Minimum', array(), NULL, 'boinc:account-preferences-preset'),
189
      'custom' => bts('Custom', array(), NULL, 'boinc:account-preferences-preset')
190
    ),
191
    '#prefix' => '<div class="simple-form-controls">',
192
    '#suffix' => '</div>',
193
    '#default_value' => $default['preset'],
194
    '#ahah' => array(
195
      'event' => 'change',
196
      'path' => ahah_helper_path(array('prefs')),
197
      'wrapper' => 'prefs-wrapper'
198
    )
199
  );
200
  $form['prefs']['select preset'] = array(
201
    '#type'  => 'submit',
202
    '#value' => bts('Update preset', array(), NULL, 'boinc:account-preferences-preset'),
203
    '#submit' => array('ahah_helper_generic_submit'),
204
    // The 'no-js' class only displays this button if javascript is disabled
205
    '#attributes' => array('class' => 'no-js'),
206
  );
207
208
  // Advanced preferences
209
  $form['prefs']['advanced'] = array(
210
    '#title' => bts('Advanced settings', array(), NULL, 'boinc:account-preferences-option'),
211
    '#type' => 'fieldset',
212
    '#description' => '',
213
    '#collapsible' => TRUE,
214
    '#collapsed' => !$advanced,
215
    '#attributes' => array('class' => 'advanced-settings'),
216
  );
217
218
  // Processing preferences
219
220
  $form['prefs']['advanced']['anchor'] = array(
221
    '#value' => '<a name="advanced"></a>'
222
  );
223
224
  $form['prefs']['advanced']['separator_top'] = array(
225
    '#value' => '<div class="separator"></div>'
226
  );
227
228
  $form['prefs']['advanced']['processor'] = array(
229
    '#title' => bts('Processor usage', array(), NULL, 'boinc:account-preferences-computing'),
230
    '#type' => 'fieldset',
231
    '#description' => '',
232
    '#collapsible' => FALSE,
233
    '#collapsed' => FALSE
234
  );
235
  $form['prefs']['advanced']['processor']['run_on_batteries'] = array(
236
    '#title' => bts('Suspend when computer is on battery?', array(), NULL, 'boinc:account-preferences-computing'),
237
    '#type' => 'radios',
238
    '#description' => bts('Suspends computing on portables when running on battery power.', array(), NULL, 'boinc:account-preferences-computing'),
239
    '#options' => $form['boolean_options']['#value'],
240
    '#attributes' => array('class' => 'fancy'),
241
    '#default_value' => ($default['run_on_batteries']) ? 0 : 1 // intentional inversion of setting
242
  );
243
  $form['prefs']['advanced']['processor']['run_if_user_active'] = array(
244
    '#title' => bts('Suspend when computer is in use?', array(), NULL, 'boinc:account-preferences-computing'),
245
    '#type' => 'radios',
246
    '#description' => bts("Suspends computing and file transfers when you're using the computer.", array(), NULL, 'boinc:account-preferences-computing'),
247
    '#options' => $form['boolean_options']['#value'],
248
    '#attributes' => array('class' => 'fancy'),
249
    '#default_value' => ($default['run_if_user_active']) ? 0 : 1 // intentional inversion of setting
250
  );
251
  $form['prefs']['advanced']['processor']['run_gpu_if_user_active'] = array(
252
    '#title' => bts('Suspend GPU computing when computer is in use?', array(), NULL, 'boinc:account-preferences-computing'),
253
    '#type' => 'radios',
254
    '#description' => bts("Suspends GPU computing when you're using the computer.", array(), NULL, 'boinc:account-preferences-computing'),
255
    '#options' => $form['boolean_options']['#value'],
256
    '#attributes' => array('class' => 'fancy'),
257
    '#default_value' => ($default['run_gpu_if_user_active']) ? 0 : 1 // intentional inversion of setting
258
  );
259
  $form['prefs']['advanced']['processor']['idle_time_to_run'] = array(
260
      '#title' => bts('"In use" means mouse/keyboard input in last', array(), NULL, 'boinc:account-preferences-computing'),
261
    '#type' => 'textfield',
262
    '#field_suffix' => bts('minutes', array(), NULL, 'boinc:unit-of-time'),
263
    '#default_value' => $default['idle_time_to_run'],
264
    '#size' => 1,
265
    '#description' => bts('This determines when the computer is considered "in use".', array(), NULL, 'boinc:account-preferences-computing')
266
  );
267
  $form['prefs']['advanced']['processor']['suspend_if_no_recent_input'] = array(
268
    '#title' => bts('Suspend when no mouse/keyboard input in last', array(), NULL, 'boinc:account-preferences-computing'),
269
    '#type' => 'textfield',
270
    '#field_suffix' => bts('minutes', array(), NULL, 'boinc:unit-of-time'),
271
    '#default_value' => $default['suspend_if_no_recent_input'],
272
    '#size' => 1,
273
    '#description' => bts('This allows some computers to enter low-power mode when not in use.', array(), NULL, 'boinc:account-preferences-computing')
274
  );
275
  $form['prefs']['advanced']['processor']['suspend_cpu_usage'] = array(
276
    '#title' => bts('Suspend when non-BOINC CPU usage is above', array(), NULL, 'boinc:account-preferences-computing'),
277
    '#type' => 'textfield',
278
    '#field_suffix' => '%',
279
    '#default_value' => $default['suspend_cpu_usage'],
280
    '#size' => 1,
281
    '#description' => bts('Suspend computing when your computer is busy running other programs.', array(), NULL, 'boinc:account-preferences-computing'),
282
  );
283
  $form['prefs']['advanced']['processor']['hour_label'] = array(
284
    '#value' => '<div class="form-item"><label>' . bts('Compute only between:', array(), NULL, 'boinc:account-preferences-computing') . '</label></div>'
285
  );
286
  $form['prefs']['advanced']['processor']['start_hour'] = array(
287
    '#type' => 'select',
288
    '#options' => $form['hour_options']['#value'],
289
    '#default_value' => $default['start_hour']
290
  );
291
  $form['prefs']['advanced']['processor']['hour_delimiter'] = array(
292
    '#value' => '<span>' . bts('and', array(), NULL, 'boinc:account-preference') . '</span>'
293
  );
294
  $form['prefs']['advanced']['processor']['end_hour'] = array(
295
    '#type' => 'select',
296
    '#options' => $form['hour_options']['#value'],
297
    '#default_value' => $default['end_hour']
298
  );
299
  $form['prefs']['advanced']['processor']['hour_description'] = array(
300
    '#value' => '<div class="form-item slim"><div class="description">' . bts('Compute only during a particular period each day.', array(), NULL, 'boinc:account-preferences-computing') . '</div></div>'
301
  );
302
  $form['prefs']['advanced']['processor']['leave_apps_in_memory'] = array(
303
    '#title' => bts('Leave non-GPU tasks in memory while suspended?', array(), NULL, 'boinc:account-preferences-computing'),
304
    '#type' => 'radios',
305
    '#options' => $form['boolean_options']['#value'],
306
    '#attributes' => array('class' => 'fancy'),
307
    '#default_value' => $default['leave_apps_in_memory'],
308
    '#description' => bts('If "Yes", suspended tasks stay in memory, and resume with no work lost. If "No", suspended tasks are removed from memory, and resume from their last checkpoint.', array(), NULL, 'boinc:account-preferences-computing')
309
  );
310
  $form['prefs']['advanced']['processor']['cpu_scheduling_period_minutes'] = array(
311
    '#title' => bts('Switch between tasks every', array(), NULL, 'boinc:account-preferences-computing'),
312
    '#type' => 'textfield',
313
    '#field_suffix' => bts('minutes', array(), NULL, 'boinc:unit-of-time'),
314
    '#default_value' => $default['cpu_scheduling_period_minutes'],
315
    '#size' => 1,
316
    '#description' => bts('If you run several projects, BOINC may switch between them this often.', array(), NULL, 'boinc:account-preferences-computing')
317
  );
318
  $form['prefs']['advanced']['processor']['max_ncpus_pct'] = array(
319
    '#title' => bts('Use at most', array(), NULL, 'boinc:account-preferences-computing'),
320
    '#type' => 'textfield',
321
    '#field_suffix' => bts('% of the processors', array(), NULL, 'boinc:account-preferences-computing'),
322
    '#default_value' => $default['max_ncpus_pct'],
323
    '#size' => 1,
324
    '#description' => bts('Keep some CPUs free for other applications. Example: 75% means use 6 cores on an 8-core CPU.', array(), NULL, 'boinc:account-preferences-computing'),
325
  );
326
  $form['prefs']['advanced']['processor']['cpu_usage_limit'] = array(
327
    '#title' => bts('Use at most', array(), NULL, 'boinc:account-preferences-computing'),
328
    '#type' => 'textfield',
329
    '#field_suffix' => bts('% of the CPU time', array(), NULL, 'boinc:account-preferences-computing'),
330
    '#default_value' => $default['cpu_usage_limit'],
331
    '#size' => 1,
332
    '#description' => bts('Suspend/resume computing every few seconds to reduce CPU temperature and energy usage. Example: 75% means compute for 3 seconds, wait for 1 second, and repeat.', array(), NULL, 'boinc:account-preferences-computing')
333
  );
334
335
  // Disk and memory preferences
336
  $form['prefs']['advanced']['storage'] = array(
337
    '#title' => bts('Disk and memory usage', array(), NULL, 'boinc:account-preferences-computing'),
338
    '#type' => 'fieldset',
339
    '#description' => '',
340
    '#collapsible' => FALSE,
341
    '#collapsed' => FALSE
342
  );
343
  $form['prefs']['advanced']['storage']['disk_max_used_gb'] = array(
344
    '#title' => bts('Disk: use no more than', array(), NULL, 'boinc:account-preferences-computing'),
345
    '#type' => 'textfield',
346
    '#field_suffix' => 'GB',
347
    '#default_value' => $default['disk_max_used_gb'],
348
    '#size' => 1,
349
    '#description' => bts('Limit the total amount of disk space used by BOINC.', array(), NULL, 'boinc:account-preferences-computing'),
350
  );
351
  $form['prefs']['advanced']['storage']['disk_min_free_gb'] = array(
352
    '#title' => bts('Disk: leave at least', array(), NULL, 'boinc:account-preferences-computing'),
353
    '#type' => 'textfield',
354
    '#field_suffix' => 'GB free',
355
    '#default_value' => $default['disk_min_free_gb'],
356
    '#size' => 1,
357
    '#description' => bts('Limit disk usage to leave this much free space on the volume where BOINC stores data.', array(), NULL, 'boinc:account-preferences-computing'),
358
  );
359
  $form['prefs']['advanced']['storage']['disk_max_used_pct'] = array(
360
    '#title' => bts('Disk: use no more than', array(), NULL, 'boinc:account-preferences-computing'),
361
    '#type' => 'textfield',
362
    '#field_suffix' => bts('% of total', array(), NULL, 'boinc:account-preferences-computing'),
363
    '#default_value' => $default['disk_max_used_pct'],
364
    '#size' => 1,
365
    '#description' => bts('Limit the percentage of disk space used by BOINC on the volume where it stores data.', array(), NULL, 'boinc:account-preferences-computing')
366
  );
367
  $form['prefs']['advanced']['storage']['disk_interval'] = array(
368
    '#title' => bts('Request tasks to checkpoint at most every', array(), NULL, 'boinc:account-preferences-computing'),
369
    '#type' => 'textfield',
370
    '#field_suffix' => bts('seconds', array(), NULL, 'boinc:unit-of-time'),
371
    '#default_value' => $default['disk_interval'],
372
    '#size' => 1,
373
    '#description' => bts('This controls how often tasks save their state to disk, so that later they can be continued from that point.', array(), NULL, 'boinc:account-preferences-computing')
374
  );
375
  $form['prefs']['advanced']['storage']['vm_max_used_pct'] = array(
376
    '#title' => bts('Page/swap file: use at most', array(), NULL, 'boinc:account-preferences-computing'),
377
    '#type' => 'textfield',
378
    '#field_suffix' => bts('% of total', array(), NULL, 'boinc:account-preferences-computing'),
379
    '#default_value' => $default['vm_max_used_pct'],
380
    '#size' => 1,
381
    '#description' => bts('Limit the swap space (page file) used by BOINC.', array(), NULL, 'boinc:account-preferences-computing')
382
  );
383
  $form['prefs']['advanced']['storage']['ram_max_used_busy_pct'] = array(
384
    '#title' => bts('Memory: when computer is in use, use at most', array(), NULL, 'boinc:account-preferences-computing'),
385
    '#type' => 'textfield',
386
    '#field_suffix' => bts('% of total', array(), NULL, 'boinc:account-preferences-computing'),
387
    '#default_value' => $default['ram_max_used_busy_pct'],
388
    '#size' => 1,
389
    '#description' => bts("Limit the memory used by BOINC when you're using the computer.", array(), NULL, 'boinc:account-preferences-computing')
390
  );
391
  $form['prefs']['advanced']['storage']['ram_max_used_idle_pct'] = array(
392
    '#title' => bts('Memory: when computer is not in use, use at most', array(), NULL, 'boinc:account-preferences-computing'),
393
    '#type' => 'textfield',
394
    '#field_suffix' => bts('% of total', array(), NULL, 'boinc:account-preferences-computing'),
395
    '#default_value' => $default['ram_max_used_idle_pct'],
396
    '#size' => 1,
397
    '#description' => bts("Limit the memory used by BOINC when you're not using the computer.", array(), NULL, 'boinc:account-preferences-computing')
398
  );
399
400
  // Network preferences
401
  $form['prefs']['advanced']['network'] = array(
402
    '#title' => bts('Network usage', array(), NULL, 'boinc:account-preferences-computing'),
403
    '#type' => 'fieldset',
404
    '#description' => '',
405
    '#collapsible' => FALSE,
406
    '#collapsed' => FALSE
407
  );
408
  $form['prefs']['advanced']['network']['work_buf_min_days'] = array(
409
    '#title' => bts('Store at least', array(), NULL, 'boinc:account-preferences-computing'),
410
    '#type' => 'textfield',
411
    '#field_suffix' => bts('days of work', array(), NULL, 'boinc:account-preferences-computing'),
412
    '#default_value' => $default['work_buf_min_days'],
413
    '#size' => 1,
414
    '#description' => bts('Store at least enough tasks to keep the computer busy for this long.', array(), NULL, 'boinc:account-preferences-computing')
415
  );
416
  $form['prefs']['advanced']['network']['work_buf_additional_days'] = array(
417
    '#title' => bts('Store up to an additional', array(), NULL, 'boinc:account-preferences-computing'),
418
    '#type' => 'textfield',
419
    '#field_suffix' => bts('days', array(), NULL, 'boinc:unit-of-time'),
420
    '#default_value' => $default['work_buf_additional_days'],
421
    '#size' => 1,
422
    '#description' => bts('Store additional tasks above the minimum level.  Determines how much work is requested when contacting a project.', array(), NULL, 'boinc:account-preferences-computing')
423
  );
424
  $form['prefs']['advanced']['network']['confirm_before_connecting'] = array(
425
    '#title' => bts('Confirm before connecting to Internet?', array(), NULL, 'boinc:account-preferences-computing'),
426
    '#type' => 'radios',
427
    '#options' => $form['boolean_options']['#value'],
428
    '#attributes' => array('class' => 'fancy'),
429
    '#default_value' => $default['confirm_before_connecting'],
430
    '#description' => bts('Useful only if you have a modem, ISDN or VPN connection.', array(), NULL, 'boinc:account-preferences-computing')
431
  );
432
  $form['prefs']['advanced']['network']['hangup_if_dialed'] = array(
433
    '#title' => bts('Disconnect when done?', array(), NULL, 'boinc:account-preferences-computing'),
434
    '#type' => 'radios',
435
    '#options' => $form['boolean_options']['#value'],
436
    '#attributes' => array('class' => 'fancy'),
437
    '#default_value' => $default['hangup_if_dialed'],
438
    '#description' => bts('Useful only if you have a modem, ISDN or VPN connection.', array(), NULL, 'boinc:account-preferences-computing')
439
  );
440
  $form['prefs']['advanced']['network']['max_bytes_sec_down'] = array(
441
    '#title' => bts('Limit download rate to', array(), NULL, 'boinc:account-preferences-computing'),
442
    '#type' => 'textfield',
443
    '#field_suffix' => 'Kbytes/sec',
444
    '#default_value' => $default['max_bytes_sec_down']/1000,
445
    '#size' => 1,
446
    '#description' => bts('Limit the download rate of file transfers.', array(), NULL, 'boinc:account-preferences-computing')
447
  );
448
  $form['prefs']['advanced']['network']['max_bytes_sec_up'] = array(
449
    '#title' => bts('Limit upload rate to', array(), NULL, 'boinc:account-preferences-computing'),
450
    '#type' => 'textfield',
451
    '#field_suffix' => 'Kbytes/sec',
452
    '#default_value' => $default['max_bytes_sec_up']/1000,
453
    '#size' => 1,
454
    '#description' => bts('Limit the upload rate of file transfers.', array(), NULL, 'boinc:account-preferences-computing')
455
  );
456
  $form['prefs']['advanced']['network']['hour_label'] = array(
457
    '#value' => '<div class="form-item"><label>' . bts('Transfer files only between', array(), NULL, 'boinc:account-preferences-computing') . '</label></div>'
458
  );
459
  $form['prefs']['advanced']['network']['net_start_hour'] = array(
460
    '#type' => 'select',
461
    '#options' => $form['hour_options']['#value'],
462
    '#default_value' => $default['net_start_hour']
463
  );
464
  $form['prefs']['advanced']['network']['hour_delimiter'] = array(
465
    '#value' => '<span>' . bts('and', array(), NULL, 'boinc:account-preference') . '</span>'
466
  );
467
  $form['prefs']['advanced']['network']['net_end_hour'] = array(
468
    '#type' => 'select',
469
    '#options' => $form['hour_options']['#value'],
470
    '#default_value' => $default['net_end_hour']
471
  );
472
  $form['prefs']['advanced']['network']['hour_description'] = array(
473
    '#value' => '<div class="form-item slim"><div class="description">' . bts('Transfer files only during a particular period each day.', array(), NULL, 'boinc:account-preferences-computing') . '</div></div>'
474
  );
475
  $form['prefs']['advanced']['network']['daily_xfer_limit_mb'] = array(
476
    '#title' => bts('Limit usage to', array(), NULL, 'boinc:account-preferences-computing'),
477
    '#type' => 'textfield',
478
    '#field_suffix' => 'Mbytes',
479
    '#default_value' => $default['daily_xfer_limit_mb'],
480
    '#size' => 1
481
  );
482
  $form['prefs']['advanced']['network']['daily_xfer_period_days'] = array(
483
    '#field_prefix' => 'every',
484
    '#type' => 'textfield',
485
    '#field_suffix' => bts('days', array(), NULL, 'boinc:unit-of-time'),
486
    '#default_value' => $default['daily_xfer_period_days'],
487
    '#size' => 1,
488
    '#description' => bts('Example: BOINC should transfer at most 2000 MB of data every 30 days.', array(), NULL, 'boinc:account-preferences-computing'),
489
  );
490
  $form['prefs']['advanced']['network']['dont_verify_images'] = array(
491
    '#title' => bts('Skip data verification for image files?', array(), NULL, 'boinc:account-preferences-computing'),
492
    '#type' => 'radios',
493
    '#options' => $form['boolean_options']['#value'],
494
    '#attributes' => array('class' => 'fancy'),
495
    '#default_value' => $default['dont_verify_images'],
496
    '#description' => bts('Only select "Yes" if your Internet provider modifies image files. Skipping verification reduces the security of BOINC.', array(), NULL, 'boinc:account-preferences-computing')
497
  );
498
499
  // The "fancy radios" are made via javascript on document load. In order for
500
  // these to work with AHAH, we need this crazy setTimeout() call.
501
  $form['prefs']['fancy-radios'] = array(
502
    '#value' => '
503
      <script>
504
        setTimeout(
505
          function() {
506
            fancyRadiosInit();
507
            customPrefsListener();
508
          },
509
          300
510
        )
511
      </script>'
512
  );
513
  $form['prefs']['view advanced'] = array(
514
    '#type' => 'hidden',
515
    '#value' => 1
516
  );
517
518
  $form['prefs']['separator_bottom'] = array(
519
    '#value' => '<div class="separator buttons"></div>'
520
  );
521
522
  // Form control
523
  $form['prefs']['form control tabs prefix'] = array(
524
    '#value' => '<ul class="form-control tab-list">'
525
  );
526
  $form['prefs']['submit'] = array(
527
    '#prefix' => '<li class="first tab">',
528
    '#type' => 'submit',
529
    '#value' => bts('Save changes', array(), NULL, 'boinc:form-save'),
530
    '#suffix' => '</li>'
531
  );
532
  $form['prefs']['form control tabs'] = array(
533
    '#value' => '<li class="tab">' . l(bts('Cancel', array(), NULL, 'boinc:form-cancel'), drupal_get_path_alias("account/prefs/computing/edit")) . '</li>'
534
  );
535
  if ($venue AND $venue != 'generic') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
536
    global $base_path;
537
    $form['prefs']['form control tabs']['#value'] .= '<li class="tab">' .
538
      l(bts('Clear', array(), NULL, 'boinc:form-clear'), "account/prefs/computing/clear/{$venue}",
539
        array(
540
          'query' => 'destination=' . urlencode(drupal_get_path_alias('account/prefs/computing/combined')),
541
          'attributes' => array(
542
            'onclick' => 'return confirm(\'' . bts('This will remove all of your settings from the @name preference set. Are you sure?',
543
              array('@name' => $venue), NULL, 'boinc:account-preferences') . '\')'
544
          )
545
        )
546
      ) . '</li>';
547
  }
548
  $form['prefs']['view control'] = array(
549
    '#value' => '<li class="first alt tab">' . l('(' . bts('Show comparison view', array(), NULL, 'boinc:account-preferences') . ')', 'account/prefs/computing/combined') . '</li>'
550
  );
551
  $form['prefs']['form control tabs suffix'] = array(
552
    '#value' => '</ul>'
553
  );
554
  $form['#submit'][] = 'boincwork_generalprefs_form_submit';
555
556
  return $form;
557
}
558
559
/**
560
  * Validate the general preferences form.
561
  */
562
function boincwork_generalprefs_form_validate($form, &$form_state) {
563
  require_boinc('util');
564
  $values = $form_state['values']['prefs']['advanced'];
565
566
  //drupal_set_message('<pre>' . print_r($form_state['values'], true) . '</pre>');
567
  // Verify all non-boolean user input values and notify form API of failures
568
569
  // Processing preferences
570
  if (!verify_numeric($values['processor']['idle_time_to_run'], 1, 9999)) form_set_error('idle_time_to_run', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['processor']['idle_time_to_run']['#title']} [x] {$form['prefs']['advanced']['processor']['idle_time_to_run']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
571
  if (!verify_numeric($values['processor']['suspend_if_no_recent_input'], 0, 9999)) form_set_error('suspend_if_no_recent_input', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['processor']['suspend_if_no_recent_input']['#title']} [x] {$form['prefs']['advanced']['processor']['suspend_if_no_recent_input']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
572
  if (!verify_numeric($values['processor']['suspend_cpu_usage'], 0, 100)) form_set_error('suspend_cpu_usage', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['processor']['suspend_cpu_usage']['#title']} [x] {$form['prefs']['advanced']['processor']['suspend_cpu_usage']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
573
  if (!verify_numeric($values['processor']['start_hour'], 0, 23)) form_set_error('start_hour', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['processor']['start_hour']['#title']} [x] {$form['prefs']['advanced']['processor']['start_hour']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
574
  if (!verify_numeric($values['processor']['end_hour'], 0, 23)) form_set_error('end_hour', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['processor']['end_hour']['#title']} [x] {$form['prefs']['advanced']['processor']['end_hour']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
575
  if (!verify_numeric($values['processor']['cpu_scheduling_period_minutes'], 1, 9999)) form_set_error('cpu_scheduling_period_minutes', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['processor']['cpu_scheduling_period_minutes']['#title']} [x] {$form['prefs']['advanced']['processor']['cpu_scheduling_period_minutes']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
576
  if (!verify_numeric($values['processor']['max_ncpus_pct'], 0, 100)) form_set_error('max_ncpus_pct', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['processor']['max_ncpus_pct']['#title']} [x] {$form['prefs']['advanced']['processor']['max_ncpus_pct']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
577
  if (!verify_numeric($values['processor']['cpu_usage_limit'], 0, 100)) form_set_error('cpu_usage_limit', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['processor']['cpu_usage_limit']['#title']} [x] {$form['prefs']['advanced']['processor']['cpu_usage_limit']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
578
579
  // Storage preferences
580
  if (!verify_numeric($values['storage']['disk_max_used_gb'], 0, 9999999)) form_set_error('disk_max_used_gb', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['storage']['disk_max_used_gb']['#title']} [x] {$form['prefs']['advanced']['storage']['disk_max_used_gb']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
581
  if (!verify_numeric($values['storage']['disk_min_free_gb'], 0.001, 9999999)) form_set_error('disk_min_free_gb', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['storage']['disk_min_free_gb']['#title']} [x] {$form['prefs']['advanced']['storage']['disk_min_free_gb']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
582
  if (!verify_numeric($values['storage']['disk_max_used_pct'], 0, 100)) form_set_error('disk_max_used_pct', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['storage']['disk_max_used_pct']['#title']} [x] {$form['prefs']['advanced']['storage']['disk_max_used_pct']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
583
  if (!verify_numeric($values['storage']['disk_interval'], 0, 9999999)) form_set_error('disk_interval', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['storage']['disk_interval']['#title']} [x] {$form['prefs']['advanced']['storage']['disk_interval']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
584
  if (!verify_numeric($values['storage']['vm_max_used_pct'], 0, 100)) form_set_error('vm_max_used_pct', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['storage']['vm_max_used_pct']['#title']} [x] {$form['prefs']['advanced']['storage']['vm_max_used_pct']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
585
  if (!verify_numeric($values['storage']['ram_max_used_busy_pct'], 0, 100)) form_set_error('ram_max_used_busy_pct', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['storage']['ram_max_used_busy_pct']['#title']} [x] {$form['prefs']['advanced']['storage']['ram_max_used_busy_pct']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
586
  if (!verify_numeric($values['storage']['ram_max_used_idle_pct'], 0, 100)) form_set_error('ram_max_used_idle_pct', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['storage']['ram_max_used_idle_pct']['#title']} [x] {$form['prefs']['advanced']['storage']['ram_max_used_idle_pct']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
587
588
  // Network preferences
589
  if (!verify_numeric($values['network']['work_buf_min_days'], 0, 10)) form_set_error('work_buf_min_days', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['network']['work_buf_min_days']['#title']} [x] {$form['prefs']['advanced']['network']['work_buf_min_days']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
590
  if (!verify_numeric($values['network']['work_buf_additional_days'], 0, 10)) form_set_error('work_buf_additional_days', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['network']['work_buf_additional_days']['#title']} [x] {$form['prefs']['advanced']['network']['work_buf_additional_days']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
591
  if (!verify_numeric($values['network']['max_bytes_sec_down'], 0, 9999.999)) form_set_error('max_bytes_sec_down', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['network']['max_bytes_sec_down']['#title']} [x] {$form['prefs']['advanced']['network']['max_bytes_sec_down']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
592
  if (!verify_numeric($values['network']['max_bytes_sec_up'], 0, 9999.999)) form_set_error('max_bytes_sec_up', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['network']['max_bytes_sec_up']['#title']} [x] {$form['prefs']['advanced']['network']['max_bytes_sec_up']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
593
  if (!verify_numeric($values['network']['net_start_hour'], 0, 23)) form_set_error('net_start_hour', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['network']['net_start_hour']['#title']} [x] {$form['prefs']['advanced']['network']['net_start_hour']['#field_suffix']}"), NULL, 'boinc:account-prefrences-computing'));
594
  if (!verify_numeric($values['network']['net_end_hour'], 0, 23)) form_set_error('net_end_hour', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['network']['net_end_hour']['#title']} [x] {$form['prefs']['advanced']['network']['net_end_hour']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
595
  if (!verify_numeric($values['network']['daily_xfer_limit_mb'], 0, 9999999)) form_set_error('daily_xfer_limit_mb', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['network']['daily_xfer_limit_mb']['#title']} [x] {$form['prefs']['advanced']['network']['daily_xfer_limit_mb']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
596
  if (!verify_numeric($values['network']['daily_xfer_period_days'], 0, 9999999)) form_set_error('daily_xfer_period_days', bts('Invalid setting for "%preference"', array('%preference' => "{$form['prefs']['advanced']['network']['daily_xfer_limit_mb']['#title']} [x] {$form['prefs']['advanced']['network']['daily_xfer_limit_mb']['#field_suffix']}"), NULL, 'boinc:account-preferences-computing'));
597
}
598
599
/**
600
  * Handle post-validation submission of general preferences form.
601
  */
602
function boincwork_generalprefs_form_submit($form, &$form_state) {
603
  global $user;
604
  $account = user_load($user->uid);
605
606
  $values = $form_state['values']['prefs']['advanced'];
607
  $venue = $form_state['values']['prefs']['venue'];
608
  $preset = $form_state['values']['prefs']['preset'];
609
610
  // Load preferences from BOINC account
611
  $prefs = boincwork_load_prefs('general', $venue);
612
613
  // Processing preferences
614
  $prefs['run_on_batteries'] = ($values['processor']['run_on_batteries']) ? 0 : 1;
615
  $prefs['run_if_user_active'] = ($values['processor']['run_if_user_active']) ? 0 : 1;
616
  $prefs['run_gpu_if_user_active'] = ($values['processor']['run_gpu_if_user_active']) ? 0 : 1;
617
  $prefs['idle_time_to_run'] = $values['processor']['idle_time_to_run'];
618
  $prefs['suspend_if_no_recent_input'] = $values['processor']['suspend_if_no_recent_input'];
619
  $prefs['suspend_cpu_usage'] = $values['processor']['suspend_cpu_usage'];
620
  $prefs['start_hour'] = $values['processor']['start_hour'];
621
  $prefs['end_hour'] = $values['processor']['end_hour'];
622
  $prefs['leave_apps_in_memory'] = ($values['processor']['leave_apps_in_memory']) ? 1 : 0;
623
  $prefs['cpu_scheduling_period_minutes'] = $values['processor']['cpu_scheduling_period_minutes'];
624
  $prefs['max_ncpus_pct'] = $values['processor']['max_ncpus_pct'];
625
  $prefs['cpu_usage_limit'] = $values['processor']['cpu_usage_limit'];
626
627
  // Storage preferences
628
  $prefs['disk_max_used_gb'] = $values['storage']['disk_max_used_gb'];
629
  $prefs['disk_min_free_gb'] = $values['storage']['disk_min_free_gb'];
630
  $prefs['disk_max_used_pct'] = $values['storage']['disk_max_used_pct'];
631
  $prefs['disk_interval'] = $values['storage']['disk_interval'];
632
  $prefs['vm_max_used_pct'] = $values['storage']['vm_max_used_pct'];
633
  $prefs['ram_max_used_busy_pct'] = $values['storage']['ram_max_used_busy_pct'];
634
  $prefs['ram_max_used_idle_pct'] = $values['storage']['ram_max_used_idle_pct'];
635
636
  // Network preferences
637
  $prefs['work_buf_min_days'] = $values['network']['work_buf_min_days'];
638
  $prefs['work_buf_additional_days'] = $values['network']['work_buf_additional_days'];
639
  $prefs['confirm_before_connecting'] = ($values['network']['confirm_before_connecting']) ? 1 : 0;
640
  $prefs['hangup_if_dialed'] = ($values['network']['hangup_if_dialed']) ? 1 : 0;
641
  $prefs['max_bytes_sec_down'] = $values['network']['max_bytes_sec_down']*1000;
642
  $prefs['max_bytes_sec_up'] = $values['network']['max_bytes_sec_up']*1000;
643
  $prefs['net_start_hour'] = $values['network']['net_start_hour'];
644
  $prefs['net_end_hour'] = $values['network']['net_end_hour'];
645
  $prefs['daily_xfer_limit_mb'] = $values['network']['daily_xfer_limit_mb'];
646
  $prefs['daily_xfer_period_days'] = $values['network']['daily_xfer_period_days'];
647
  $prefs['dont_verify_images'] = ($values['network']['dont_verify_images']) ? 1 : 0;
648
649
  // transform old way to store the preset into new way
650
  // ideally this should already have happened in boincwork_generalprefs_form()
651
  if (isset($prefs['@attributes']['preset'])) {
652
    $prefs['preset'] = $prefs['@attributes']['preset'];
653
    unset($prefs['@attributes']['preset']);
654
  }
655
  // Save the preset selection (or lack thereof)
656
  if (!$preset OR $preset == 'custom') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected or, but found OR.
Loading history...
657
    $prefs['preset'] = 'custom';
658
  }
659
  else {
660
    $prefs['preset'] = $preset;
661
  }
662
663
  // If this is a new preference set, be sure to unset the "cleared" attribute
664
  if (isset($prefs['@attributes']['cleared'])) {
665
    unset($prefs['@attributes']['cleared']);
666
  }
667
668
  // Update database
669
  $result = boincwork_save_prefs($prefs, 'general', $venue);
670
671
  if (!$result) {
672
    watchdog('boincwork', 'Error updating global prefs for user @id: @message', array('@id' => $account->id, '@message' => mysqli_error()), WATCHDOG_ERROR);
0 ignored issues
show
The call to mysqli_error() has too few arguments starting with mysql. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

672
    watchdog('boincwork', 'Error updating global prefs for user @id: @message', array('@id' => $account->id, '@message' => /** @scrutinizer ignore-call */ mysqli_error()), WATCHDOG_ERROR);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
673
    drupal_set_message(t('Your changes could not be saved. Please contact support!'), 'error');
674
  }
675
  elseif (!drupal_get_messages('status', FALSE)) {
676
    // Show this message if the set wasn't created automatically (in which case
677
    // there is a message tailored to that) {
678
    drupal_set_message(t('Your preferences have been updated.
679
      Client-related preferences will take effect when your computer
680
      communicates with @project or you issue the "Update"
681
      command from the BOINC client.', array('@project' => PROJECT)));
682
  }
683
}
684
685
686
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
687
 * Merge host form handlers and functions
688
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
689
690
/**
691
 * Find compatible hosts for merging
692
 */
693
function boincwork_host_get_compatible_hosts($host_id) {
694
  require_boinc('host');
695
  global $user;
696
  $account = user_load($user->uid);
697
  $compatible_hosts = array();
698
  $host_count = 0;
699
  db_set_active('boinc_ro');
700
  $current_host = db_fetch_object(db_query("
701
    SELECT id, domain_name, create_time, total_credit, rpc_time, os_name,
702
      p_vendor, p_model
703
    FROM {host}
704
    WHERE userid = '%d' AND id = '%d'",
705
    $account->boincuser_id, $host_id
706
  ));
707
  db_set_active('default');
708
  $current_host->task_count = boincwork_host_get_task_count($current_host->id);
709
  $current_host->is_new = !$current_host->total_credit AND !$current_host->task_count;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
710
  // Get the list of all other hosts owned by this user for comparison
711
  db_set_active('boinc_ro');
712
  $all_other_hosts = db_query("
713
    SELECT id, domain_name, create_time, total_credit, rpc_time, os_name,
714
      p_vendor, p_model
715
    FROM {host}
716
    WHERE userid = '%d' AND id <> '%d'",
717
    $account->boincuser_id, $host_id
718
  );
719
  db_set_active('default');
720
  // Compare all hosts to see if any are plausible duplicates
721
  while ($other_host = db_fetch_object($all_other_hosts)) {
722
    // First, disqualify if hosts were active at the same time
723
    if (!$current_host->is_new) {
724
      $other_host->task_count = boincwork_host_get_task_count($other_host->id);
725
      $other_host->is_new = !$other_host->total_credit AND !$other_host->task_count;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
726
      if (!$other_host->is_new) {
727
        // If both hosts being compared are not new, see if times overlap
728
        if (!times_disjoint($current_host, $other_host)) {
729
          // Hosts were active at the same time; can't be a duplicate
730
          continue;
731
        }
732
      }
733
    }
734
    // Next, disqualify if hosts have different OS platforms
735
    if (!os_compatible($current_host, $other_host)) {
736
      // Hosts have different OS platforms; not really a duplicate
737
      continue;
738
    }
739
    // Finally, disqualify if hosts have different CPUs
740
    if (!cpus_compatible($current_host, $other_host)) {
741
      // CPUs don't match; not a duplicate
742
      continue;
743
    }
744
    // If not disqualified, this host is available for merging
745
    $hosts[] = $other_host;
746
    $host_count++;
747
    if ($host_count == 500) {
748
      // This is enough!
749
      break;
750
    }
751
  }
752
  return $hosts;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $hosts does not seem to be defined for all execution paths leading up to this point.
Loading history...
753
}
754
755
/**
756
 * Perform the database updates to merge the old host into the new host
757
 */
758
function boincwork_host_merge($old_host, $new_host, &$message = NULL) {
759
  // Decay the average credit of the two hosts
760
  require_boinc('credit');
761
  $now = time();
762
  update_average($now, 0, 0, $old_host->expavg_credit, $old_host->expavg_time);
763
  update_average($now, 0, 0, $new_host->expavg_credit, $new_host->expavg_time);
764
765
  // Update the database:
766
  // - add credit from old host to new host
767
  // - change results to refer to the new host
768
  // - put old host in "zombie" state (userid=0, rpc_seqno=[new_host_id])
769
770
  $total_credit = $old_host->total_credit + $new_host->total_credit;
771
  $recent_credit = $old_host->expavg_credit + $new_host->expavg_credit;
772
773
  if ($new_host->rpc_seqno == $old_host->id) {
774
    rules_invoke_event('boincwork_circular_merge_error', $old_host->id, $new_host->id, variable_get('boinc_admin_mailing_list_subject_tag', ''));
775
    watchdog('boincwork',
776
      'Circular merge attempted, target host rpc_seqno is equal to old host\'s id: old host id=%old_host, target host id=%new_host',
777
      array(
778
        '%old_host' => $old_host->id,
779
        '%new_host' => $new_host->id,
780
      ),
781
      WATCHDOG_WARNING
782
    );
783
    $message = 'Could not merge due to a circular merge error. The site administrators have been contacted about this issue, and will investigate further.';
784
    return FALSE;
785
  }
786
787
  if ($new_host->userid==0) {
788
    rules_invoke_event('boincwork_zombie_merge_error', $old_host->id, $new_host->id, variable_get('boinc_admin_mailing_list_subject_tag', ''));
789
    watchdog('boincwork',
790
      'Zombie merge attempted, target host has userid=0: old host id=%old_host, target host id=%new_host',
791
      array(
792
        '%old_host' => $old_host->id,
793
        '%new_host' => $new_host->id,
794
      ),
795
      WATCHDOG_WARNING
796
    );
797
    $message = 'Could not merge because the target host has userid=0. The site administrators have been contacted about this issue, and will investigate further.';
798
    return FALSE;
799
  }
800
801
  // Move credit from the old host to the new host
802
  db_set_active('boinc_rw');
803
  $credit_updated = db_query("
804
    UPDATE {host}
805
    SET
806
      total_credit = '%d',
807
      expavg_credit = '%d',
808
      expavg_time = '%d'
809
    WHERE id = '%d'",
810
    $total_credit, $recent_credit, $now, $new_host->id
811
  );
812
  db_set_active('default');
813
  if (!$credit_updated) {
814
    if ($message !== NULL) {
815
      $message = bts('Could not update credit', array(), NULL, 'boinc:account-host-merge');
816
    }
817
    return FALSE;
818
  }
819
820
  // Move results from the old host to the new host
821
  db_set_active('boinc_rw');
822
  $results_updated = db_query("
823
    UPDATE {result}
824
    SET hostid = '%d'
825
    WHERE hostid = '%d'",
826
    $new_host->id, $old_host->id
827
  );
828
  db_set_active('default');
829
  if (!$results_updated) {
830
    if ($message !== NULL) {
831
      $message = bts('Could not update results', array(), NULL, 'boinc:account-host-merge');
832
    }
833
    return FALSE;
834
  }
835
836
  // Retire the old host
837
  db_set_active('boinc_rw');
838
  $old_host_retired = db_query("
839
    UPDATE {host}
840
    SET
841
      total_credit = '0',
842
      expavg_credit = '0',
843
      userid = '0',
844
      rpc_seqno = '%d'
845
    WHERE id = '%d'",
846
    $new_host->id, $old_host->id
847
  );
848
  db_set_active('default');
849
  if (!$old_host_retired) {
850
    if ($message !== NULL) {
851
      $message = bts('Could not retire old computer', array(), NULL, 'boinc:account-host-merge');
852
    }
853
    return FALSE;
854
  }
855
856
  return TRUE;
857
}
858
859
/**
860
 * Merge host form
861
 */
862
function boincwork_host_merge_form(&$form_state, $host_id) {
863
864
  if (!boincwork_host_user_is_owner($host_id)) {
865
    drupal_goto("host/{$host_id}");
866
  }
867
868
  $form = array();
869
  $form_state['storage']['current_host_id'] = $host_id;
870
  $current_host = boincwork_host_get_info($host_id);
871
872
  // Get hosts that could be merged with this one
873
  $hosts = boincwork_host_get_compatible_hosts($host_id);
874
875
  if (!$hosts) {
876
    drupal_set_message(t('There are no computers eligible for merging with this
877
      one'), 'warning'
878
    );
879
    drupal_goto("host/{$host_id}");
880
  }
881
882
  $form['overview'] = array(
883
    '#value' => '<p>' . bts('Sometimes BOINC assigns separate identities to'
884
      . ' the same computer by mistake. You can correct this by merging old'
885
      . ' identities with the newest one.', array(), NULL, 'boinc:account-host-merge') . '</p>'
886
      . '<p>'
887
      . bts('Check the computers that are the same as @name'
888
      . ' (created on @date at @time with computer ID @id)',
889
        array(
890
          '@name' => $current_host->domain_name,
891
          '@date' => date('j M Y', $current_host->create_time),
892
          '@time' => date('G:i:s T', $current_host->create_time),
893
          '@id' => $current_host->id,
894
        ),
895
        NULL, 'boinc:account-host-merge') . '</p>',
896
  );
897
898
  $options = array();
899
  foreach ($hosts as $host) {
900
    $options[$host->id] = array(
901
      $host->domain_name,
902
      date('j M Y G:i:s T', $host->create_time),
903
      $host->id,
904
    );
905
  }
906
907
  $form['merge'] = array(
908
    '#title' => '',
909
    '#type' => 'tableselect',
910
    '#header' => array(bts('Name', array(), NULL, 'boinc:details:-1:name-of-the-host-or-task-or-workunit-etc-being-viewed-ignoreoverwrite'), bts('Created', array(), NULL, 'boinc:host-details'), bts('Computer ID', array(), NULL, 'boinc:host-list')),
911
    '#options' => $options,
912
  );
913
914
  $form['prefs']['separator_bottom'] = array(
915
  //  '#value' => '<div class="separator buttons"></div>'
916
  );
917
918
  // Form control
919
  $form['prefs']['form control tabs prefix'] = array(
920
    '#value' => '<ul class="form-control tab-list">'
921
  );
922
  $form['prefs']['submit'] = array(
923
    '#prefix' => '<li class="first tab">',
924
    '#type' => 'submit',
925
    '#value' => bts('Merge', array(), NULL, 'boinc:form-merge'),
926
    '#suffix' => '</li>'
927
  );
928
  $form['prefs']['form control tabs'] = array(
929
    '#value' => '<li class="tab">' . l(bts('Cancel', array(), NULL, 'boinc:form-cancel'), "host/{$host_id}") . '</li>'
930
  );
931
932
  return $form;
933
}
934
935
/**
936
 * Validate the merge host form
937
 */
938
function boincwork_host_merge_form_validate($form, &$form_state) {
939
}
940
941
/**
942
 * Handle submission of the merge host form
943
 */
944
function boincwork_host_merge_form_submit($form, &$form_state) {
945
  $merged = array();
946
  $errors = array();
947
  $current_host_id = $form_state['storage']['current_host_id'];
948
  $current_host = boincwork_host_get_info($current_host_id);
949
  $selected_hosts = array_filter($form_state['values']['merge']);
950
951
  foreach ($selected_hosts as $host_id) {
952
    // Attempt to merge each host, noting the results
953
    $message = '';
954
    $old_host = boincwork_host_get_info($host_id);
955
    if (boincwork_host_merge($old_host, $current_host, $message)) {
956
      $merged[$old_host->id] = $old_host->id;
957
      $current_host = boincwork_host_get_info($current_host_id);
958
    }
959
    else {
960
      $errors[$old_host->id] = $message;
961
    }
962
  }
963
964
  if ($merged) {
965
    // Generate a natural language list of IDs that were merged
966
    $oxford_comma = ',';
967
    $conjunction = bts('and', array(), NULL, 'boinc:account-preference');
968
    $list = array_keys($merged);
969
    $last = array_pop($list);
970
    if ($list) {
971
      if (count($merged) == 2) {
972
        $oxford_comma = '';
973
      }
974
      $list = implode(', ', $list) . $oxford_comma . ' ' . $conjunction . ' ' . $last;
975
    }
976
    else {
977
      $list = $last;
978
    }
979
    if (count($merged) == 1) {
980
      drupal_set_message(bts(
981
        'Computer @old_id has been merged successfully into @id.',
982
        array(
983
          '@old_id' => $list,
984
          '@id' => $current_host_id
985
        ),
986
        NULL, 'boinc:account-host-merge'));
987
    }
988
    else {
989
      drupal_set_message(bts(
990
        'Computers @old_ids have been merged successfully into @id.',
991
        array(
992
          '@old_ids' => $list,
993
          '@id' => $current_host_id
994
        ),
995
        NULL, 'boinc:account-host-merge'));
996
    }
997
  }
998
999
  if ($errors) {
0 ignored issues
show
$errors is an empty array, thus is always false.
Loading history...
Bug Best Practice introduced by
The expression $errors of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1000
    // Report any hosts that failed to merge
1001
    foreach ($errors as $id => $error) {
1002
      drupal_set_message(
1003
        bts('Computer @old_id failed to merge: @message',
1004
          array(
1005
            '@old_id' => $id,
1006
            '@message' => $error,
1007
          ),
1008
          NULL, 'boinc:account-host-merge'),
1009
        'warning'
1010
      );
1011
    }
1012
  }
1013
1014
  drupal_goto("host/{$current_host_id}");
1015
}
1016
1017
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
1018
 * Project preferences form handlers and functions
1019
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
1020
1021
/**
1022
 * The structure of the project preferences form
1023
 */
1024
function boincwork_projectprefs_form(&$form_state, $venue) {
1025
1026
  global $user;
1027
  $account = user_load($user->uid);
1028
1029
  $established = TRUE;
1030
1031
  // Get availability of special BOINC preferences
1032
  require_boinc(array('util'));
1033
  $app_types = get_app_types();
1034
1035
  // Load any existing preferences from BOINC account
1036
  $prefs = boincwork_load_prefs('project', $venue);
1037
1038
  // Take note if this is not an established preference set on the account
1039
  if (isset($prefs['@attributes']['cleared'])) {
1040
    $established = FALSE;
1041
  }
1042
1043
  // Extract modified tag if present
1044
  $modified = NULL;
1045
  if (isset($prefs['modified']['@value'])) {
1046
    $modified = $prefs['modified']['@value'];
1047
  }
1048
1049
  $venue_is_default = FALSE;
1050
  if ($account->boincuser_default_pref_set) {
1051
    if ($account->boincuser_default_pref_set == $venue) {
1052
      $venue_is_default = TRUE;
1053
    }
1054
  }
1055
  elseif (!$venue OR $venue == 'generic') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected or, but found OR.
Loading history...
1056
    $venue_is_default = TRUE;
1057
  }
1058
  else {
1059
    $venue_is_default = FALSE;
1060
  }
1061
1062
  // Define form defaults
1063
  $default = array(
1064
    'resource_share' => 100,
1065
    'no_cpu' => 0,
1066
    'no_cuda' => 0,
1067
    'no_ati' => 0,
1068
    'no_intel_gpu' => 0,
1069
    'no_apple_gpu' => 0,
1070
    'default_venue' => $venue_is_default,
1071
    'allow_beta_work' => $prefs['allow_beta_work'],
1072
  );
1073
  foreach ($default as $name => $value) {
1074
    if (isset($prefs[$name])) {
1075
      if (is_array($prefs[$name])) {
1076
        if (isset($prefs[$name]['@value'])) {
1077
          $default[$name] = $prefs[$name]['@value'];
1078
        }
1079
      }
1080
      else {
1081
        $default[$name] = $prefs[$name];
1082
      }
1083
    }
1084
  }
1085
1086
  // Standard option sets
1087
  $form['boolean_options'] = array(
1088
    '#type' => 'value',
1089
    '#value' => array(1 => bts('yes', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-no'), 0 => bts('no', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-yes'))
1090
  );
1091
1092
  // Identify preference sets that are established to distinguish what has been
1093
  // saved to the database from what is just showing default values
1094
  $form['#established'] = $established;
1095
1096
  // Top level form options
1097
  $form['#tree'] = TRUE;
1098
1099
  // Hidden elements
1100
  $form['modified'] = array(
1101
    '#type' => 'hidden',
1102
    '#value' => $modified,
1103
  );
1104
  $form['venue'] = array(
1105
    '#type' => 'hidden',
1106
    '#value' => $venue,
1107
  );
1108
1109
  $form['separator_top'] = array(
1110
    '#value' => '<div class="separator"></div>'
1111
  );
1112
1113
  // Common project preferences
1114
  $form['resource'] = array(
1115
    '#title' => bts('Resource settings', array(), NULL, 'boinc:account-preferences-project'),
1116
    '#type' => 'fieldset',
1117
    '#description' => null,
1118
    '#collapsible' => TRUE,
1119
    '#collapsed' => FALSE
1120
  );
1121
  $form['resource']['resource_share'] = array(
1122
    '#title' => bts('Resource share', array(), NULL, 'boinc:account-preferences-project'),
1123
    '#type' => 'textfield',
1124
    '#default_value' => $default['resource_share'],
1125
    '#size' => 5,
1126
    '#description' => bts("Determines the proportion of your computer's resources allocated to this project. Example: if you participate in two BOINC projects with resource shares of 100 and 200, the first will get 1/3 of your resources and the second will get 2/3.", array(), NULL, 'boinc:account-preferences-project')
1127
  );
1128
  if ($app_types->count > 1) {
1129
    if ($app_types->cpu) {
1130
      $form['resource']['no_cpu'] = array(
1131
        '#title' => bts('Use CPU', array(), NULL, 'boinc:account-preferences-project'),
1132
        '#type' => 'radios',
1133
        '#options' => $form['boolean_options']['#value'],
1134
        '#attributes' => array('class' => 'fancy'),
1135
        '#default_value' => $default['no_cpu'] ? 0 : 1,
1136
        '#description' => bts('Request CPU-only tasks from this project.', array(), NULL, 'boinc:account-preferences-project')
1137
      );
1138
    }
1139
    if ($app_types->cuda) {
1140
      $form['resource']['no_cuda'] = array(
1141
        '#title' => bts('Use NVIDIA GPU', array(), NULL, 'boinc:account-preferences-project'),
1142
        '#type' => 'radios',
1143
        '#options' => $form['boolean_options']['#value'],
1144
        '#attributes' => array('class' => 'fancy'),
1145
        '#default_value' => $default['no_cuda'] ? 0 : 1,
1146
        '#description' => bts('Request NVIDIA GPU tasks from this project.', array(), NULL, 'boinc:account-preferences-project')
1147
      );
1148
    }
1149
    if ($app_types->ati) {
1150
      $form['resource']['no_ati'] = array(
1151
        '#title' => bts('Use AMD GPU', array(), NULL, 'boinc:account-preferences-project'),
1152
        '#type' => 'radios',
1153
        '#options' => $form['boolean_options']['#value'],
1154
        '#attributes' => array('class' => 'fancy'),
1155
        '#default_value' => $default['no_ati'] ? 0 : 1,
1156
        '#description' => bts('Request AMD GPU tasks from this project.', array(), NULL, 'boinc:account-preferences-project')
1157
      );
1158
    }
1159
    if ($app_types->intel_gpu) {
1160
      $form['resource']['no_intel_gpu'] = array(
1161
        '#title' => bts('Use INTEL GPU', array(), NULL, 'boinc:account-preferences-project'),
1162
        '#type' => 'radios',
1163
        '#options' => $form['boolean_options']['#value'],
1164
        '#attributes' => array('class' => 'fancy'),
1165
        '#default_value' => $default['no_intel_gpu'] ? 0 : 1,
1166
        '#description' => bts('Request Intel GPU tasks from this project.', array(), NULL, 'boinc:account-preferences-project')
1167
      );
1168
    }
1169
    if ($app_types->apple_gpu) {
1170
      $form['resource']['no_apple_gpu'] = array(
1171
        '#title' => bts('Use Apple GPU', array(), NULL, 'boinc:account-preferences-project'),
1172
        '#type' => 'radios',
1173
        '#options' => $form['boolean_options']['#value'],
1174
        '#attributes' => array('class' => 'fancy'),
1175
        '#default_value' => $default['no_apple_gpu'] ? 0 : 1,
1176
        '#description' => bts('Request Apple GPU tasks from this project.', array(), NULL, 'boinc:account-preferences-project')
1177
      );
1178
    }
1179
  }
1180
1181
  if (variable_get('boinc_prefs_options_beta', FALSE)) {
1182
    $form['beta'] = array(
1183
      '#title' => bts('Beta settings', array(), NULL, 'boinc:account-preferences-project'),
1184
      '#type' => 'fieldset',
1185
      '#description' => null,
1186
      '#collapsible' => TRUE,
1187
      '#collapsed' => FALSE
1188
    );
1189
    $form['beta']['allow_beta_work'] = array(
1190
      '#title' => bts('Run test applications?', array(), NULL, 'boinc:account-preferences-project'),
1191
      '#type' => 'radios',
1192
      '#options' => $form['boolean_options']['#value'],
1193
      '#attributes' => array('class' => 'fancy'),
1194
      '#default_value' => ($default['allow_beta_work']) ? 1 : 0,
1195
      '#description' => bts('This helps us develop applications, but may cause jobs to fail on your computer', array(), NULL, 'boinc:account-preferences-project')
1196
    );
1197
  }
1198
1199
  // Add project specific prefs to the form
1200
  boincwork_add_project_specific_prefs($form, $prefs);
1201
1202
  // Set whether to use this preference set by default for new computers
1203
  $form['default_set'] = array(
1204
    '#title' => bts('Default set', array(), NULL, 'boinc:account-preferences-project'),
1205
    '#type' => 'fieldset',
1206
    '#description' => null,
1207
    '#collapsible' => TRUE,
1208
    '#collapsed' => FALSE
1209
  );
1210
  $form['default_set']['default_venue'] = array(
1211
    '#title' => bts('Set used for new computers', array(), NULL, 'boinc:account-preferences-project'),
1212
    '#type' => 'radios',
1213
    '#options' => $form['boolean_options']['#value'],
1214
    '#attributes' => array('class' => 'fancy'),
1215
    '#default_value' => $default['default_venue'] ? 1 : 0,
1216
    '#description' => ''
1217
  );
1218
1219
  $form['prefs']['separator_bottom'] = array(
1220
    '#value' => '<div class="separator buttons"></div>'
1221
  );
1222
1223
  // Form control
1224
  $form['prefs']['form control tabs prefix'] = array(
1225
    '#value' => '<ul class="form-control tab-list">'
1226
  );
1227
  $form['prefs']['submit'] = array(
1228
    '#prefix' => '<li class="first tab">',
1229
    '#type' => 'submit',
1230
    '#value' => bts('Save changes', array(), NULL, 'boinc:form-save'),
1231
    '#suffix' => '</li>'
1232
  );
1233
  $form['prefs']['form control tabs'] = array(
1234
    '#value' => '<li class="tab">' . l(bts('Cancel', array(), NULL, 'boinc:form-cancel'), $_GET['q']) . '</li>'
1235
  );
1236
  if ($venue AND $venue != 'generic') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
1237
    global $base_path;
1238
    $form['prefs']['form control tabs']['#value'] .= '<li class="tab">' .
1239
      l(bts('Clear', array(), NULL, 'boinc:form-clear'), "account/prefs/project/clear/{$venue}",
1240
        array(
1241
          'query' => 'destination=' . urlencode(drupal_get_path_alias('account/prefs/project/combined')),
1242
          'attributes' => array(
1243
            'onclick' => 'return confirm(\'' . bts('This will remove all of your settings from the @name preference set. Are you sure?',
1244
              array('@name' => $venue), NULL, 'boinc:account-preferences') . '\')'
1245
          )
1246
        )
1247
      ) . '</li>';
1248
  }
1249
  $form['prefs']['view control'] = array(
1250
      '#value' => '<li class="first alt tab">' . l('(' . bts('Show comparison view', array(), NULL, 'boinc:account-preferences') . ')', 'account/prefs/project/combined') . '</li>'
1251
  );
1252
  $form['prefs']['form control tabs suffix'] = array(
1253
    '#value' => '</ul>'
1254
  );
1255
1256
  return $form;
1257
}
1258
1259
/**
1260
 * Add project specific preferences to the project preferences form
1261
 */
1262
function boincwork_add_project_specific_prefs(&$form, $prefs) {
1263
  // Load project specific preferences from XML config
1264
  $xml = boincwork_get_project_specific_config();
1265
1266
  // Respect the order of the top level elements
1267
  $ordered_array = array();
1268
  $unordered_array = array();
1269
  foreach ($xml['project_specific_preferences'] as $type => $element) {
1270
    if (is_array($element) AND is_numeric(key($element))) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
1271
      foreach ($element as $ordered_element) {
1272
        if (isset($ordered_element['@position'])) {
1273
          $ordered_array[$ordered_element['@position']] = array($type => $ordered_element);
1274
        }
1275
        else {
1276
          $unordered_array[] = array($type => $ordered_element);
1277
        }
1278
      }
1279
    }
1280
    elseif (isset($element['@position'])) {
1281
      $ordered_array[$element['@position']] = array($type => $element);
1282
    }
1283
    else {
1284
      $unordered_array[] = array($type => $element);
1285
    }
1286
  }
1287
  ksort($ordered_array);
1288
  $primed_array = array_merge($ordered_array, $unordered_array);
1289
  $xml = array('project_specific_preferences' => $primed_array);
1290
1291
  foreach ($xml['project_specific_preferences'] as $wrapped_element) {
1292
    $type = key($wrapped_element);
1293
    $element= reset($wrapped_element);
1294
    boincwork_generate_prefs_element($form, $type, $element, $prefs['project_specific']);
1295
  }
1296
}
1297
1298
/**
1299
  * Validate the project preferences form.
1300
  */
1301
function boincwork_projectprefs_form_validate($form, &$form_state) {
1302
1303
  // Verify all text user input values and notify form API of failures
1304
  $validation_rules = array(
1305
    'resource' => array(
1306
      'resource_share' => array(
1307
        'datatype' => 'integer',
1308
        'min' => 0
1309
      ),
1310
    ),
1311
  );
1312
1313
  // Add validation rules for project specific settings
1314
  $validation_rules += boincwork_get_project_specific_config_validation_rules();
1315
1316
  // Perform validation
1317
  boincwork_validate_form($validation_rules, $form_state['values']);
1318
1319
  // Check for app validation
1320
  if (isset($validation_rules['apps'])) {
1321
    if (isset($validation_rules['apps']['minimum selected'])
1322
        AND $validation_rules['apps']['minimum selected'] > 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
1323
      $apps_selected = 0;
1324
      foreach ($validation_rules['apps']['list'] as $app) {
1325
        if ($form_state['values']['applications'][$app]) $apps_selected++;
1326
      }
1327
      if ($apps_selected < $validation_rules['apps']['minimum selected']) {
1328
        form_set_error(
1329
          'applications',
1330
          bts('At least one application must be selected', array(), NULL, 'boinc:account-preferences-project')
1331
        );
1332
      }
1333
      if ($apps_selected == count($validation_rules['apps']['list'])) {
1334
        foreach ($validation_rules['apps']['list'] as $app) {
1335
          unset($form_state['values']['applications'][$app]);
1336
        }
1337
        $form_state['storage']['all apps selected'] = TRUE;
1338
      }
1339
    }
1340
  }
1341
}
1342
1343
/**
1344
  * Handle post-validation submission of project preferences form.
1345
  */
1346
function boincwork_projectprefs_form_submit($form, &$form_state) {
1347
  global $user;
1348
  global $site_name;
1349
1350
  require_boinc(array('util'));
1351
  $app_types = get_app_types();
1352
1353
  $account = user_load($user->uid);
1354
  $edit = $form_state['values'];
1355
  $venue = $edit['venue'];
1356
1357
  // Load preferences from BOINC account
1358
  $prefs = boincwork_load_prefs('project', $venue);
1359
1360
  // Resource preferences
1361
  $prefs['resource_share'] = $edit['resource']['resource_share'];
1362
  if ($app_types->count > 1) {
1363
    if ($app_types->cpu) $prefs['no_cpu'] = ($edit['resource']['no_cpu']) ? 0 : 1;
1364
    if ($app_types->cuda) $prefs['no_cuda'] = ($edit['resource']['no_cuda']) ? 0 : 1;
1365
    if ($app_types->ati) $prefs['no_ati'] = ($edit['resource']['no_ati']) ? 0 : 1;
1366
    if ($app_types->intel_gpu) $prefs['no_intel_gpu'] = ($edit['resource']['no_intel_gpu']) ? 0 : 1;
1367
    if ($app_types->apple_gpu) $prefs['no_apple_gpu'] = ($edit['resource']['no_apple_gpu']) ? 0 : 1;
1368
  }
1369
1370
  // Beta preferences
1371
  if (variable_get('boinc_prefs_options_beta', FALSE)) {
1372
    $prefs['allow_beta_work'] = ($edit['beta']['allow_beta_work']) ? 1 : 0;
1373
  }
1374
1375
  // Load project specific preferences from XML config
1376
  $xml = boincwork_get_project_specific_config();
1377
  $updated_prefs = array(
1378
    'project_specific' => boincwork_format_project_specific_prefs_data($edit)
1379
  );
1380
  $prefs = $updated_prefs + $prefs;
1381
1382
  // Don't specify apps if all are selected
1383
  if (isset($form_state['storage']['all apps selected'])) {
1384
    unset($prefs['project_specific']['app_id']);
1385
    unset($form_state['storage']['all apps selected']);
1386
  }
1387
1388
  // If this is a new preference set, be sure to unset the "cleared" attribute
1389
  if (isset($prefs['@attributes']['cleared'])) {
1390
    unset($prefs['@attributes']['cleared']);
1391
  }
1392
1393
  // Save preferences back to the BOINC account
1394
  $result = boincwork_save_prefs($prefs, 'project', $venue);
1395
1396
  // Update the user's default preference set
1397
  if ($edit['default_set']['default_venue']) {
1398
    boincwork_set_default_venue($venue);
1399
  }
1400
  elseif ($venue == $account->boincuser_default_pref_set) {
1401
    // User has cleared out the default venue setting
1402
    boincwork_set_default_venue();
1403
  }
1404
1405
  if (!$result) {
1406
    watchdog('boincwork', 'Error updating project prefs for user @id: @message', array('@id' => $user->id, '@message' => mysqli_error()), WATCHDOG_ERROR);
0 ignored issues
show
The call to mysqli_error() has too few arguments starting with mysql. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1406
    watchdog('boincwork', 'Error updating project prefs for user @id: @message', array('@id' => $user->id, '@message' => /** @scrutinizer ignore-call */ mysqli_error()), WATCHDOG_ERROR);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
1407
    drupal_set_message(t('Your changes could not be saved. Please contact support!'), 'error');
1408
  }
1409
  elseif (!drupal_get_messages('status', FALSE)) {
1410
    // Show this message if the set wasn't created automatically (in which case
1411
    // there is a message tailored to that)
1412
    drupal_set_message(t('Your preferences have been updated.
1413
        Client-related preferences will take effect when your computer
1414
        communicates with @project or you issue the "Update"
1415
        command from the BOINC client.',
1416
        array('@project' => $site_name)));
1417
  }
1418
}
1419
1420
/**
1421
 * The structure of the community preferences form
1422
 */
1423
function communityprefs_form(&$form_state) {
1424
  global $user;
1425
  $account = user_load($user->uid);
1426
  $form = array();
1427
1428
  // Pull in some elements from the profile form
1429
  $profile_form_state = array();
1430
  $profile = new stdClass();
1431
  $profile->type = 'profile';
1432
  $profile->language = '';
1433
  if ($profile_nid = content_profile_profile_exists($profile, $account->uid)) {
1434
    $profile_node = node_load($profile_nid);
1435
    $form_state['storage']['profile_node'] = $profile_node;
1436
    module_load_include('inc', 'node', 'node.pages');
1437
    $profile_form = drupal_retrieve_form('profile_node_form', $profile_form_state, $profile_node);
1438
    drupal_prepare_form('profile_node_form', $profile_form, $profile_form_state);
1439
  }
1440
1441
  // Standard option sets
1442
  $form['boolean_options'] = array(
1443
    '#type' => 'value',
1444
    '#value' => array(1 => bts('yes', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-no'), 0 => bts('no', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-yes'))
1445
  );
1446
1447
  $default = array(
1448
    'pm_send_notification' => '', // This is set already in pm_email_notify_user
1449
    'friend_notification' => isset($account->friend_notification) ? $account->friend_notification : 0,
1450
    'comments_per_page' => (isset($account->comments_per_page) AND $account->comments_per_page) ? $account->comments_per_page : variable_get('comment_default_per_page_forum', 50),
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
1451
    'comments_order' => (isset($account->sort) AND $account->sort) ? $account->sort : variable_get('comment_default_order_forum', COMMENT_ORDER_OLDEST_FIRST),
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
As per coding-style, PHP keywords should be in lowercase; expected and, but found AND.
Loading history...
1452
  );
1453
1454
  // General options
1455
  $form['general'] = array(
1456
    '#type' => 'fieldset',
1457
    '#title' => bts('General settings', array(), NULL, 'boinc:account-preferences-community'),
1458
    '#weight' => 0,
1459
    '#collapsible' => TRUE,
1460
    '#collapsed' => FALSE
1461
  );
1462
  // Add the BOINC user name (non-unique, user editable)
1463
  $form['general']['boincuser_name'] = array(
1464
    '#type' => 'textfield',
1465
    '#title' => bts('Name', array(), NULL, 'boinc:user-or-team-name'),
1466
    '#default_value' => $account->boincuser_name,
1467
    '#maxlength' => USERNAME_MAX_LENGTH,
1468
    '#required' => TRUE,
1469
    '#description' => '',
1470
    '#size' => 40
1471
  );
1472
  // Time zone
1473
  if (variable_get('configurable_timezones', 1)) {
1474
    $zones = _system_zonelist();
1475
    $form['general']['timezone'] = array(
1476
      '#type' => 'select',
1477
      '#title' => bts('Time zone', array(), NULL, 'boinc:account-preferences-community'),
1478
      '#default_value' => ($account->timezone !== NULL) ? $account->timezone : variable_get('date_default_timezone', 0),
1479
      '#options' => $zones,
1480
      '#description' => '',
1481
    );
1482
  }
1483
1484
  // Notification options
1485
  $form['notifications'] = array(
1486
    '#type' => 'fieldset',
1487
    '#title' => bts('Notification settings', array(), NULL, 'boinc:account-preferences-community'),
1488
    '#weight' => 5,
1489
    '#collapsible' => TRUE,
1490
    '#collapsed' => FALSE
1491
  );
1492
  // Pull in private message notification handling and tweak the form
1493
  $pm_notify = pm_email_notify_user('form', $edit, $account, 'account');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $edit seems to be never defined.
Loading history...
1494
  $form['notifications']['pm_send_notifications'] = array_replace(
1495
    $pm_notify['enable_pm_mail']['pm_send_notifications'],
1496
    array(
1497
      '#type' => 'radios',
1498
      '#title' => bts('Receive email notification for private messages?', array(), NULL, 'boinc:account-preferences-community'),
1499
      '#description' => ' ',
1500
      '#options' => $form['boolean_options']['#value'],
1501
      '#attributes' => array('class' => 'fancy')
1502
    )
1503
  );
1504
  $form['notifications']['friend_notification'] = array(
1505
    '#type' => 'radios',
1506
    '#title' => bts('Receive email notification for friend requests?', array(), NULL, 'boinc:account-preferences-community'),
1507
    '#description' => ' ',
1508
    '#options' => array(0 => bts('yes', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-no'), -1 => bts('no', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-yes')),
1509
    '#attributes' => array('class' => 'fancy'),
1510
    '#default_value' => $default['friend_notification']
1511
  );
1512
1513
  // Internationalization options
1514
  if (module_exists('internationalization')) {
1515
    $languages = language_list('enabled');
1516
    $languages = $languages[1];
1517
    $names = array();
1518
    foreach ($languages as $langcode => $item) {
1519
      $name = t($item->name);
1520
      $names[check_plain($langcode)] = check_plain($name . ($item->native != $name ? ' ('. $item->native .')' : ''));
1521
    }
1522
    $form['locale'] = array(
1523
      '#type' => 'fieldset',
1524
      '#title' => bts('Language settings', array(), NULL, 'boinc:account-preferences-community'),
1525
      '#weight' => 10,
1526
      '#collapsible' => TRUE,
1527
      '#collapsed' => FALSE,
1528
    );
1529
1530
    // Get language negotiation settings.
1531
    $mode = variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE);
1532
    $user_preferred_language = user_preferred_language($account);
1533
    $form['locale']['language'] = array(
1534
      '#type' => 'select',
1535
      '#title' => bts('Language', array(), NULL, 'boinc:account-preferences-community'),
1536
      '#default_value' => check_plain($user_preferred_language->language),
1537
      '#options' => $names,
1538
      '#description' => ($mode == LANGUAGE_NEGOTIATION_PATH) ? bts("This account's default language for e-mails and preferred language for site presentation.", array(), NULL, 'boinc:account-preferences-community') : bts("This account's default language for e-mails.", array(), NULL, 'boinc:account-preferences-community'),
1539
    );
1540
  }
1541
1542
  // Avatar options
1543
  $form['gravatar'] = array(
1544
    '#type' => 'item',
1545
    '#value' => bts('If you have a <a href="@gravatar-check">valid Gravatar</a> associated with your e-mail address, it will be used for your user picture.', array('@gravatar-check' => 'http://en.gravatar.com/site/check/' . $account->mail), NULL, 'boinc:account-preferences-community'),
1546
    '#description' => bts('Your Gravatar will not be shown if you upload a user picture.', array(), NULL, 'boinc:account-preferences-community'),
1547
  );
1548
  if (user_access('disable own gravatar', $account)) {
1549
    $form['gravatar'] = array(
1550
      '#type' => 'checkbox',
1551
      '#title' => bts('If you have a <a href="@gravatar-check">valid Gravatar</a> associated with your e-mail address, use it for your user picture.', array('@gravatar-check' => 'http://en.gravatar.com/site/check/' . $account->mail), NULL, 'boinc:account-preferences-community'),
1552
      '#description' => bts('Gravatar will not be shown if an avatar is uploaded.', array(), NULL, 'boinc:account-preferences-community'),
1553
      '#default_value' => isset($account->gravatar) ? $account->gravatar : 0,
1554
      '#disabled' => !empty($account->picture),
1555
    );
1556
  }
1557
  $form['gravatar']['#weight'] = 15;
1558
  $form['gravatar']['#prefix'] = '<fieldset class="collapsible"><legend><a href="#">' . bts('Avatar settings', array(), NULL, 'boinc:account-preferences-community') . '</a></legend>';
1559
  // Upload an avatar (pulled from profile_node_form):
1560
  if (!empty($profile_form['field_image'])) {
1561
    $form['field_image'] = $profile_form['field_image'];
1562
  }
1563
  else {
1564
    $form['field_image'] = array(
1565
      '#value' => '<div class="form-item">'
1566
        . '<label class="placeholder">'
1567
        . bts('This is not available until your profile is set up.', array(), NULL, 'boinc:account-preferences-community')
1568
        . '</label>'
1569
        . l(bts('Create a profile', array(), NULL, 'boinc:account-preferences-community'), 'account/profile/edit', array('attributes' => array('class' => 'form-link')))
1570
        . '</div>',
1571
    );
1572
  }
1573
  $form['field_image'][0]['#title'] = bts('Upload an avatar', array(), NULL, 'boinc:account-preferences-community');
1574
  $form['field_image']['#weight'] = 20;
1575
  $form['field_image']['#suffix'] = '</fieldset>';
1576
1577
  // Forum options
1578
  $form['forums'] = array(
1579
    '#type' => 'fieldset',
1580
    '#title' => bts('Forum settings', array(), NULL, 'boinc:account-preferences-community'),
1581
    '#weight' => 25,
1582
    '#collapsible' => TRUE,
1583
    '#collapsed' => FALSE
1584
  );
1585
  $form['forums']['comments_per_page'] = array(
1586
    '#type' => 'select',
1587
    '#title' => bts('In discussion topics, show at most @comments_per_page', array('@comments_per_page' => ''), NULL, 'boinc:account-preferences-community'),
1588
    '#options' => array(10 => 10, 20 => 20, 30 => 30, 50 => 50, 100 => 100),
1589
    '#default_value' => $default['comments_per_page']
1590
  );
1591
  // Can't have a typical Drupal form suffix on a select box?
1592
  $form['forums']['comments_per_page_suffix'] = array(
1593
    '#value' => '<span>' . bts('comments per page', array(), NULL, 'boinc:account-preferences-community') . '</span>'
1594
  );
1595
  $form['forums']['comments_order'] = array(
1596
    '#type' => 'select',
1597
    '#title' => bts('Sort comments in discussions', array(), NULL, 'boinc:account-preferences-community'),
1598
    '#options' => array(1 => bts('Newest post first', array(), NULL, 'boinc:account-preferences-community'), 2 => bts('Oldest post first', array(), NULL, 'boinc:account-preferences-community')),
1599
    '#default_value' => $default['comments_order']
1600
  );
1601
  // Signature (pulled from user_edit_form):
1602
  if (variable_get('user_signatures', 0) && module_exists('comment')) {
1603
    $form['forums']['signature'] = array(
1604
      '#type' => 'textarea',
1605
      '#title' => bts('Signature', array(), NULL, 'boinc:account-preferences-community'),
1606
      '#description' => bts('Your signature will be publicly displayed at the end of your comments.', array(), NULL, 'boinc:account-preferences-community'),
1607
      '#default_value' => $account->signature
1608
      );
1609
    // Prevent a "validation error" message when the user attempts to save with a default value they
1610
    // do not have access to.
1611
    if (!filter_access($account->signature_format) && empty($_POST)) {
1612
      drupal_set_message(t("The signature input format has been set to a format you don't have access to. It will be changed to a format you have access to when you save this page."));
1613
      $edit['signature_format'] = FILTER_FORMAT_DEFAULT;
1614
    }
1615
    $form['forums']['signature_format'] = filter_form($account->signature_format, NULL, array('signature_format'));
1616
    // Optionally hide signatures from comments
1617
    $form['forums']['hide_signatures'] = array(
1618
      '#type' => 'radios',
1619
      '#title' => bts('Hide signatures in forums', array(), NULL, 'boinc:account-preferences-community'),
1620
      '#description' => ' ',
1621
      '#options' => $form['boolean_options']['#value'],
1622
      '#attributes' => array('class' => 'fancy'),
1623
      '#default_value' => isset($account->hide_signatures) ? $account->hide_signatures : 0,
1624
    );
1625
  }
1626
1627
  //Bottom separator
1628
  $form['separator_bottom'] = array(
1629
    '#value' => '<div class="separator buttons"></div>',
1630
    '#weight' => 999,
1631
  );
1632
1633
  // Form control
1634
  $form['form control tabs prefix'] = array(
1635
    '#value' => '<ul class="form-control tab-list">',
1636
    '#weight' => 1001,
1637
  );
1638
  $form['submit'] = array(
1639
    '#prefix' => '<li class="first tab">',
1640
    '#type' => 'submit',
1641
    '#value' => bts('Save changes', array(), NULL, 'boinc:form-save'),
1642
    '#suffix' => '</li>',
1643
    '#weight' => 1002,
1644
  );
1645
  $form['form control tabs'] = array(
1646
    '#value' => '<li class="tab">' . l(bts('Cancel', array(), NULL, 'boinc:form-cancel'), $_GET['q']) . '</li>',
1647
    '#weight' => 1003,
1648
  );
1649
  $form['form control tabs suffix'] = array(
1650
    '#value' => '</ul>',
1651
    '#weight' => 1004,
1652
  );
1653
  return $form;
1654
}
1655
1656
/**
1657
  * Handle validation submission of community preferences form.
1658
  */
1659
function communityprefs_form_validate($form, &$form_state) {
1660
  // require_boinc();
1661
  global $user;
1662
  $account = user_load($user->uid);
1663
  $boinc_user = BoincUser::lookup_id($account->boincuser_id);
1664
  $edit = $form_state['values'];
1665
1666
  if ($edit['boincuser_name'] != $boinc_user->name) {
1667
    $blacklist1 = preg_split('/\r\n|\r|\n/', variable_get('boinc_weboptions_blacklisted_usernames', "admin\nadministrator\nmoderator"));
1668
    $blacklist2 = array();
1669
    if (is_array($blacklist1)) {
0 ignored issues
show
The condition is_array($blacklist1) is always true.
Loading history...
1670
      $blacklist2 = array_map('strtolower', $blacklist1);
1671
    }
1672
    if (in_array(strtolower($edit['boincuser_name']), $blacklist2)) {
1673
      form_set_error('boincuser_name',
1674
        bts('You may not use username @blname, as that name is not allowed. Please choose another name.',
1675
            array('@blname' => $edit['boincuser_name']),
1676
            NULL, 'boinc:account-preferences-community'));
1677
      return false;
1678
    }
1679
  }
1680
1681
  return true;
1682
}
1683
1684
/**
1685
  * Handle post-validation submission of community preferences form.
1686
  */
1687
function communityprefs_form_submit($form, &$form_state) {
1688
  require_boinc('boinc_db');
1689
  global $user;
1690
  $account = user_load($user->uid);
1691
  $boinc_user = BoincUser::lookup_id($account->boincuser_id);
1692
  $edit = $form_state['values'];
1693
  $profile_node = $form_state['storage']['profile_node'];
1694
1695
  // Display name
1696
  if ($edit['boincuser_name'] != $boinc_user->name) {
1697
    $boincuser_name = $edit['boincuser_name'];
1698
    $result = $boinc_user->update(
1699
        "name='{$boincuser_name}'"
1700
    );
1701
  }
1702
1703
  // Private message settings
1704
  pm_email_notify_user('submit', $edit, $user);
1705
1706
  // Avatar settings - only set if profile_node exists.
1707
  if ($profile_node) {
1708
    if (!$edit['field_image']) $edit['field_image'] = array();
1709
    $profile_node->field_image = $edit['field_image'];
1710
    node_save($profile_node);
1711
    // Flush this from the node cache or changes won't show up immediately!
1712
    $profile_node = node_load($profile_node->nid, NULL, TRUE);
1713
  }
1714
1715
  // All other settings
1716
  $settings = array(
1717
    'signature' => $edit['signature'],
1718
    'signature_format' => $edit['signature_format'],
1719
    'timezone' => $edit['timezone'],
1720
    'friend_notification' => $edit['friend_notification'],
1721
    'comments_per_page' => $edit['comments_per_page'],
1722
    'hide_signatures' => $edit['hide_signatures'],
1723
    'sort' => $edit['comments_order'],
1724
    'gravatar' => $edit['gravatar'],
1725
  );
1726
  if (module_exists('internationalization')) {
1727
    $settings['language'] = $edit['language'];
1728
    global $language;
1729
    if ($user->language != $edit['language']) {
1730
      global $base_url;
1731
      if ($edit['language'] != language_default('language')) {
1732
        $form_state['redirect'] = $base_url . '/' . $edit['language'] . '/' . $_GET['q'];
1733
      }
1734
      else {
1735
        $form_state['redirect'] = $base_url . '/' . $_GET['q'];
1736
      }
1737
    }
1738
  }
1739
  user_save($user, $settings);
1740
1741
  drupal_set_message(bts('Your community preferences have been updated.', array(), NULL, 'boinc:account-preferences-community'));
1742
1743
  // Form will not redirect if storage is set; not good if language changes
1744
  unset($form_state['storage']);
1745
}
1746
1747
/**
1748
 * The structure of the privacy preferences form
1749
 */
1750
function boincwork_privacyprefs_form(&$form_state) {
1751
  require_boinc(array('user', 'prefs', 'util', 'consent'));
1752
1753
  global $user;
1754
  $account = user_load($user->uid);
1755
  $boincuser = BoincUser::lookup_id($account->boincuser_id);
1756
1757
  // Load preferences from BOINC account
1758
  $prefs = boincwork_load_prefs('project');
1759
1760
  //if (!$prefs AND !$initialize_if_empty) return null;
1761
1762
  $privacy_consent_types = boincwork_load_privacyconsenttypes();
1763
1764
  // Define form defaults
1765
  $default = array(
1766
    'privacy' => array(
1767
      'send_email' => ($boincuser->send_email) ? 1 : 0,
1768
      'show_hosts' => ($boincuser->show_hosts) ? 1 : 0
1769
    )
1770
  );
1771
1772
  // Standard option sets
1773
  $form['boolean_options'] = array(
1774
    '#type' => 'value',
1775
    '#value' => array(1 => bts('yes', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-no'), 0 => bts('no', array(), NULL, 'boinc:form-yes-no:-1:binary-form-option-pairs-with-yes'))
1776
  );
1777
1778
  $form['privacy'] = array(
1779
    '#title' => bts('Privacy settings', array(), NULL, 'boinc:account-preferences-privacy'),
1780
    '#type' => 'fieldset',
1781
    '#description' => null,
1782
    '#collapsible' => TRUE,
1783
    '#collapsed' => FALSE
1784
  );
1785
  $form['privacy']['send_email'] = array(
1786
    '#title' => bts('Is it OK for @project and your team (if any) to email you?', array('@project' => variable_get('site_name', 'Drupal-BOINC')), NULL, 'boinc:account-preferences-privacy'),
1787
    '#type' => 'radios',
1788
    '#options' => $form['boolean_options']['#value'],
1789
    '#attributes' => array('class' => 'fancy'),
1790
    '#default_value' => $default['privacy']['send_email']
1791
  );
1792
  $form['privacy']['show_hosts'] = array(
1793
    '#title' => bts('Should @project show your computers on its website?', array('@project' => variable_get('site_name', 'Drupal-BOINC')), NULL, 'boinc:account-preferences-privacy'),
1794
    '#description' => bts('At times, you may be asked to enable this option in order to receive help from the forums. Advanced users may need to be able to inspect your computers\' information in order to help diagnose any problems.', array(), NULL, 'boinc:account-preferences-privacy'),
1795
    '#type' => 'radios',
1796
    '#options' => $form['boolean_options']['#value'],
1797
    '#attributes' => array('class' => 'fancy'),
1798
    '#default_value' => $default['privacy']['show_hosts']
1799
  );
1800
1801
  // Loop over privacy consent types and create form question for each
1802
  // option that deals with privacy.
1803
  foreach ($privacy_consent_types as $ct) {
1804
1805
    $currstate = (check_user_consent($boincuser, $ct['shortname'])) ? 1 : 0 ;
0 ignored issues
show
Space found before semicolon; expected "0;" but found "0 ;"
Loading history...
1806
    // Set name to 'privacyconsent_SHORTNAME', which can be parsed
1807
    // later in the submit function.
1808
    $form['privacy']['privacyconsent_'.$ct['shortname']] = array(
1809
      '#title' => bts($ct['description'], array(), NULL, 'boinc:account-preferences-privacy'),
1810
      '#type' => 'radios',
1811
      '#options' => $form['boolean_options']['#value'],
1812
      '#attributes' => array('class' => 'fancy'),
1813
      '#default_value' => $currstate,
1814
    );
1815
1816
    // Add a description with link to the question 'Do you consent to
1817
    // exporting your data...'.
1818
    $mypatt = '/Do you consent to exporting your data/';
1819
    if (preg_match($mypatt, $ct['description']) ) {
1820
      $form['privacy']['privacyconsent_'.$ct['shortname']]['#description'] = bts('See our !privacy_policy_link for the current list of statistics exports.',
1821
      array(
1822
        '!privacy_policy_link' => l(
1823
          bts('privacy policy', array(), NULL, 'boinc:account-preferences-privacy'),
1824
          '/privacy'
1825
        )
1826
      ),
1827
      NULL, 'boinc:account-preferences-privacy');
1828
    }
1829
  }
1830
1831
  // Ignore and block users
1832
  if (module_exists('ignore_user')) {
1833
    $form['ignoreblock'] = array(
1834
      '#title' => bts('Ignore Users', array(), NULL, 'boinc:account-preferences-privacy'),
1835
      '#type' => 'fieldset',
1836
      '#description' => bts('<p>You may ignore users in the forums and block users from sending you private messages.<p>', array(), NULL, 'boinc:ignore-user-help'),
1837
      '#collapsible' => TRUE,
1838
      '#collapsed' => FALSE
1839
    );
1840
1841
    // Table for ignored users
1842
    $form['ignoreblock']['current_ignore_section'] = array(
1843
      '#type' => 'item',
1844
      '#value' => bts('Current users on your Ignore List', array(), NULL, 'boinc:ignore-user-list'),
1845
      '#prefix' => '<h4>',
1846
      '#suffix' => '</h4>',
1847
      '#weight' => -20,
1848
    );
1849
1850
    $ignored_users = _ignore_user_ignored_users();
1851
    foreach ($ignored_users as $ignored_user) {
1852
      $form['ignoreblock']['username'][$ignored_user['iuid']] = array(
1853
        '#value' => $ignored_user['username'],
1854
      );
1855
      $form['ignoreblock']['delete'][$ignored_user['iuid']] = array(
1856
        '#value' => l(
1857
          bts('delete', array(), NULL, 'boinc:ignore-user-delete-button'),
1858
          'account/prefs/privacy/ignore_user/remove/'. $ignored_user['iuid'],
1859
          array()
1860
        ),
1861
      );
1862
    }
1863
    $form['ignoreblock']['pager'] = array('#value' => theme('pager', NULL, 10, 0));
1864
1865
    // Sub-form to add user to ignore list
1866
    $form['ignoreblock']['add_ignore_user_section'] = array(
1867
      '#type' => 'item',
1868
      '#value' => bts('Add user to Ignore List', array(), NULL, 'boinc:ignore-user-add'),
1869
      '#prefix' => '<h4>',
1870
      '#suffix' => '</h4>',
1871
      '#weight' => 10,
1872
    );
1873
1874
    $form['ignoreblock']['addusername_toignorelist'] = array(
1875
      '#type' => 'textfield',
1876
      '#title' => bts('Username', array(), NULL, 'boinc:ignore-user-searchbox'),
1877
      '#description' => bts('To lookup a username start typing in the search box. A list of usernames will appear as you type. The number appearing in the suffix is the BOINC id. You can find a user\'s BOINC id on their user profile page.', array(), NULL, 'boinc:ignore-user-searchbox-help'),
1878
      '#weight' => 11,
1879
      '#size' => 50,
1880
      '#autocomplete_path' => 'boincuser/autocomplete',
1881
    );
1882
1883
    $form['ignoreblock']['addusername_submit'] = array(
1884
      '#type' => 'submit',
1885
      '#value' => bts('Ignore user', array(), NULL, 'boinc:ignore-user-add'),
1886
      '#submit' => array('_boincwork_ignore_list_form_submit'),
1887
      '#weight' => 12,
1888
      '#attributes' => array('class' => 'add_ignore_user'),
1889
    );
1890
  }// endif module_exists
1891
1892
  $form['prefs']['separator_bottom'] = array(
1893
    '#value' => '<div class="separator buttons"></div>'
1894
  );
1895
1896
  // Form control
1897
  $form['prefs']['form control tabs prefix'] = array(
1898
    '#value' => '<ul class="form-control tab-list">'
1899
  );
1900
  $form['prefs']['submit'] = array(
1901
    '#prefix' => '<li class="first tab">',
1902
    '#type' => 'submit',
1903
    '#value' => bts('Save changes', array(), NULL, 'boinc:form-save'),
1904
    '#validate' => array('boincwork_privacyprefs_form_validate'),
1905
    '#submit' => array('boincwork_privacyprefs_form_submit'),
1906
    '#suffix' => '</li>'
1907
  );
1908
  $form['prefs']['form control tabs'] = array(
1909
    '#value' => '<li class="tab">' . l(bts('Cancel', array(), NULL, 'boinc:form-cancel'), $_GET['q']) . '</li>'
1910
  );
1911
  $form['prefs']['form control tabs suffix'] = array(
1912
    '#value' => '</ul>'
1913
  );
1914
1915
  return $form;
1916
}
1917
1918
/**
1919
 * Theme the form where user's can manage their ignore list
1920
 */
1921
function theme_boincwork_privacyprefs_form($form) {
1922
1923
  $output = '';
1924
  $output .= drupal_render($form['privacy']);
1925
1926
  $header = array(
1927
    bts('Username', array(), NULL, 'boinc:ignore-user-list'),
1928
    bts('Operations', array(), NULL, 'boinc:ignore-user-list')
0 ignored issues
show
There should be a trailing comma after the last value of an array declaration.
Loading history...
1929
  );
1930
1931
  $rows = array();
1932
  if (isset($form['ignoreblock']['username']) && is_array($form['ignoreblock']['username'])) {
1933
    foreach (element_children($form['ignoreblock']['username']) as $key) {
1934
      $row = array();
1935
      $row[] = drupal_render($form['ignoreblock']['username'][$key]);
1936
      $row[] = drupal_render($form['ignoreblock']['delete'][$key]);
1937
      $rows[] = $row;
1938
    }
1939
  }
1940
  else {
1941
    $rows[] = array(
1942
      array(
1943
        'data' => bts('You have not added any users to your Ignore List.', array(), NULL, 'boinc:ignore-user-list'),
1944
        'colspan' => '2',
1945
      )
0 ignored issues
show
There should be a trailing comma after the last value of an array declaration.
Loading history...
1946
    );
1947
  }
1948
1949
  $attr = array('class' => 'ignore_user');
1950
  $form['ignoreblock']['current_list']['ignored_users']['#value'] = theme('table', $header, $rows, $attr);
1951
  $output .= drupal_render($form['current_list']);
1952
1953
  if ($form['pager']['#value']) {
1954
    $output .= drupal_render($form['pager']);
1955
  }
1956
1957
  $output .= drupal_render($form);
1958
1959
  return $output;
1960
}
1961
1962
/**
1963
  * Validate the privacy preferences form.
1964
  */
1965
function boincwork_privacyprefs_form_validate($form, &$form_state) {
1966
  require_boinc('util');
1967
1968
  // Verify all non-boolean user input values and notify form API of failures
1969
  // ... currently there are no non-boolean values!
1970
}
1971
1972
/**
1973
  * Handle post-validation submission of privacy preferences form.
1974
  */
1975
function boincwork_privacyprefs_form_submit($form, &$form_state) {
1976
  require_boinc(array('user', 'prefs', 'consent'));
1977
1978
  global $user;
1979
  $account = user_load($user->uid);
1980
1981
  // Load BOINC account
1982
  $boincuser = BoincUser::lookup_id($account->boincuser_id);
1983
1984
  // Privacy preferences
1985
  $boincuser->send_email = ($form_state['values']['send_email']) ? true : false;
1986
  $boincuser->show_hosts = ($form_state['values']['show_hosts']) ? true : false;
1987
1988
  // Privacy consent options, extract the 'privacyconsent_SHORTNAME'
1989
  // from values array, and loop over them; each is checked with
1990
  // check_consent_type(). Also check the current state of the option
1991
  // in the database. If the form value is a new state, then set it.
1992
  $result = preg_grep("/^privacyconsent/", array_keys($form_state['values']));
1993
  $privacyconsent_prefs = array_intersect_key($form_state['values'], array_flip($result));
1994
  foreach ($privacyconsent_prefs as $name => $newstate) {
1995
    $subname = explode('_', $name)[1];
1996
    $currstate = (check_user_consent($boincuser, $subname)) ? 1 : 0 ;
0 ignored issues
show
Space found before semicolon; expected "0;" but found "0 ;"
Loading history...
1997
    list($checkct, $ctid) = check_consent_type($subname);
1998
    if ($checkct && ($currstate != $newstate)) {
1999
      consent_to_a_policy($boincuser, $ctid, $newstate, 0, 'Webform', time());
2000
    }
2001
  }
2002
2003
  //project_prefs_update($boincuser, $main_prefs);
2004
2005
  db_set_active('boinc_rw');
2006
  db_query("UPDATE user SET send_email = '{$boincuser->send_email}', show_hosts = '{$boincuser->show_hosts}' WHERE id = '{$boincuser->id}'");
2007
  db_set_active('default');
2008
2009
  drupal_set_message(t('Your privacy preferences have been updated.'));
2010
}
2011
2012
/**
2013
 * Additional submit handler for privacy form, button to add user to
2014
 * ignore list.
2015
 */
2016
function _boincwork_ignore_list_form_submit($form, $form_state) {
2017
  boincwork_ignore_user_add_user_username($form_state['values']['addusername_toignorelist']);
2018
  drupal_set_message(
2019
    bts('@username has been added to your ignore list. See your !privacy_preferences for more details.',
2020
      array(
2021
        '@username' => $form_state['values']['addusername_toignorelist'],
2022
        '!privacy_preferences' => l(bts('privacy preferences', array(), NULL, 'boinc:ignore-user-add'), 'account/prefs/privacy'),
2023
      ),
2024
      NULL, 'boinc:ignore-user-add'),
2025
    'status');
2026
}
2027
2028
/**
2029
 * Structure of the select application form in the task table.
2030
 */
2031
function boincwork_selectapp_form(&$form_state, $apps, $current_app) {
2032
2033
  $form['selectapp'] = array(
2034
    '#type' => 'select',
2035
    '#attributes' => array(
2036
      'class' => 'task-app-filter',
2037
      'onchange' => 'this.form.submit();',
2038
    ),
2039
    '#default_value' => $current_app,
2040
    '#options' => $apps,
2041
    '#post_render' => array('_boincwork_selectapp_form_callback'),
2042
  );
2043
2044
  // Class task-app-filter-submit for this form is used in
2045
  // theming. CSS sets 'display:none' if javascript is present. Thus
2046
  // only non-js users/browsers will see the Apply Filter button.
2047
  $form['submit'] = array(
2048
    '#type' => 'submit',
2049
    '#value' => bts('Apply Filter', array(), NULL, 'boinc:form-save'),
2050
    '#attributes' => array('class' => 'js-hide',),
0 ignored issues
show
Comma not allowed after last value in single-line array declaration
Loading history...
2051
  );
2052
2053
  return $form;
2054
}
2055
2056
/**
2057
 * Submit function for select appliacation form.
2058
 */
2059
function boincwork_selectapp_form_submit($form, &$form_state) {
2060
  $myargs = arg();
2061
  array_pop($myargs);
0 ignored issues
show
It seems like $myargs can also be of type null; however, parameter $array of array_pop() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2061
  array_pop(/** @scrutinizer ignore-type */ $myargs);
Loading history...
2062
  $newpath = implode('/', $myargs ) . '/' . $form['selectapp']['#value'];
2063
  $form_state['redirect'] = $newpath;
2064
}
2065
2066
/**
2067
 * Select application helper callback.
2068
 *
2069
 * Manually disables the option with value -1, which acts as the
2070
 * 'title' for the Application drop down box.
2071
 */
2072
function _boincwork_selectapp_form_callback($theContent, $theElement) {
2073
  $disabled = '<option value="-1" disabled hidden';
2074
  $newContent = preg_replace('/<option value="-1"/', $disabled, $theContent);
2075
  return $newContent;
2076
}
2077