Source of “pachyletV1.php”.
2807 lines, 81.2 KBytes.   Last modified 6:31 pm, 1st September 2015 PDT.
1 <?php // Emacs settings: -*- mode: Fundamental; tab-width: 4; -*- 2 3 //////////////////////////////////////////////////////////////////////////// 4 // // 5 // Pachylet: Andrew's Web Mail Interface, Version 1 // 6 // // 7 // Copyright (c) 2002-2006 // 8 // // 9 // See http://birrell.org/pachylet/help.php // 10 // // 11 // Main program for HTML client // 12 // // 13 //////////////////////////////////////////////////////////////////////////// 14 15 $startTime = microtime(); 16 17 require("pachysql.php"); 18 require("pachyauth.php"); 19 20 // Conceptually pachylib.php goes right here, but we delay including it 21 // so that we can skip it for the more common operations (and we don't 22 // know yet what operation we're doing). 23 24 25 // 26 // HTML generation: subroutines 27 // 28 29 function docStart(&$state, $url = "", $extraTitle = "", $extraHead = "") { 30 // Output HTML to get us into the document body 31 // $state might be null (e.g. login) 32 // $url is optional meta-equiv refresh destination 33 global $HTTP_USER_AGENT; 34 ob_start(); 35 $title = C_program; 36 $title = $title . (isset($state->user) ? " ($state->user)" : ""); 37 if (isset($state->totalUnread) && $state->totalUnread > 0) { 38 $title = $title . " $state->totalUnread unread message" . 39 ($state->totalUnread == 1 ? "" : "s"); 40 } 41 if (!headers_sent()) { 42 header("Expires: Sat, 1 Jan 2000 00:00:01 GMT"); 43 header("Cache-Control: no-store, no-cache, " . 44 "must-revalidate, proxy-revalidate"); 45 header("Content-Type: text/html; charset=UTF-8"); 46 } 47 ?> 48 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 49 <html> 50 <head> 51 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 52 <?php 53 if ($url != "") { 54 echo "<meta http-equiv=refresh\n\tcontent=\"0;url=$url\">\n"; 55 } 56 ?> 57 <title><?php echo "$title$extraTitle" ?></title> 58 <link href="pachyletV1.css" rel=stylesheet> 59 <script type="text/javascript" src="pachyletV1.js"> 60 </script> 61 </head> 62 <body<?php if ($extraHead != "") echo " $extraHead" ?>> 63 <?php 64 } 65 66 function docEnd() { 67 // Terminate the body and HTML 68 echo "\n<!-- The end -->\n</body>\n</html>\n"; 69 } 70 71 function stateToString(&$state, $op = NULL, $m = NULL, $d = NULL) { 72 // Return a string representing the state (modified by $op, $m, $d). 73 // Result is URL-encoded, except for $op, so $op can include 74 // extra args for the URL 75 global $sqlTiming; 76 if (is_null($op)) $op = $state->op; 77 if (is_null($m)) $m = $state->m; 78 if (is_null($d)) $d = $state->d; 79 return 80 urlencode($m) . 81 urlencode($state->popups) . 82 urlencode($state->scanning) . 83 ( isset($state->query->unread) ? "Y" : "N") . 84 urlencode($state->query->acctid) . 85 urlencode($state->query->findin) . 86 urlencode($state->x) . 87 urlencode($state->query->datefrom) . 88 urlencode($state->pageSize) . 89 urlencode($state->query->dateto) . 90 urlencode($state->v) . 91 ( $sqlTiming ? "Y" : "N" ) . 92 ( $state->managing ? "Y" : "N") . 93 urlencode($state->managing ? $state->managingUser : "") . "!" . 94 urlencode($state->contacts->display) . 95 urlencode($state->contacts->find) . "!" . 96 urlencode($state->query->f) . "!" . 97 urlencode($state->query->t) . "!" . 98 urlencode($d) . "!" . 99 ($op == "show" ? "" : $op); 100 } 101 102 function stringToState(&$state, $s) { 103 // Given the value of a "z" parameter, as from stateToString, update 104 // $state to match it. 105 // $state, $state->query, and $state->contacts are already initialized 106 global $sqlTiming; 107 $matches = array(); 108 preg_match('#^([-0-9]*)(.)([-0-9]*)(.)([-0-9]*)' . 109 '(.)([-0-9]*)(.)([-0-9]*)(.)(.)' . 110 '(.)(.)([^!]*)!(.)([^!]*)!([^!]*)!([^!]*)!([^!]*)!(.*)#', 111 $s, $matches); 112 $state->m = $matches[1]; 113 $state->popups = $matches[2]; 114 $state->scanning = $matches[3]; 115 if ($matches[4] == 'Y') $state->query->unread = 'Y'; 116 $state->query->acctid = $matches[5]; 117 $state->query->findin = $matches[6]; 118 $state->x = $matches[7]; 119 $state->query->datefrom = $matches[8]; 120 $state->pageSize = $matches[9]; 121 $state->query->dateto = $matches[10]; 122 $state->v = $matches[11]; 123 if ($matches[12] == 'Y') $sqlTiming = true; 124 $state->managing = ($matches[13] == 'Y'); 125 $state->managingUser = $matches[14]; 126 $state->contacts->display = $matches[15]; 127 $state->contacts->find = $matches[16]; 128 $state->query->f = $matches[17]; 129 $state->query->t = $matches[18]; 130 $state->d = $matches[19]; 131 $state->op = ($matches[20] == "" ? "show" : $matches[20]); 132 } 133 134 function selfUrlRaw(&$state, $op = NULL, $m = NULL) { 135 // Return URL for this script with given args. 136 return "$state->baseURL?z=" . stateToString($state, $op, $m); 137 } 138 139 function selfUrl(&$state, $op = NULL, $m = NULL) { 140 // Return selfUrlRaw with HTML entities escaped 141 return htmlspecialchars(selfUrlRaw($state, $op, $m)); 142 } 143 144 function creditLine($withHelp = false, $anchor = "") { 145 // Show a credit line 146 global $sqlTiming, $startTime; 147 echo "\n<!-- Credit line -->\n"; 148 if ($withHelp) { 149 ?> 150 <div class=npd> 151 <a class=crBtn href="help.html<?php 152 if ($anchor != "") echo htmlspecialchars("#$anchor"); 153 ?>" target="_blank">Help</a> 154 </div> 155 <?php 156 } 157 ?> 158 <div class=cr> 159 <?php 160 echo C_program . ", version " . C_version; 161 if ($sqlTiming || true) { 162 ?> 163 164 <span class=npd> 165 &nbsp; 166 (<?php echo elapsed($startTime); ?> secs) 167 </span> 168 <?php 169 } 170 ?> 171 </div> 172 <?php 173 } 174 175 function reportMsg(&$state, $why, $id = NULL, $url = "") { 176 // Display a message page, optionally with meta-equiv refresh to $url 177 docStart($state, $url); 178 ?> 179 <div class=okPad> 180 <div class=ok <?php 181 if (!is_null($id)) echo " id=$id"; 182 echo ">$why"; 183 ?> 184 </div> 185 </div> 186 <?php 187 creditLine(); 188 } 189 190 function putConfirmButton(&$state, $op, $prompt, $dest = NULL) { 191 echo "<div class=okBtn>\n"; 192 echo "<form action=\"$state->baseURL\" method=GET>\n"; 193 putHiddenArg("z", urldecode(stateToString($state, $op))); 194 if (!is_null($dest)) putHiddenArg("dest", $dest); 195 echo "&nbsp;&nbsp;<input type=submit value=\" $prompt \">" . 196 "&nbsp;&nbsp;\n"; 197 echo "</form>\n"; 198 echo "</div>\n"; 199 } 200 201 function putConfirmForm(&$state, $op, $prompt, 202 $dest = NULL, $next = "show") { 203 // Put form confirming a dangerous operation $op with arg $dest 204 // If not confirmed, do operation $next instead 205 docStart($state); 206 ?> 207 208 <!-- Confirmation Dialog --> 209 <div class=okPad> 210 <div class=ok id=confirm> 211 <?php putConfirmButton($state, $next, "No") ?> 212 <?php putConfirmButton($state, $op, "Yes", $dest) ?> 213 <?php echo htmlspecialchars($prompt); ?> 214 </div> 215 </div> 216 <?php 217 creditLine(); 218 } 219 220 function reportError(&$state, $prompt, $OK = true, $next = "show") { 221 // Display an error message page for user-sensible failure 222 docStart($state); 223 ?> 224 225 <!-- Error Dialog --> 226 <div class=okPad> 227 <div class=ok id=error> 228 <?php if ($OK) putConfirmButton($state, $next, "OK") ?> 229 <?php echo htmlspecialchars($prompt); ?> 230 </div> 231 </div> 232 <?php 233 creditLine(); 234 } 235 236 function putRedirect(&$state) { 237 // Redirect (after POST or to move to a more stable URL) 238 $url = selfUrl($state); 239 if (headers_sent()) { 240 // I don't think this happens, but just in case ... 241 reportMsg($state, 242 "Redirecting (to <a href=\"$url\">this URL</a>) ...", 243 NULL, $url); 244 } else { 245 Header("Location: " . selfUrlRaw($state)); 246 reportMsg($state, 247 "You should have been redirected " . 248 "<a href=\"$url\">here</a>"); 249 } 250 } 251 252 function button(&$state, $action, $text, $active, 253 $popup = false, $newWin = null, $nextBtn = false) { 254 // Output HTML for a textual button, optionally active 255 // Iff $popup, include script to activate popup dialog 256 // Iff $newWin isn't null, non-popup action creates new window 257 global $forPopup; 258 echo "<td class=btn" . 259 ($nextBtn ? " id=nextBtn rowspan=2" : "") . ">"; 260 if ($active) { 261 echo "<a href=\""; 262 echo selfUrl($state, $action); 263 echo "\""; 264 if ($state->popups == "Y" && $popup) { 265 echo "\n\tonClick=\"return toggle('$action')\""; 266 } else if (!is_null($forPopup)) { 267 echo "\n\tonClick=\"{toggle('$forPopup');return true;}\""; 268 } 269 if (!is_null($newWin)) echo "\n\ttarget=\"$newWin\""; 270 echo ">"; 271 } else { 272 echo "<div class=disabledBtn>"; 273 } 274 echo $text; 275 if ($active) { 276 echo "</a>"; 277 } else { 278 echo "</div>"; 279 } 280 echo "</td>\n"; 281 } 282 283 function putHiddenArg($name, $value) { 284 // Put a hidden arg for a form 285 echo "<input type=hidden name=$name value=\"" . 286 htmlspecialchars($value) . "\">\n"; 287 } 288 289 function showTextInput($prompt, $k, $v = "", $tp = false, $ro = false) { 290 // Show a row containing a text input field of a form. Use type = 291 // password iff $tp. 292 // 293 $t = ($tp ? "password" : "text"); 294 $w = ($tp ? 18 : 60); 295 echo "<tr>\n<td align=right nowrap>" . htmlspecialchars($prompt) . 296 ($tp ? "<br><span class=comment>&nbsp;</span>\n" : "") . 297 "</td>\n<td>"; 298 if ($ro) { 299 echo htmlspecialchars($v); 300 putHiddenArg($k, $v); 301 } else { 302 echo "<input type=$t name=$k value=\"" . 303 htmlspecialchars($v) . "\" size=$w>"; 304 } 305 if ($tp) { 306 echo " = <input type=$t name=${k}_2 size=$w><br>\n"; 307 echo "<span class=comment>(Leave passwords blank " . 308 "to keep them unchanged)</span>"; 309 } 310 echo "</td>\n</tr>\n"; 311 } 312 313 function putOption($default, $value, $prompt = "") { 314 // Put an <option> tag for within a <select> form item 315 $h = htmlspecialchars(($prompt == "" ? $value : $prompt)); 316 echo "\t<option " . ($value==$default ? "selected " : "") . 317 "value=\"" . htmlspecialchars($value) . "\">$h\n"; 318 return ($value == $default); 319 } 320 321 function putRadio($default, $name, $value, $prompt = "") { 322 // Show a radio button form item 323 $h = htmlspecialchars(($prompt == "" ? $value : $prompt)); 324 echo "<input type=radio name=\"" . htmlspecialchars($name) . 325 "\" value=\"" . htmlspecialchars($value) . "\"" . 326 ($value==$default ? " checked" : "") . ">$h\n"; 327 } 328 329 function putCheckbox($checked, $name, $value, $prompt = "", 330 $after = "\n") { 331 // Put a <checkbox> item for a form 332 $h = htmlspecialchars(($prompt == "" ? $value : $prompt)); 333 echo "<input type=checkbox name=\"" . htmlspecialchars($name) . 334 "\" value=\"" . htmlspecialchars($value) . "\"" . 335 ($checked ? " checked" : "") . ">$h$after"; 336 } 337 338 $forPopup = NULL; // changes formStart and formEnd to do popups 339 340 function popupCancel(&$state, $name) { 341 // Output HTML for a cancel button for popups in main window 342 global $forPopup; 343 ?> 344 <td align=right class=nowrap> 345 <input type=submit name="<?php echo $name ?>" value=" Cancel " 346 <?php 347 if (!is_null($forPopup)) { 348 echo " onClick=\"return toggle('$forPopup')\""; 349 } 350 ?> 351 > 352 </td> 353 <?php 354 } 355 356 function popupStart($id) { 357 // Put boilerplate for start of a pop-up dialog 358 echo "\n<!-- Popup dialog \"$id\" -->\n"; 359 ?> 360 <table class=flt id="<?php echo $id ?>"><tr><td> 361 <?php 362 } 363 364 function popupEnd() { 365 // Put boilerplate for end of a pop-up dialog 366 ?> 367 </td></tr></table> 368 <?php 369 } 370 371 function formStart($state, $method, $op, $start = true, $multi = false, 372 $extraTitle = "", $extraHead = "") { 373 // Put <form> tag and z parameter with current state, 374 // with optional document start boilerplate 375 global $forPopup; 376 if ($start) { 377 if (is_null($forPopup)) { 378 docStart($state, "", $extraTitle, $extraHead); 379 } else { 380 popupStart($forPopup); 381 } 382 } 383 echo "<form action=\"$state->baseURL\" method=$method class=trim" . 384 ($multi ? " enctype=\"multipart/form-data\"" : "") . ">\n"; 385 putHiddenArg("z", urldecode(stateToString($state, $op))); 386 echo "<table class=bb>"; 387 } 388 389 function formEnd($bbar = true, $help = false, $anchor = "") { 390 global $forPopup; 391 if ($bbar) echo "</table>\n"; 392 if (is_null($forPopup)) { 393 if ($bbar) creditLine($help, $anchor); 394 echo "</form>\n"; 395 if (!$bbar) creditLine($help, $anchor); 396 } else { 397 echo "</form>\n"; 398 popupEnd(); 399 } 400 } 401 402 403 // 404 // HTML generation: main screen 405 // 406 407 function buttonBar(&$state, $lastIsSelected, $moreToRead) { 408 // Output HTML for the main button bar 409 global $forPopup; 410 ?> 411 412 <!-- Main Button-bar --> 413 <table class=bb cellspacing=3><tr> 414 <?php 415 $drafts = ($state->query->f == C_unsent); 416 button($state, "showContacts", "Contacts", true); 417 button($state, "resendSel", "Resend...", $state->m > 0, false); 418 button($state, "compose", "Compose", true, false, "_blank"); 419 button($state, "inc", "Fetch Mail", true, false); 420 echo "<td class=btnPad></td>\n"; 421 button($state, 422 ($lastIsSelected && $state->totalUnread > 0 ? "scan" : "next"), 423 ($lastIsSelected && $state->totalUnread > 0 ? "Scan" : "Next"), 424 (!$lastIsSelected && !$drafts) || $state->totalUnread > 0, 425 false, null, true); 426 echo "<td class=btnPad></td>\n"; 427 button($state, "find", "Find...", true); 428 button($state, "folderSel", "Folders", true); 429 button($state, "options", "Settings", true); 430 button($state, "logout", "Logout", true); 431 echo "</tr><tr>\n"; 432 button($state, "forward", "Forward", $state->m > 0, false, "_blank"); 433 button($state, "replyAll", "To All", $state->m > 0, false, "_blank"); 434 button($state, "reply", "To Author", $state->m > 0, false, "_blank"); 435 button($state, "scan", "Scan", $state->totalUnread > 0); 436 echo "<td class=btnPad></td>\n"; 437 echo "<td class=btnPad></td>\n"; 438 button($state, "drop", "Drop", 439 $state->m > 0 && $state->query->f != C_dropped); 440 button($state, 441 ($state->query->f == C_trash ? "deleteSel" : "trash"), 442 ($state->query->f == C_trash ? "Delete..." : "Trash"), 443 ($state->query->f == C_trash || $state->m > 0), 444 true); 445 button($state, "moveCopySel", "Move-Copy...", !$drafts, true); 446 button($state, "markSel", "Mark...", !$drafts, true); 447 ?> 448 </tr></table> 449 450 <?php 451 if ($state->popups == "Y") { 452 popupStart("warning"); 453 ?> 454 Your can disable use of Javascript and CSS for popups by using 455 <a href="<?php echo htmlspecialchars("$state->baseURL?popups=N") ?>">this 456 URL</a>. 457 <?php 458 popupEnd(); 459 $forPopup = "moveCopySel"; 460 selectMoveCopy($state); 461 if ($state->query->f == C_trash) { 462 $forPopup = "deleteSel"; 463 selectDelete($state); 464 } 465 $forPopup = "markSel"; 466 selectMark($state); 467 $forPopup = NULL; 468 } 469 } 470 471 function vButton(&$state, $op, $prompt, $active = true) { 472 // Output HTML for a link in a vertical list 473 if ($active) { 474 echo "<a href=\"" . selfUrl($state, $op) . "\">"; 475 } else { 476 echo "<div class=disabledBtn>"; 477 } 478 echo htmlspecialchars($prompt); 479 if ($active) { 480 echo "</a>"; 481 } else { 482 echo "</div>"; 483 } 484 echo "\n"; 485 } 486 487 function setPage(&$state, $dest, $prompt, $total) { 488 // Output HTML for the page adjustment links 489 if ($dest > $total - $state->pageSize) $dest = $total-$state->pageSize; 490 if ($dest < 0) $dest = 0; 491 vButton($state, "page&dest=$dest", $prompt, ($dest != $state->x)); 492 } 493 494 function setPageSize(&$state, $dest) { 495 // Output HTML for the pageSize adjustment links 496 vButton($state, "pageSize&dest=$dest", $dest, $state->pageSize != $dest) ; 497 } 498 499 function putPre($s) { 500 // Put string with spaces replaced by &nbsp 501 echo preg_replace('# #', ' &nbsp;', $s); 502 echo "<br>\n"; 503 } 504 505 function showTocButtons(&$state, $total, $showing) { 506 // Show TOC button bar, varying according to msg list being visible 507 ?> 508 <tr><td class=btnComment> 509 &nbsp; Msg List: &nbsp; 510 </td></tr> 511 <tr> 512 <td class=btn style="text-align: left"> 513 <?php 514 if ($showing) { 515 vButton($state, "view", "Hide", $state->query->f != C_unsent); 516 setPageSize($state, 10); 517 setPageSize($state, 30); 518 setPageSize($state, 90); 519 setPage($state, $total, "First", $total); 520 setPage($state, $state->x + $state->pageSize, "Earlier", $total); 521 setPage($state, $state->x - $state->pageSize, "Later", $total); 522 setPage($state, 0, "Last", $total); 523 } else { // not showing 524 vButton($state, "view", "Show", true); 525 ?> 526 </td></tr> 527 <?php 528 } 529 } 530 531 function openFolderButton(&$state, $folder) { 532 // Show a button to open $folder 533 // Assumes that $state->query was set by jumpToFolder, and that it 534 // may be destroyed. 535 $state->query->f = $folder; 536 vButton($state, "show", $folder, true); 537 } 538 539 function showOpenFolderButtons(&$state) { 540 // Show message button bar 541 ?> 542 <tr><td class=btnComment> 543 &nbsp; Folders: &nbsp; 544 </td></tr><tr><td class=btn style="text-align: left"> 545 <?php 546 $save = new stdClass(); 547 $save->query = $state->query; 548 $save->m = $state->m; 549 $save->d = $state->d; 550 $save->scanning = $state->scanning; 551 jumpToFolder($state, "foo"); 552 openFolderButton($state, C_inbox); 553 openFolderButton($state, C_dropped); 554 openFolderButton($state, C_trash); 555 openFolderButton($state, C_unsent); 556 ?> 557 <div class=sep style="margin-top: 2px"></div> 558 <?php 559 $folders = getFolders($state->user); 560 appendQueryNames($state->user, $folders); 561 natcasesort($folders); 562 foreach($folders as $folder) openFolderButton($state, $folder); 563 $state->query = $save->query; 564 $state->m = $save->m; 565 $state->d = $save->d; 566 $state->scanning = $save->scanning; 567 ?> 568 </td></tr> 569 <?php 570 } 571 572 function showMsgList(&$state, &$msgs, $total) { 573 // Display the given message list, a set of rows from getMsgList 574 // Current position in $msgs is undefined - a seek is required 575 ?> 576 577 <!-- Message list --> 578 <div class=msg> 579 <tt> 580 <?php 581 582 $rows = mysql_num_rows($msgs); 583 $xMin = $total-($state->x+$rows-1); 584 $xMax = $total-$state->x; 585 echo "<b>" . 586 htmlspecialchars(($state->query->f=="" ? C_all : $state->query->f)) . 587 ": " . 588 ($total == 0 ? "no" : 589 ($xMax - $xMin + 1 == $total ? "all " : 590 "$xMin-$xMax of ") . $total) . 591 " matching messages</b><br>\n"; 592 $lines = buildTocLines($state->user, $msgs); 593 for ($i = $rows-1; $i >= 0; $i--) { 594 $thisLine = $lines[$i]; 595 $anchor = ""; 596 if ($state->query->f == C_unsent) { 597 if (!isset($_COOKIE["pachydraft$thisLine->id"]) || 598 $_COOKIE["pachydraft$thisLine->id"] != "Y") { 599 $anchor = "<a href=\"" . 600 selfUrl($state, "reopenDraft&draftId=$thisLine->id") . 601 "\" target=\"_blank\">"; 602 } 603 } else if ($thisLine->id != $state->m) { 604 $anchor = "<a href=\"" . 605 selfUrl($state, "show", $thisLine->id) . "\">"; 606 } 607 echo(($thisLine->id == $state->m ? "&gt; " : 608 ($thisLine->unread == 'Y' ? "? " : "&nbsp; ") ) . 609 "$thisLine->date&nbsp;\n$anchor$thisLine->from&nbsp;\n" . 610 "$thisLine->subject" . ($anchor == "" ? "" : "</a>") . 611 "<br>\n"); 612 } 613 for ($j = $rows; $j < 10; $j++) echo "&nbsp;<br>\n"; 614 ?> 615 </tt> 616 </div> 617 <?php 618 } 619 620 function putItemLink($state, $part, &$classes, $partNo, $headerPartID) { 621 // Put an HTML link to the given part (which is $partNo relative to 622 // the message being shown). $headerPartID is the partID at which the 623 // message being shown starts. 624 if (!isset($classes[$partNo])) return; 625 $class = $classes[$partNo]; 626 if ($class == "N") return; 627 $type = getPartType($part); 628 $name = getPartName($part); 629 $length = ($part->length < 0 ? -$part->length : $part->length); 630 if ($type=="message/rfc822" && $partNo != 0) { 631 // Link for displaying an attached message 632 $url = selfUrl($state, "showMsg&dest=$part->part"); 633 } else if ($class == "A") { 634 // Link for displaying this message with an alternative chosen body 635 $url = selfUrl($state, 636 "showMsg&chosenPart=$partNo&dest=$headerPartID"); 637 } else { 638 // Link for displaying an attachment 639 $url = htmlspecialchars(getPartURL($state->user, $part->part)); 640 } 641 echo "<div class=npd><tt><b>"; 642 echo ( $class == "M" ? "Raw Header: &nbsp;</b>" : 643 ( $class == "A" ? "Alternative:</b> " : 644 ( $class == "N" ? "Unused: </b>" : 645 "Attachment: &nbsp;</b>") ) ); 646 echo "<a href=\"$url\">"; 647 echo htmlspecialchars(!is_null($name) ? $name : $type); 648 echo "</a>"; 649 if ($part->children == 0) { 650 echo " ("; 651 if (!is_null($name)) echo htmlspecialchars($type) . ", "; 652 putByteLength($length); 653 echo ")"; 654 } 655 echo "<br></tt></div>\n"; 656 } 657 658 function showMsgHeader($state, $part, &$mimeKludge, $labels) { 659 // If $part has type message/rfc822, render it in HTML 660 $hdr = getAndParseHeader($state->user, $part, $mimeKludge); 661 echo "<tt>\n"; 662 if (!is_null($labels)) { 663 putPre("<b>Folder: </b>" . 664 htmlspecialchars(implode(", ", $labels))); 665 } 666 if ($hdr) { 667 putPre("<b>From: </b>" . 668 contactRecipients($state, $hdr->msgfrom)); 669 putPre("<b>Subject: </b>" . 670 htmlFromRfc1342($hdr->subject, 999)); 671 putPre("<b>Date: </b>" . 672 ($hdr->udate ? formatUserTime("l, jS F Y, g:i:s a", 673 $state->displaytz, $hdr->udate) : 674 "")); 675 putPre("<b>To: </b>" . 676 contactRecipients($state, $hdr->msgto)); 677 putPre("<b>Cc: </b>" . 678 contactRecipients($state, $hdr->msgcc)); 679 } else { 680 putPre("<b>Header: </b>not available"); 681 } 682 echo "</tt>\n"; 683 } 684 685 function showAltMsg($state, &$parts, $chosenPart, $labels = NULL) { 686 // Generate HTML for message consisting of the given parts 687 688 // Find best renderable part 689 $classes = array(); 690 startMsgParts($parts, $partNo, $children); 691 scanMsgItem($classes, $parts, $partNo, $children, "M"); 692 $bestPartNo = (isset($classes["best"]) ? $classes["best"] : -1); 693 if (!is_null($chosenPart)) $bestPartNo = $chosenPart; 694 $classes[$bestPartNo] = "N"; 695 if ($bestPartNo >= 0) { 696 mysql_data_seek($parts, $bestPartNo); 697 $bestPart = mysql_fetch_object($parts); 698 } 699 // Render the header (if any) and links for non-ignored non-best parts 700 $mimeKludge = false; 701 $headerPartID = 0; 702 startMsgParts($parts, $partNo, $children); 703 while ($children > 0) { 704 $part = nextMsgPart($parts, $partNo, $children); 705 $children += $part->children; 706 if ($partNo == 0) { 707 $headerPartID = $part->part; 708 showMsgHeader($state, $part, $mimeKludge, $labels); 709 } else { 710 putItemLink($state, $part, $classes, $partNo, $headerPartID); 711 } 712 } 713 if (isset($bestPart)) { 714 $textPlain = $bestPart->type == "text" && 715 $bestPart->subtype == "PLAIN"; 716 $textHtml = $bestPart->type == "text" && 717 $bestPart->subtype == "HTML"; 718 if ($mimeKludge && $textPlain) { 719 $textPlain = false; $textHtml = true; 720 } 721 } 722 723 // Add links for the viewing options 724 echo "<div class=npd>\n<tt>\n<b>Other Views: </b>\n"; 725 if (isset($bestPart) && $textHtml) { 726 echo "<a href=\"" . 727 htmlspecialchars(getPartURL($state->user, $bestPart->part)) . 728 "\">As Web Page</a> ...\n"; 729 } 730 if ($headerPartID > 0) { 731 echo "<a href=\"" . 732 htmlspecialchars(getPartURL($state->user, $headerPartID)) . 733 "\">Raw Header</a> ...\n"; 734 } 735 echo "<a href=\"" . selfUrl($state, "showRawMsg&dest=$headerPartID") . 736 "\">Raw Message</a> ...\n"; 737 echo "<a href=\"" . selfUrl($state, "showRawList") . 738 "\">Raw List</a>"; 739 echo "<br>\n</tt>\n</div>\n"; 740 741 echo "<tt>-----</tt><br>\n"; 742 743 // Render the best part, if any 744 if (isset($bestPart)) { 745 if ($textPlain) { 746 echo getTextContent($state->user, $bestPart->part); 747 } else if ($textHtml) { 748 echo getHtmlContent($state->user, $bestPart->part, true); 749 } else { 750 echo htmlspecialchars( 751 "Content-type: $bestPart->type/$bestPart->subtype"); 752 } 753 } 754 } 755 756 function showMainScreen(&$state) { 757 // Select appropriate message; display msg list and message. 758 $total = 0; 759 $lastIsSelected = false; 760 $moreToRead = false; 761 $msgs = selectMessage($state->user, $state->query, $state->m, $state->x, 762 $state->pageSize, 763 $total, $lastIsSelected, $moreToRead); 764 if ($state->m > 0) { 765 addLabel($state->user, C_unread, $state->m, 'N'); 766 if (isset($state->query->unread)) { 767 deleteCachedHit($state->user, $state->m); 768 } 769 } 770 771 $state->totalUnread = countMsgsWithLabel($state->user, C_unread); 772 if ($state->query->f == C_unsent) $state->m = 0; 773 $showList = ($state->v != "M" || $state->query->f == C_unsent); 774 775 docStart($state); 776 ?> 777 778 <div class=npd> 779 <?php 780 buttonBar($state, $lastIsSelected, $moreToRead); 781 ?> 782 783 <!-- vertical button bar --> 784 <table class=bb id=vbb cellspacing=3> 785 <?php 786 showTocButtons($state, $total, $showList); 787 showOpenFolderButtons($state); 788 ?> 789 </table> 790 <?php 791 792 if ($showList) { 793 showMsgList($state, $msgs, $total); 794 } 795 ?> 796 797 </div> <!-- end npd --> 798 799 <!-- Message body --> 800 <div class=msg> 801 <?php 802 if ($state->query->f == C_unsent) { 803 echo "<tt>Click on an unsent message to resume editing it.</tt>\n"; 804 } else if ($state->m > 0) { 805 ob_end_flush(); ob_start(); 806 $parts = getMsgParts($state->user, $state->m); 807 if (mysql_num_rows($parts) == 0) { 808 echo "<tt><b>Message $state->m doesn't exist.</b></tt>\n"; 809 } else { 810 $labels = getMsgLabels($state->user, $state->m); 811 showAltMsg($state, $parts, NULL, $labels); 812 } 813 } else { 814 echo "<tt><b>No message selected.</b></tt>\n"; 815 } 816 ?> 817 </div> 818 <div class=clear></div> 819 <?php 820 creditLine(true); 821 } 822 823 function jumpToNext(&$state, $doNextUnread = false, $sticky = true) { 824 // Update state to select next message and its scroll position 825 selectNextMessage($state->user, $state->query, $state->m, 826 $state->x, $state->pageSize, $doNextUnread, $sticky); 827 } 828 829 function jumpToFolder(&$state, $f) { 830 // Change query to be for $f, and auto-select a message 831 // If the folder changes, keeps previous folder in $state->d, for 832 // better defaults in later folder open and move operations. 833 $state->m = -1; 834 if ($state->query->f != $f) { 835 $state->d = $state->query->f; 836 } 837 // assemble a new query, discarding old optional fields 838 $query = new stdClass(); 839 $query->f = $f; 840 $query->t = ""; 841 $query->findin = "A"; 842 $query->datefrom = "B"; 843 $query->dateto = "E"; 844 $query->acctid = 0; 845 $state->query = $query; 846 $state->scanning = 0; 847 } 848 849 function findQuery(&$state, $name) { 850 // Change query to the named one, ignoring its folder 851 jumpToFolder($state, ""); 852 $state->query = getQuery($state->user, $name); 853 $state->query->f = ""; 854 unset($state->query->unread); 855 } 856 857 858 // 859 // HTTP response: show sub-messages and raw message list 860 // 861 862 function showPartAsMsg(&$state, $partID, $chosenPart) { 863 // Given partID, get its contents and render as a message 864 $part = getPart($state->user, $partID); 865 if (!$part) { 866 reportError($state, "Part $partID not found in database"); 867 } else { 868 docStart($state); 869 ?> 870 <table class=bb cellspacing=3><tr> 871 <td width="88%" nowrap><b><?php 872 echo htmlspecialchars("Message #$part->id"); 873 if ($part->imapnum != "0") { 874 echo htmlspecialchars(", attached message $part->imapnum"); 875 } 876 if (!is_null($chosenPart)) { 877 echo htmlspecialchars(", viewing part #$chosenPart"); 878 } 879 ?></b></td> 880 <?php button($state, "show", "Done", true) ?> 881 </tr></table><!--bbarEnd--> 882 <div class=msg> 883 <?php 884 $parts = getMsgParts($state->user, $part->id, $partID); 885 showAltMsg($state, $parts, $chosenPart); 886 echo "</div>\n"; 887 formEnd(false); 888 } 889 } 890 891 function showRawList(&$state) { 892 // Show list of matching messages. Intended for extracting raw email 893 docStart($state); 894 echo "<tt>\n"; 895 $offset = 0; 896 $total = 0; 897 $ids = getMsgIds($state->user, $state->query); 898 foreach ($ids as $id) { 899 echo "<a href=\"" . selfUrl($state, "showRawMsg&dest=0", $id) . 900 "\">$id</a><br>\n"; 901 } 902 echo "</tt>\n"; 903 } 904 905 906 // 907 // HTML generation: miscellaneous dialogs (open, find, etc.) 908 // 909 910 function putFolderSelect($user, $fName, $default, $which, $size = 0) { 911 // Put the HTML for the SELECT for a folder pull-down 912 // $which is "real", "queries", "scanOrder", "system", "writeable", 913 // or "all" 914 if ($which == "system" || $which == "queries" || 915 $which == "scanOrder") { 916 $folders = array(); 917 } else { 918 $folders = getFolders($user); 919 } 920 if ($which == "system" || $which == "writeable" || $which == "all") { 921 $folders[] = C_dropped; 922 $folders[] = C_inbox; 923 $folders[] = C_trash; 924 if ($which != "writeable") $folders[] = C_unsent; 925 } 926 if ($which == "queries" || $which == "scanOrder" || 927 $which == "writeable" || $which == "all") { 928 appendQueryNames($user, $folders); 929 } 930 if ($which != "scanOrder") natcasesort($folders); 931 if (!in_array($default, $folders) && 932 ($default != "" || ($which != "system" && $which != "all"))) { 933 foreach ($folders as $folder) { 934 $default = $folder; 935 break; 936 } 937 } 938 echo "<select name=$fName" . 939 ($size == 0 ? "" : " size=$size") . ">\n"; 940 if ($which == "system" || $which == "all") { 941 putOption($default, "", C_all); 942 } 943 foreach ($folders as $folder) putOption($default, $folder); 944 echo "</select>\n"; 945 } 946 947 function putDateSelect($field, $default) { 948 // Put the HTML for datefrom or dateto 949 echo "<select name=$field>\n"; 950 if ($field == "datefrom") putOption($default, "B", "the start of time"); 951 if ($field == "dateto") putOption($default, "E", "the end of time"); 952 putOption($default, "H", "48 hours ago"); 953 putOption($default, "W", "a week ago"); 954 putOption($default, "M", "a month ago"); 955 putOption($default, "Q", "three months ago"); 956 putOption($default, "Y", "a year ago"); 957 $delta = ($field == "datefrom" ? "the start of " : "the end of "); 958 for ($i = 0; $i < 20; $i++) { 959 putOption($default, chr(ord("a")+$i), $delta . (1995+$i)); 960 } 961 echo "</select>\n"; 962 } 963 964 function selectFolder(&$state, $dest) { 965 // Put form for modifying folders collections 966 // $dest if non-null provides default folder selection; 967 // otherwise default is $state->query->f. 968 docStart($state); 969 ?> 970 <table class=bb cellspacing=3><tr> 971 <td class=nowrap></td> 972 <?php button($state, "show", "Done", true) ?> 973 </tr></table> 974 975 <div class=sep></div> 976 977 <?php formStart($state, "GET", "adjustFolder", false) ?> 978 <tr valign=top> 979 <td class=folderScreenL><b>Manage Your Normal Folders</b> 980 <p> 981 <span class=comment>Normal folders let you manually organize your messages 982 into appropriate piles. 983 </span></td> 984 <td class=folderScreenM align=right> 985 <?php 986 putFolderSelect($state->user, "dest", 987 (is_null($dest) ? $state->query->f : $dest), "real", 5); 988 ?> 989 </td><td class=folderScreenR> 990 <input type=submit name=createFolder value=" Create... "><br> 991 <input type=submit name=deleteFolder value=" Delete... "><br> 992 </td> 993 </tr> 994 </table></form> 995 996 <div class=sep></div> 997 998 <?php formStart($state, "GET", "adjustFolder", false) ?> 999 <tr valign=top> 1000 <td class=folderScreenL><b>Manage Your Smart Folders</b> 1001 <p> 1002 <span class=comment>Smart folders provide automatic sorting for your 1003 incoming mail, and saved queries. 1004 </span><p><span class=comment> 1005 "Order" lets you adjust the order in which "Scan" examines your 1006 smart folders. 1007 </span><p><span class=comment> 1008 "Find" finds all messages (not in Trash) 1009 matching the smart folder's query, ignoring the folder name. 1010 </span> 1011 </td> 1012 <td class=folderScreenM align=right> 1013 <?php 1014 putFolderSelect($state->user, "dest", 1015 (is_null($dest) ? $state->query->f : $dest), "queries", 10); 1016 ?> 1017 </td><td class=folderScreenR> 1018 <input type=submit name=createQuery value=" Create... "><br> 1019 <input type=submit name=deleteQuery value=" Delete... "><br> 1020 <input type=submit name=editQuery value=" Edit... "><br> 1021 <input type=submit name=scanOrderQuery value=" Order... "><br> 1022 <input type=submit name=findQuery value=" Find "><br> 1023 </td> 1024 </tr><?php 1025 formEnd(true, true, "Smart Folders"); 1026 } 1027 1028 function selectScanOrder(&$state) { 1029 // Put form for adjusting query's scan order 1030 formStart($state, "GET", "adjustScanOrder"); 1031 ?> 1032 <tr valign=top> 1033 <td width="55%"><b>Smart Folders' Scan Order</b> 1034 <p> 1035 <span class=comment>The "Scan" button on the main screen examines your 1036 smart folders in this order, looking for unread messages. 1037 Use the "Promote" and "Demote" buttons to adjust this order. 1038 </span><p><span class=comment> 1039 This will let you scan your new mail in priority order, 1040 and stop scanning 1041 when you've got down to stuff that's not worth viewing yet. 1042 </span><p><span class=comment> 1043 Additionally, when your smart folders' queries are applied to 1044 incoming mail to pre-sort it, they are applied in this order. 1045 </span> 1046 </td> 1047 <td width="22%" align=right nowrap> 1048 <?php 1049 putFolderSelect($state->user, "dest", $state->d, "scanOrder", 25); 1050 ?> 1051 </td><td width="11%"> 1052 <input type=submit name=promoteScanOrder value=" Promote "><br> 1053 <input type=submit name=demoteScanOrder value=" Demote "><br> 1054 </td><td width="11%" align=center> 1055 <input type=submit name=doneScanOrder value=" Done "> 1056 </td> 1057 </tr><?php 1058 formEnd(); 1059 } 1060 1061 function selectMoveCopy(&$state) { 1062 // Put form for move/copy operations 1063 $disable = ($state->m > 0 ? "" : "disabled"); 1064 formStart($state, "GET", "moveCopy"); 1065 ?> 1066 <tr><td colspan=2 class=nowrap> 1067 <b>Move or copy to...</b> 1068 </td> 1069 <?php popupCancel($state, "moveCopyCancel") ?> 1070 </tr> 1071 <tr><td class=fsep colspan=3></td></tr> 1072 <tr valign=top><td> 1073 <?php 1074 putFolderSelect($state->user, "dest", $state->d, "writeable", 15); 1075 ?> 1076 </td><td> 1077 <input <?php echo $disable; ?> type=submit name=move value=" Move "><br> 1078 <input <?php echo $disable; ?> type=submit name=copy value=" Copy "><br> 1079 <input type=submit name=moveAll value=" Move All "><br> 1080 <input type=submit name=copyAll value=" Copy All "> 1081 </td> 1082 </tr><tr><td colspan=3 class=popupComment align=right> 1083 <span class=comment>("All" means "all messages matching this query")</span> 1084 </td></tr><?php 1085 formEnd(); 1086 } 1087 1088 function selectDelete(&$state) { 1089 // Put form for message deletion operations 1090 $disable = ($state->m > 0 ? "" : "disabled"); 1091 formStart($state, "GET", "deleteMsg"); 1092 ?> 1093 <tr><td colspan=2 class=nowrap> 1094 <b>Permanently delete...</b> 1095 </td> 1096 <?php popupCancel($state, "deleteCancel") ?> 1097 </tr> 1098 <tr><td class=fsep colspan=3></td></tr> 1099 <tr valign=top><td colspan=2> 1100 <input <?php echo $disable; ?> type=submit name=delThis 1101 value=" Delete "><br> 1102 <input type=submit name=delAll value=" Delete All "> 1103 </td> 1104 </tr><tr><td colspan=3 class=popupComment align=right> 1105 <span class=comment>This action <i>permanently</i> deletes either the 1106 selected message, or all messages matching this query</span> 1107 </td></tr><?php 1108 formEnd(); 1109 } 1110 1111 function selectMark(&$state) { 1112 // Put form for mark read/unread operations 1113 $disable = ($state->m > 0 ? "" : "disabled"); 1114 formStart($state, "GET", "mark"); 1115 ?> 1116 <tr><td colspan=2 class=nowrap> 1117 <b>Mark as...</b> 1118 </td> 1119 <?php popupCancel($state, "markCancel") ?> 1120 </tr> 1121 <tr><td class=fsep colspan=3></td></tr> 1122 <tr valign=top><td colspan=3> 1123 <input <?php echo $disable; ?> type=submit name=markUnread 1124 value=" Unread "><br> 1125 <input type=submit name=markAllUnread value=" All Unread "><br> 1126 <input type=submit name=markAllRead value=" All Read "> 1127 </td> 1128 </tr><tr><td colspan=3 class=popupComment align=right> 1129 <span class=comment>("All" means "all messages matching this query")</span> 1130 </td></tr><?php 1131 formEnd(); 1132 } 1133 1134 function putCreateForm(&$state) { 1135 // Put a form for creating a folder 1136 formStart($state, "GET", "createFolder"); 1137 ?> 1138 <tr> 1139 <td class=nowrap><b>Create a Normal Folder</b></td> 1140 <td align=right class=nowrap> 1141 <input type=submit value=" Save "> 1142 <input type=submit name=createCancel value=" Cancel "> 1143 </td> 1144 </tr> 1145 <tr><td class=fsep colspan=2></td></tr> 1146 <?php 1147 showTextInput("Folder name:", "dest"); 1148 formEnd(); 1149 } 1150 1151 function composeQuery(&$state, $query) { 1152 // Ask user to compose a query (op=="find") 1153 // or edit/create a saved query (op=="adjustFolder"). 1154 // $query (often $state->query) provides default values 1155 if ($state->op == "adjustFolder") { 1156 if (is_null($query)) { // Creation 1157 $query = $state->query; 1158 $query->f = ""; 1159 $query->filter = ""; 1160 $query->unread = ""; 1161 } 1162 formStart($state, "GET", "saveQuery"); 1163 echo "<tr><td class=nowrap><b>"; 1164 if (isset($query->scan)) putHiddenArg("destScan", $query->scan); 1165 if (isset($query->qid)) { 1166 echo "Edit a Smart Folder"; 1167 putHiddenArg("destId", $query->qid); 1168 } else { 1169 echo "Create a Smart Folder"; 1170 } 1171 putHiddenArg("f", ""); 1172 ?> 1173 </b> 1174 </td> 1175 <td align=right class=nowrap> 1176 <input type=submit value=" Save "> 1177 <input type=submit name=saveCancel value=" Cancel "> 1178 </td> 1179 </tr> 1180 <tr><td class=fsep colspan=2></td></tr> 1181 <?php 1182 showTextInput("Folder name:", "dest", 1183 (isset($query->name) ? $query->name : ""), 1184 false, isset($query->qid)) ?> 1185 <tr><td align=right nowrap> 1186 When new mail arrives: 1187 </td><td> 1188 <?php putCheckbox(isset($query->filter), "filter", "") ?> 1189 &nbsp;move matching messages to this folder 1190 </td> 1191 </tr> 1192 <tr><td> 1193 </td><td> 1194 <?php putCheckbox(isset($query->unread), "unread", "") ?> 1195 &nbsp;leave moved messages marked as "Unread" 1196 </td></tr> 1197 <tr><td class=fsep colspan=2></td></tr> 1198 <?php 1199 } else { // ad hoc query composition 1200 if (is_null($query)) { // Clear 1201 $query = new stdClass(); 1202 $query->f = ""; 1203 $query->t = ""; 1204 $query->findin = "A"; 1205 $query->datefrom = "B"; 1206 $query->dateto = "E"; 1207 $query->acctid = 0; 1208 } 1209 formStart($state, "GET", "findQuery"); 1210 ?> 1211 <tr><td colspan=2 class=nowrap> 1212 <b>Find...</b> 1213 </td><td align=right class=nowrap> 1214 <input type=submit value=" Find "> 1215 <input type=submit name="findCancel" value=" Cancel "> 1216 </td> 1217 </tr> 1218 <tr><td class=fsep colspan=3></td></tr> 1219 <tr> 1220 <td align=left valign=top class=nowrap rowspan=8>In Folder:<br> 1221 <?php 1222 putFolderSelect($state->user, "f", $query->f, "all", 15); 1223 ?> 1224 </td> 1225 <td>&nbsp;</td> 1226 <td> 1227 <input type=submit name="findClear" value=" Everything, Everywhere "> 1228 </td> 1229 </tr> 1230 <?php 1231 } 1232 ?> 1233 <?php showTextInput("Search for words:", "t", $query->t) ?> 1234 <tr> 1235 <td align=right valign=top class=nowrap> 1236 Search in: 1237 </td><td> 1238 <?php 1239 putRadio($query->findin == "A", "findin", "A", 1240 "the entire message"); 1241 echo "<br>\n"; 1242 putRadio($query->findin == "H", "findin", "H", 1243 "only the message header"); 1244 echo "<br>\n"; 1245 putRadio($query->findin == "S", "findin", "S", 1246 "only the \"Subject\" field"); 1247 echo "<br>\n"; 1248 putRadio($query->findin == "F", "findin", "F", 1249 "only the \"From\" field"); 1250 echo "<br>\n"; 1251 putRadio($query->findin == "T", "findin", "T", 1252 "only the \"To\" and \"cc\" fields"); 1253 ?> 1254 </td> 1255 </tr><tr> 1256 <td align=right class=nowrap> 1257 Dated from: 1258 </td><td> 1259 <?php putDateSelect("datefrom", $query->datefrom) ?> 1260 </td> 1261 </tr><tr> 1262 <td align=right class=nowrap> 1263 to: 1264 </td><td> 1265 <?php putDateSelect("dateto", $query->dateto) ?> 1266 </td> 1267 </tr><tr> 1268 <td align=right class=nowrap> 1269 Restrict to account: 1270 </td><td> 1271 <select name=acctid> 1272 <?php 1273 $accts = getAccts($state->user); 1274 putOption($query->acctid, "0", "Any"); 1275 foreach ($accts as $acct) { 1276 putOption($query->acctid, $acct->acctid, 1277 "#$acct->acctid ($acct->user on $acct->server)"); 1278 } 1279 ?> 1280 </select> 1281 </td> 1282 </tr> 1283 <?php 1284 if ($state->op != "adjustFolder") { 1285 ?> 1286 <tr><td align=right class=nowrap> 1287 Restrict to: 1288 </td><td nowrap> 1289 <?php 1290 putCheckbox(isset($query->unread), "unread", ""); 1291 ?> 1292 unread messages only 1293 </td> 1294 </tr> 1295 <tr><td colspan=2>&nbsp;</td></tr> 1296 <?php 1297 } 1298 formEnd(true, true, 1299 ($state->op != "adjustFolder" ? "Searching" : "Smart Folders")); 1300 } 1301 1302 function selectResend(&$state) { 1303 // Put form for acquiring recipients for resend operation 1304 formStart($state, "POST", "resend"); 1305 ?> 1306 <tr> 1307 <td width="44%" nowrap> 1308 <b>Resend Message #<?php echo $state->m ?></b> 1309 </td> 1310 <td width="11%" align=right> 1311 <input type=submit name=send value=" Send "> 1312 </td><td width="11%" align=center> 1313 <input type=submit name=resendCancel value=" Cancel "> 1314 </td> 1315 </tr> 1316 <tr><td class=fsep colspan=3></td></tr> 1317 <?php showTextInput("To:", "dest") ?> 1318 <tr><td></td><td colspan=2><span class=comment> 1319 Resends the message to these recipients, as if they had been in the 1320 "bcc" list when the message was originally sent. 1321 </span></td></tr> 1322 <?php 1323 formEnd(); 1324 } 1325 1326 1327 // 1328 // HTML generation: message composition 1329 // 1330 1331 function draftScript($draftId) { 1332 // Return javascript for the head tag of a draft window 1333 // The cookies keep track of which draft windows are open 1334 return "onload=\"setCookie('pachydraft$draftId','Y', null, '/')\"" . 1335 "\n onunload=\"setCookie('pachydraft$draftId','N', null, '/')\""; 1336 } 1337 1338 function putDraft(&$state, $draft, $sendError) { 1339 // Put a composition form for the given draft message 1340 formStart($state, "POST", "send", true, true, 1341 " Draft #$draft->id", draftScript($draft->id)); 1342 ?> 1343 <tr><td width="55%" colspan=2> 1344 <b>Draft message #<?php echo $draft->id ?></b> 1345 </td> 1346 <td align=right> 1347 <?php putHiddenArg("draftId", $draft->id); ?> 1348 <input type=submit value=" Send ">&nbsp;&nbsp;&nbsp; 1349 <input type=submit name=cSave value=" Save ">&nbsp;&nbsp;&nbsp 1350 <input type=submit name=cDelete value=" Discard ">&nbsp;&nbsp;&nbsp 1351 </td> 1352 </tr> 1353 <?php 1354 if (!is_null($sendError)) { 1355 ?> 1356 <tr><td class=fsep colspan=3></td></tr> 1357 <tr><td colspan=3> 1358 <div class=ok id=error><?php echo htmlspecialchars($sendError) ?></div> 1359 </td></tr> 1360 <?php 1361 } 1362 ?> 1363 </table><!--bbarEnd--> 1364 1365 <!-- Draft message --> 1366 <div class=msg> 1367 <?php putHiddenArg("draftId", $draft->id) ?> 1368 <table class=compose> 1369 <tr> 1370 <td>From:</td> 1371 <td> 1372 <?php 1373 $accts = getAccts($state->user); 1374 if (count($accts) == 1) { 1375 $acct = $accts[0]; 1376 putHiddenArg("from", "$acct->person <$acct->msgfrom>"); 1377 echo htmlspecialchars("$acct->person <$acct->msgfrom>"); 1378 } else { 1379 ?> 1380 <select name=from size=0> 1381 <?php 1382 foreach ($accts as $acct) { 1383 putOption($draft->msgfrom, "$acct->person <$acct->msgfrom>"); 1384 } 1385 ?></select><?php 1386 } 1387 ?> 1388 1389 </td> 1390 </tr> 1391 <tr> 1392 <td>To:</td> 1393 <td><input type=text size=60 name=to value="<?php 1394 echo htmlspecialchars($draft->msgto) ?>"> 1395 <input type=submit name=cContacts value=" Contacts... "> 1396 </td> 1397 </tr> 1398 <tr> 1399 <td>Cc:</td> 1400 <td><input type=text size=60 name=cc value="<?php 1401 echo htmlspecialchars($draft->msgcc) ?>"></td> 1402 </tr> 1403 <tr> 1404 <td>Subject:</td> 1405 <td><input type=text size=60 name=subject value="<?php 1406 echo htmlspecialchars($draft->subject) ?>"></td> 1407 </tr> 1408 <?php 1409 if ($draft->attachMsg != "none") { 1410 $attachMsgs = explode(",", $draft->attachMsg); 1411 foreach ($attachMsgs as $attachMsg) { 1412 $details = getMsgDetails($state->user, $attachMsg); 1413 echo "<tr><td>Attached:</td>\n" . 1414 "<td>Message #$draft->attachMsg \"" . 1415 htmlspecialchars(substr($details->subject, 0, 54)) . 1416 "\"</td></tr>\n"; 1417 } 1418 } 1419 foreach ($draft->attachParts as $att) { 1420 echo "<tr><td>Attached:</td>" . 1421 "<td><input type=submit name=cForget-$att->part " . 1422 "value=\" Forget \"> " . htmlspecialchars($att->name) . " ("; 1423 putByteLength($att->length); 1424 echo ")</td></tr>\n"; 1425 } 1426 echo "<tr><td>Attach:</td>" . 1427 "<td><input type=\"file\" name=\"attachment\" size=\"50\">"; 1428 putHiddenArg("MAX_FILE_SIZE", "50000000"); 1429 ?> 1430 </td></tr> 1431 <tr><td></td><td> 1432 <span class=comment>After choosing an attachment, 1433 if you want to add another one or forget this one, click "Save".</span> 1434 </td></tr> 1435 <tr><td colspan=2> 1436 <textarea name=body cols=80 rows=25> 1437 <?php echo htmlspecialchars($draft->body) ?> 1438 </textarea></td></tr> 1439 <tr> 1440 <td><span class=comment>Saved:</span></td> 1441 <td><span class=comment> 1442 <?php echo htmlspecialchars(formatUserTime("l, jS F Y, g:i:s a", 1443 $state->displaytz, $draft->udate)) ?> 1444 </span></td> 1445 </tr> 1446 </table> 1447 </div> 1448 <table class=bb> 1449 <tr><td class=fsep colspan=3></td></tr> 1450 <tr valign=top> 1451 <td width="44%"><span class=comment> 1452 Recipients can be an email address, 1453 or a name from your contacts list. 1454 <br> 1455 <br> 1456 After sending, saving, or deleting you should just 1457 close this window. To view saved unsent drafts, open your 1458 "<?php echo C_unsent ?>" folder. 1459 </span></td> 1460 <td width="11%">&nbsp;</td> 1461 <td width="44%"><span class=comment> 1462 You can identify a recipient from your contacts list 1463 by giving the first name, or 1464 last name, or first and last, or nickname: but whatever you use it 1465 must identify a unique entry in your contacts list. 1466 Alternatively, you can click "Contacts..." and then click "Add". 1467 </span></td> 1468 </tr> 1469 <?php 1470 formEnd(true, true, "Composing"); 1471 } 1472 1473 function recompose(&$state, $id, $sendError, $add) { 1474 // Redisplay message draft on new screen, possibly with error and 1475 // possibly adding recipients 1476 $draft = getDraft($state->user, $id + 0); 1477 if (is_null($draft)) { 1478 reportError($state, "Draft #$id seems to have been deleted", false); 1479 } else { 1480 if (!is_null($add) && count($add) > 0) { 1481 if ($draft->msgto != "") { 1482 $old = explode(",", $draft->msgto); 1483 $add = array_merge($old, $add); 1484 } 1485 $draft->msgto = implode(", ", $add); 1486 } 1487 putDraft($state, $draft, $sendError); 1488 } 1489 } 1490 1491 1492 // 1493 // HTML generation: contacts database 1494 // 1495 1496 function contactRecipients($state, $list) { 1497 // Return HTML for recipient list, with "keep" tags for those who 1498 // aren't in the contacts database 1499 $addrs = imap_rfc822_parse_adrlist($list, C_localDomain); 1500 $res = array(); 1501 foreach ($addrs as $value) { 1502 if (isset($value->host) && isset($value->mailbox) && 1503 $value->host != ".SYNTAX-ERROR.") { 1504 $rows = doSqlQuery("check contact email", 1505 "select count(*) as total from contacts$state->user " . 1506 "where email = " . 1507 wrapSqlArg("$value->mailbox@$value->host")); 1508 $row = mysql_fetch_object($rows); 1509 $addr = imap_rfc822_write_address( 1510 $value->mailbox, $value->host, 1511 (isset($value->personal) ? $value->personal : "")); 1512 $addr = trim($addr); 1513 $res[] = htmlFromRfc1342($addr, 999) . 1514 ($row->total > 0 ? "" : 1515 "\n(<a href=\"" . 1516 selfUrl($state, "newContact&dest=" . urlencode($addr)) . 1517 "\">keep</a>)"); 1518 } 1519 } 1520 return implode(", ", $res); 1521 } 1522 1523 function putHeaderChoice(&$state, $d, $prompt) { 1524 // Put HTML for one header column choice button/link 1525 echo "<a href=\"" . 1526 selfUrl($state, "changeContacts&dest=$d") . 1527 "\">$prompt</a>"; 1528 } 1529 1530 function putHeaderChoices(&$state) { 1531 // Put HTML for header for other column choices 1532 echo " (or "; 1533 if ($state->contacts->display != "E") { 1534 putHeaderChoice($state, "E", "Email"); 1535 echo " or "; 1536 } 1537 if ($state->contacts->display != "P") { 1538 putHeaderChoice($state, "P", "Phones"); 1539 if ($state->contacts->display != "A") echo " or "; 1540 } 1541 if ($state->contacts->display != "A") { 1542 putHeaderChoice($state, "A", "Address"); 1543 } 1544 echo ")"; 1545 } 1546 1547 function putPadded($s, $n, $with = "_ ") { 1548 // Put $s padded and escaped 1549 if (strlen($s)%2 == 1 && strlen($s) < $n) $s = $s . " "; 1550 echo htmlspecialchars(str_pad($s, $n, $with)); 1551 } 1552 1553 function putContactList(&$state, $composing) { 1554 // Output the list of contacts (surprise) 1555 $display = ($composing ? "E" : $state->contacts->display); 1556 $rows = enumContacts($state->user, $state->contacts->find); 1557 echo "<div class=msg>\n<pre>"; 1558 if ($composing) echo " <input type=submit name=cAdd value=Add>"; 1559 putPadded(" Name (Nickname)", 30, " "); 1560 echo " View: "; 1561 echo ($display == "E" ? "Email" : 1562 ($display == "P" ? "Phones" : "Address")); 1563 if (!$composing) putHeaderChoices($state); 1564 echo "\n"; 1565 $lineCount = 0; 1566 while ($row = mysql_fetch_object($rows)) { 1567 if ($lineCount%5 == 0) { echo "\n"; flush(); } 1568 $lineCount++; 1569 if ($composing) { 1570 putPadded("", 4, " "); 1571 putCheckbox(false, "x$row->id", "", "", ""); 1572 } 1573 putPadded(" $row->first $row->last" . 1574 ($row->nickname == "" ? "" : " ($row->nickname)"), 30); 1575 echo str_pad("", 2); 1576 if ($display == "E") { 1577 putPadded($row->email, 49); 1578 } else if ($display == "P") { 1579 putPadded("h: " . $row->home, 15); 1580 putPadded(" w: " . $row->work, 17); 1581 putPadded(" m: " . $row->mobile, 17); 1582 } else { 1583 putPadded($row->address, 49); 1584 } 1585 echo str_pad("", 2); 1586 if ($composing) { 1587 echo "<input type=submit name=y$row->id value=Add>"; 1588 } else { 1589 echo "<a href=\"" . 1590 selfUrl($state, "editContact&dest=$row->id") . 1591 "\">Edit</a>"; 1592 echo " <a href=\"" . 1593 selfUrl($state, "deleteContact&dest=$row->id") . 1594 "\">Delete</a>"; 1595 } 1596 echo "\n"; 1597 } 1598 echo "</pre>\n</div>\n"; 1599 } 1600 1601 function showContacts(&$state) { 1602 // Put window for displaying contacts database 1603 docStart($state); 1604 ?> 1605 <table class=bb cellspacing=3><tr> 1606 <td width="68%" nowrap><b>Your Pachylet Contacts<?php 1607 echo ($state->contacts->find == "" ? "" : 1608 htmlspecialchars(" Matching \"" . $state->contacts->find) . "\""); 1609 ?> ... 1610 </b></td> 1611 <?php 1612 button($state, "newContact", "New...", true); 1613 button($state, "findContactsSel", "Find...", true); 1614 button($state, "show", "Done", true); 1615 ?> 1616 </tr></table> 1617 <?php 1618 putContactList($state, false); 1619 creditLine(true, "Composing"); 1620 } 1621 1622 function findContactsSelect(&$state) { 1623 // Put form for searching contacts database 1624 formStart($state, "GET", "findContact"); 1625 ?> 1626 <tr> 1627 <td width="44%"><b>Find contacts</b></td> 1628 <td align=right> 1629 <input type=submit name=cSelect value=" Find "> 1630 <input type=submit name=cSelectAll value=" All "> 1631 </td> 1632 <td width="11%" align=center> 1633 <input type=submit name="findContactCancel" value = " Cancel "> 1634 </td> 1635 </tr> 1636 <tr><td class=fsep colspan=3></td></tr> 1637 <?php showTextInput("Find:", "dest", $state->contacts->find) ?> 1638 <tr> 1639 <td></td> 1640 <td><span class=comment>Searches first, last, and nickname</span></td> 1641 </tr> 1642 <?php 1643 formEnd(); 1644 } 1645 1646 function putEditContactForm(&$state, &$row, $prompt, $thenBrowse) { 1647 formStart($state, "GET", 1648 ($thenBrowse ? "saveContact" : "saveCtctShow")); 1649 ?> 1650 <tr><td class=nowrap> 1651 <b><?php echo htmlspecialchars($prompt) ?></b> 1652 <?php putHiddenArg("dest", $row->id); ?> 1653 </td> 1654 <td align=right class=nowrap> 1655 <input type=submit value=" Save "> 1656 <input type=submit name="saveContactCancel" value=" Cancel "> 1657 </td> 1658 </tr> 1659 <tr><td class=fsep colspan=2></td></tr> 1660 <?php 1661 showTextInput("First name", "firstContact", $row->first); 1662 showTextInput("Last name", "lastContact", $row->last); 1663 showTextInput("Nickname", "nicknameContact", $row->nickname); 1664 showTextInput("Email Address", "emailContact", $row->email); 1665 showTextInput("Postal Address", "addressContact", $row->address); 1666 showTextInput("Home phone", "homeContact", $row->home); 1667 showTextInput("Work phone", "workContact", $row->work); 1668 showTextInput("Mobile phone", "mobileContact", $row->mobile); 1669 formEnd(); 1670 } 1671 1672 function newContact(&$state, $dest) { 1673 $row = new stdClass(); 1674 $row->id = 0; 1675 $row->first = ""; 1676 $row->last = ""; 1677 $row->nickname = ""; 1678 $row->email = ""; 1679 $row->address = ""; 1680 $row->home = ""; 1681 $row->work = ""; 1682 $row->mobile = ""; 1683 if (!is_null($dest)) { 1684 $parsed = imap_rfc822_parse_adrlist($dest, C_localDomain); 1685 while (list($key, $val) = each($parsed)) { 1686 $row->email = $val->mailbox . "@" . $val->host; 1687 if (isset($val->personal)) { 1688 $matches = array(); 1689 preg_match('#^([^ ]*) ?(.*)$#', $val->personal, $matches); 1690 $row->first = $matches[1]; 1691 $row->last = $matches[2]; 1692 } else { 1693 $row->first = ""; 1694 $row->last = ""; 1695 } 1696 } 1697 } 1698 putEditContactForm($state, $row, "Create a New Contact Record", 1699 is_null($dest)); 1700 } 1701 1702 function editContact(&$state, $contact) { 1703 $row = getContactById($state->user, $contact); 1704 putEditContactForm($state, $row, "Edit Contact Record #$row->id", 1705 true); 1706 } 1707 1708 function contactsAction(&$state, $dest, $composing, $cArgs) { 1709 // Various actions from buttons in the "showContacts" form 1710 $res = array(); 1711 addContactEmail($state->user, $cArgs, 1712 (isset($cArgs["cAdd"]) ? "x" : "y"), 1713 $res); 1714 if (isset($cArgs["cContinue"]) || isset($cArgs["cAdd"]) || 1715 count($res) > 0) { 1716 // Continue a draft, possibly adding selected contacts 1717 recompose($state, $cArgs["draftId"], null, $res); 1718 } else { 1719 // Just update the contacts display, possibly with new filter 1720 $state->contacts->find = $dest; 1721 if (isset($cArgs["cSelectAll"])) $state->contacts->find = ""; 1722 if ($composing) { 1723 composeContacts($state, $cArgs["draftId"]); 1724 } else { 1725 showContacts($state); 1726 } 1727 } 1728 } 1729 1730 function putComposeField($prompt, $key, $value) { 1731 // Put to/cc/subject for composeContacts 1732 ?> 1733 <tr> 1734 <td><?php echo $prompt ?>:</td> 1735 <td><?php 1736 echo htmlspecialchars($value); 1737 putHiddenArg($key, $value); 1738 ?></td> 1739 </tr> 1740 <?php 1741 } 1742 1743 function composeContacts(&$state, $draftId) { 1744 // "contacts" button in the message composition form 1745 formStart($state, "POST", "addContact", true, false, 1746 " Draft #$draftId", 1747 draftScript($draftId)); 1748 ?> 1749 <tr> 1750 <td><b>Choose recipient(s) to add to current draft</b></td> 1751 <td width="11%" align=center> 1752 <input type=submit name=cContinue value=" Continue "> 1753 </td> 1754 </tr> 1755 <tr><td class=fsep colspan=2></td></tr> 1756 1757 <!-- Search line --> 1758 <tr><td>&nbsp;</td></tr> 1759 <tr> 1760 <td colspan=2 align=center> 1761 Search for "first", "last", or "nickname":&nbsp; 1762 <input type=text name=dest size=30 value="<?php 1763 echo htmlspecialchars($state->contacts->find) ?>">&nbsp;&nbsp; 1764 <input type=submit name=cSelect value=" Find ">&nbsp;&nbsp; 1765 <input type=submit name=cSelectAll value=" All "> 1766 </td> 1767 </tr> 1768 <tr><td>&nbsp;</td></tr> 1769 </table> 1770 <?php 1771 putContactList($state, true); 1772 putHiddenArg("draftId", $draftId); 1773 formEnd(false, true, "Composing"); 1774 } 1775 1776 1777 // 1778 // HTML generation: options screen 1779 // 1780 1781 function showOptions(&$state) { 1782 // Show a form with current account options for $state->managingUser 1783 $user = $state->managingUser; 1784 $accts = getAccts($user); 1785 $displaytz = $accts[0]->displaytz; 1786 $abstz = abs($displaytz); 1787 $tz = sprintf("%s%02d%02d", 1788 ($displaytz < 0 ? "-" : "+"), 1789 $abstz/60, $abstz%60); 1790 docStart($state); 1791 ?> 1792 <table class=bb cellspacing=3><tr> 1793 <td width="77%" nowrap><b>Pachylet Settings for 1794 "<?php echo htmlspecialchars($user) ?>" ...</b></td> 1795 <?php 1796 if ($state->managing) { 1797 button($state, "manageUsers", "Done", true); 1798 } else { 1799 button($state, "manageUsers", "Manage Users", true); 1800 button($state, "show", "Done", true); 1801 } 1802 ?> 1803 </tr></table> 1804 <div class=sep></div> 1805 <?php formStart($state, "GET", "editSettings", false) ?> 1806 <tr> 1807 <td width="20%"><b>General Settings</b></td> 1808 <td width="30%" align=right>Display timezone:</td> 1809 <td><?php 1810 echo ($displaytz == 0 ? "British" : 1811 ($displaytz == -5*60 ? "U.S. Eastern" : 1812 ($displaytz == -6*60 ? "U.S. Central" : 1813 ($displaytz == -7*60 ? "U.S. Mountain" : 1814 ($displaytz == -8*60 ? "U.S. Pacific" : $tz ))))); 1815 ?> 1816 </td> 1817 </tr> 1818 <tr> 1819 <td></td> 1820 <td align=right>Pachylet password:</td> 1821 <td>********</td> 1822 </tr> 1823 <tr> 1824 <td></td><td></td> 1825 <td> 1826 <input type=submit name="miscEdit" value=" Edit "> 1827 <input type=submit name="acctNew", value=" Add Account "> 1828 </td></tr> 1829 <?php 1830 foreach ($accts as $acct) { 1831 ?> 1832 <tr><td class=fsep colspan=4></td></tr> 1833 <tr> 1834 <td><b>Account #<?php $id = $acct->acctid; echo $id ?></b></td> 1835 <td align=right>Server name:</td> 1836 <td><?php echo htmlspecialchars($acct->server) ?></td> 1837 </tr> 1838 <tr> 1839 <td></td> 1840 <td align=right>User at server:</td> 1841 <td><?php echo htmlspecialchars($acct->user) ?></td> 1842 </tr> 1843 <tr> 1844 <td></td> 1845 <td align=right>From:</td> 1846 <td><?php echo htmlspecialchars("$acct->person <$acct->msgfrom>") ?></td> 1847 </tr> 1848 <tr> 1849 <td></td><td></td> 1850 <td> 1851 <input type=submit name="acctEdit_<?php echo $id ?>" value=" Edit ">&nbsp; 1852 <?php 1853 if ($id != 1) { 1854 ?> 1855 <input type=submit name="acctForget_<?php echo $id ?>" value=" Forget "> 1856 </td> 1857 </tr> 1858 <?php 1859 } 1860 } 1861 if ($state->managing) { 1862 ?> 1863 <tr><td class=fsep colspan=3></td></tr> 1864 <tr><td></td><td align=right>Orphan Messages:</td> 1865 <td><?php echo countOrphanMsgs($user) ?></td></tr> 1866 <tr><td></td><td align=right>Orphan Parts:</td> 1867 <td><?php echo countOrphanParts($user) ?></td></tr> 1868 <tr><td></td><td align=right>Orphan Part Files:</td> 1869 <td><?php echo countOrphanPartFiles($user) ?></td></tr> 1870 <tr><td></td><td align=right>Messages with bad dates:</td> 1871 <td><?php echo countBadDates($user) ?></td></tr> 1872 <?php 1873 } 1874 formEnd(); 1875 } 1876 1877 function showSettings(&$state) { 1878 // Show edittable misc. settings for $state->managingUser 1879 $acct = getAcct($state->managingUser); 1880 $displaytz = $acct->displaytz; 1881 $abstz = abs($displaytz); 1882 $tz = sprintf("%s%02d%02d", 1883 ($displaytz < 0 ? "-" : "+"), 1884 $abstz/60, $abstz%60); 1885 formStart($state, "GET", "saveSettings"); 1886 ?> 1887 <tr> 1888 <td width="44%"><b>General settings for 1889 "<?php echo $state->managingUser ?>"</b></td> 1890 <td width="44%" align=right> 1891 <input type=submit value=" Save "> 1892 </td><td width="11%" align=center> 1893 <input type=submit name="modifyCancel" value=" Cancel "> 1894 </td> 1895 </tr> 1896 <tr><td class=fsep colspan=3></td></tr> 1897 <tr><td align=right>Display timezone:</td> 1898 <td> 1899 <?php 1900 echo "<select name=displaytz>\n"; 1901 $tzFound = false; 1902 $tzFound |= putOption($displaytz, 0, "British"); 1903 $tzFound |= putOption($displaytz, -5*60, "U.S. Eastern"); 1904 $tzFound |= putOption($displaytz, -6*60, "U.S. Central"); 1905 $tzFound |= putOption($displaytz, -7*60, "U.S. Mountain"); 1906 $tzFound |= putOption($displaytz, -8*60, "U.S. Pacific"); 1907 if (!$tzFound) putOption($displaytz, $displaytz, $tz); 1908 echo "</select></td></tr>\n"; 1909 showTextInput(C_program . " password:", "ppwd", "", true); 1910 formEnd(); 1911 } 1912 1913 function showAcct(&$state, $acctid) { 1914 // Show edittable account details for $state->managingUser 1915 $acct = getAcct($state->managingUser, null, $acctid); 1916 formStart($state, "GET", "saveAcct"); 1917 ?> 1918 <tr> 1919 <td width="44%"><b>Account 1920 #<?php echo "$acctid for \"$state->managingUser\"" ?></b></td> 1921 <td width="44%" align=right> 1922 <?php 1923 putHiddenArg("dest", $acctid); 1924 ?> 1925 <input type=submit value=" Save "> 1926 </td><td width="11%" align=center> 1927 <input type=submit name="modifyCancel" value=" Cancel "> 1928 </td> 1929 </tr> 1930 <tr><td class=fsep colspan=3></td></tr> 1931 <tr><td align=right>Protocol:</td><td> 1932 <select name=type> 1933 <?php 1934 $typeFound = false; 1935 $typeFound |= putOption($acct->type, "POP3", "POP"); 1936 $typeFound |= putOption($acct->type, "SPOP", "POP over SSL"); 1937 $typeFound |= putOption($acct->type, "IMAP", "IMAP"); 1938 $typeFound |= putOption($acct->type, "SIMAP", "IMAP over SSL"); 1939 $typeFound |= putOption($acct->type, "SEND", "\"From\" only"); 1940 if (!$typeFound) putOption($acct->type, $acct->type); 1941 ?> 1942 </select> 1943 </td></tr> 1944 <?php 1945 showTextInput("Server name:", "server", $acct->server); 1946 ?> 1947 <tr><td></td><td><span class=comment> 1948 (For IMAP, use "server" or "server/folder") 1949 </span></td></tr> 1950 <?php 1951 showTextInput("User at server:", "msuser", $acct->user); 1952 showTextInput("Password at server:", "mspwd", "", true); 1953 showTextInput("From email:", "msgfrom", $acct->msgfrom); 1954 showTextInput("From person:", "person", $acct->person); 1955 ?> 1956 <tr><td align=right> 1957 Delete after retrieving: 1958 </td><td nowrap> 1959 <?php 1960 putRadio($acct->dodelete, "dodelete", "Y", "yes"); 1961 echo "&nbsp;"; 1962 putRadio($acct->dodelete, "dodelete", "N", "no"); 1963 echo "</td></tr>\n"; 1964 formEnd(); 1965 } 1966 1967 1968 // 1969 // Login screen 1970 // 1971 1972 function showLoginPage(&$state, $defaultUser, $why = null) { 1973 // request name and password, optionally with error message 1974 if ($state->op == "send" || $state->op == "addContact") { 1975 // Can't login here, sadly 1976 if (is_null($why)) $why = "You have logged out of Pachylet"; 1977 reportError($state, 1978 "$why. Login to Pachylet again, then reload this window.", 1979 false); 1980 return; 1981 } 1982 $focus = (is_null($defaultUser) ? "loginUser" : "loginPwd"); 1983 setcookie("pachytest", "test", 0, "/"); 1984 unset($state->user); // to prevent it being used by docStart 1985 docStart($state, "", ": please login", 1986 "onload=\"document.forms['login'].elements['$focus'].focus()\""); 1987 ?> 1988 <div class=okPad> 1989 <?php 1990 if (!is_null($why)) { 1991 echo "<div class=ok id=error>" . htmlspecialchars($why) . 1992 "</div>\n"; 1993 } 1994 ?> 1995 <div class=ok id=login> 1996 <form name=login action="<?php 1997 echo htmlspecialchars($state->baseURL) ?>" method=POST> 1998 <table align=center> 1999 <tr> 2000 <td colspan=3 align=center> 2001 <span class=loginTitle><b>Pachylet</b></span> 2002 <hr> 2003 </td> 2004 </tr><tr> 2005 <td align=right style="width: 94px"><input 2006 type=hidden name=op value=login>Name:</td> 2007 <td><input type=text name=loginUser 2008 value="<?php echo htmlspecialchars($defaultUser) ?>"></td> 2009 <td rowspan=3><img style="margin-left: 6px; border: 0px" 2010 src=pachyletStatic.gif 2011 width=88 height=108 alt=""></td> 2012 </tr><tr> 2013 <td align=right>Password:</td> 2014 <td><input type=password name=loginPwd></td> 2015 </tr><tr> 2016 <td></td> 2017 <td><input type=submit value=" Login "></td> 2018 </tr><tr> 2019 <td colspan=3><hr></td> 2020 </tr> 2021 </table> 2022 </form> 2023 </div> 2024 </div> 2025 <?php 2026 creditLine(true); 2027 docEnd(); 2028 } 2029 2030 2031 // 2032 // Main program for HTML client 2033 // 2034 2035 // Enforce SSL 2036 if (!isset($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] != "on") { 2037 header("Location: https://" . $_SERVER["SERVER_NAME"] . 2038 $_SERVER["REQUEST_URI"]); 2039 ?> 2040 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html 4/strict.dtd"> 2041 <html> 2042 <head><title>Redirect</title></head> 2043 <body>This service is available only with SSL (https).</body> 2044 </html> 2045 <?php 2046 exit; 2047 } 2048 2049 // Avoid some silliness 2050 if (isset($_SERVER["PATH_INFO"]) && $_SERVER["PATH_INFO"] != "") { 2051 header("HTTP/1.0 403 Forbidden"); 2052 ?> 2053 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html 4/strict.dtd"> 2054 <html> 2055 <head><title>Forbidden</title></head> 2056 <body>Extra path arcs are not allowed</body> 2057 </html> 2058 <?php 2059 exit; 2060 } 2061 2062 $args = ($_SERVER['REQUEST_METHOD'] == "POST" ? $_POST : $_GET); 2063 if (get_magic_quotes_gpc() == 1) { 2064 while ( list($key, $value) = each($args) ) { 2065 $args[$key] = stripslashes($value); 2066 } 2067 } 2068 // set_magic_quotes_runtime(0); 2069 2070 if (isset($args["op"])) $op = $args["op"]; 2071 if (isset($args["z"])) $z = $args["z"]; 2072 if (isset($args["m"])) $m = $args["m"]; 2073 if (isset($args["filter"])) $filter = $args["filter"]; 2074 if (isset($args["unread"])) $unread = $args["unread"]; 2075 if (isset($args["f"])) $f = $args["f"]; 2076 if (isset($args["t"])) $t = $args["t"]; 2077 if (isset($args["findin"])) $findin = $args["findin"]; 2078 if (isset($args["datefrom"])) $datefrom = $args["datefrom"]; 2079 if (isset($args["dateto"])) $dateto = $args["dateto"]; 2080 if (isset($args["acctid"])) $acctid = $args["acctid"]; 2081 if (isset($args["dest"])) $dest = $args["dest"]; 2082 2083 // Default $state for initial entry with no parameters. 2084 // 2085 2086 $state = new stdClass(); 2087 $state->baseURL = basename($_SERVER["SCRIPT_NAME"]); 2088 if ($state->baseURL == "") $state->baseURL = "./"; 2089 $state->m = -1; 2090 $state->popups = "Y"; 2091 $state->scanning = 0; 2092 $state->query = new stdClass(); 2093 $state->query->f = C_inbox; 2094 $state->query->t = ""; 2095 $state->query->findin = "A"; 2096 $state->query->datefrom = "B"; 2097 $state->query->dateto = "E"; 2098 $state->query->acctid = 0; 2099 $state->x = 0; 2100 $state->pageSize = 10; 2101 $state->v = "B"; 2102 $state->managing = false; 2103 $state->managingUser = ""; 2104 $state->d = ""; 2105 $state->contacts = new stdClass(); 2106 $state->contacts->active = "Y"; 2107 $state->contacts->display = "E"; 2108 $state->contacts->find = ""; 2109 $state->op = "show"; 2110 2111 // On re-entry, previous state is passed in $z 2112 // 2113 if (isset($z)) stringToState($state, $z); unset($z); 2114 $zQuery = $state->query; // query unmodified by other args, for saveQuery 2115 2116 // Override $state with any explicit parameters 2117 if (isset($scanning) || 2118 isset($x) || 2119 isset($v) || 2120 isset($d)) die("Unexpected parameter override"); 2121 if (isset($popups)) $state->popups = $popups; unset($popups); 2122 if (isset($m)) $state->m = $m; unset($m); 2123 if (isset($unread)) { 2124 $state->query->unread = ""; unset($unread); 2125 } else if (isset($findin)) { 2126 // We came from the "find" dialog, without "unread" chosen 2127 unset($state->query->unread); 2128 } 2129 if (isset($f)) $state->query->f = $f; unset($f); 2130 if (isset($t)) { 2131 $state->query->t = str_replace("!", "#", $t); 2132 unset($t); 2133 } 2134 if (isset($findin)) $state->query->findin = $findin; unset($findin); 2135 if (isset($datefrom)) $state->query->datefrom = $datefrom; unset($datefrom); 2136 if (isset($dateto)) $state->query->dateto = $dateto; unset($dateto); 2137 if (isset($acctid)) $state->query->acctid = $acctid; unset($acctid); 2138 if (isset($filter)) $state->query->filter = ""; unset($filter); 2139 if (isset($op)) $state->op = $op; unset($op); 2140 2141 // Force integer fields to really be integers (pesky users!) 2142 // 2143 $state->m += 0; 2144 $state->scanning += 0; 2145 $state->x += 0; 2146 $state->pageSize += 0; 2147 2148 // Include stuff that we usually don't need 2149 // 2150 2151 if ($state->op == "showRawMsg" || 2152 $state->op == "mergeLabels" || 2153 $state->op == "sql" || 2154 $state->op == "inc" || 2155 $state->op == "send" || 2156 $state->op == "recompose" || 2157 $state->op == "resend" || 2158 $state->op == "compose" || 2159 $state->op == "addContact" || 2160 $state->op == "reply" || 2161 $state->op == "replyAll" || 2162 $state->op == "forward" || 2163 $state->op == "reopenDraft" || 2164 $state->op == "editSettings" || 2165 $state->op == "saveSettings" || 2166 $state->op == "saveAcct" || 2167 $state->op == "forgetAcct" || 2168 $state->op == "modify") { 2169 require("pachylib.php"); 2170 } 2171 2172 2173 // Authentication 2174 // 2175 2176 openlog(C_program . "V1", LOG_PID, LOG_DAEMON); 2177 2178 $loginPwd = (isset($args["loginPwd"]) ? $args["loginPwd"] : ""); 2179 if (isset($args["loginUser"])) { 2180 $state->user = $args["loginUser"]; 2181 } else if (isset($_COOKIE[C_dkUser])) { 2182 $state->user = $_COOKIE[C_dkUser]; 2183 } else { 2184 $state->user = null; 2185 } 2186 if ($state->op == "login" && $loginPwd != "") { 2187 $dk = getDerivedKey($state->user, $loginPwd); 2188 } else { 2189 $dk = readDk(); 2190 } 2191 2192 if (is_null($state->user) || 2193 (($dk == "unset" || $dk == "gone") && $state->op != "login")) { 2194 // This is the normal initial entry 2195 showLoginPage($state, $state->user); 2196 exit; 2197 } else if ($state->op == "logout") { 2198 // Explicit logout - redirect to the top-level URL with no state 2199 writeLog("user $state->user logout"); 2200 header("Location: https://" . $_SERVER["SERVER_NAME"] . 2201 $_SERVER["SCRIPT_NAME"]); 2202 recordDk($state->user, false); 2203 unset($state->user); // to prevent it being used by docStart 2204 reportMsg($state, "Logged out of <a href=\"" . 2205 htmlspecialchars($state->baseURL) . "\">Pachylet</a>"); 2206 docEnd(); 2207 exit; 2208 } 2209 2210 // Compute $loginStatus, with value "ok" on success 2211 // 2212 if (!isset($_COOKIE["pachytest"])) { 2213 $loginStatus = "no cookies"; 2214 $dk = "unset"; 2215 } else if (!checkReferrer()) { 2216 $loginStatus = "cross-site request forbidden"; 2217 $dk = "unset"; 2218 } else if (!($h2 = verifyDerivedKey($state->user, $dk))) { 2219 $loginStatus = ($state->op == "login" ? 2220 ($loginPwd == "" ? "password required" : 2221 "incorrect name or password") : 2222 ($dk == "unset" ? "missing" : "incorrect") . 2223 " authentication cookie"); 2224 $dk = "unset"; 2225 } else if (!connectDB($state->user, $h2)) { 2226 $loginStatus = "failed to login to MySQL; consult expert"; 2227 $dk = "unset"; 2228 } else { 2229 $loginStatus = "ok"; 2230 } 2231 2232 if ($loginStatus != "ok" || $state->op == "login") { 2233 writeLog("user $state->user login $loginStatus"); 2234 } 2235 if ($state->op == "login") recordDk($state->user, $dk); 2236 2237 if ($loginStatus != "ok") { 2238 showLoginPage($state, $state->user, $loginStatus); 2239 } else if ($state->op == "manageUsers" || 2240 $state->op == "manageCreateDelete" || 2241 $state->op == "manageDelete" || 2242 ($state->op == "login" && canManage($state->user))) { 2243 if ($state->op == "login") { 2244 writeLog("user $state->user managing"); 2245 $state->op = "manageUsers"; 2246 } 2247 require("pachylib.php"); 2248 require("pachymgmt.php"); 2249 } else if ($state->op == "showRawMsg") { 2250 header("Content-type: text/plain; charset=iso-8859-1"); 2251 header("Content-Disposition: inline"); 2252 echo getRawMsg($state->user, $state->m, $dest); 2253 } else { 2254 2255 // Fill in account data, now that we're logged in 2256 // 2257 if ($state->managing) { 2258 $state->displaytz = 0; 2259 } else { 2260 $acct = getAcct($state->user); 2261 $state->displaytz = $acct->displaytz; 2262 $state->managingUser = $state->user; 2263 } 2264 2265 $redirect = false; // Set true to redirect before sending HTML 2266 2267 2268 // Perform the actions requested by the operation, if any. 2269 // 2270 // Nothing in this conditional generates any output. 2271 // 2272 // Operations that have a side-effect on stable storage force a redirect to 2273 // a side-effect-free operation. 2274 // 2275 2276 if ($state->op == "mark") { 2277 // markSel form 2278 if (isset($args["markCancel"])) { 2279 $state->op = "show"; 2280 $redirect = true; 2281 } else if (isset($args["markUnread"])) { 2282 $state->op = "markUnread"; 2283 } else if (isset($args["markAllUnread"])) { 2284 $state->op = "markAllUnread"; 2285 } else if (isset($args["markAllRead"])) { 2286 $state->op = "markAllRead"; 2287 } 2288 } else if ($state->op == "deleteMsg") { 2289 // deleteSel form 2290 if (isset($args["deleteCancel"])) { 2291 $state->op = "show"; 2292 $redirect = true; 2293 } else if (isset($args["delThis"])) { 2294 $state->op = "deleteThisMsg"; 2295 } else if (isset($args["delAll"])) { 2296 $state->op = "deleteAllMsgsConf"; 2297 } 2298 } 2299 2300 if ($state->op == "login") { 2301 $state->op = "show"; 2302 $redirect = true; 2303 } else if ($state->op == "page") { 2304 $state->x = $dest; 2305 $state->op = "show"; 2306 } else if ($state->op == "pageSize") { 2307 $state->pageSize = $dest; 2308 $state->op = "show"; 2309 } else if ($state->op == "view") { 2310 $state->v = ($state->v == "M" ? "B" : "M"); 2311 $state->op = "show"; 2312 } else if ($state->op == "inc") { 2313 $state->m = 0; // in case selected message gets expunged 2314 inc($state->user, $h2); 2315 jumpToFolder($state, C_inbox); 2316 $state->op = "show"; 2317 $redirect = true; 2318 } else if ($state->op == "send") { 2319 $draftId = $args["draftId"] + 0; 2320 $files = (isset($_FILES) ? $_FILES : $HTTP_POST_FILES); 2321 saveDraft($state->user, $draftId, 2322 $args["from"], $args["to"], $args["cc"], 2323 $args["subject"], $args["body"]); 2324 if (isset($files["attachment"])) { 2325 $file = $files["attachment"]; 2326 if (isset($file["name"]) && $file["name"] != "") { 2327 $att = new stdClass(); 2328 $att->localPath = $file["tmp_name"]; 2329 $att->name = (isset($file["name"]) ? $file["name"] : NULL); 2330 $att->size = (isset($file["size"]) ? $file["size"] : NULL); 2331 $att->type = (isset($file["type"]) ? $file["type"] : NULL); 2332 insertUploadedPart($state->user, $h2, $draftId, $att); 2333 } 2334 } 2335 if (isset($args["cContacts"])) { 2336 $state->op = "composeContacts"; 2337 } else if (isset($args["cSave"])) { 2338 $state->op = "recompose"; 2339 } else if (isset($args["cDelete"])) { 2340 deleteDraft($state->user, $draftId); 2341 $state->op = "deletedDraft"; 2342 $redirect = true; 2343 } 2344 $draftParts = getDraftPartNumbers($state->user, $draftId); 2345 foreach ($draftParts as $part) { 2346 if (isset($args["cForget-$part"])) { 2347 deletePart($state->user, $part); 2348 $state->op = "recompose"; 2349 } 2350 } 2351 if ($state->op == "send") { 2352 $sendError = send($state->user, $draftId); 2353 if (is_null($sendError)) { 2354 $state->op = "sent"; 2355 $redirect = true; 2356 } else { 2357 $state->op = "recompose"; 2358 } 2359 } 2360 } else if ($state->op == "reopenDraft") { 2361 $draftId = $args["draftId"]; 2362 if (isset($_COOKIE["pachydraft$draftId"]) && 2363 $_COOKIE["pachydraft$draftId"] == "Y") { 2364 $state->op = "dontRecompose"; 2365 } else { 2366 $state->op = "recompose"; 2367 } 2368 } else if ($state->op == "compose" || $state->op == "reply" || 2369 $state->op == "replyAll" || $state->op == "forward") { 2370 $draftId = buildDraft($state->user, $h2, $state->m, $state->op); 2371 $state->op = "recompose&draftId=$draftId"; 2372 $redirect = true; 2373 } else if ($state->op == "resend") { 2374 if (isset($args["resendCancel"])) { 2375 $state->op = "show"; 2376 $redirect = true; 2377 } else { 2378 $content = getRawMsg($state->user, $state->m); 2379 if (resend($state->user, $dest, $content) > 0) { 2380 $state->op = "show"; 2381 $redirect = true; 2382 // other cases drop through to error handling below 2383 } 2384 } 2385 } else if ($state->op == "adjustFolder") { 2386 if (isset($args["openFolder"])) { 2387 jumpToFolder($state, $dest); 2388 $state->op = "show"; 2389 } else if (isset($args["findQuery"])) { 2390 findQuery($state, $dest); 2391 $state->op = "show"; 2392 } // Other options generate a form 2393 } else if ($state->op == "adjustScanOrder") { 2394 if (isset($args["doneScanOrder"])) { 2395 $state->op = "folderSel&dest=" . urlencode($dest); 2396 $redirect = true; 2397 } else if (isset($args["promoteScanOrder"])) { 2398 promoteQuery($state->user, $dest); 2399 $state->d = $dest; 2400 $redirect = true; 2401 } else if (isset($args["demoteScanOrder"])) { 2402 demoteQuery($state->user, $dest); 2403 $state->d = $dest; 2404 $redirect = true; 2405 } // Redirected version generates our form again 2406 } else if ($state->op == "createFolder") { 2407 if (isset($args["createCancel"])) { 2408 $state->op = "folderSel"; 2409 $redirect = true; 2410 } else if (strpos($dest, "!") !== false) { 2411 $state->op = "badFolderName"; 2412 } else { 2413 createFolder($state->user, $dest); 2414 $state->d = $dest; 2415 $state->op = "folderSel&dest=" . urlencode($dest); 2416 $redirect = true; 2417 } 2418 } else if ($state->op == "deleteFolder") { 2419 if ($dest != "" && $dest != C_inbox && 2420 $dest != C_dropped && $dest != C_trash && 2421 $dest != C_unsent && $dest != C_incoming) { 2422 deleteFolder($state->user, $dest, C_dropped); 2423 if ($state->query->f == $dest) jumpToFolder($state, C_inbox); 2424 if ($state->d == $dest) $state->d = C_inbox; 2425 $state->op = "folderSel"; 2426 $redirect = true; 2427 } 2428 } else if ($state->op == "saveQuery") { 2429 $sQuery = $state->query; 2430 $state->query = $zQuery; // revert to old query for main line 2431 if (isset($args["saveCancel"])) { 2432 $state->op = "folderSel"; 2433 $redirect = true; 2434 } else if (strpos($dest, "!") !== false) { 2435 $state->op = "badFolderName"; 2436 } else { 2437 if (isset($args["destScan"])) $sQuery->scan = 2438 0 + $args["destScan"]; 2439 if (isset($args["destId"])) $sQuery->qid = 0 + $args["destId"]; 2440 $sQuery->name = $dest; 2441 saveQuery($state->user, $sQuery); 2442 $state->d = $dest; 2443 $state->op = "folderSel&dest=" . urlencode($dest); 2444 $redirect = true; 2445 } 2446 } else if ($state->op == "deleteQuery") { 2447 deleteQuery($state->user, $dest); 2448 if ($state->query->f == $dest) jumpToFolder($state, C_inbox); 2449 if ($state->d == $dest) $state->d = C_inbox; 2450 $state->op = "folderSel"; 2451 $redirect = true; 2452 } else if ($state->op == "findQuery") { 2453 if (isset($args["findCancel"])) { 2454 $state->query = $zQuery; 2455 $state->op = "show"; 2456 $redirect = true; 2457 } else if (isset($args["findClear"])) { 2458 $state->op = "findClear"; 2459 } else { 2460 if ($zQuery->f != $state->query->f) { 2461 $state->d = $zQuery->f; // previous folder 2462 } 2463 $state->m = -1; 2464 $state->op = "show"; 2465 $redirect = true; 2466 } 2467 } else if ($state->op == "next") { 2468 jumpToNext($state); 2469 $state->op = "show"; 2470 $redirect = true; 2471 } else if ($state->op == "nextUnread") { 2472 jumpToNext($state, true); 2473 $state->op = "show"; 2474 $redirect = true; 2475 } else if ($state->op == "moveCopy") { 2476 getHits($state->user, $state->query); // acquire cache lock 2477 if (isset($args["moveCopyCancel"])) { 2478 $state->op = "show"; 2479 $redirect = true; 2480 } else if (isset($args["move"])) { 2481 moveMsg($state->user, $state->query->f, $dest, $state->m); 2482 jumpToNext($state); 2483 $state->op = "show"; 2484 $state->d = $dest; 2485 $redirect = true; 2486 } else if (isset($args["copy"])) { 2487 addLabel($state->user, $dest, $state->m); 2488 jumpToNext($state); 2489 $state->op = "show"; 2490 $state->d = $dest; 2491 $redirect = true; 2492 } // isset(moveAll, copyAll) generate a confirmation form, below 2493 } else if ($state->op == "moveAll") { 2494 moveAllMsgs($state->user, $state->query, $dest); 2495 $state->m = 0; 2496 $state->op = "show"; 2497 $redirect = true; 2498 } else if ($state->op == "copyAll") { 2499 copyAllMsgs($state->user, $state->query, $dest); 2500 $state->op = "show"; 2501 $redirect = true; 2502 } else if ($state->op == "drop") { 2503 getHits($state->user, $state->query); // acquire cache lock 2504 moveMsg($state->user, $state->query->f, C_dropped, $state->m); 2505 jumpToNext($state); 2506 $state->op = "show"; 2507 $redirect = true; 2508 } else if ($state->op == "trash") { 2509 getHits($state->user, $state->query); // acquire cache lock 2510 moveMsg($state->user, $state->query->f, C_trash, $state->m); 2511 jumpToNext($state); 2512 $state->op = "show"; 2513 $redirect = true; 2514 } else if ($state->op == "deleteThisMsg") { 2515 getHits($state->user, $state->query); // acquire cache lock 2516 moveMsg($state->user, $state->query->f, "", $state->m); 2517 jumpToNext($state); 2518 $state->op = "show"; 2519 $redirect = true; 2520 } else if ($state->op == "deleteAllMsgs") { 2521 moveAllMsgs($state->user, $state->query, ""); 2522 $state->m = 0; 2523 $state->op = "show"; 2524 $redirect = true; 2525 } else if ($state->op == "markUnread") { 2526 getHits($state->user, $state->query); // acquire cache lock 2527 if ($state->m > 0) { 2528 if (isset($state->query->unread)) { 2529 setCachedQuery($state->user, null); 2530 } 2531 addLabel($state->user, C_unread, $state->m); 2532 jumpToNext($state, false, false); 2533 } 2534 $state->op = "show"; 2535 $redirect = true; 2536 } else if ($state->op == "markAllUnread") { 2537 copyAllMsgs($state->user, $state->query, C_unread); 2538 $state->m = 0; // to avoid reading the newly unread messages 2539 $state->op = "show"; 2540 } else if ($state->op == "markAllRead") { 2541 copyAllMsgs($state->user, $state->query, C_unread, 'N'); 2542 $state->m = 0; 2543 $state->op = "show"; 2544 $redirect = true; 2545 } else if ($state->op == "scan") { 2546 $f = findUnreadFolder($state->user, $state->query->f); 2547 jumpToFolder($state, ($f == "" ? C_inbox : $f)); 2548 $state->op = "show"; 2549 } else if ($state->op == "editSettings") { 2550 if (isset($args["acctNew"])) { 2551 newAcct($state->managingUser); 2552 $state->op = "options"; 2553 $redirect = true; 2554 } 2555 // "forget" and "acctEdit" generate forms, below 2556 } else if ($state->op == "saveSettings") { 2557 if (isset($args["modifyCancel"])) { 2558 $state->op = "options"; 2559 $redirect = true; 2560 } else { 2561 if ($args["ppwd"] != $args["ppwd_2"]) { 2562 $modifyError = "Pachylet password duplicates aren't equal"; 2563 } else { 2564 $newDk = setSettings($state->managingUser, $dk, $h2, 2565 0 + $args["displaytz"], $args["ppwd"]); 2566 if ($newDk != $dk && 2567 $state->managingUser == $state->user) { 2568 recordDk($state->user, $newDk); 2569 } 2570 $state->op = "options"; 2571 $redirect = true; 2572 } 2573 } 2574 } else if ($state->op == "saveAcct") { 2575 if (isset($args["modifyCancel"])) { 2576 $state->op = "options"; 2577 $redirect = true; 2578 } else { 2579 $acct = new stdClass(); 2580 $acct->acctid = $dest; 2581 $acct->server = $args["server"]; 2582 $acct->msgfrom = $args["msgfrom"]; 2583 $acct->person = $args["person"]; 2584 $acct->type = $args["type"]; 2585 $acct->user = $args["msuser"]; 2586 $acct->dodelete = $args["dodelete"]; 2587 $acct->pwd = $args["mspwd"]; 2588 if ($acct->pwd != $args["mspwd_2"]) { 2589 $modifyError = "Account password duplicates aren't equal"; 2590 } else { 2591 setAcct($state->managingUser, $h2, $acct); 2592 $state->op = "options"; 2593 $redirect = true; 2594 } 2595 } 2596 } else if ($state->op == "forgetAcct") { 2597 forgetAcct($state->managingUser, $dest); 2598 $state->op = "options"; 2599 $redirect = true; 2600 } else if ($state->op == "changeContacts") { 2601 $state->contacts->display = $dest; 2602 $state->op = "showContacts"; 2603 } else if ($state->op == "saveContact") { 2604 if (!isset($args["saveContactCancel"])) { 2605 saveContact($state->user, $dest, $args); 2606 } 2607 $state->op = "showContacts"; 2608 $redirect = true; 2609 } else if ($state->op == "saveCtctShow") { 2610 if (!isset($args["saveContactCancel"])) { 2611 saveContact($state->user, $dest, $args); 2612 } 2613 $state->op = "show"; 2614 $redirect = true; 2615 } else if ($state->op == "deleteContact") { 2616 deleteContact($state->user, $dest); 2617 $state->op = "showContacts"; 2618 $redirect = true; 2619 } 2620 2621 // Generate the HTTP response. 2622 // Nothing in this conditional has side-effect on the stable storage 2623 // (except for marking a message as having been read) 2624 // 2625 2626 if ($redirect) { 2627 putRedirect($state); 2628 } else if ($state->op == "inc") { 2629 // Report error, or use redirect to continue operation 2630 if ($r->id < 0) { 2631 reportError($state, "Can't connect to mail server $r->server"); 2632 } else { 2633 $url = 2634 selfUrl($state, "inc&dest=".urlencode(serialize($r))); 2635 echo "<html><head>" . 2636 "<meta http-equiv=refresh content=\"0;url=$url\"></head>"; 2637 $msg = ($r->phase=="inc" ? 2638 "$r->remaining message" . 2639 ($r->remaining == 1 ? "" : "s") . " from " . 2640 htmlspecialchars($r->server) . " ..." : 2641 ($r->remaining < 0 ? 2642 "Starting synchronization ..." : 2643 "$r->remaining messages to copy ...")); 2644 reportMsg($state, $msg); 2645 } 2646 } else if ($state->op == "resend") { 2647 reportError($state, 2648 "No recipients (or syntax error - use comma-separated list)"); 2649 } else if ($state->op == "deletedDraft") { 2650 reportMsg($state, 2651 "The draft message has now been deleted. " . 2652 "You should probably just close this window."); 2653 } else if ($state->op == "sent") { 2654 reportMsg($state, 2655 "The message has been sent on its way. " . 2656 "You should probably just close this window."); 2657 } else if ($state->op == "recompose") { 2658 $draftId = $args["draftId"]; 2659 recompose($state, $draftId, 2660 (isset($sendError) ? $sendError : null), null); 2661 } else if ($state->op == "dontRecompose") { 2662 $draftId = $args["draftId"]; 2663 reportError($state, 2664 "Draft #$draftId is already open in another window. " . 2665 "You should probably just close this window.", false); 2666 } else if ($state->op == "show") { 2667 showMainScreen($state); 2668 } else if ($state->op == "showMsg") { 2669 showPartAsMsg($state, 0 + $dest, 2670 (isset($args["chosenPart"]) ? 0 + $args["chosenPart"] : NULL)); 2671 } else if ($state->op == "showRawList") { 2672 showRawList($state); 2673 } else if ($state->op == "find") { 2674 composeQuery($state, $state->query); 2675 } else if ($state->op == "findClear") { 2676 composeQuery($state, null); 2677 } else if ($state->op == "folderSel") { 2678 selectFolder($state, (isset($dest) ? $dest : null)); 2679 } else if ($state->op == "moveCopySel") { 2680 selectMoveCopy($state); 2681 } else if ($state->op == "deleteSel") { 2682 selectDelete($state); 2683 } else if ($state->op == "markSel") { 2684 selectMark($state); 2685 } else if ($state->op == "resendSel") { 2686 selectResend($state); 2687 } else if ($state->op == "adjustFolder") { 2688 if (isset($args["createFolder"])) { 2689 putCreateForm($state); 2690 } else if (isset($args["deleteFolder"])) { 2691 $delCount = countMsgsWithLabel($state->user, $dest); 2692 putConfirmForm($state, "deleteFolder", 2693 "Really delete the folder \"$dest\" " . 2694 "(moving its $delCount messages into \"Dropped\")?", 2695 $dest, "folderSel"); 2696 } else if (isset($args["createQuery"])) { 2697 composeQuery($state, null); 2698 } else if (isset($args["editQuery"])) { 2699 $state->d = $dest; 2700 composeQuery($state, getQuery($state->user, $dest)); 2701 } else if (isset($args["deleteQuery"])) { 2702 $delCount = countMsgsWithLabel($state->user, $dest); 2703 putConfirmForm($state, "deleteQuery", 2704 "Really delete the smart folder \"$dest\" " . 2705 "(moving its $delCount messages into \"Dropped\")?", 2706 $dest, "folderSel"); 2707 } else if (isset($args["scanOrderQuery"])) { 2708 $state->d = $dest; 2709 selectScanOrder($state); 2710 } else { 2711 reportError($state, "Internal error: adjustFolder"); 2712 } 2713 } else if ($state->op == "adjustScanOrder") { 2714 selectScanOrder($state); 2715 } else if ($state->op == "badFolderName") { 2716 reportError($state, "Folder names must not contain \"!\".", 2717 true, "folderSel"); 2718 } else if ($state->op == "deleteFolder") { 2719 reportError($state, "That folder can't be deleted."); 2720 } else if ($state->op == "moveCopy") { 2721 $moveCount = countQueryMsgs($state->user, $state->query); 2722 if (isset($args["moveAll"])) { 2723 putConfirmForm($state, "moveAll", 2724 "Really move all $moveCount matching messages to " . 2725 "\"$dest\"?", 2726 $dest); 2727 } else if (isset($args["copyAll"])) { 2728 putConfirmForm($state, "copyAll", 2729 "Really copy all $moveCount matching messages to " . 2730 "\"$dest\"?", 2731 $dest); 2732 } else { 2733 reportError($state, "Internal error: moveCopy"); 2734 } 2735 } else if ($state->op == "deleteAllMsgsConf") { 2736 $delCount = countQueryMsgs($state->user, $state->query); 2737 if (isset($args["delAll"])) { 2738 putConfirmForm($state, "deleteAllMsgs", 2739 "Permanently delete all $delCount matching messages?"); 2740 } else { 2741 reportError($state, "Internal error: deleteMsg"); 2742 } 2743 } else if ($state->op == "options") { 2744 if (isset($dest)) $state->managingUser = $dest; 2745 showOptions($state); 2746 } else if ($state->op == "editSettings") { 2747 if (isset($args["miscEdit"])) { 2748 showSettings($state); 2749 } else { 2750 $bad = true; 2751 reset($args); 2752 while ( list($key, $value) = each($args)) { 2753 $matches = array(); 2754 if (preg_match('#acctEdit_([0-9]+)#', $key, $matches) > 0) { 2755 showAcct($state, $matches[1]); 2756 $bad = false; 2757 break; 2758 } 2759 $matches = array(); 2760 if (preg_match('#acctForget_([0-9]+)#', 2761 $key, $matches) > 0) { 2762 putConfirmForm($state, "forgetAcct", 2763 "Really forget account #$matches[1] for " . 2764 "\"$state->managingUser\"? " . 2765 "(Its messages will be left as they are.)", 2766 $matches[1], "options"); 2767 $bad = false; 2768 break; 2769 } 2770 } 2771 if ($bad) reportError($state, "Internal error: editSettings"); 2772 } 2773 } else if ($state->op == "saveSettings" || 2774 $state->op == "saveAcct") { 2775 reportError($state, $modifyError, true, "options"); 2776 } else if ($state->op == "showContacts") { 2777 showContacts($state); 2778 } else if ($state->op == "findContactsSel") { 2779 findContactsSelect($state); 2780 } else if ($state->op == "newContact") { 2781 newContact($state, (isset($dest) ? $dest : NULL)); 2782 } else if ($state->op == "editContact") { 2783 editContact($state, $dest); 2784 } else if ($state->op == "findContact") { 2785 if (strpos($dest, "!") !== false) { 2786 reportError($state, "Search string can't include \"!\"", true, 2787 "findContactsSel"); 2788 } else { 2789 contactsAction($state, 2790 (isset($args["findContactCancel"]) ? $state->contacts->find 2791 : $dest), 2792 false, 2793 $args); 2794 } 2795 } else if ($state->op == "addContact") { 2796 contactsAction($state, $dest, true, $args); 2797 } else if ($state->op == "composeContacts") { 2798 $draftId = $args["draftId"]; 2799 composeContacts($state, $draftId); 2800 } else { 2801 reportError($state, "Unknown op=$state->op", false); 2802 } 2803 2804 docEnd(); 2805 } 2806 2807 ?>
End of listing