Source of “pachyletV2.php”.
903 lines, 23.2 KBytes.   Last modified 6:07 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 2 // 6 // // 7 // Copyright (c) 2002-2014 // 8 // // 9 // See http://birrell.org/pachylet/help.html // 10 // // 11 // Server-side script // 12 // // 13 //////////////////////////////////////////////////////////////////////////// 14 15 require("pachysql.php"); 16 require("pachyauth.php"); 17 require("pachylib.php"); 18 19 $xmlDataPatterns = array('#&#', '#<#', '#>#'); 20 $xmlDataEscapes = array('&#38;', '&#60;', '&#62;'); 21 22 function xmlAttrValue($str) { 23 // return string minimally escaped to live inside XML attribute value 24 // Sadly, Safari doesn't handle character entities within attributes 25 return rawurlencode($str); 26 } 27 28 function xmlCharData($str) { 29 // Return string minimally escaped to live inside XML char data 30 // Removes illegal control characters too 31 global $xmlDataPatterns, $xmlDataEscapes; 32 $str = strtr($str, 33 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f" . 34 "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 35 "_____________" . "________________"); 36 return preg_replace($xmlDataPatterns, $xmlDataEscapes, $str); 37 } 38 39 function putBulkData($content) { 40 // Write XML for bulk data, suitably encoded 41 // Compensates for a Firefox 1.5 bug limiting text runs to 4096 chars 42 $length = strlen($content); 43 $i = 0; 44 while (true) { 45 $thisTime = ($length > 4096 ? 4096 : $length); 46 echo "<content>"; 47 echo xmlCharData(substr($content, $i, $thisTime)); 48 echo "</content>\n"; 49 $i += $thisTime; 50 $length -= $thisTime; 51 if ($length <= 0) break; 52 } 53 } 54 55 function putContactXML($tag, $contact) { 56 // Write XML for a contact record 57 ?> 58 <<?php echo $tag ?> 59 id="<?php echo $contact->id ?>" 60 first="<?php echo xmlAttrValue($contact->first) ?>" 61 last="<?php echo xmlAttrValue($contact->last) ?>" 62 nickname="<?php echo xmlAttrValue($contact->nickname) ?>" 63 email="<?php echo xmlAttrValue($contact->email) ?>" 64 address="<?php echo xmlAttrValue($contact->address) ?>" 65 home="<?php echo xmlAttrValue($contact->home) ?>" 66 work="<?php echo xmlAttrValue($contact->work) ?>" 67 mobile="<?php echo xmlAttrValue($contact->mobile) ?>" 68 /> 69 <?php 70 } 71 72 function putAccountXML($tag, $acct) { 73 // Write XML for an account record 74 ?> 75 <<?php echo $tag ?> 76 id="<?php echo $acct->acctid ?>" 77 server="<?php echo xmlAttrValue($acct->server) ?>" 78 user="<?php echo xmlAttrValue($acct->user) ?>" 79 type="<?php echo $acct->type ?>" 80 msgfrom="<?php echo xmlAttrValue($acct->msgfrom) ?>" 81 person="<?php echo xmlAttrValue($acct->person) ?>" 82 dodelete="<?php echo xmlAttrValue($acct->dodelete) ?>" 83 displaytz="<?php echo $acct->displaytz ?>" 84 /> 85 <?php 86 } 87 88 function putDraftXML($user, $draftId) { 89 // Write XML for a message draft 90 // 91 $draft = getDraft($user, $draftId); 92 if (!$draft) { 93 ?> 94 <draft id=0><?php 95 } else { 96 ?> 97 <draft 98 id="<?php echo $draftId ?>" 99 from="<?php echo xmlAttrValue($draft->msgfrom) ?>" 100 to="<?php echo xmlAttrValue($draft->msgto) ?>" 101 cc="<?php echo xmlAttrValue($draft->msgcc) ?>" 102 subject="<?php echo xmlAttrValue($draft->subject) ?>" 103 attachMsg="<?php echo xmlAttrValue($draft->attachMsg) ?>" 104 ><?php 105 foreach ($draft->attachParts as $att) { 106 ?> 107 <att 108 part="<?php echo $att->part ?>" 109 length="<?php putByteLength($att->length) ?>" 110 name="<?php echo xmlAttrValue($att->name) ?>" 111 /><?php 112 } 113 putBulkData($draft->body); 114 ?> 115 </draft> 116 <?php 117 } 118 } 119 120 function contactRecipientsXML($user, $list) { 121 // Return HTML for recipient list, with "keep" tags for those who 122 // aren't in the contacts database 123 $addrs = imap_rfc822_parse_adrlist($list, C_localDomain); 124 $res = array(); 125 foreach ($addrs as $value) { 126 if (isset($value->host) && isset($value->mailbox) && 127 $value->host != ".SYNTAX-ERROR.") { 128 $rows = doSqlQuery("check contact email", 129 "select count(*) as total from contacts$user " . 130 "where email = " . 131 wrapSqlArg("$value->mailbox@$value->host")); 132 $row = mysql_fetch_object($rows); 133 $addr = trim(imap_rfc822_write_address( 134 $value->mailbox, $value->host, 135 (isset($value->personal) ? $value->personal : ""))); 136 $res[] = htmlFromRfc1342($addr, 99) . 137 ($row->total > 0 ? "" : 138 " (<a href=\"./\" title=\"Add this address to your " . 139 "contacts list\" onClick=\"return keepContact('" . 140 rawurlencode("$value->mailbox@$value->host") . "','" . 141 rawurlencode(isset($value->personal) ? 142 $value->personal : "") . "')\">keep</a>)"); 143 } 144 } 145 return implode(", ", $res); 146 } 147 148 149 // 150 // Acquire parameters 151 // 152 153 // Enforce SSL 154 if (!isset($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] != "on") { 155 header("Location: https://" . $_SERVER["SERVER_NAME"] . 156 $_SERVER["REQUEST_URI"]); 157 ?> 158 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html 4/strict.dtd"> 159 <html> 160 <head><title>Redirect</title></head> 161 <body>This service is available only with SSL (https).</body> 162 </html> 163 <?php 164 exit; 165 } 166 167 $args = ($_SERVER['REQUEST_METHOD'] == "POST" ? $_POST : $_GET); 168 if (get_magic_quotes_gpc() == 1) { 169 while ( list($key, $value) = each($args) ) { 170 $args[$key] = stripslashes($value); 171 } 172 } 173 // set_magic_quotes_runtime(0); 174 175 $op = (isset($args["op"]) ? $args["op"] : "missing"); 176 $user = (isset($args["user"]) ? $args["user"] : ""); 177 $persistDK = (preg_match("#Mobile#i", $_SERVER["HTTP_USER_AGENT"]) || 178 preg_match("#Android#i", $_SERVER["HTTP_USER_AGENT"])); 179 $query = new stdClass(); 180 $query->f = (isset($args["folder"]) ? $args["folder"] : ""); 181 $query->t = (isset($args["words"]) ? $args["words"] : ""); 182 $query->findin = (isset($args["findIn"]) ? $args["findIn"] : "A"); 183 $query->datefrom = (isset($args["dateFrom"]) ? $args["dateFrom"] : "B"); 184 $query->dateto = (isset($args["dateTo"]) ? $args["dateTo"] : "E"); 185 $query->acctid = (isset($args["acct"]) ? 0+$args["acct"] : 0); 186 if (isset($args["unread"]) && $args["unread"] == "Y") $query->unread = ""; 187 if (isset($args["filter"]) && $args["filter"] == "Y") $query->filter = ""; 188 $selected = (isset($args["selected"]) ? 0+$args["selected"] : -1); 189 $offset = (isset($args["offset"]) ? 0+$args["offset"] : 0); 190 $pageSize = (isset($args["pageSize"]) ? 0+$args["pageSize"] : 10); 191 $dest = (isset($args["dest"]) ? $args["dest"] : ""); 192 $startAt = (isset($args["startAt"]) ? 0+$args["startAt"] : 0); 193 if (isset($args["draftId"])) { 194 $draftArg = new stdClass(); 195 $draftArg->id = 0 + $args["draftId"]; 196 $draftArg->msgfrom = (isset($args["msgfrom"]) ? $args["msgfrom"] : ""); 197 $draftArg->msgto = (isset($args["msgto"]) ? $args["msgto"] : ""); 198 $draftArg->msgcc = (isset($args["msgcc"]) ? $args["msgcc"] : ""); 199 $draftArg->subject = (isset($args["subject"]) ? $args["subject"] : ""); 200 $draftArg->content = (isset($args["content"]) ? $args["content"] : ""); 201 } 202 203 set_time_limit(0); 204 205 206 // 207 // Authentication 208 // 209 210 if ($op == "login" && $dest != "") { 211 $dk = getDerivedKey($user, $dest); 212 $dest = "erased"; 213 } else { 214 $dk = readDk(); 215 } 216 if (!checkReferrer()) { 217 $loginStatus = "cross-site request forbidden"; 218 $dk = "unset"; 219 } else if (!($h2 = verifyDerivedKey($user, $dk))) { 220 $loginStatus = ($op == "login" ? 221 ($dest == "" ? "password required" : "incorrect name or password") : 222 ($dk == "unset" ? "missing" : "incorrect") . 223 " authentication cookie"); 224 $dk = "unset"; 225 } else if (!connectDB($user, $h2)) { 226 $loginStatus = "failed to login to MySQL; consult expert"; 227 $dk = "unset"; 228 } else { 229 $loginStatus = "ok"; 230 } 231 if ($op == "login") recordDk($user, $dk, $persistDK); 232 if ($loginStatus != "ok" || $op == "login") { 233 writeLog("user $user login $loginStatus"); 234 } 235 236 237 // 238 // Attaching a file to a draft. Response is plain-text. 239 // 240 241 if ($op == "attach") { 242 // 243 // Attach a file to the given draftId 244 // 245 header("Expires: Sat, 1 Jan 2000 00:00:01 GMT"); 246 header("Cache-Control: no-store, no-cache, " . 247 "must-revalidate, proxy-revalidate"); 248 header("Content-type: text/plain; charset=UTF-8"); 249 if ($loginStatus != "ok") { 250 echo "Not allowed: $loginStatus"; 251 } else { 252 $draftId = 0 + $dest; 253 if ($draftId > 0 && isset($_FILES["attachment"])) { 254 $file = $_FILES["attachment"]; 255 if (isset($file["name"]) && $file["name"] != "") { 256 $att = new stdClass(); 257 $att->localPath = $file["tmp_name"]; 258 $att->name = (isset($file["name"]) ? $file["name"] : NULL); 259 $att->size = (isset($file["size"]) ? $file["size"] : NULL); 260 $att->type = (isset($file["type"]) ? $file["type"] : NULL); 261 insertUploadedPart($user, $h2, $draftId, $att); 262 } 263 } 264 echo "Done"; 265 } 266 exit; 267 } 268 269 270 // 271 // Operations with XML results 272 // 273 274 ob_start(); 275 276 header("Expires: Sat, 1 Jan 2000 00:00:01 GMT"); 277 header("Cache-Control: no-store, no-cache, " . 278 "must-revalidate, proxy-revalidate"); 279 header("Content-type: text/xml; charset=UTF-8"); 280 echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; 281 282 if ($op == "logout") { 283 // 284 // Erases the DK cookie (which is not accessible to the script). 285 // Allowed without authentication. 286 // 287 writeLog("user $user logout"); 288 recordDk($user, false, $persistDK); 289 ?> 290 <logout /> 291 <?php 292 293 294 } else if ($loginStatus != "ok") { 295 ?> 296 <loginFailed 297 status="<?php echo $loginStatus ?>" 298 /> 299 <?php 300 301 302 } else if ($op == "login") { 303 // 304 // Return basic stuff: account list, folder list 305 // 306 $accts = getAccts($user); 307 $folders = getFolders($user); 308 $queries = array(); 309 appendQueryNames($user, $queries); 310 ?> 311 <user ro="<?php echo ($readOnly ? true : false) ?>" > 312 <?php 313 if ($readOnly) echo "<readOnly />\n"; 314 foreach ($accts as $acct) putAccountXML("account", $acct); 315 foreach ($folders as $folder) { 316 ?> 317 <folder folder="<?php echo xmlAttrValue($folder) ?>" /> 318 <?php 319 } 320 foreach ($queries as $queryName) { 321 $savedQuery = getQuery($user, $queryName); 322 ?> 323 <query 324 name="<?php echo xmlAttrValue($queryName) ?>" 325 filter="<?php echo (isset($savedQuery->filter) ? "Y" : "N") ?>" 326 unread="<?php echo (isset($savedQuery->unread) ? "Y" : "N") ?>" 327 folder="<?php echo xmlAttrValue($savedQuery->f) ?>" 328 words="<?php echo xmlAttrValue($savedQuery->t) ?>" 329 findIn="<?php echo $savedQuery->findin ?>" 330 dateFrom="<?php echo $savedQuery->datefrom ?>" 331 dateTo="<?php echo $savedQuery->dateto ?>" 332 acct="<?php echo $savedQuery->acctid ?>" 333 /> 334 <?php 335 } 336 ?> 337 </user> 338 <?php 339 340 341 } else if ($op == "scan") { 342 // 343 // Scan for unread messages and return folder name 344 // Scans inbox then smart folders, starting after current folder 345 // Returns "" if nothing is found 346 // 347 ?> 348 <scanned 349 folder="<?php echo findUnreadFolder($user, $query->f) ?>" 350 /> 351 <?php 352 353 354 } else if ($op == "fetchMail" || $op == "getMsgs") { 355 // 356 // Execute query, optionally first fetching some new mail, if any 357 // 358 if ($op == "fetchMail") inc($user, $h2); 359 360 361 // 362 // Execute query 363 // 364 $total = 0; 365 $lastIsSelected = false; 366 $moreToRead = false; 367 $msgs = selectMessage($user, $query, $selected, $offset, $pageSize, 368 $total, $lastIsSelected, $moreToRead); 369 $tocLines = buildTocLines($user, $msgs); 370 ?> 371 <toc 372 selected="<?php echo $selected ?>" 373 offset="<?php echo $offset ?>" 374 total="<?php echo $total ?>" 375 totalUnread="<?php echo countMsgsWithLabel($user, C_unread) ?>" 376 > 377 <?php 378 for ($i = 0; $i < count($tocLines); $i++) { 379 $thisLine = $tocLines[$i]; 380 ?> 381 <tocLine 382 id="<?php echo $thisLine->id ?>" 383 date="<?php echo xmlAttrValue($thisLine->date) ?>" 384 from="<?php echo xmlAttrValue($thisLine->from) ?>" 385 subject="<?php echo xmlAttrValue($thisLine->subject) ?>" 386 unread="<?php echo $thisLine->unread ?>" 387 /> 388 <?php 389 } 390 ?> 391 </toc> 392 <?php 393 394 395 } else if ($op == "getMsg" || $op == "getFullMsg") { 396 // 397 // Fetch message contents 398 // $selected is message ID 399 // $startAt is partID of the chosen sub-message's header, or 0 400 // $dest is message-relative partNo of chosen best part, or "" 401 // 402 $acct = getAcct($user); 403 $displaytz = $acct->displaytz; 404 $labels = getMsgLabels($user, $selected); 405 $parts = getMsgParts($user, $selected, $startAt); 406 407 // Find best renderable part, and classify other parts 408 $classes = array(); 409 startMsgParts($parts, $partNo, $children); 410 scanMsgItem($classes, $parts, $partNo, $children, "M"); 411 $bestPartNo = (isset($classes["best"]) ? $classes["best"] : -1); 412 if ($dest != "") $bestPartNo = 0+$dest; 413 $classes[$bestPartNo] = "N"; 414 if ($bestPartNo >= 0) { 415 mysql_data_seek($parts, $bestPartNo); 416 $bestPart = mysql_fetch_object($parts); 417 } 418 419 // Find and parse the header (always part 0, and assumed always exists) 420 $mimeKludge = false; 421 mysql_data_seek($parts, 0); 422 $headerPart = mysql_fetch_object($parts); 423 $headerPartID = $headerPart->part; 424 $hdr = getAndParseHeader($user, $headerPart, $mimeKludge); 425 426 // Render the best part, if any 427 if (isset($bestPart)) { 428 $textPlain = $bestPart->type == "text" && 429 $bestPart->subtype == "PLAIN"; 430 $textHtml = $bestPart->type == "text" && 431 $bestPart->subtype == "HTML"; 432 if ($mimeKludge && $textPlain) { 433 $textPlain = false; $textHtml = true; 434 } 435 if ($textPlain) { 436 $content = getTextContent($user, $bestPart->part); 437 } else if ($textHtml) { 438 $content = getHtmlContent($user, $bestPart->part, true); 439 } else { 440 $content = htmlspecialchars( 441 "Content-type: $bestPart->type/$bestPart->subtype"); 442 } 443 $fullLength = strlen($content); 444 if ($op != "getFullMsg" && $fullLength > C_maxDBLength) { 445 $content = substr($content, 0, C_maxDBLength); 446 $sentLength = C_maxDBLength; 447 } else { 448 $sentLength = $fullLength; 449 } 450 } else { 451 $textPlain = false; 452 $textHtml = false; 453 $content = ""; 454 $fullLength = 0; 455 $sentLength = $fullLength; 456 } 457 $bodyPartID = 458 (isset($bestPart) && !$textPlain ? $bestPart->part : 0); 459 $bodyPartURL = 460 ($bodyPartID == 0 ? "none" : getPartURL($user, $bodyPartID)); 461 462 ?> 463 <msg 464 id="<?php echo $selected ?>" 465 folders="<?php echo xmlAttrValue(implode(", ", $labels)) ?>" 466 startAt="<?php echo $startAt ?>" 467 selectedPart="<?php echo ($dest == "" ? "" : 0+$dest) ?>" 468 header="<?php echo $headerPartID ?>" 469 bodyPartID="<?php echo $bodyPartID ?>" 470 bodyPartURL="<?php echo xmlAttrValue($bodyPartURL) ?>" 471 fullLength="<?php echo $fullLength ?>" 472 sentLength="<?php echo $sentLength ?>" 473 from="<?php echo xmlAttrValue(contactRecipientsXML($user, 474 $hdr->msgfrom)) ?>" 475 subject="<?php echo xmlAttrValue(htmlFromRfc1342($hdr->subject, 99)) ?>" 476 date="<?php echo xmlAttrValue($hdr->udate ? 477 formatUserTime("l, jS F Y, g:i:s a", 478 $displaytz, $hdr->udate) : 479 "") ?>" 480 to="<?php echo xmlAttrValue(contactRecipientsXML($user, 481 $hdr->msgto)) ?>" 482 cc="<?php echo xmlAttrValue(contactRecipientsXML($user, 483 $hdr->msgcc)) ?>" 484 ><?php 485 putBulkData($content); 486 startMsgParts($parts, $partNo, $children); 487 while ($children > 0) { 488 $part = nextMsgPart($parts, $partNo, $children); 489 $children += $part->children; 490 if ($partNo > 0) { 491 $class = $classes[$partNo]; 492 ?> 493 <part 494 partNo="<?php echo $partNo ?>" 495 partID="<?php echo $part->part ?>" 496 type="<?php echo getPartType($part) ?>" 497 name="<?php echo xmlAttrValue(getPartName($part)) ?>" 498 length="<?php echo ($part->length < 0 ? -$part->length : 499 $part->length) ?>" 500 class="<?php echo ( $class == "A" ? "Alternative" : 501 ($class == "N" ? "Unused" : "Attachment")) ?>" 502 url="<?php echo xmlAttrValue(getPartURL($user, $part->part)) ?>" 503 /> 504 <?php 505 } 506 } 507 ?> 508 </msg> 509 <?php 510 511 512 } else if ($op == "getRawHeader") { 513 // 514 // Get raw header, as it might appear in RFC822 515 // 516 $parts = getMsgParts($user, $selected, $startAt); 517 $headerPart = mysql_fetch_object($parts); 518 $headerPartDetails = getPart($user, $headerPart->part); 519 $content = getPartContent($user, $headerPartDetails); 520 ?> 521 <rawHeader 522 id="<?php echo $selected ?>" 523 startAt="<?php echo $startAt ?>" 524 ><?php putBulkData(utf8_encode($content)) ?> 525 </rawHeader> 526 <?php 527 528 529 } else if ($op == "getRawMessage") { 530 // 531 // Get re-assembled raw message, as it might appear in RFC822. 532 // 533 $content = getRawMsg($user, $selected, $startAt); 534 ?> 535 <rawMessage 536 id="<?php echo $selected ?>" 537 startAt="<?php echo $startAt ?>" 538 ><?php putBulkData(utf8_encode($content)) ?> 539 </rawMessage> 540 <?php 541 542 543 } else if ($op == "delete") { 544 // 545 // Delete selected message 546 // 547 getHits($user, $query); // acquire cache lock, to flush in moveMsg 548 moveMsg($user, $query->f, "", $selected); 549 ?> 550 <done /> 551 <?php 552 553 554 } else if ($op == "move") { 555 // 556 // Move to dest 557 // 558 getHits($user, $query); // acquire cache lock, to flush in moveMsg 559 moveMsg($user, $query->f, $dest, $selected); 560 ?> 561 <done /> 562 <?php 563 564 565 } else if ($op == "copy") { 566 // 567 // Copy to dest 568 // 569 getHits($user, $query); // acquire cache lock, so no flush needed 570 addLabel($user, $dest, $selected); 571 ?> 572 <done /> 573 <?php 574 575 576 } else if ($op == "deleteAll") { 577 // 578 // Delete all matching messages 579 // 580 moveAllMsgs($user, $query, ""); 581 ?> 582 <done /> 583 <?php 584 585 586 } else if ($op == "moveAll") { 587 // 588 // Move all to dest 589 // 590 moveAllMsgs($user, $query, $dest); 591 ?> 592 <done /> 593 <?php 594 595 596 } else if ($op == "copyAll") { 597 // 598 // Copy all to dest 599 // 600 copyAllMsgs($user, $query, $dest); 601 ?> 602 <done /> 603 <?php 604 605 606 } else if ($op == "markRead") { 607 // 608 // Mark selected message as not unread, fixing up the hit cache 609 // 610 getHits($user, $query); // acquire cache lock, to flush below 611 addLabel($user, C_unread, $selected, 'N'); 612 if (isset($query->unread)) deleteCachedHit($user, $selected); 613 ?> 614 <done /> 615 <?php 616 617 618 } else if ($op == "markUnread") { 619 // 620 // Mark selected message as unread, fixing up the hit cache 621 // 622 getHits($user, $query); // acquire cache lock, to flush below 623 addLabel($user, C_unread, $selected); 624 if (isset($query->unread)) setCachedQuery($user, null); 625 ?> 626 <done /> 627 <?php 628 629 630 } else if ($op == "markAllRead") { 631 // 632 // Copy all to dest 633 // 634 copyAllMsgs($user, $query, C_unread, "N"); 635 ?> 636 <done /> 637 <?php 638 639 640 } else if ($op == "markAllUnread") { 641 // 642 // Copy all to dest 643 // 644 copyAllMsgs($user, $query, C_unread); 645 ?> 646 <done /> 647 <?php 648 649 650 } else if ($op == "compose" || 651 $op == "reply" || 652 $op == "replyAll" || 653 $op == "forward") { 654 // 655 // Create and send a draft 656 // 657 $draftId = buildDraft($user, $h2, $selected, $op); 658 putDraftXML($user, $draftId); 659 660 } else if ($op == "reopenDraft") { 661 // 662 // Open an existing draft and send it 663 // 664 putDraftXML($user, 0 + $dest); 665 666 667 } else if ($op == "attachDelete") { 668 // 669 // Remove an attachment from a draft 670 // 671 deletePart($user, $startAt); 672 putDraftXML($user, 0 + $dest); 673 674 675 } else if ($op == "resend") { 676 // 677 // Resend selected message as bcc to recipients in dest 678 // 679 $content = getRawMsg($user, $selected); 680 resend($user, $dest, $content); 681 ?> 682 <done /> 683 <?php 684 685 686 } else if ($op == "sendDraft" || 687 $op == "saveDraft") { 688 // 689 // Save current draft state, and possibly actually send it 690 // 691 if (isset($args["draftId"])) { 692 saveDraft($user, $draftArg->id, 693 $draftArg->msgfrom, $draftArg->msgto, $draftArg->msgcc, 694 $draftArg->subject, $draftArg->content); 695 if ($op == "sendDraft") { 696 $sendError = send($user, $draftArg->id); 697 } else { 698 $sendError = null; 699 } 700 } else { 701 $sendError = "missing arguments"; 702 } 703 echo "<sendDone " . 704 (is_null($sendError) ? "" : 705 "err=\"" . xmlAttrValue($sendError) . "\" ") . "/>\n"; 706 707 708 } else if ($op == "deleteDraft") { 709 // 710 // Delete draft message 711 // 712 if (isset($args["draftId"])) { 713 deleteDraft($user, $draftArg->id); 714 } 715 ?> 716 <sendDone /> 717 <?php 718 719 720 } else if ($op == "getContacts") { 721 // 722 // Return the user's contacts list 723 // 724 $contacts = enumContacts($user, ""); 725 ?> 726 <contacts> 727 <?php 728 while ($contact = mysql_fetch_object($contacts)) { 729 putContactXML("contact", $contact); 730 } 731 ?> 732 </contacts> 733 <?php 734 735 736 } else if ($op == "saveContact") { 737 // 738 // Save or create contact 739 // 740 // The fields are passed in $dest, separated by newline 741 // They get passed to "saveContact" as globals, sadly 742 $fields = explode("\n", $dest); 743 $contactArgs["firstContact"] = $fields[1]; 744 $contactArgs["lastContact"] = $fields[2]; 745 $contactArgs["nicknameContact"] = $fields[3]; 746 $contactArgs["emailContact"] = $fields[4]; 747 $contactArgs["addressContact"] = $fields[5]; 748 $contactArgs["homeContact"] = $fields[6]; 749 $contactArgs["workContact"] = $fields[7]; 750 $contactArgs["mobileContact"] = $fields[8]; 751 $id = saveContact($user, 0+$fields[0], $contactArgs); 752 ?> 753 <contactSaved id="<?php echo $id ?>" /> 754 <?php 755 756 } else if ($op == "deleteContact") { 757 // 758 // Delete given contact 759 // 760 deleteContact($user, 0+$dest); 761 ?> 762 <contactDeleted id="<?php echo 0+$dest ?>" /> 763 <?php 764 765 766 } else if ($op == "createFolder") { 767 // 768 // Create a folder named dest 769 // 770 createFolder($user, $dest); 771 ?> 772 <folderCreated folder="<?php echo xmlAttrValue($dest) ?>" /> 773 <?php 774 775 776 } else if ($op == "deleteFolder") { 777 // 778 // Delete the folder named dest 779 // 780 if ($dest != "" && $dest != C_inbox && 781 $dest != C_dropped && $dest != C_trash && 782 $dest != C_unsent && $dest != C_incoming) { 783 deleteFolder($user, $dest, C_dropped); 784 } 785 ?> 786 <folderDeleted folder="<?php echo xmlAttrValue($dest) ?>" /> 787 <?php 788 789 790 } else if ($op == "saveQuery") { 791 // 792 // Save query named dest (includes creation) 793 // 794 if ($savedQuery = getQuery($user, $dest)) { 795 $query->scan = $savedQuery->scan; 796 $query->qid = $savedQuery->qid; 797 } 798 $query->name = $dest; 799 saveQuery($user, $query); 800 ?> 801 <querySaved folder="<?php echo xmlAttrValue($dest) ?>" /> 802 <?php 803 804 805 } else if ($op == "promoteQuery") { 806 // 807 // Promote saved query named dest 808 // 809 promoteQuery($user, $dest); 810 ?> 811 <promoted folder="<?php echo xmlAttrValue($dest) ?>" /> 812 <?php 813 814 815 } else if ($op == "demoteQuery") { 816 // 817 // Demote saved query named dest 818 // 819 demoteQuery($user, $dest); 820 ?> 821 <demoted folder="<?php echo xmlAttrValue($dest) ?>" /> 822 <?php 823 824 825 } else if ($op == "deleteQuery") { 826 // 827 // Delete query named dest 828 // 829 deleteQuery($user, $dest); 830 ?> 831 <queryDeleted folder="<?php echo xmlAttrValue($dest) ?>" /> 832 <?php 833 834 835 } else if ($op == "saveSettings") { 836 // 837 // Save miscellaneous account settings 838 // 839 $fields = explode("\n", $dest); 840 $dest = "erased"; 841 $tz = 0 + $fields[0]; 842 $newPwd = $fields[2]; 843 $fields[2] = "erased"; 844 // The new password, like all user generated data, should be in UTF-8 845 $newDk = setSettings($user, $dk, $h2, $tz, $newPwd); 846 $newPwd = "erased"; 847 if ($newDk != $dk) recordDk($user, $newDk, $persistDK); 848 ?> 849 <settingsSaved 850 displaytz="<?php echo $tz ?>" 851 /> 852 <?php 853 854 855 } else if ($op == "saveAccount") { 856 // 857 // Save or create account 858 // 859 $fields = explode("\n", $dest); 860 $dest = "erased"; 861 $acct = new stdClass(); 862 $acct->acctid = 0 + $fields[0]; 863 $acct->server = $fields[1]; 864 $acct->user = $fields[2]; 865 $acct->pwd = $fields[4]; 866 $fields[4] = "erased"; 867 $acct->type = $fields[5]; 868 $acct->msgfrom = $fields[6]; 869 $acct->person = $fields[7]; 870 $acct->dodelete = ($fields[8] == "Y" ? "Y" : "N"); 871 if ($acct->acctid == 0) $acct->acctid = newAcct($user); 872 setAcct($user, $h2, $acct); 873 $acct->pwd = "erased"; 874 $savedAcct = getAcct($user, null, $acct->acctid); 875 putAccountXML("accountSaved", $savedAcct); 876 877 878 } else if ($op == "forgetAccount") { 879 // 880 // Delete account with given id 881 // 882 forgetAcct($user, 0+$dest); 883 ?> 884 <accountForgotten id="<?php echo 0+$dest ?>" /> 885 <?php 886 887 888 } else { 889 // 890 // Unknown operation 891 // 892 893 // Result XML is an <unknown> tag, with op attribute and text message 894 ?> 895 <unknownOp 896 op="<?php echo xmlAttrValue($op) ?>" 897 >Unknown operator "<?php echo xmlCharData($op) ?>"</unknownOp> 898 <?php 899 } 900 901 ob_end_flush(); 902 903 ?>
End of listing