A bunch of little errors, including a fix to the balancehash computation
[Trubanc.git] / client / index.php
blob4e055091e7acca2df3c254e4cce988b485f3fe66
1 <?php
3 // client/index.php
4 // A Trubanc web client
6 require_once "../lib/weblib.php";
8 // Define $dbdir, $require_coupon, $ssl_domain
9 if (file_exists('settings.php')) require_once "settings.php";
10 if (!$template_file) $template_file = "template.php";
12 die_unless_client_properly_configured();
13 maybe_forward_to_ssl($ssl_domain);
15 require_once "../lib/fsdb.php";
16 require_once "../lib/ssl.php";
17 require_once "../lib/client.php";
18 require_once "../lib/timestamp.php";
19 require_once "../lib/perf.php";
21 function mq($x) {
22 if (get_magic_quotes_gpc()) return stripslashes($x);
23 else return $x;
26 function mqpost($x) {
27 return mq(@$_POST[$x]);
30 function mqrequest($x) {
31 return mq(@$_REQUEST[$x]);
34 function hsc($x) {
35 return htmlspecialchars($x);
38 function printr($x) {
39 echo "<pre>\n";
40 print_r($x);
41 echo "</pre>\n";
44 $debug = '';
46 function appenddebug($x) {
47 global $debug;
48 $debug .= $x;
51 // Add a string to the debug output.
52 // Does NOT add a newline.
53 // Use var_export($val, true) to dump arrays
54 function debugmsg($x) {
55 global $client;
57 $client->debugmsg($x);
60 $cmd = @mq($_REQUEST['cmd']);
62 $db = new fsdb($dbdir);
63 $ssl = new ssl();
64 $client = new client($db, $ssl);
65 $timestamp = new timestamp();
66 $iphone = strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone');
67 $history = false;
70 if (@$_COOKIE['debug']) {
71 $client->showprocess = 'appenddebug';
72 perf_init();
73 $perf_idx = perf_start('The rest');
76 $default_menuitems = array('balance' => 'Balance',
77 'contacts' => 'Contacts',
78 'banks' => 'Banks',
79 'assets' => 'Assets',
80 //'admins' => 'Admin',
81 'logout' => 'Logout');
83 // Initialize (global) inputs to template.php
84 $title = "Trubanc Client";
85 $bankline = '';
87 $error = false;
89 $session = @$_COOKIE['session'];
90 if ($session) {
91 $err = $client->login_with_sessionid($session);
92 if ($err) {
93 setcookie('session', false);
94 $error = "Session login error: $err";
95 $cmd = 'logout';
96 $session = false;
97 } else {
98 if (!$cmd) $cmd = 'balance';
102 if ($client->id) {
103 $keephistory = $client->userpreference('keephistory');
104 // Default is to keep history
105 if (!$keephistory) $keephistory = 'keep';
106 $client->keephistory($keephistory == 'keep');
108 setbank();
110 if (!$client->bankid) {
111 if ($cmd && $cmd != 'logout' && $cmd != 'login' & $cmd != 'bank') {
112 $cmd = 'banks';
115 } elseif ($cmd != 'login' && $cmd != 'register') $cmd = '';
117 if (!$cmd) draw_login();
119 elseif ($cmd == 'logout') do_logout();
120 elseif ($cmd == 'login') do_login();
121 elseif ($cmd == 'contact') do_contact();
122 elseif ($cmd == 'bank') do_bank();
123 elseif ($cmd == 'asset') do_asset();
124 elseif ($cmd == 'admin') do_admin();
125 elseif ($cmd == 'spend') do_spend();
126 elseif ($cmd == 'canceloutbox') do_canceloutbox();
127 elseif ($cmd == 'processinbox') do_processinbox();
128 elseif ($cmd == 'storagefees') do_storagefees();
129 elseif ($cmd == 'dohistory') do_history();
130 elseif ($cmd == 'togglehistory') do_togglehistory();
131 elseif ($cmd == 'toggleinstructions') do_toggleinstructions();
133 elseif ($cmd == 'register') draw_register();
134 elseif ($cmd == 'balance') draw_balance();
135 elseif ($cmd == 'rawbalance') draw_raw_balance();
136 elseif ($cmd == 'contacts') draw_contacts();
137 elseif ($cmd == 'banks') draw_banks();
138 elseif ($cmd == 'assets') draw_assets();
139 elseif ($cmd == 'admins') draw_admin();
140 elseif ($cmd == 'coupon') draw_coupon();
141 elseif ($cmd == 'history') draw_history();
142 elseif ($session) draw_balance();
144 else draw_login();
146 // Use $title, $body, and $onload, $debug to fill the page template.
147 if ($debug) $debug = "<b>=== Debug log ===</b><br/><pre>$debug</pre>\n";
149 if ($client->showprocess) {
150 perf_stop($perf_idx);
151 $client->debugmsg("<table><tr><td>\n");
152 $times = draw_times(null, '=== Client Timing ===');
153 $server_times = $client->server_times();
154 if ($server_times) {
155 $client->debugmsg("</td><td>");
156 draw_times($server_times, '=== Server Timing ===');
157 $times = $client->accumulate_times($times, $server_times);
158 $client->debugmsg("</td><td>");
159 draw_times($times, '=== Totals ===');
161 $client->debugmsg("</tr></table>\n");
164 // Here's where the output happens
165 include $template_file;
166 return;
168 function draw_times($times, $caption) {
169 global $client;
171 $times = perf_times($times);
172 if (count($times) > 0) {
173 $client->debugmsg('<table border="1">
174 <caption><b>' . $caption . '</b></caption>
175 <tr><th>Function</th><th>Count</th><th>Time</th></tr>
177 foreach($times as $name => $stats) {
178 $cnt = $stats['cnt'];
179 $time = $stats['time'];
180 $client->debugmsg("<tr><td>$name</td><td>$cnt</td><td>$time</td></tr>\n");
182 $client->debugmsg("</table>\n");
184 return $times;
187 function settitle($subtitle) {
188 global $title;
190 $title = "$subtitle - Trubanc Client";
193 function menuitem($cmd, $text, $highlight) {
194 $res = "<a href=\"./?cmd=$cmd\">";
195 if ($cmd == $highlight) $res .= '<b>';
196 $res .= $text;
197 if ($cmd == $highlight) $res .= '</b>';
198 $res .= '</a>';
199 return $res;
202 function setmenu($highlight=false, $menuitems=false) {
203 global $menu, $default_menuitems;
204 global $client;
206 if (!$menuitems) $menuitems = $default_menuitems;
208 $menu = '';
209 if ($highlight && $client->bankid) {
210 foreach ($menuitems as $cmd => $text) {
211 if ($cmd != 'admins' ||
212 ($client->bankid && $client->id == $client->bankid)) {
213 if ($menu) $menu .= '&nbsp;&nbsp';
214 $menu .= menuitem($cmd, $text, $highlight);
217 } else {
218 $menu .= menuitem('logout', 'Logout', false);
222 function do_logout() {
223 global $session, $client, $bankline, $error;
225 if ($session) $client->logout();
226 setcookie('session', false);
227 $bankline = '';
228 $error = '';
229 draw_login();
232 // Here from the login page when the user presses one of the buttons
233 function do_login() {
234 global $title, $body, $onload;
235 global $keysize, $require_coupon;
236 global $error;
237 global $client, $ssl;
239 $t = $client->t;
241 $passphrase = mqpost('passphrase');
242 $passphrase2 = mqpost('passphrase2');
243 $coupon = mqpost('coupon');
244 $name = mqpost('name');
245 $keysize = mqpost('keysize');
246 $login = mqpost('login');
247 $newacct = mqpost('newacct');
248 $showkey = mqpost('showkey');
250 if ($showkey) {
251 $key = $client->getprivkey($passphrase);
252 if (!$key) $error = "No key for passphrase";
253 draw_login($key);
254 return;
255 } elseif ($newacct) {
256 $login = false;
257 $privkey = mqpost('privkey');
258 if (!$passphrase) {
259 $error = "Passphrase may not be blank";
260 } elseif (!$privkey && $passphrase != $passphrase2) {
261 $error = "Passphrase didn't match Verification";
262 } else {
263 if ($privkey) {
264 // Support adding a passphrase to a private key without one
265 $pk = $ssl->load_private_key($privkey);
266 if ($pk) {
267 if ($passphrase != $passphrase2) {
268 $error = "Passphrase didn't match Verification";
269 draw_login();
270 return;
272 openssl_pkey_export($pk, $privkey, $passphrase);
273 openssl_free_key($pk);
275 } else $privkey = $keysize;
277 if ($coupon) {
278 $err = $client->parsecoupon($coupon, $bankid, $url, $coupon_number);
279 if ($err) {
280 // See if "coupon" is just a URL, meaning the user
281 // already has an account at that bank.
282 $err2 = $client->verifybank($coupon, $bankid);
283 if ($err2) $error = "Invalid coupon: $err";
284 } else {
285 $error = $client->verifycoupon($coupon, $bankid, $url);
287 } elseif ($require_coupon && !privkey) {
288 $error = "Bank coupon required for registration";
291 if (!$error) {
292 $error = $client->newuser($passphrase, $privkey);
293 if (!$error) $login = true;
298 if ($login) {
299 $session = $client->login_new_session($passphrase);
300 if (is_string($session)) {
301 $error = "Login error: $session";
302 } else {
303 $session = $session[0];
304 if (!setcookie('session', $session)) {
305 $error = "You must enable cookies to use this client";
306 } else {
307 if ($newacct) {
308 $error = $client->addbank($coupon, $name, true);
310 if (!$error) {
311 setbank();
312 if ($client->bankid) draw_balance();
313 else draw_banks();
314 return;
320 draw_login();
323 // Here to change banks or add a new bank
324 function do_bank() {
325 global $client;
326 global $error;
328 $error = false;
330 $newbank = mqpost('newbank');
331 $selectbank = mqpost('selectbank');
333 $bankurl = '';
334 $name = '';
335 if ($newbank) {
336 $bankurl = trim(mqpost('bankurl'));
337 $name = mqpost('name');
338 $error = $client->addbank($bankurl, $name);
339 if (!$error) $client->userpreference('bankid', $client->bankid);
340 } elseif ($selectbank) {
341 $bankid = mqpost('bank');
342 if (!$bankid) $error = "You must choose a bank";
343 else $client->userpreference('bankid', $bankid);
344 setbank(true);
346 if ($error) draw_banks($bankurl, $name);
347 else draw_balance();
350 function do_contact() {
351 global $client;
352 global $error;
354 $addcontact = mqpost('addcontact');
355 $deletecontacts = mqpost('deletecontacts');
356 $chkcnt = mqpost('chkcnt');
358 if ($addcontact) {
359 $id = mqpost('id');
360 $nickname = mqpost('nickname');
361 $notes = mqpost('notes');
362 if (!$id) {
363 for ($i=0; $i<$chkcnt; $i++) {
364 $chki = mqpost("chk$i");
365 if ($chki) {
366 $id = mqpost("id$i");
367 break;
371 $err = '';
372 if ($id) $err = $client->addcontact($id, $nickname, $notes);
373 else $error = "You must specify an ID, either explicitly or by checking an existing contact";
374 if ($err) {
375 $error = "Can't add contact: $err";
376 draw_contacts($id, $nickname, $notes);
377 } else draw_contacts();
378 } elseif ($deletecontacts) {
379 for ($i=0; $i<$chkcnt; $i++) {
380 $chki = mqpost("chk$i");
381 if ($chki) {
382 $id = mqpost("id$i");
383 $client->deletecontact($id);
386 draw_contacts();
387 } else draw_balance();
391 // Here to add a new asset
392 function do_asset() {
393 global $client;
394 global $error;
396 $t = $client->t;
397 $error = false;
399 $newasset = mqpost('newasset');
400 $updatepercent = mqpost('updatepercent');
402 if ($newasset) {
403 $scale = mqpost('scale');
404 $precision = mqpost('precision');
405 $assetname = mqpost('assetname');
406 $storage = mqpost('storage');
407 if (!((strlen($scale) > 0) && (strlen($precision) > 0) &&
408 (strlen($assetname) > 0))) {
409 $error = "Scale, Precision, and Asset name must all be specified";
410 } elseif (!(is_numeric($scale) && is_numeric($precision))) {
411 $error = "Scale and Precision must be numbers";
412 } elseif ($storage && !is_numeric($storage)) {
413 $error = "Storage fee must be a number";
414 } else {
415 $error = $client->addasset($scale, $precision, $assetname, $storage);
417 if ($error) draw_assets($scale, $precision, $assetname, $storage);
418 else draw_assets();
419 } elseif ($updatepercent) {
420 $percentcnt = mqpost('percentcnt');
421 for ($i=0; $i<$percentcnt; $i++) {
422 $assetid = mqpost("assetid$i");
423 $opercent = mqpost("opercent$i");
424 $percent = mqpost("percent$i");
425 if (!($percent === $opercent)) { // Detect differences in trailing zeroes
426 $asset = $client->getasset($assetid);
427 if (is_string($asset)) {
428 $error = "Can't find assetid: $assetid";
429 } else {
430 $scale = $asset[$t->SCALE];
431 $precision = $asset[$t->PRECISION];
432 $assetname = $asset[$t->ASSETNAME];
433 $error = $client->addasset($scale, $precision, $assetname, $percent);
435 if ($error) break;
438 draw_assets();
439 } else draw_balance();
442 function do_admin() {
443 global $client;
447 function do_spend() {
448 global $error;
449 global $client;
450 global $fraction_asset;
452 $t = $client->t;
453 $u = $client->u;
454 $id = $client->id;
456 $amount = mqpost('amount');
457 $recipient = mqpost('recipient');
458 $mintcoupon = mqpost('mintcoupon');
459 $recipientid = mqpost('recipientid');
460 $allowunregistered = mqpost('allowunregistered');
461 $note = mqpost('note');
462 $nickname = mqpost('nickname');
463 $toacct = mqpost('toacct');
464 $tonewacct = mqpost('tonewacct');
465 $acct2 = '';
467 $error = false;
468 if (!$recipient) {
469 $recipient = $recipientid;
470 if ($recipient && !$allowunregistered &&
471 $u->is_id($recipient) && !$client->get_id($recipient)) {
472 $error = 'Recipient ID not registered at bank';
475 if (!$recipient) {
476 if ($mintcoupon) $recipient = $t->COUPON;
477 } elseif ($mintcoupon) $error = "To mint a coupon don't specify a recipient";
478 if (!$error) {
479 if (!($amount || ($amount === '0'))) $error = 'Spend amount missing';
480 elseif ($id == $recipient || !$recipient) {
481 // Spend to yourself = transfer
482 $recipient = $id;
483 $acct2 = $toacct;
484 if (!$acct2) $acct2 = $tonewacct;
485 elseif ($tonewacct) $error = 'Choose "Transfer to" from the selector or by typing, but not both';
486 if (!$acct2) $error = 'Recipient missing';
487 } elseif ($recipient != $t->COUPON && !$u->is_id($recipient)) {
488 $error = "Recipient ID malformed";
491 if ($error) {
492 draw_balance($amount, $recipient, $note, $toacct, $tonewacct, $nickname);
493 } else {
494 // Add contact if nickname specified
495 if ($nickname) {
496 $client->addcontact($recipient, $nickname);
499 // Find the spent asset
500 $found = false;
501 foreach ($_POST as $key => $value) {
502 $prefix = 'spentasset';
503 $prelen = strlen($prefix);
504 if (substr($key, 0, $prelen) == $prefix) {
505 $acctdotasset = substr($key, $prelen);
506 $acctdotasset = explode('|', $acctdotasset);
507 if (count($acctdotasset) != 2) {
508 $error = "Bug: don't understand spentasset";
509 draw_balance($amount, $recipient, $note, $toacct, $tonewacct, $nickname);
510 } else {
511 $acctidx = $acctdotasset[0];
512 $assetidx = $acctdotasset[1];
513 $acct = mqpost("acct$acctidx");
514 $assetid = mqpost("assetid$acctidx|$assetidx");
515 if (!$acct || !$assetid) {
516 $error = "Bug: blank acct or assetid";
517 draw_balance($amount, $recipient, $note, $toacct, $tonewacct, $nickname);
518 } else {
519 if ($acct2) $acct = array($acct, $acct2);
520 $error = $client->spend($recipient, $assetid, $amount, $acct, $note);
521 if ($error) {
522 draw_balance($amount, $recipient, $note, $toacct, $tonewacct, $nickname);
523 } elseif ($mintcoupon) {
524 draw_coupon($client->lastspendtime);
525 } else {
526 $fraction_asset = $assetid;
527 draw_balance();
531 $found = true;
532 break;
535 if (!$found) {
536 $error = "Bug: can't find acct/asset to spend";
537 draw_balance($amount, $recipient, $note, $toacct, $tonewacct, $nickname);
542 function do_canceloutbox() {
543 global $error;
544 global $client;
546 $cancelcount = mqpost('cancelcount');
547 for ($i=0; $i<$cancelcount; $i++) {
548 if (mqpost("cancel$i")) {
549 $canceltime = mqpost("canceltime$i");
550 $error = $client->spendreject($canceltime, "Spend cancelled");
551 draw_balance();
552 break;
557 function do_processinbox() {
558 global $error;
559 global $client;
561 $t = $client->t;
563 $spendcnt = mqpost('spendcnt');
564 $nonspendcnt = mqpost('nonspendcnt');
566 $directions = array();
567 for ($i=0; $i<$spendcnt; $i++) {
568 $time = mqpost("spendtime$i");
569 $spend = mqpost("spend$i");
570 $note = mqpost("spendnote$i");
571 $acct = mqpost("acct$i");
572 if ($spend == 'accept' || $spend == 'reject') {
573 $dir = array($t->TIME => $time);
574 if ($note) $dir[$t->NOTE] = $note;
575 $dir[$t->REQUEST] = ($spend == 'accept') ? $t->SPENDACCEPT : $t->SPENDREJECT;
576 if ($acct) $dir[$t->ACCT] = $acct;
577 $directions[] = $dir;
579 $nickname = mqpost("spendnick$i");
580 $spendid = mqpost("spendid$i");
581 if ($nickname && $spendid) {
582 $client->addcontact($spendid, $nickname);
586 for ($i=0; $i<$nonspendcnt; $i++) {
587 $time = mqpost("nonspendtime$i");
588 $process = mqpost("nonspend$i");
589 if ($process) {
590 $dir = array($t->TIME => $time);
591 $directions[] = $dir;
593 $nickname = mqpost("nonspendnick$i");
594 $spendid = mqpost("nonspendid$i");
595 if ($nickname && $spendid) {
596 $client->addcontact($spendid, $nickname);
600 if (count($directions) > 0) {
601 $err = $client->processinbox($directions);
602 if ($err) $error = "error from processinbox: $err";
605 draw_balance();
608 function do_storagefees() {
609 global $client;
610 global $error;
612 $error = $client->storagefees();
613 draw_balance();
616 function do_history() {
617 $history = gethistory();
618 $history->do_history();
621 function do_togglehistory() {
622 global $client, $keephistory, $error;
624 $keephistory = ($keephistory == 'keep' ? 'forget' : 'keep');
625 $client->keephistory($keephistory == 'keep');
627 $client->userpreference('keephistory', $keephistory);
628 $error = ($keephistory == 'keep' ? "History enabled" : "History disabled");
630 draw_balance();
633 function hideinstructions($newvalue=false) {
634 global $client;
636 $key = 'hideinstructions';
637 if ($newvalue === false) $newvalue = $client->userpreference($key);
638 else $client->userpreference($key, $newvalue);
639 return $newvalue;
642 function do_toggleinstructions() {
643 global $client;
645 $page = mqrequest('page');
646 hideinstructions(hideinstructions() ? '' : 'hide');
647 if ($page == 'history') draw_history();
648 else draw_balance();
651 function draw_login($key=false) {
652 global $title, $menu, $body, $onload;
653 global $error;
655 $page = mqpost('page');
656 if ($page == 'register') return draw_register($key);
658 $menu = '';
659 $onload = "document.forms[0].passphrase.focus()";
660 $body = <<<EOT
661 <form method="post" action="./" autocomplete="off">
662 <input type="hidden" name="cmd" value="login"/>
663 <table>
664 <tr>
665 <td><b>Passphrase:</b></td>
666 <td><input type="password" name="passphrase" size="50"/>
667 <input type="submit" name="login" value="Login"/></td>
668 </tr><tr>
669 <td></td>
670 <td style="color: red">$error&nbsp;</td>
671 </tr>
672 </table>
673 <a href="./?cmd=register">Register a new account</a>
674 </form>
676 EOT;
679 function draw_register($key=false) {
681 global $title, $menu, $body, $onload;
682 global $keysize, $require_tokens;
683 global $error;
685 $key = hsc($key);
687 settitle('Register');
688 $menu = '';
689 $onload = "document.forms[0].passphrase.focus()";
691 if (!$keysize) $keysize = 3072;
692 $sel = ' selected="selected"';
693 $sel512 = ($keysize == 512) ? $sel : '';
694 $sel1024 = ($keysize == 1024) ? $sel : '';
695 $sel2048 = ($keysize == 2048) ? $sel : '';
696 $sel3072 = ($keysize == 3072) ? $sel : '';
697 $sel4096 = ($keysize == 4096) ? $sel : '';
699 $body = <<<EOT
700 <form method="post" action="./" autocomplete="off">
701 <input type="hidden" name="cmd" value="login"/>
702 <table>
703 <tr>
704 <td><b>Passphrase:</b></td>
705 <td><input type="password" name="passphrase" size="50"/>
706 <input type="submit" name="login" value="Login"/></td>
707 <input type="hidden" name="page" value="register"/>
708 </tr><tr>
709 <td></td>
710 <td style="color: red">$error&nbsp;</td>
711 </tr><tr>
712 <td><b>Verification:</b></td>
713 <td><input type="password" name="passphrase2" size="50"/>
714 </tr><tr>
715 <td><b>Coupon:</b></td>
716 <td><input type="text" name="coupon" size="64"/></td>
717 </tr><tr>
718 <td><b>Account Name<br/>(Optional):</b></td>
719 <td><input type="text" name="name" size="40"/></td>
720 </tr><tr>
721 <td><b>Key size:</b></td>
722 <td>
723 <select name="keysize">
724 <option value="512"$sel512>512</option>
725 <option value="1024"$sel1024>1024</option>
726 <option value="2048"$sel2048>2048</option>
727 <option value="3072"$sel3072>3072</option>
728 <option value="4096"$sel4096>4096</option>
729 </select>
730 <input type="submit" name="newacct" value="Create account"/>
731 <input type="submit" name="showkey" value="Show key"/></td>
732 </tr><tr>
733 <td></td>
734 <td>
735 To generate a new private key, leave the area below blank, enter a
736 passphrase, the passphrase again to verify, a bank coupon, an optional
737 account name, a key size, and click the "Create account" button. To
738 use an existing private key, paste the private key below, enter its
739 passphrase above, a bank coupon, an optional account name, and click
740 the "Create account" button. To show your encrypted private key,
741 enter its passphrase, and click the "Show key" button. Warning: if you
742 forget your passphrase, <b>nobody can recover it, ever</b>.
743 </td>
744 </tr><tr>
745 <td></td>
746 <td><textarea name="privkey" cols="64" rows="42">$key</textarea></td>
747 </table>
749 EOT;
752 function bankline() {
753 global $client;
755 $t = $client->t;
756 $bankid = $client->bankid;
758 $bankline = '';
759 if ($bankid) {
760 $bank = $client->getbank($bankid);
762 if ($bank) {
763 $name = $bank[$t->NAME];
764 $url = $bank[$t->URL];
765 $bankline = "<b>Bank:</b> $name <a href=\"$url\">$url</a><br/>\n";
768 return $bankline;
771 function idcode() {
772 global $client;
774 $id = '';
775 if ($client) $id = $client->id;
776 if (!$id) return '';
777 $args = $client->get_id($id);
778 if ($args) {
779 $t = $client->t;
780 $name = $args[$t->NAME];
781 if ($name) $res = "<b>Account name:</b> $name<br/>\n";
783 $res .= "<b>Your ID:</b> $id<br/>\n";
784 return $res;
787 function setbank($reporterror=false) {
788 global $banks, $bank;
789 global $error;
790 global $client;
792 $t = $client->t;
794 $banks = $client->getbanks();
795 $bank = false;
796 $bankid = $client->userpreference('bankid');
797 if ($bankid) {
798 $err = $client->setbank($bankid, false);
799 if ($err) {
800 $err = "Can't set bank: $err";
801 $client->userpreference('bankid', '');
802 $bankid = false;
805 if (!$bankid) {
806 foreach ($banks as $bank) {
807 $bankid = $bank[$t->BANKID];
808 $err = $client->setbank($bankid);
809 if ($err) {
810 $err = "Can't set bank: $err";
811 $bankid = false;
813 else {
814 $client->userpreference('bankid', $bankid);
815 break;
818 if (!$bankid) {
819 $err = "No known banks. Please add one.";
823 if ($reporterror) $error = $err;
826 function namestr($nickname, $name, $id) {
827 if ($nickname) {
828 if ($name) {
829 if ($name != $nickname) $namestr = "$nickname ($name)";
830 else $namestr = $name;
831 } else $namestr = $nickname;
832 } elseif ($name) $namestr = "($name)";
833 else $namestr = "$id";
834 return "$namestr";
837 function contact_namestr($contact) {
838 global $client;
840 $t = $client->t;
842 $nickname = hsc(@$contact[$t->NICKNAME]);
843 $name = hsc($contact[$t->NAME]);
844 $recipid = hsc($contact[$t->ID]);
845 return namestr($nickname, $name, $recipid);
848 function id_namestr($fromid, &$contact, $you=false) {
849 global $client;
851 if ($fromid == 'coupon') return $fromid;
853 if ($you && $fromid == $client->id) return $you;
855 $contact = $client->getcontact($fromid);
856 if ($contact) {
857 $namestr = contact_namestr($contact);
858 if ($namestr == $fromid) $namestr = "[unknown]";
859 $namestr = "<span title=\"$fromid\">$namestr</span>";
860 } else $namestr = hsc($fromid);
861 return $namestr;
864 // Return the ready-for-html-output formatted date for a timestamp
865 function datestr($time) {
866 global $timestamp;
868 $unixtime = $timestamp->stripfract($time);
869 return hsc(date("j-M-y g:i:sa T", $unixtime));
872 function draw_balance($spend_amount=false, $recipient=false, $note=false,
873 $toacct=false, $tonewacct=false, $nickname=false) {
874 global $client;
875 global $error;
876 global $onload, $body;
877 global $iphone, $keephistory;
878 global $fraction_asset;
880 $t = $client->t;
882 $bankid = $client->bankid();
883 $banks = $client->getbanks();
885 settitle('Balance');
886 setmenu('balance');
888 $saveerror = $error;
889 $error = false;
891 $bankopts = '';
892 foreach ($banks as $bid => $b) {
893 if ($bid != $bankid) {
894 if ($client->userreq($bid) != -1) {
895 $bname = $b[$t->NAME];
896 $burl = $b[$t->URL];
897 $bankopts .= "<option value=\"$bid\">$bname $burl</option>\n";
902 $bankcode = '';
903 if ($bankopts) {
904 $bankcode .= <<<EOT
905 <form method="post" action="./" autocomplete="off">
906 <input type="hidden" name="cmd" value="bank">
907 <select name="bank">
908 <option value="">Choose a bank...</option>
909 $bankopts
910 </select>
911 <input type="submit" name="selectbank" value="Change Bank"/>
912 </form>
914 EOT;
917 $inboxcode = '';
918 $balcode = '';
919 $assetlist = '';
920 $assetidx = 0;
921 $acctidx = 0;
922 $gotbal = false;
923 $contacts = $client->getcontacts();
924 $havecontacts = (count($contacts) > 0);
926 if (!$error && $client->bankid) {
927 // Print inbox, if there is one
928 $inbox = $client->getinbox();
929 $outbox = $client->getoutbox();
930 $accts = $client->getaccts();
932 $acctoptions = '';
933 if (count($accts) > 1) {
934 $first = true;
935 foreach ($accts as $acct) {
936 $acct = hsc($acct);
937 $acctoptions .= <<<EOT
938 <option value="$acct">$acct</option>
940 EOT;
944 // Try again, in case we just needed to sync.
945 // Maybe this should be hidden by getinbox()
946 if (is_string($inbox)) $inbox = $client->getinbox();
948 $acctheader = '';
949 if (is_string($inbox)) {
950 $error = "Error getting inbox: $inbox";
951 $inbox = array();
953 elseif (count($inbox) == 0) $inboxcode .= "<b>=== Inbox empty ===</b><br/><br/>\n";
954 else {
955 if ($acctoptions) $acctheader = "\n<th>To Acct</th>";
957 $inboxcode .= <<<EOT
958 <table border="1">
959 <caption><b>=== Inbox ===</b></caption>
960 <tr>
961 <th>Request</th>
962 <th>From</th>
963 <th colspan="2">Amount</th>
964 <th>Note</th>
965 <th>Action</th>
966 <th>Reply</th>$acctheader
967 <th>Time</th>
968 </tr>
970 EOT;
971 $seloptions = <<<EOT
972 <option value="accept">Accept</option>
973 <option value="reject">Reject</option>
974 <option value="ignore">Ignore</option>
976 EOT;
978 if (is_string($outbox)) {
979 $error = "Error getting outbox: $outbox";
980 $outbox = array();
982 $nonspends = array();
983 $spendcnt = 0;
984 $assets = $client->getassets();
985 foreach ($inbox as $itemkey => $item) {
986 $item = $item[0];
987 $request = $item[$t->REQUEST];
988 $fromid = $item[$t->ID];
989 $time = $item[$t->TIME];
990 $namestr = id_namestr($fromid, $contact);
992 if ($request != $t->SPEND) {
993 $msgtime = $item[$t->MSGTIME];
994 $outitem = $outbox[$msgtime];
995 // outbox entries are array($spend, $tranfee)
996 if ($outitem) $outitem = $outitem[0];
997 if ($outitem) {
998 $item[$t->ASSETNAME] = $outitem[$t->ASSETNAME];
999 $item[$t->FORMATTEDAMOUNT] = $outitem[$t->FORMATTEDAMOUNT];
1000 $item['reply'] = $item[$t->NOTE];
1001 $item[$t->NOTE] = $outitem[$t->NOTE];
1003 $nonspends[] = $item;
1005 else {
1006 $assetid = $item[$t->ASSET];
1007 $assetname = hsc($item[$t->ASSETNAME]);
1008 if (!@$assets[$assetid]) {
1009 $assetname .= ' <span style="color: red;"><i>(new)</i></span>';
1011 $amount = hsc($item[$t->FORMATTEDAMOUNT]);
1012 $itemnote = hsc($item[$t->NOTE]);
1013 if (!$itemnote) $itemnote = '&nbsp;';
1014 else $itemnote = str_replace("\n", "<br/>\n", $itemnote);
1015 $selname = "spend$spendcnt";
1016 $notename = "spendnote$spendcnt";
1017 $acctselname = "acct$spendcnt";
1018 if (!@$contact[$t->CONTACT]) {
1019 $namestr .= <<<EOT
1020 <br/>
1021 <input type="hidden" name="spendid$spendcnt" value="$fromid"/>
1022 Nickname:
1023 <input type="text" name="spendnick$spendcnt" size="10"/>
1024 EOT;
1026 $timecode = <<<EOT
1027 <input type="hidden" name="spendtime$spendcnt" value="$time">
1028 EOT;
1030 $spendcnt++;
1031 $selcode = <<<EOT
1032 <select name="$selname">
1033 $seloptions
1034 </select>
1036 EOT;
1037 $acctcode = '';
1038 if ($acctoptions) {
1039 $acctcode = <<<EOT
1040 <td><select name="$acctselname">
1041 $acctoptions
1042 </select></td>
1043 EOT;
1045 $date = datestr($time);
1046 $inboxcode .= <<<EOT
1047 $timecode
1048 <tr>
1049 <td>Spend</td>
1050 <td>$namestr</td>
1051 <td align="right" style="border-right-width: 0;">$amount</td>
1052 <td style="border-left-width: 0;">$assetname</td>
1053 <td>$itemnote</td>
1054 <td>$selcode</td>
1055 <td><textarea name="$notename" cols="20" rows="2"></textarea></td>
1056 $acctcode
1057 <td>$date</td>
1058 </tr>
1060 EOT;
1063 $nonspendcnt = 0;
1064 foreach ($nonspends as $item) {
1065 $request = $item[$t->REQUEST];
1066 $fromid = $item[$t->ID];
1067 $reqstr = ($request == $t->SPENDACCEPT) ? "Accept" : "Reject";
1068 $time = $item[$t->TIME];
1069 $namestr = id_namestr($fromid, $contact);
1070 $assetname = hsc($item[$t->ASSETNAME]);
1071 $amount = hsc($item[$t->FORMATTEDAMOUNT]);
1072 $itemnote = hsc($item[$t->NOTE]);
1073 if (!$itemnote) $itemnote = '&nbsp;';
1074 else $itemnote = $itemnote = str_replace("\n", "<br/>\n", $itemnote);
1075 $reply = hsc($item['reply']);
1076 if (!$reply) $reply = '&nbsp;';
1077 else $reply = str_replace("\n", "<br/>\n", $reply);
1078 $selname = "nonspend$nonspendcnt";
1079 if (!@$contact[$t->CONTACT]) {
1080 $namestr .= <<<EOT
1081 <br/>
1082 <input type="hidden" name="nonspendid$nonspendcnt" value="$fromid"/>
1083 Nickname:
1084 <input type="text" name="nonspendnick$nonspendcnt" size="10"/>
1085 EOT;
1087 $timecode = <<<EOT
1088 <input type="hidden" name="nonspendtime$nonspendcnt" value="$time">
1089 EOT;
1090 $nonspendcnt++;
1091 $selcode = <<<EOT
1092 <input type="checkbox" name="$selname" checked="checked">Remove</input>
1094 EOT;
1095 $date = datestr($time);
1096 $acctcode = '';
1097 if ($acctoptions) $acctcode = "\n<td>&nbsp;</td>";
1098 $inboxcode .= <<<EOT
1099 $timecode
1100 <tr>
1101 <td>$reqstr</td>
1102 <td>$namestr</td>
1103 <td align="right" style="border-right-width: 0;">$amount</td>
1104 <td style="border-left-width: 0;">$assetname</td>
1105 <td>$itemnote</td>
1106 <td>$selcode</td>
1107 <td>$reply</td>$acctcode
1108 <td>$date</td>
1109 </tr>
1111 EOT;
1114 $inboxcode = <<<EOT
1115 <form method="post" action="./" autocomplete="off">
1116 <input type="hidden" name="cmd" value="processinbox"/>
1117 <input type="hidden" name="spendcnt" value="$spendcnt"/>
1118 <input type="hidden" name="nonspendcnt" value="$nonspendcnt"/>
1119 $inboxcode
1120 </table>
1121 <br/>
1122 <input type="submit" name="submit" value="Process Inbox"/>
1123 </form>
1125 EOT;
1128 // Index the spends in the inbox by MSGTIME
1129 $inboxspends = array();
1130 foreach ($inbox as $items) {
1131 $item = $items[0];
1132 $request = $item[$t->REQUEST];
1133 $inboxspends[$item[$t->MSGTIME]] = $item;
1136 // Prepare outbox display
1137 $cancelcount = 0;
1138 $outboxcode = '';
1139 foreach ($outbox as $time => $items) {
1140 $timestr = hsc($time);
1141 $date = datestr($time);
1142 foreach ($items as $item) {
1143 $request = $item[$t->REQUEST];
1144 if ($request == $t->SPEND) {
1145 $recip = $item[$t->ID];
1146 if (!$outboxcode) $outboxcode = <<<EOT
1147 <table border="1">
1148 <caption><b>=== Outbox ===</b></caption>
1149 <tr>
1150 <th>Time</th>
1151 <th>Recipient</th>
1152 <th colspan="2">Amount</th>
1153 <th>Note</th>
1154 <th>Action</th>
1155 </tr>
1156 EOT;
1157 $assetname = hsc($item[$t->ASSETNAME]);
1158 $amount = hsc($item[$t->FORMATTEDAMOUNT]);
1159 $not = hsc($item[$t->NOTE]);
1160 if (!$not) $not = '&nbsp;';
1161 $label = 'Cancel';
1162 if ($recip == $t->COUPON) {
1163 $label = 'Redeem';
1164 $recip = hsc($recip);
1165 $timearg = urlencode($time);
1166 $namestr = <<<EOT
1167 <a href="./?cmd=coupon&time=$timearg">$recip</a>
1168 EOT;
1169 } else {
1170 $namestr = id_namestr($recip, $contact);
1172 $cancelcode = '&nbsp;';
1173 if (!@$inboxspends[$time]) {
1174 $cancelcode = <<<EOT
1175 <input type="hidden" name="canceltime$cancelcount" value="$timestr"/>
1176 <input type="submit" name="cancel$cancelcount" value="$label"/>
1178 EOT;
1179 $cancelcount++;
1181 $outboxcode .= <<<EOT
1182 <tr>
1183 <td>$date</td>
1184 <td>$namestr</td>
1185 <td align="right" style="border-right-width: 0;">$amount</td>
1186 <td style="border-left-width: 0;">$assetname</td>
1187 <td>$not</td>
1188 <td>$cancelcode</td>
1189 </tr>
1190 EOT;
1194 if ($outboxcode) {
1195 $outboxcode .= "</table>\n";
1196 if ($cancelcount > 0) {
1197 $outboxcode = <<<EOT
1198 <form method="post" action="./" autocomplete="off">
1199 <input type="hidden" name="cmd" value="canceloutbox"/>
1200 <input type="hidden" name="cancelcount" value="$cancelcount"/>
1201 $outboxcode
1202 </form>
1204 EOT;
1208 $balance = $client->getbalance();
1209 if (is_string($balance)) $error = $balance;
1210 elseif (count($balance) > 0) {
1211 $balcode = "<table border=\"1\">\n<caption><b>=== Balances ===</b></caption>
1212 <tr><td><table>";
1213 $firstacct = true;
1214 foreach ($balance as $acct => $assets) {
1215 $acct = hsc($acct);
1216 $assetcode = '';
1217 $newassetlist = '';
1218 foreach ($assets as $asset => $data) {
1219 if ($data[$t->AMOUNT] != 0) {
1220 $gotbal = true;
1221 $assetid = hsc($data[$t->ASSET]);
1222 $assetname = hsc($data[$t->ASSETNAME]);
1223 $formattedamount = hsc($data[$t->FORMATTEDAMOUNT]);
1224 $submitcode = '';
1225 $newassetlist .= <<<EOT
1226 <input type="hidden" name="assetid$acctidx|$assetidx" value="$assetid"/>
1228 EOT;
1229 $submitcode = <<<EOT
1230 <input type="submit" name="spentasset$acctidx|$assetidx" value="Spend"/>
1232 EOT;
1233 $assetidx++;
1234 $assetcode .= <<<EOT
1235 <tr>
1236 <td align="right"><span style="margin-right: 5px">$formattedamount</span></td>
1237 <td>$assetname</td>
1238 <td>$submitcode</td>
1239 </tr>
1241 EOT;
1245 if ($assetcode) {
1246 if (!$firstacct) {
1247 $balcode .= "<tr><td colspan=\"3\">&nbsp;</td></tr>\n";
1248 } else $firstacct = false;
1249 $balcode .= "<tr><th colspan=\"3\">- $acct -</th></tr>\n$assetcode";
1252 if ($newassetlist) {
1253 $assetlist .= <<<EOT
1254 <input type="hidden" name="acct$acctidx" value="$acct"/>
1255 $newassetlist
1256 EOT;
1257 $acctidx++;
1260 $balcode .= "</table>\n</td></tr></table>\n";
1261 $enabled = ($keephistory == 'keep' ? 'enabled' : 'disabled');
1262 if ($fraction_asset && $_COOKIE['debug']) {
1263 $fraction = $client->getfraction($fraction_asset);
1264 $amt = $fraction[$t->AMOUNT];
1265 $scale = $fraction[$t->SCALE];
1266 $balcode .= "Fractional balance: $amt";
1267 if ($scale) $balcode .= " x 10<sup>-$scale</sup>";
1268 $balcode .= "<br/>\n";
1270 $balcode .= <<<EOT
1271 <br/>
1272 <a href="./?cmd=rawbalance">Show raw balance</a>
1273 <br/>
1274 <a href="./?cmd=history">Show history</a> ($enabled)
1275 <br/>
1277 EOT;
1280 $openspend = '';
1281 $spendcode = '';
1282 $closespend = '';
1283 $instructions = '';
1284 $storagefeecode = '';
1285 if ($gotbal) {
1286 $recipopts = '<select name="recipient">
1287 <option value="">Choose contact...</option>
1289 $found = false;
1290 foreach ($contacts as $contact) {
1291 $namestr = contact_namestr($contact);
1292 $recipid = $contact[$t->ID];
1293 if ($recipid != $client->id) {
1294 $selected = '';
1295 if ($recipid == $recipient) {
1296 $selected = ' selected="selected"';
1297 $found = true;
1299 $recipopts .= <<<EOT
1300 <option value="$recipid"$selected>$namestr</option>
1302 EOT;
1305 $recipopts .= "</select>\n";
1306 $selectmint = '';
1307 if ($recipient == $t->COUPON) $selectmint = ' checked="checked"';
1308 $recipientid = '';
1309 if (!$found && $recipient != $t->COUPON) $recipientid = $recipient;
1310 $openspend = '<form method="post" action="./" autocomplete="off">
1311 <input type="hidden" name="cmd" value="spend"/>
1314 $acctoptions = '';
1315 if (count($accts) > 1) {
1316 $first = true;
1317 foreach ($accts as $acct) {
1318 $selcode = '';
1319 if ($acct == $toacct) $selcode = ' selected="selected"';
1320 $acct = hsc($acct);
1321 $acctoptions .= <<<EOT
1322 <option value="$acct"$selcode>$acct</option>
1324 EOT;
1327 $acctcode = '';
1328 if ($acctoptions) {
1329 $acctcode = <<<EOT
1331 <td><select name="toacct">
1332 <option value="">Select or fill-in below...</option>
1333 $acctoptions
1334 </select></td>
1335 </tr>
1336 <tr>
1337 <td><b>&nbsp;</b></td>
1339 EOT;
1342 $storagefeecode = '';
1343 $storagefees = $client->getstoragefee();
1344 if (is_string($storagefees)) {
1345 $error = $storagefees;
1346 $storagefees = array();
1348 $storagefeecode = '';
1349 if (count($storagefees) > 0) {
1350 $storagefeecode = <<<EOT
1351 <form method="post" action="./" autocomplete="off">
1352 <input type="hidden" name="cmd" value="storagefees"/>
1353 <table border="1">
1354 <caption><b>=== Storage Fees ===</b></caption>
1355 <tr><td><table>
1357 EOT;
1358 foreach ($storagefees as $assetid => $storagefee) {
1359 $formattedamount = $storagefee[$t->FORMATTEDAMOUNT];
1360 $assetname = $storagefee[$t->ASSETNAME];
1361 $time = $storagefee[$t->TIME];
1362 $timestr = hsc($time);
1363 $date = datestr($time);
1364 $storagefeecode .= <<<EOT
1365 <tr>
1366 <td align="right"><span style="margin-right: 5px">$formattedamount</span></td>
1367 <td><span style="margin-right: 5px">$assetname</span></td>
1368 <td>$date</td>
1369 </tr>
1371 EOT;
1373 $storagefeecode .= <<<EOT
1374 </table></td></tr>
1375 </table>
1376 <input type="submit" name="accept" value="Move to Inbox"/>
1377 </form>
1379 EOT;
1382 $disablemint = '';
1383 if ($client->id == $client->bankid) {
1384 $selectmint = '';
1385 $disablemint = ' disabled="disabled"';
1387 $spendcode = <<<EOT
1389 <table>
1390 <tr>
1391 <td><b>Spend amount:</b></td>
1392 <td><input type="text" name="amount" size="20" value="$spend_amount" style="text-align: right;"/>
1393 </tr><tr>
1394 <td><b>Recipient:</b></td>
1395 <td>$recipopts
1396 <input type="checkbox" name="mintcoupon"$selectmint$disablemint>Mint coupon</input></td>
1397 </tr><tr>
1398 <td><b>Note:</b></td>
1399 <td><textarea name="note" cols="40" rows="10">$note</textarea></td>
1400 </tr><tr>
1401 <td><b>Recipient ID:</b></td>
1402 <td><input type="text" name="recipientid" size="40" value="$recipientid"/>
1403 <input type="checkbox" name="allowunregistered">Allow unregistered</input></td>
1404 </tr><tr>
1405 <td><b>Nickname:</b></td>
1406 <td><input type="text" name="nickname" size="30" value="$nickname"/></td>
1407 <tr>
1408 <td><b>Transfer to:</b></td>$acctcode
1409 <td><input type="text" name="tonewacct" size="30" value="$tonewacct"/></td>
1410 </tr>
1411 </table>
1412 EOT;
1413 $onload = "document.forms[0].amount.focus()";
1414 $closespend = "</form>\n";
1415 $historytext = ($keephistory == 'keep' ? "Disable" : "Enable") . " history";
1416 $instructions = '<p><a href="./?cmd=togglehistory">' .
1417 $historytext . "</a>\n";
1418 if (hideinstructions()) {
1419 $instructions .= '<br>
1420 <a href="./?cmd=toggleinstructions">Show Instructions</a>
1421 </p>
1423 } else {
1424 $instructions .= <<<EOT
1425 </p>
1427 To make a spend, fill in the "Spend amount", choose a "Recipient" or
1428 enter a "Recipient ID, enter (optionally) a "Note", and click the
1429 "Spend" button next to the asset you wish to spend.
1430 </p>
1432 To transfer balances, enter the "Spend Amount", select or fill-in the
1433 "Transfer to" name (letters, numbers, and spaces only), and click
1434 the"Spend" button next to the asset you want to transfer from. Each
1435 storage location costs one usage token, and there is currently no way
1436 to recover an unused location. 0 balances will show only on the raw
1437 balance screen.
1438 </p>
1440 To mint a coupon, enter the "Spend Amount", check the "Mint coupon"
1441 box, and click the "Spend" button next to the asset you want to
1442 transfer to the coupon. You can redeem a coupon on the "Banks" page.
1443 </p>
1445 Entering a "Nickname" will add the "Recipient ID" to your contacts
1446 list with that nickname, or change the nickname of the selected
1447 "Recipient".
1448 </p>
1450 <a href="./?cmd=toggleinstructions">Hide Instructions</a>
1451 </p>
1452 EOT;
1457 if ($saveerror) {
1458 if ($error) $error = "$saveerror<br/>$error";
1459 else $error = $saveerror;
1461 if ($error) {
1462 $error = "<span style=\"color: red\";\">$error</span>\n";
1464 $fullspend = <<<EOT
1465 $openspend
1466 <table>
1467 <tr>
1468 <td valign="top">
1469 $assetlist$balcode
1470 </td>
1472 EOT;
1473 if ($iphone) $fullspend .= "</tr>\n<tr>\n";
1474 $fullspend .= <<<EOT
1475 <td valign="top">
1476 $spendcode
1477 </td>
1478 </table>
1479 $closespend
1480 EOT;
1481 $body = "$error<br/>$bankcode$inboxcode$fullspend$outboxcode$storagefeecode$instructions";
1484 function draw_coupon($time = false) {
1485 global $client;
1486 global $error;
1487 global $onload, $body;
1489 $t = $client->t;
1491 settitle('Coupon');
1492 setmenu('balance');
1494 $outbox = $client->getoutbox();
1495 if (!$time) $time = mq($_REQUEST['time']);
1496 $items = $outbox[$time];
1497 $timestr = hsc($time);
1498 $datestr = datestr($time);
1499 if ($items) {
1500 foreach ($items as $item) {
1501 $request = $item[$t->REQUEST];
1502 if ($request == $t->SPEND) {
1503 $assetname = hsc($item[$t->ASSETNAME]);
1504 $formattedamount = hsc($item[$t->FORMATTEDAMOUNT]);
1505 $note = hsc($item[$t->NOTE]);
1506 if ($note) $note = "<tr><td><b>Note:</b></td><td><span style=\"margin: 5px;\">$note</span></td></tr>\n";
1507 } elseif ($request == $t->COUPONENVELOPE) {
1508 $coupon = hsc(trim($item[$t->COUPON]));
1509 $body = <<<EOT
1510 <br/>
1511 <b>Coupon for outbox entry at $datestr</b>
1512 <table border="1">
1513 <tr><td><b>Amount:</b></td><td><span style="margin: 5px;">$formattedamount $assetname</span></td></tr>
1514 $note<tr><td><b>Coupon:</b></td><td><span style="margin: 5px;">$coupon</span></td></tr>
1515 </table>
1516 EOT;
1517 return;
1521 $error = "Couldn't find coupon: $timestr";
1522 draw_balance();
1525 function draw_raw_balance() {
1526 global $body;
1527 global $client;
1529 settitle('Raw Balance');
1530 setmenu('balance');
1532 if ($client) {
1533 $t = $client->t;
1534 $db = $client->db;
1535 $id = $client->id;
1536 $bankid = $client->bankid;
1537 if (!($id && $bankid)) return;
1539 $body = '';
1542 $key = $client->userbankkey($t->INBOX);
1543 $inbox = $db->contents($key);
1544 if (count($inbox) == 0) {
1545 $body .= "<br/><b>=== Inbox empty ===</b><br/>\n";
1546 } else {
1547 $body .= '<br/><b>=== Inbox ===</b><br/>
1548 <table border="1">
1551 foreach ($inbox as $file) {
1552 $msg = $db->get("$key/$file");
1553 $body .= <<<EOT
1554 <tr>
1555 <td valign="top">$file</td>
1556 <td><pre>$msg</pre></td>
1557 </tr>
1559 EOT;
1561 $body .= "</table>\n";
1564 $key = $client->userbankkey($t->OUTBOX);
1565 $outbox = $db->contents($key);
1566 if (count($outbox) == 0) {
1567 $body .= "<br/><b>=== Outbox empty ===</b><br/>\n";
1568 } else {
1569 $body .= '<br/><b>=== Outbox===</b><br/>
1570 <table border="1">
1573 foreach ($outbox as $file) {
1574 $msg = $db->get("$key/$file");
1575 $body .= <<<EOT
1576 <tr>
1577 <td valign="top">$file</td>
1578 <td><pre>$msg</pre></td>
1579 </tr>
1581 EOT;
1583 $body .= "</table>\n";
1586 $key = $client->userbankkey($t->BALANCE);
1587 $accts = $db->contents($key);
1588 foreach ($accts as $acct) {
1589 $body .= '<br/><b>' . $acct . '</b><br/>
1590 <table border="1">
1593 $assets = $db->contents("$key/$acct");
1594 foreach ($assets as $assetid) {
1595 $asset = $client->getasset($assetid);
1596 $assetname = $asset[$t->ASSETNAME];
1597 $msg = $db->get("$key/$acct/$assetid");
1598 $body .= <<<EOT
1599 <tr>
1600 <td valign="top">$assetname</td>
1601 <td><pre>$msg</pre></td>
1602 </tr>
1603 EOT;
1605 $body .= "</table><br/>\n";
1608 $key = $client->userfractionkey();
1609 $assetids = $db->contents($key);
1610 if (count($assetids) > 0) {
1611 $body .= '<br/><b>=== Fractional Balances ===</b><br/>
1612 <table border="1">
1614 foreach($assetids as $assetid) {
1615 $asset = $client->getasset($assetid);
1616 $assetname = $asset[$t->ASSETNAME];
1617 $msg = $db->get("$key/$assetid");
1618 $body .= <<<EOT
1619 <tr>
1620 <td valign="top">$assetname</td>
1621 <td><pre>$msg</pre></td>
1622 </tr>
1623 EOT;
1625 $body .= "</table><br/>\n";
1630 function draw_banks($bankurl='', $name='') {
1631 global $onload, $body;
1632 global $error;
1633 global $client;
1635 $t = $client->t;
1637 $banks = $client->getbanks();
1639 $onload = "document.forms[0].bankurl.focus()";
1640 settitle('Banks');
1641 setmenu('banks');
1643 $body .= <<<EOT
1644 <span style="color: red;">$error</span><br/>
1645 <form method="post" action="./" autocomplete="off">
1646 <input type="hidden" name="cmd" value="bank"/>
1647 <table>
1648 <tr>
1649 <td><b>Bank URL<br/>or Coupon:</b></td>
1650 <td><input type="text" name="bankurl" size="64" value="$bankurl"/>
1651 </tr><tr>
1652 <td><b>Account Name<br/>(optional):</b></td>
1653 <td><input type="text" name="name" size="40" value="$name"/></td>
1654 </tr><tr>
1655 <td></td>
1656 <td><input type="submit" name="newbank" value="Add Bank"/>
1657 <input type="submit" name="cancel" value="Cancel"/></td>
1658 </tr>
1659 </table>
1660 </form>
1662 EOT;
1664 if (count($banks) > 0) {
1665 $body .= '<table border="1">
1666 <tr>
1667 <th>Bank</th>
1668 <th>URL</th>
1669 <th>ID</th>
1670 <th>Choose</th>
1671 </tr>
1673 foreach ($banks as $bid => $b) {
1674 if ($client->userreq($bid) != -1) {
1675 $name = hsc($b[$t->NAME]);
1676 if (!$name) $name = "unnamed";
1677 $url = hsc($b[$t->URL]);
1678 $body .= <<<EOT
1679 <form method="post" action="./" autocomplete="off">
1680 <input type="hidden" name="cmd" value="bank"/>
1681 <input type="hidden" name="bank" value="$bid"/>
1682 <tr>
1683 <td>$name</td>
1684 <td><a href="$url">$url</a></td>
1685 <td>$bid</td>
1686 <td><input type="submit" name="selectbank" value="Choose"/></td>
1687 </tr>
1688 </form>
1690 EOT;
1693 $body .= "</table>\n";
1698 function draw_contacts($id=false, $nickname=false, $notes=false) {
1699 global $onload, $body;
1700 global $error;
1701 global $client;
1703 $t = $client->t;
1705 $onload = "document.forms[0].id.focus()";
1706 settitle('Contacts');
1707 setmenu('contacts');
1709 $id = hsc($id);
1710 $nickname = hsc($nickname);
1711 $notes = hsc($notes);
1713 $body = <<<EOT
1714 <span style="color: red;">$error</span><br/>
1715 <form method="post" action="./" autocomplete="off">
1716 <input type="hidden" name="cmd" value="contact">
1717 <table>
1718 <tr>
1719 <td align="right"><b>ID:</b></td>
1720 <td><input type="text" name="id" size="40" value="$id"/></td>
1721 </tr><tr>
1722 <td><b>Nickname<br/>(Optional):</b></td>
1723 <td><input type="text" name="nickname" size="30" value="$nickname"/></td>
1724 </tr><tr>
1725 <td><b>Notes<br/>(Optional):</b></td>
1726 <td><textarea name="notes" cols="30" rows="10">$notes</textarea></td>
1727 </tr><tr>
1728 <td></td>
1729 <td><input type="submit" name="addcontact" value="Add/Change Contact"/>
1730 <input type="submit" name="cancel" value="Cancel"/></td>
1731 </tr>
1732 </table>
1734 EOT;
1736 $contacts = $client->getcontacts();
1737 $cnt = count($contacts);
1738 if ($cnt > 0) {
1739 $body .= '<br/><form method="post" action="./" autocomplete="off">
1740 <input type="hidden" name="cmd" value="contact"/>
1741 <input type="hidden" name="chkcnt" value="' . $cnt . '"/>
1742 <table border="1">
1743 <tr>
1744 <th>Nickname</th>
1745 <th>Name</th>
1746 <th>Display</th>
1747 <th>ID</th>
1748 <th>Notes</th>
1749 <th>x</th>
1750 </tr>';
1751 $idx = 0;
1752 foreach ($contacts as $contact) {
1753 $id = hsc($contact[$t->ID]);
1754 $name = trim(hsc($contact[$t->NAME]));
1755 $nickname = trim(hsc($contact[$t->NICKNAME]));
1756 $display = namestr($nickname, $name, $id);
1757 if (!$name) $name = '&nbsp;';
1758 if (!$nickname) $nickname = '&nbsp;';
1760 $note = hsc($contact[$t->NOTE]);
1761 if (!$note) $note = "&nbsp;";
1762 else $note = str_replace("\n", "<br/>\n", $note);
1763 $body .= <<<EOT
1764 <tr>
1765 <td>$nickname</td>
1766 <td>$name</td>
1767 <td>$display</td>
1768 <td>$id</td>
1769 <td>$note</td>
1770 <td>
1771 <input type="hidden" name="id$idx" value="$id"/>
1772 <input type="checkbox" name="chk$idx"/>
1773 </td>
1774 </tr>
1776 EOT;
1777 $idx++;
1779 $body .= <<<EOT
1780 </table>
1781 <br/>
1782 <input type="submit" name="deletecontacts" value="Delete checked"/>
1783 </form>
1784 EOT;
1788 function draw_assets($scale=false, $precision=false, $assetname=false, $storage=false) {
1789 global $onload, $body;
1790 global $error;
1791 global $client;
1793 $t = $client->t;
1795 $onload = "document.forms[0].scale.focus()";
1797 settitle('Assets');
1798 setmenu('assets');
1800 $scale = hsc($scale);
1801 $precision = hsc($precision);
1802 $assetname = hsc($assetname);
1804 $body .= <<<EOT
1805 <span style="color: red;">$error</span><br/>
1806 <form method="post" action="./" autocomplete="off">
1807 <input type="hidden" name="cmd" value="asset"/>
1808 <table>
1809 <tr>
1810 <td><b>Scale:</b></td>
1811 <td><input type="text" name="scale" size="3" value="$scale"/>
1812 </tr><tr>
1813 <td><b>Precision:</b></td>
1814 <td><input type="text" name="precision" size="3" value="$precision"/></td>
1815 </tr><tr>
1816 <td><b>Asset name:</b></td>
1817 <td><input type="text" name="assetname" size="30" value="$assetname"/></td>
1818 </tr><tr>
1819 <td><b>Storage fee (%/year):</b></td>
1820 <td><input type="text" name="storage" size="5" value="$storage"/></td>
1821 </tr><tr>
1822 <td></td>
1823 <td><input type="submit" name="newasset" value="Add Asset"/>
1824 <input type="submit" name="cancel" value="Cancel"/></td>
1825 </tr>
1826 </table>
1827 </form>
1829 EOT;
1831 $assets = $client->getassets();
1832 if (count($assets) > 0) {
1833 $body .= '<form method="post" action="./" autocomplete="off">
1834 <table border="1">
1835 <tr>
1836 <th>Asset name</th>
1837 <th>Scale</th>
1838 <th>Precision</th>
1839 <th>Storage Fee<br/>(%/year)</th>
1840 <th>Owner</th>
1841 <th>Asset ID</th>
1842 </tr>
1844 $incnt = 0;
1845 foreach ($assets as $asset) {
1846 $ownerid = $asset[$t->ID];
1847 $namestr = id_namestr($ownerid, $contact);
1848 $assetid = $asset[$t->ASSET];
1849 $scale = $asset[$t->SCALE];
1850 $precision = $asset[$t->PRECISION];
1851 $assetname = $asset[$t->ASSETNAME];
1852 $percent = $asset[$t->PERCENT];
1853 if ($ownerid == $client->id) {
1854 $percent = <<<EOT
1855 <input type="hidden" name="assetid$incnt" value="$assetid"/>
1856 <input type="hidden" name="opercent$incnt" value="$percent"/>
1857 <input type="text" name="percent$incnt" value="$percent" size="10" style="text-align: right;"/>
1858 EOT;
1859 $incnt++;
1861 if (!$percent) $percent = "&nbsp;";
1862 $body .= <<<EOT
1863 <tr>
1864 <td>$assetname</td>
1865 <td align="right">$scale</td>
1866 <td align="right">$precision</td>
1867 <td align="right">$percent</td>
1868 <td>$namestr</td>
1869 <td>$assetid</td>
1870 </tr>
1872 EOT;
1874 $body .= "</table>\n";
1875 if ($incnt > 0) {
1876 $body .= '<input type="hidden" name="percentcnt" value="' . $incnt . '"/>
1877 <input type="hidden" name="cmd" value="asset"/>
1878 <br/><input type="submit" name="updatepercent" value="Update Storage Fees"/>
1881 $body .= "</form>\n";
1885 function gethistory() {
1886 global $history;
1888 if (!$history) {
1889 require_once "history.php";
1890 $history = new history();
1892 return $history;
1895 function draw_history() {
1896 global $client;
1898 $history = gethistory();
1899 return $history->draw_history();
1902 function draw_admin($name=false, $tokens=false) {
1903 global $onload, $body;
1904 global $error;
1905 global $client;
1907 settitle('Admin');
1908 setmenu('admin');
1910 $onload = "document.forms[0].name.focus()";
1912 $body = 'No admin stuff yet';
1915 // Copyright 2008 Bill St. Clair
1917 // Licensed under the Apache License, Version 2.0 (the "License");
1918 // you may not use this file except in compliance with the License.
1919 // You may obtain a copy of the License at
1921 // http://www.apache.org/licenses/LICENSE-2.0
1923 // Unless required by applicable law or agreed to in writing, software
1924 // distributed under the License is distributed on an "AS IS" BASIS,
1925 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1926 // See the License for the specific language governing permissions
1927 // and limitations under the License.