Added encryption stuff + rewrote sendWernisApiRequest() to handle the decryption.
[mailer.git] / inc / libs / wernis_functions.php
1 <?php
2 /************************************************************************
3  * Mailer v0.2.1-FINAL                                Start: 10/19/2003 *
4  * ===================                          Last change: 08/12/2004 *
5  *                                                                      *
6  * -------------------------------------------------------------------- *
7  * File              : what-points.php                                  *
8  * -------------------------------------------------------------------- *
9  * Short description : All your collected points...                     *
10  * -------------------------------------------------------------------- *
11  * Kurzbeschreibung  : Alle Ihrer gesammelten Punkte                    *
12  * -------------------------------------------------------------------- *
13  * $Revision::                                                        $ *
14  * $Date::                                                            $ *
15  * $Tag:: 0.2.1-FINAL                                                 $ *
16  * $Author::                                                          $ *
17  * -------------------------------------------------------------------- *
18  * Copyright (c) 2003 - 2009 by Roland Haeder                           *
19  * Copyright (c) 2009 - 2015 by Mailer Developer Team                   *
20  * For more information visit: http://mxchange.org                      *
21  *                                                                      *
22  * This program is free software; you can redistribute it and/or modify *
23  * it under the terms of the GNU General Public License as published by *
24  * the Free Software Foundation; either version 2 of the License, or    *
25  * (at your option) any later version.                                  *
26  *                                                                      *
27  * This program is distributed in the hope that it will be useful,      *
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
30  * GNU General Public License for more details.                         *
31  *                                                                      *
32  * You should have received a copy of the GNU General Public License    *
33  * along with this program; if not, write to the Free Software          *
34  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,               *
35  * MA  02110-1301  USA                                                  *
36  ************************************************************************/
37
38 // Some security stuff...
39 if (!defined('__SECURITY')) {
40         die();
41 } // END - if
42
43 // Sets a status message and code
44 function setWernisStatusMessage ($message, $status) {
45         $GLOBALS['wernis_data']['message'] = $message;
46         $GLOBALS['wernis_data']['status']  = $status;
47 }
48
49 // Get the status message
50 function getWernisErrorMessage () {
51         if (isset($GLOBALS['wernis_data']['message'])) {
52                 // Use raw message
53                 return $GLOBALS['wernis_data']['message'];
54         } elseif (isset($GLOBALS['wernis_data']['status'])) {
55                 // Fall-back to status
56                 return '{%message,WERNIS_ERROR_STATUS=' . $GLOBALS['wernis_data']['status'] . '%}';
57         } else {
58                 // Something bad happend
59                 return '{--WERNIS_UNKNOWN_ERROR--}';
60         }
61 }
62
63 // Get the status code
64 function getWernisErrorCode () {
65         if (isset($GLOBALS['wernis_data']['status'])) {
66                 // Use raw message
67                 return $GLOBALS['wernis_data']['status'];
68         } else {
69                 // Something bad happend
70                 return '{--WERNIS_UNKNOWN_ERROR--}';
71         }
72 }
73
74 // Sends out a request to the API and returns it's result
75 function sendWernisApiRequest ($scriptName, $requestData = array()) {
76         // Debug call
77         //* DEBUG */ reportBug(__FUNCTION__, __LINE__, 'scriptName=' . $scriptName . ',requestData=<pre>' . print_r($requestData, TRUE) . '</pre>');
78
79         // Is the requestData an array?
80         if (!is_array($requestData)) {
81                 // Then abort here!
82                 return array(
83                         'status'  => 'failed_general',
84                         'message' => '{--WERNIS_API_REQUEST_DATA_INVALID--}'
85                 );
86         } // END - if
87
88         // Is the API id and MD5 hash there?
89         if ((getWernisApiId() == '') || (getWernisApiMd5() == '')) {
90                 // Abort here...
91                 return array(
92                         'status'  => 'failed_general',
93                         'message' => '{--WERNIS_API_REQUEST_DATA_MISSING--}'
94                 );
95         } // END - if
96
97         // Add more request data
98         $requestData['api_id']  = getWernisApiId();
99         $requestData['api_key'] = getWernisApiMd5();
100
101         // Is a purpose there?
102         if (!empty($requestData['purpose'])) {
103                 // Eval the purpose
104                 eval('$purpose = "' . doFinalCompilation($requestData['purpose'], FALSE) . '";');
105
106                 // Prepare the purpose, it needs encoding
107                 $requestData['purpose'] = encodeString($purpose);
108         } // END - if
109
110         // Construct the request string
111         $requestString = getWernisApiUrl() . $scriptName;
112
113         // Get the raw response from the lower function
114         $response = sendHttpPostRequest($requestString, $requestData);
115
116         // Check the response header if all is fine
117         if (!isHttpStatusOkay($response[0])) {
118                 // Something bad happend... :(
119                 return array(
120                         'status'  => 'request_error',
121                         'message' => '{%message,WERNIS_API_REQUEST_ERROR=' . $response[0] . '%}'
122                 );
123         } // END - if
124
125         // All (maybe) fine so remove the response header from server
126         $responseLine = '*INVALID*';
127         for ($idx = (count($response) - 1); $idx > 1; $idx--) {
128                 $line = trim($response[$idx]);
129                 if (!empty($line)) {
130                         $responseLine = $line;
131                         break;
132                 } // END - if
133         } // END - for
134
135         // Is the response leaded by a & symbol?
136         if (substr($responseLine, 0, 1) != '&') {
137                 // Something badly happened on server-side
138                 return array(
139                         'status'  => 'request_problem',
140                         'message' => sprintf(getMessage('WERNIS_API_REQUEST_PROBLEM'), $response[0], secureString($responseLine))
141                 );
142         } // END - if
143
144         // Remove the leading & (which can be used in Flash)
145         $responseLine = substr($responseLine, 1);
146
147         // Bring back the response
148         $data = explode('=', $responseLine);
149
150         // Default return array (should not stay empty)
151         $return = array();
152
153         // We use only the first two entries (which shall be fine)
154         if ($data[0] === 'error') {
155                 // The request has failed... :(
156                 switch ($data[1]) {
157                         case '404': // Invalid API id
158                         case 'AUTH': // Authorization has failed
159                                 $return = array(
160                                         'status'  => 'auth_failed',
161                                         'message' => '{--WERNIS_API_REQUEST_FAILED_AUTH--}'
162                                 );
163                                 break;
164
165                         case 'LOCKED': // User account is locked!
166                         case 'PASS': // Bad passphrase entered
167                         case 'USER': // Missing account or invalid password
168                                 $return = array(
169                                         'status'  => 'user_failed',
170                                         'message' => '{--WERNIS_API_REQUEST_FAILED_USER--}'
171                                 );
172                                 break;
173
174                         case 'OWN': // Transfer to own account
175                                 $return = array(
176                                         'status'  => 'own_failed',
177                                         'message' => '{--WERNIS_API_REQUEST_FAILED_OWN--}'
178                                 );
179                                 break;
180
181                         case 'AMOUNT': // Amount is depleted
182                                 $return = array(
183                                         'status'  => 'amount_failed',
184                                         'message' => '{--WERNIS_API_REQUEST_FAILED_AMOUNT--}'
185                                 );
186                                 break;
187
188                         case 'AMOUNT-SEND': // API amount is depleted
189                                 $return = array(
190                                         'status'  => 'api_amount_failed',
191                                         'message' => '{--WERNIS_API_REQUEST_FAILED_API_AMOUNT--}'
192                                 );
193                                 break;
194
195                         default: // Unknown error (maybe new?)
196                                 logDebugMessage(__FUNCTION__, __LINE__, sprintf('Unknown error %s from WDS66 API received.', $data[1]));
197                                 $return = array(
198                                         'status'  => 'request_failed',
199                                         'message' => '{%message,WERNIS_API_REQUEST_FAILED=' . $data[1] . '%}'
200                                 );
201                                 break;
202                 }
203         } else {
204                 // All fine, then analyze API response
205                 $return = convertApiResponseToArray($responseLine, '&', '=');
206
207                 // Nothing is fine now
208                 $return['status']  = 'generic_failed';
209                 $return['message'] = '--WERNIS_API_REQUEST_FAILED_GENERIC--}';
210
211                 // Are 'encrypted', 'key' and 'iv' set?
212                 //* DEBUG-DIE */ die(__FUNCTION__ . ':return=<pre>' . print_r($return, TRUE) . '</pre>');
213                 if ((isset($return['encrypted'])) && (isset($return['key'])) && (isset($return['iv']))) {
214                         // Fully decode it (URL-encoded BASE64)
215                         $decoded = decodeString($return['encrypted']);
216                         $iv      = decodeString($return['iv']);
217
218                         // Generate decryption key
219                         $decryptionKey = generateWernisDecryptionKey($return['key']);
220
221                         // Decrypt string
222                         $decrypted = decrytStringByCipher($decoded, getWernisEncryptionAlgorithm(), getWernisEncryptionMode(), $decryptionKey, $iv);
223                         //* DEBUG-DIE */ die('key="' . $return['key'] . '"<br />decryptionKey="' . $decryptionKey . '"<br />decoded="' . $decoded . '"<br />decrypted="' . $decrypted . '"');
224
225                         // First char must be an &
226                         assert(substr($decrypted, 0, 1) == '&');
227
228                         // Now the string needs to be turned into an array, first explode all &
229                         $elements = explode('&', $decrypted);
230
231                         // And remove first element
232                         array_shift($elements);
233                         //* DEBUG-DIE */ die('elements=<pre>' . print_r($elements, TRUE) . '</pre>');
234
235                         // Now "walk" all ements
236                         foreach ($elements as $idx => $element) {
237                                 // Explode element
238                                 $keyValue = explode('=', $element);
239
240                                 // Make sure it is valid
241                                 assert(count($keyValue) == 2);
242
243                                 // Now handle all over
244                                 $return[$keyValue[0]] = $keyValue[1];
245                         } // END - foreach
246
247                         // Remove encryption stuff
248                         unset($return['encrypted'], $return['key'], $return['iv']);
249                 } // END - if
250
251                 // All fine ...
252                 $return['status']  = 'OK';
253                 $return['message'] = NULL;
254         }
255
256         // Return the result
257         //* DEBUG-DIE */ die(__FUNCTION__ . ':return=<pre>' . print_r($return, TRUE) . '</pre>');
258         return $return;
259 }
260
261 // Tests the function by calling balance.php on the API
262 function doAdminTestWernisApi () {
263         // Only as admin
264         assert(isAdmin());
265
266         // Result is always failed
267         $result = FALSE;
268
269         // Prepare the request data
270         $requestData = array(
271                 't_uid' => getWernisRefid(),
272                 't_md5' => getWernisPassMd5()
273         );
274
275         // Return the result from the lower functions
276         $return = sendWernisApiRequest('balance.php', $requestData);
277
278         // Did it went smoothly?
279         if (isHttpResponseStatusOkay($return)) {
280                 // All fine!
281                 $result = TRUE;
282         } else {
283                 // Status failure text
284                 setWernisStatusMessage($return['message'], $return['status']);
285         }
286
287         // Return result
288         return $result;
289 }
290
291 // Widthdraw this amount
292 function executeWernisApiWithdraw ($wdsId, $userMd5, $amount) {
293         // Is the sponsor extension installed?
294         if (!isWernisWithdrawActive()) {
295                 if (!isExtensionActive('sponsor')) {
296                         // No, abort here
297                         return FALSE;
298                 } elseif (!isSponsor()) {
299                         // No sponsor, not allowed to withdraw!
300                         return FALSE;
301                 }
302         } // END - if
303
304         // Default is failed attempt
305         $result = FALSE;
306
307         // Prepare the request data
308         $requestData = array(
309                 'sub_request' => 'receive',
310                 't_uid'       => bigintval($wdsId),
311                 't_md5'       => $userMd5,
312                 'r_uid'       => getWernisRefid(),
313                 'amount'      => bigintval($amount),
314                 'purpose'     => getMaskedMessage('WERNIS_API_PURPOSE_WITHDRAW', getMemberId())
315         );
316
317         // Return the result from the lower functions
318         $return = sendWernisApiRequest('book.php', $requestData);
319
320         // Did it went smoothly?
321         if (isHttpResponseStatusOkay($return)) {
322                 // All fine!
323                 $result = TRUE;
324
325                 // Log the transfer
326                 logWernisTransfer($wdsId, $amount, 'WITHDRAW');
327         } else {
328                 // Status failure text
329                 setWernisStatusMessage($return['message'], $return['status']);
330
331                 // Log the transfer
332                 logWernisTransfer($wdsId, $amount, 'FAILED', $return['message'], $return['status']);
333         }
334
335         // Return result
336         return $result;
337 }
338
339 // Payout this amount
340 function executeWernisApiPayout ($wdsId, $amount) {
341         // Default is failed attempt
342         $result = FALSE;
343
344         // Prepare the request data
345         $requestData = array(
346                 'sub_request' => 'send',
347                 't_uid'       => getWernisRefid(),
348                 't_md5'       => getWernisPassMd5(),
349                 'r_uid'       => bigintval($wdsId),
350                 'amount'      => bigintval($amount),
351                 'purpose'     => getMaskedMessage('WERNIS_API_PURPOSE_PAYOUT', getMemberId())
352         );
353
354         // Return the result from the lower functions
355         $return = sendWernisApiRequest('book.php', $requestData);
356
357         if (isHttpResponseStatusOkay($return)) {
358                 // All fine!
359                 $result = TRUE;
360
361                 // Log the transfer
362                 logWernisTransfer($wdsId, $amount, 'PAYOUT');
363         } else {
364                 // Status failure text
365                 setWernisStatusMessage($return['message'], $return['status']);
366
367                 // Log the transfer
368                 logWernisTransfer($wdsId, $amount, 'FAILED', $return['message'], $return['status']);
369         }
370
371         // Return result
372         return $result;
373 }
374
375 // Execute auth.php request
376 function executeWernisApiAuth ($wernisId, $wernisPassword) {
377         // Prepare request data
378         $requestData = array(
379                 't_uid'       => bigintval($wernisId),
380                 't_md5'       => hashSha256($wernisPassword),
381         );
382
383         // Call auth.php
384         $return = sendWernisApiRequest('auth.php', $requestData);
385
386         // Return full array
387         return $return;
388 }
389
390 // Execute get.php reguest with given auth data (not all are used)
391 function executeWernisApiGet ($authData, $subRequest, $fields) {
392         // It must be an array
393         assert(is_array($authData));
394
395         // Check required array elements
396         assert(isset($authData['wernis_userid']));
397         assert(isset($authData['api_auth_key']));
398         assert(isset($authData['api_redirect_challenge']));
399
400         // Then create request array
401         $requestData = array(
402                 'sub_request' => $subRequest,
403                 'fields'      => $fields,
404                 't_uid'       => bigintval($authData['wernis_userid']),
405                 't_md5'       => getWernisPassMd5(),
406                 'auth_key'    => $authData['api_auth_key'],
407                 'challenge'   => $authData['api_redirect_challenge']
408         );
409
410         // Call get.php
411         $return = sendWernisApiRequest('get.php', $requestData);
412
413         // Return full array
414         return $return;
415 }
416
417 // Translate the status IN/OUT
418 function translateWernisTransferStatus ($status) {
419         // Default status is unknown
420         $return = '{%message,WERNIS_STATUS_UNKNWOWN=' . $status . '%}';
421
422         // Construct message id
423         $messageId = 'WERNIS_STATUS_' . $status;
424
425         // Is it there?
426         if (isMessageIdValid($messageId)) {
427                 // Then use it as message string
428                 $return = '{--' . $messageId . '--}';
429         } // END - if
430
431         // Return the status
432         return $return;
433 }
434
435 // Log the transfer
436 function logWernisTransfer ($wdsId, $amount, $type = 'FAILED', $message = '', $status = '') {
437         // Register this wernis movement
438         sqlQueryEscaped("INSERT INTO `{?_MYSQL_PREFIX?}_user_wernis` (`userid`, `wernis_account`, `wernis_amount`, `wernis_timestamp`, `wernis_type`, `wernis_api_message`, `wernis_api_status`) VALUES (%s, %s, %s, UNIX_TIMESTAMP(), '%s', '%s', '%s')",
439                 array(
440                         getMemberId(),
441                         bigintval($wdsId),
442                         bigintval($amount),
443                         $type,
444                         $message,
445                         $status
446                 ), __FUNCTION__, __LINE__);
447 }
448
449 // Calulcate fees and factor
450 function calculateWernisFee ($points, $mode) {
451         // Payout or withdraw are allowed modes!
452         //* DEBUG: */ debugOutput('mode=' . $mode . ',points=' . $points);
453         if (!in_array($mode, array('payout', 'withdraw'))) {
454                 // Log error and abort
455                 logDebugMessage(__FUNCTION__, __LINE__, 'userid=' . getMemberId() . ',mode=' . $mode . ',points=' . $points . ' - unknown mode detected.');
456                 return FALSE;
457         } // END - if
458
459         // Is there a percentage or fixed fee?
460         if (getConfig('wernis_' . $mode . '_fee_percent') > 0) {
461                 // Percentage fee
462                 $points -= $points * getConfig('wernis_'.$mode.'_fee_percent') / 100;
463         } elseif (getConfig('wernis_' . $mode . '_fee_fix') > 0) {
464                 // Fixed fee
465                 $points -= getConfig('wernis_' . $mode . '_fee_fix');
466         }
467
468         // Divide/multiply the factor
469         if ($mode == 'payout') {
470                 // Divide for payout
471                 $points = $points / getWernisPayoutFactor();
472         } else {
473                 // Multiply for withdraw
474                 $points = $points * getWernisWithdrawFactor();
475         }
476
477         // Return value
478         //* DEBUG: */ debugOutput('mode=' . $mode . ',points=' . $points);
479         return $points;
480 }
481
482 // Add withdraw fees and factor
483 // @TODO Unused?
484 function calulcateWernisWithdrawFee ($points) {
485         // Is there a percentage or fixed fee?
486         if (getWernisWithdrawFeePercent() > 0) {
487                 // Percentage fee
488                 $points += $points * getWernisWithdrawFeePercent() / 100;
489         } elseif (getWernisWithdrawFeeFix() > 0) {
490                 // Fixed fee
491                 $points += getWernisWithdrawFeeFix();
492         }
493
494         // Return value
495         return $points;
496 }
497
498 // Displays registration form for WDS66 registration
499 function doDisplayWernisUserRegistrationForm () {
500         // Is the form sent?
501         if (isFormSent('register')) {
502                 // Is wernis_id set?
503                 if (!isPostRequestElementSet('wernis_id')) {
504                         // Id not set
505                         displayMessage('{--GUEST_WERNIS_REGISTRATION_ID_NOT_SET--}');
506                 } elseif (!isPostRequestElementSet('wernis_password')) {
507                         // Password not set
508                         displayMessage('{--GUEST_WERNIS_REGISTRATION_PASSWORD_NOT_SET--}');
509                 } else {
510                         // So far, all fine, then let's do the call-back on auth.php ...
511                         $args = executeWernisApiAuth(postRequestElement('wernis_id'), postRequestElement('wernis_password'));
512
513                         // Status was okay?
514                         if (isHttpResponseStatusOkay($args)) {
515                                 // Is status set?
516                                 //* DEBUG-DIE */ die('response=<pre>' . print_r($response, TRUE) . '</pre>,args=' . '<pre>'.print_r($args, TRUE).'</pre>');
517                                 assert(isset($args['auth_status']));
518
519                                 // Add WDS66 userid
520                                 $args['wernis_userid'] = postRequestElement('wernis_id');
521
522                                 // "Detect" auth status
523                                 $callbackFunction = 'doWernisAuth' . capitalizeUnderscoreString($args['auth_status']);
524
525                                 // Is the call-back there?
526                                 if (!is_callable($callbackFunction, FALSE, $callableName)) {
527                                         // Not there, could be bad. :(
528                                         reportBug(__FUNCTION__, __LINE__, 'Unsupported auth_status=' . $args['auth_status'] . ',args()=' . count($args) . ',callbackFunction=' . $callbackFunction . ' detected.');
529                                 } // END - if
530
531                                 // Then call it
532                                 $status = call_user_func($callbackFunction, $args);
533
534                                 // @TODO Something more to do here?
535                                 die(__FUNCTION__ . ':' . __LINE__ . ': status[' . gettype($status) . ']=' . $status . ' - Unfinished.');
536                         } else {
537                                 // Something bad happened
538                                 displayMessage($args['message']);
539                         }
540                 }
541         } // END - if
542
543         // Is there a challenge + response?
544         if ((isGetRequestElementSet('status')) && (isGetRequestElementSet('challenge')) && (isGetRequestElementSet('__challenge_response'))) {
545                 // Redirect from modules.php?module=auth, so validate challenge response ...
546                 // 1) Get first 24 characters = salt
547                 $salt = substr(getRequestElement('__challenge_response'), 0, 24);
548
549                 // 2) Generate hash for challenge response
550                 $challengeResponse = $salt . hashSha256($salt . getWernisApiMd5() . getRequestElement('challenge'));
551
552                 // Is the response valid?
553                 if ($challengeResponse != getRequestElement('__challenge_response')) {
554                         // Not valid
555                         displayMessage('{--GUEST_WERNIS_REGISTRATION_INVALID_CHALLENGE_RESPONSE--}');
556                         return;
557                 } // END - if
558
559                 /*
560                  * Now, that the challenge-response is the same, the challenge itself
561                  * is also the same. Next get the data from wernis_regs table by
562                  * challenge. There is currently no other way to get the data as there
563                  * is no Wernis user id provided. Later on the stored challenge response
564                  * can be compared with provided.
565                  */
566                 $return = doWernisFinishUserRegistration(getRequestElement('challenge'), getRequestElement('__challenge_response'), getRequestElement('status'));
567
568                 // Is the registration finished?
569                 if ($return === FALSE) {
570                         // No, then abort here silently as the function should have already displayed a message
571                         return;
572                 } // END - if
573         } elseif (!isFormSent('register')) {
574                 // Form not send, so load form template
575                 loadTemplate('guest_wernis_registration_rpc_form');
576         }
577 }
578
579 // Finish user registration with WDS66 API
580 function doWernisFinishUserRegistration ($challenge, $challengeResponse, $status) {
581         // Is the status 1? (= all fine with API call)
582         if ($status == '1') {
583                 // Get mapped data based on challenge
584                 $return = getWernisMappedDataFromApiByChallenge($challenge, $status);
585
586                 // Is the array filled?
587                 //* DEBUG-DIE */ die(__METHOD__ . ':return=<pre>' . print_r($return, TRUE) . '</pre> - EXIT!');
588                 if ((isset($return['mapped_data'])) && (count($return['mapped_data']) > 0) && (empty($return['message']))) {
589                         // Set must-fillout fields
590                         $return['mapped_data'] = runFilterChain('register_must_fillout', $return['mapped_data']);
591
592                         // Add missing elements
593                         $return['mapped_data']['gender']               = NULL;
594                         $return['mapped_data']['birthday_selection']   = generateDayMonthYearSelectionBox($return['mapped_data']['birth_day'], $return['mapped_data']['birth_month'], $return['mapped_data']['birth_year']);
595                         $return['mapped_data']['challenge']            = getRequestElement('challenge');
596                         $return['mapped_data']['__challenge_response'] = getRequestElement('__challenge_response');
597
598                         // Display form
599                         loadTemplate('guest_wernis_registration_form', FALSE, $return['mapped_data']);
600
601                         // All fine
602                         return TRUE;
603                 } else {
604                         // Something unexpected happened (e.g. no API requests left)
605                         displayMessage($return['message']);
606                         return FALSE;
607                 }
608         } else {
609                 // Status does not need to be changed
610                 die(__FUNCTION__ . ':' . __LINE__ . ': Reached!');
611         }
612 }
613
614 // "Getter" for mapped data by calling the API and given challenge and status
615 function getWernisMappedDataFromApiByChallenge ($challenge, $status) {
616         // Get stored registration data
617         $rows = getWernisRegistrationDataByKey('api_redirect_challenge', $challenge);
618
619         // Zero result found?
620         if (count($rows) == 0) {
621                 // Nothing found
622                 displayMessage('{--GUEST_WERNIS_REGISTRATION_ZERO_ROWS_FOUND--}');
623
624                 // Display form
625                 loadTemplate('guest_wernis_registration_rpc_form');
626                 return array();
627         } // END - if
628
629         // Init array
630         $return = array(
631                 // Mapped data
632                 'mapped_data' => array(),
633                 // Any error message from API
634                 'message'     => ''
635         );
636
637         // Has the auth status changed?
638         if ($rows[0]['api_auth_status'] != 'ACCEPTED') {
639                 /*
640                  * The authorization of this application has been accepted, so
641                  * update it and ignore result from function because the update
642                  * will always run.
643                  */
644                 updateWernisRegistrationDataByKey('api_auth_status', 'api_redirect_challenge', $challenge, 'ACCEPTED');
645         } // END - if
646
647         // Now call "get.php"
648         $response = executeWernisApiGet($rows[0], 'data', 'vorname|name|strasse|plz|ort|birth_day|birth_month|birth_year|email|werber');
649
650         // Was the status okay?
651         //* DEBUG-DIE */ die(__FUNCTION__ . ':response=<pre>' . print_r($response, TRUE) . '</pre>');
652         if (isHttpResponseStatusOkay($response)) {
653                 // API returned non-errous response, 'data=' must be found
654                 assert(isset($response['data']));
655
656                 // And decode it (all steps separated to later "easily" debug them)
657                 $decodedData = base64_decode(urldecode($response['data']));
658                 //* DEBUG-DIE */ die(__FUNCTION__ . ':decodedData=' . $decodedData);
659
660                 /*
661                  * Do some checks on the decoded string, it should be a
662                  * serialized array with 10 entries (see above
663                  * executeWernisApiGet() call).
664                  */
665                 assert(substr($decodedData, 0, 6) == 'a:10:{');
666                 assert(substr($decodedData, -1, 1) == '}');
667
668                 // The array seems to be fine, unserialize it
669                 $userData = unserialize($decodedData);
670                 //* DEBUG-DIE */ die(__METHOD__ . ':userData=<pre>' . print_r($userData, TRUE) . '</pre> - EXIT!');
671
672                 // All mappings WDS66->mailer
673                 $mappings = array(
674                         'vorname'     => 'surname',
675                         'name'        => 'family',
676                         'strasse'     => 'street_nr',
677                         'plz'         => 'zip',
678                         'ort'         => 'city',
679                         'email'       => 'email',
680                         'birth_day'   => 'birth_day',
681                         'birth_month' => 'birth_month',
682                         'birth_year'  => 'birth_year',
683                         'werber'      => 'wernis_refid'
684                 );
685
686                 // Map all WDS66 entries into mailer entries
687                 foreach ($mappings as $from => $to) {
688                         // All must exist
689                         if (!isset($userData[$from])) {
690                                 // Element $from does not exist
691                                 reportBug(__FUNCTION__, __LINE__, 'Cannot map from=' . $from . ' -> to=' . $to . ': element does not exist.');
692                         } // END - if
693
694                         // "Map" all
695                         $return['mapped_data'][$to] = convertEmptyToNull($userData[$from]);
696                 } // END - foreach
697
698                 // Both arrays must have same size
699                 assert(count($userData) == count($return['mapped_data']));
700
701                 // Now add userid from WDS66
702                 $return['mapped_data']['wernis_userid'] = bigintval($rows[0]['wernis_userid']);
703         } else {
704                 // Something bad happened so copy the message
705                 $return['message'] = $response['message'];
706         }
707
708         // Return mapped data array
709         //* DEBUG-DIE */ die(__METHOD__ . ':return=<pre>' . print_r($return, TRUE) . '</pre> - EXIT!');
710         return $return;
711 }
712
713 // Updates auth status by given key/value pair
714 function updateWernisRegistrationDataByKey ($updatedColumn, $key, $oldValue, $newValue) {
715         // Run the update
716         sqlQueryEscaped("UPDATE
717         `{?_MYSQL_PREFIX?}_wernis_regs`
718 SET
719         `%s` = '%s'
720 WHERE
721         `%s` = '%s' AND
722         `%s` != '%s'
723 LIMIT 1",
724                 array(
725                         $updatedColumn,
726                         $newValue,
727                         $key,
728                         $oldValue,
729                         $updatedColumn,
730                         $oldValue
731                 ), __FUNCTION__, __LINE__
732         );
733
734         // Check if rows as been affected
735         return ifSqlHasZeroAffectedRows();
736 }
737
738 // "Getter" for Wernis registration data by given key and value
739 function getWernisRegistrationDataByKey ($key, $value, $limit = 1) {
740         // Init array
741         $rows = array();
742
743         // Now search for it
744         $result = sqlQueryEscaped("SELECT
745         `local_userid`,
746         `wernis_userid`,
747         `api_auth_status`,
748         `api_auth_key`,
749         `api_redirect_challenge`,
750         UNIX_TIMESTAMP(`record_inserted`) AS `record_inserted`
751 FROM
752         `{?_MYSQL_PREFIX?}_wernis_regs`
753 WHERE
754         `%s`='%s'
755 ORDER BY
756         `id`
757 LIMIT %d",
758                 array(
759                         $key,
760                         $value,
761                         $limit
762                 ), __FUNCTION__, __LINE__
763         );
764
765         // Is there an entry?
766         if (sqlNumRows($result) > 0) {
767                 // At least one entry has been found, so loop through all
768                 while ($row = sqlFetchArray($result)) {
769                         // Add it
770                         array_push($rows, $row);
771                 } // END - while
772         } // END - if
773
774         // Free result
775         sqlFreeResult($result);
776
777         // Return found entries
778         return $rows;
779 }
780
781 // Do local user registration with data from WDS66 API
782 function doWernisUserRegistration () {
783         // Call generic registration function
784         $status = doGenericUserRegistration();
785
786         // Does this went fine?
787         if ($status === FALSE) {
788                 // No, then abort here silently
789                 return FALSE;
790         } // END - if
791
792         // Make sure the user id is valid
793         assert(isset($GLOBALS['register_userid']));
794         assert(isValidId($GLOBALS['register_userid']));
795
796         // Generic registration is finished, so add more data:
797 }
798
799 // Generates decrption key based on private key, public key and API key
800 function generateWernisDecryptionKey ($publicKey) {
801         // Generate key from most known data
802         $key = hashSha256(sprintf(
803                 '%s:%s:%s',
804                 getWernisApiMd5(),
805                 getWernisPrivateKey(),
806                 $publicKey
807         ));
808
809         // Return it
810         return $key;
811 }
812
813 //-----------------------------------------------------------------------------
814 //                      Auth status callback functions
815 //-----------------------------------------------------------------------------
816
817 // Handler for auth_status=PENDING
818 function doWernisAuthPending ($args) {
819         // $args must always be an array
820         assert(is_array($args));
821
822         // auth_key and wernis_userid must be set
823         assert(isset($args['auth_key']));
824         assert(isset($args['wernis_userid']));
825
826         // Generate a challenge that will be added to the URL
827         $challenge = hashSha256(generatePassword(128));
828
829         // Search entry in database by auth_key
830         if (countSumTotalData($args['auth_key'], 'wernis_regs', 'id', 'api_auth_key', TRUE) == 0) {
831                 // "Register" this call
832                 sqlQueryEscaped("INSERT INTO `{?_MYSQL_PREFIX?}_wernis_regs` (
833         `wernis_userid`,
834         `api_auth_status`,
835         `api_auth_key`,
836         `api_redirect_challenge`
837 ) VALUES (
838         %s,
839         'PENDING',
840         '%s',
841         '%s'
842 )",
843                         array(
844                                 bigintval($args['wernis_userid']),
845                                 $args['auth_key'],
846                                 $challenge
847                         ), __FUNCTION__, __LINE__
848                 );
849         } else {
850                 // Update challenge
851                 sqlQueryEscaped("UPDATE
852         `{?_MYSQL_PREFIX?}_wernis_regs`
853 SET
854         `api_redirect_challenge`='%s'
855 WHERE
856         `api_auth_key`='%s' AND
857         `wernis_userid`=%s AND
858         `api_auth_status`='PENDING'
859 LIMIT 1",
860                         array(
861                                 $challenge,
862                                 $args['auth_key'],
863                                 bigintval($args['wernis_userid'])
864                         ), __FUNCTION__, __LINE__
865                 );
866         }
867
868         // Should always update/insert
869         assert(sqlAffectedRows() == 1);
870
871         // Redirect to WDS66 module=auth ...
872         //* DEBUG-DIE */ die(__FUNCTION__ . ':' . __LINE__ . '<pre>' . print_r($args, TRUE) . '</pre>');
873         redirectToUrl(getWernisBaseUrl() . '/modules.php?module=auth&amp;auth_key=' . trim($args['auth_key']) . '&amp;params=' . urlencode(base64_encode('&module=' . getModule() . '&what=' . getWhat())) . '&amp;challenge=' . $challenge, FALSE, FALSE);
874 }
875
876 // Handler for auth_status=ACCEPTED
877 function doWernisAuthAccepted ($args) {
878         // $args must always be an array
879         assert(is_array($args));
880
881         // auth_key and wernis_userid must be set
882         assert(isset($args['auth_key']));
883         assert(isset($args['wernis_userid']));
884         die(__FUNCTION__ . ':' . __LINE__ . '<pre>' . print_r($args, TRUE) . '</pre>');
885 }
886
887 //------------------------------------------------------------------------------
888 //                             Template helper functions
889 //------------------------------------------------------------------------------
890
891 // Template helper to generate a selection box for encryption alogrithms
892 function doTemplateSelectWernisEncryptionAlgorithm ($templateName, $clear = FALSE, $default = NULL) {
893         // Get all available algorithms
894         $algorithms = getSupportedEncryptionAlgorithms();
895         //* DEBUG-DIE */ die('algorithms=<pre>' . print_r($algorithms, TRUE) . '</pre>');
896
897         // Init array
898         $options = array();
899
900         // And fill it
901         foreach ($algorithms as $key => $dummy) {
902                 $options[$key] = array('algorithms' => $key);
903         } // END - if
904
905         // Handle it over to generateSelectionBoxFromArray()
906         $content = generateSelectionBoxFromArray($options, 'wernis_encryption_algorithm', 'algorithms', '', '_wernis', '', $default, '', TRUE, FALSE);
907
908         // Return prepared content
909         return $content;
910 }
911
912 // Template helper to generate a selection box for encryption alogrithms
913 function doTemplateSelectWernisEncryptionMode ($templateName, $clear = FALSE, $default = NULL) {
914         // Get all available modes
915         $modes = getSupportedEncryptionModes();
916
917         // Init array
918         $options = array();
919
920         // And fill it
921         foreach ($modes as $key => $dummy) {
922                 $options[$key] = array('modes' => $key);
923         } // END - if
924
925         // Handle it over to generateSelectionBoxFromArray()
926         $content = generateSelectionBoxFromArray($options, 'wernis_encryption_mode', 'modes', '', '_wernis', '', $default, '', TRUE, FALSE);
927
928         // Return prepared content
929         return $content;
930 }
931
932 //-----------------------------------------------------------------------------
933 //                             Wrapper functions
934 //-----------------------------------------------------------------------------
935
936 // Wrapper function for 'wernis_refid'
937 function getWernisRefid () {
938         // Is there cache?
939         if (!isset($GLOBALS[__FUNCTION__])) {
940                 // Get config entry
941                 $GLOBALS[__FUNCTION__] = getConfig('wernis_refid');
942         } // END - if
943
944         // Return cache
945         return $GLOBALS[__FUNCTION__];
946 }
947
948 // Wrapper function for 'wernis_pass_md5'
949 function getWernisPassMd5 () {
950         // Is there cache?
951         if (!isset($GLOBALS[__FUNCTION__])) {
952                 // Get config entry
953                 $GLOBALS[__FUNCTION__] = getConfig('wernis_pass_md5');
954         } // END - if
955
956         // Return cache
957         return $GLOBALS[__FUNCTION__];
958 }
959
960 // Wrapper function for 'wernis_api_id'
961 function getWernisApiId () {
962         // Is there cache?
963         if (!isset($GLOBALS[__FUNCTION__])) {
964                 // Get config entry
965                 $GLOBALS[__FUNCTION__] = getConfig('wernis_api_id');
966         } // END - if
967
968         // Return cache
969         return $GLOBALS[__FUNCTION__];
970 }
971
972 // Wrapper function for 'wernis_api_md5'
973 function getWernisApiMd5 () {
974         // Is there cache?
975         if (!isset($GLOBALS[__FUNCTION__])) {
976                 // Get config entry
977                 $GLOBALS[__FUNCTION__] = getConfig('wernis_api_md5');
978         } // END - if
979
980         // Return cache
981         return $GLOBALS[__FUNCTION__];
982 }
983
984 // Wrapper function for 'wernis_api_url'
985 function getWernisApiUrl () {
986         // Is there cache?
987         if (!isset($GLOBALS[__FUNCTION__])) {
988                 // Get config entry
989                 $GLOBALS[__FUNCTION__] = getConfig('wernis_api_url');
990         } // END - if
991
992         // Return cache
993         return $GLOBALS[__FUNCTION__];
994 }
995
996 // Wrapper function for 'wernis_withdraw_active'
997 function getWernisWithdrawActive () {
998         // Is there cache?
999         if (!isset($GLOBALS[__FUNCTION__])) {
1000                 // Get config entry
1001                 $GLOBALS[__FUNCTION__] = getConfig('wernis_withdraw_active');
1002         } // END - if
1003
1004         // Return cache
1005         return $GLOBALS[__FUNCTION__];
1006 }
1007
1008 // Wrapper function for 'wernis_payout_active'
1009 function getWernisPayoutActive () {
1010         // Is there cache?
1011         if (!isset($GLOBALS[__FUNCTION__])) {
1012                 // Get config entry
1013                 $GLOBALS[__FUNCTION__] = getConfig('wernis_payout_active');
1014         } // END - if
1015
1016         // Return cache
1017         return $GLOBALS[__FUNCTION__];
1018 }
1019
1020 // Wrapper function for 'wernis_withdraw_active'
1021 function isWernisWithdrawActive () {
1022         // Is there cache?
1023         if (!isset($GLOBALS[__FUNCTION__])) {
1024                 // Get config entry
1025                 $GLOBALS[__FUNCTION__] = (getConfig('wernis_withdraw_active') == 'Y');
1026         } // END - if
1027
1028         // Return cache
1029         return $GLOBALS[__FUNCTION__];
1030 }
1031
1032 // Wrapper function for 'wernis_payout_active'
1033 function isWernisPayoutActive () {
1034         // Is there cache?
1035         if (!isset($GLOBALS[__FUNCTION__])) {
1036                 // Get config entry
1037                 $GLOBALS[__FUNCTION__] = (getConfig('wernis_payout_active') == 'Y');
1038         } // END - if
1039
1040         // Return cache
1041         return $GLOBALS[__FUNCTION__];
1042 }
1043
1044 // Wrapper function for 'wernis_withdraw_factor'
1045 function getWernisWithdrawFactor () {
1046         // Is there cache?
1047         if (!isset($GLOBALS[__FUNCTION__])) {
1048                 // Get config entry
1049                 $GLOBALS[__FUNCTION__] = getConfig('wernis_withdraw_factor');
1050         } // END - if
1051
1052         // Return cache
1053         return $GLOBALS[__FUNCTION__];
1054 }
1055
1056 // Wrapper function for 'wernis_payout_factor'
1057 function getWernisPayoutFactor () {
1058         // Is there cache?
1059         if (!isset($GLOBALS[__FUNCTION__])) {
1060                 // Get config entry
1061                 $GLOBALS[__FUNCTION__] = getConfig('wernis_payout_factor');
1062         } // END - if
1063
1064         // Return cache
1065         return $GLOBALS[__FUNCTION__];
1066 }
1067
1068 // Wrapper function for 'wernis_withdraw_fee_percent'
1069 function getWernisWithdrawFeePercent () {
1070         // Is there cache?
1071         if (!isset($GLOBALS[__FUNCTION__])) {
1072                 // Get config entry
1073                 $GLOBALS[__FUNCTION__] = getConfig('wernis_withdraw_fee_percent');
1074         } // END - if
1075
1076         // Return cache
1077         return $GLOBALS[__FUNCTION__];
1078 }
1079
1080 // Wrapper function for 'wernis_withdraw_fee_fix'
1081 function getWernisWithdrawFeeFix () {
1082         // Is there cache?
1083         if (!isset($GLOBALS[__FUNCTION__])) {
1084                 // Get config entry
1085                 $GLOBALS[__FUNCTION__] = getConfig('wernis_withdraw_fee_fix');
1086         } // END - if
1087
1088         // Return cache
1089         return $GLOBALS[__FUNCTION__];
1090 }
1091
1092 // Wrapper function for 'wernis_payout_fee_percent'
1093 function getWernisPayoutFeePercent () {
1094         // Is there cache?
1095         if (!isset($GLOBALS[__FUNCTION__])) {
1096                 // Get config entry
1097                 $GLOBALS[__FUNCTION__] = getConfig('wernis_payout_fee_percent');
1098         } // END - if
1099
1100         // Return cache
1101         return $GLOBALS[__FUNCTION__];
1102 }
1103
1104 // Wrapper function for 'wernis_payout_fee_fix'
1105 function getWernisPayoutFeeFix () {
1106         // Is there cache?
1107         if (!isset($GLOBALS[__FUNCTION__])) {
1108                 // Get config entry
1109                 $GLOBALS[__FUNCTION__] = getConfig('wernis_payout_fee_fix');
1110         } // END - if
1111
1112         // Return cache
1113         return $GLOBALS[__FUNCTION__];
1114 }
1115
1116 // Wrapper function for 'wernis_min_payout'
1117 function getWernisMinPayout () {
1118         // Is there cache?
1119         if (!isset($GLOBALS[__FUNCTION__])) {
1120                 // Get config entry
1121                 $GLOBALS[__FUNCTION__] = getConfig('wernis_min_payout');
1122         } // END - if
1123
1124         // Return cache
1125         return $GLOBALS[__FUNCTION__];
1126 }
1127
1128 // Wrapper function for 'wernis_min_withdraw'
1129 function getWernisMinWithdraw () {
1130         // Is there cache?
1131         if (!isset($GLOBALS[__FUNCTION__])) {
1132                 // Get config entry
1133                 $GLOBALS[__FUNCTION__] = getConfig('wernis_min_withdraw');
1134         } // END - if
1135
1136         // Return cache
1137         return $GLOBALS[__FUNCTION__];
1138 }
1139
1140 // Wrapper function for 'wernis_base_url'
1141 function getWernisBaseUrl () {
1142         // Is there cache?
1143         if (!isset($GLOBALS[__FUNCTION__])) {
1144                 // Get config entry
1145                 $GLOBALS[__FUNCTION__] = getConfig('wernis_base_url');
1146         } // END - if
1147
1148         // Return cache
1149         return $GLOBALS[__FUNCTION__];
1150 }
1151
1152 // Wrapper function for 'wernis_encryption_algorithm'
1153 function getWernisEncryptionAlgorithm () {
1154         // Is there cache?
1155         if (!isset($GLOBALS[__FUNCTION__])) {
1156                 // Get config entry
1157                 $GLOBALS[__FUNCTION__] = getConfig('wernis_encryption_algorithm');
1158         } // END - if
1159
1160         // Return cache
1161         return $GLOBALS[__FUNCTION__];
1162 }
1163
1164 // Wrapper function for 'wernis_encryption_mode'
1165 function getWernisEncryptionMode () {
1166         // Is there cache?
1167         if (!isset($GLOBALS[__FUNCTION__])) {
1168                 // Get config entry
1169                 $GLOBALS[__FUNCTION__] = getConfig('wernis_encryption_mode');
1170         } // END - if
1171
1172         // Return cache
1173         return $GLOBALS[__FUNCTION__];
1174 }
1175
1176 // Wrapper function for 'wernis_private_key'
1177 function getWernisPrivateKey () {
1178         // Is there cache?
1179         if (!isset($GLOBALS[__FUNCTION__])) {
1180                 // Get config entry
1181                 $GLOBALS[__FUNCTION__] = getConfig('wernis_private_key');
1182         } // END - if
1183
1184         // Return cache
1185         return $GLOBALS[__FUNCTION__];
1186 }
1187
1188 // [EOF]
1189 ?>