/** * Helper function to _getXML(). Returns xml of a header. * * @param string Name of header * @param string Value of header * @param integer Number of tabs to indent * @return string XML version of input * @access private */ function _getXML_helper($hdr_name, $hdr_value, $indent) { $htab = "\t"; $crlf = "\r\n"; $return = ''; $new_hdr_value = $hdr_name != 'received' ? mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value); $new_hdr_name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name))); // Sort out any parameters if (!empty($new_hdr_value['other'])) { foreach ($new_hdr_value['other'] as $paramname => $paramvalue) { $params[] = str_repeat($htab, $indent) . $htab . '<parameter>' . $crlf . str_repeat($htab, $indent) . $htab . $htab . '<paramname>' . htmlspecialchars($paramname) . '</paramname>' . $crlf . str_repeat($htab, $indent) . $htab . $htab . '<paramvalue>' . htmlspecialchars($paramvalue) . '</paramvalue>' . $crlf . str_repeat($htab, $indent) . $htab . '</parameter>' . $crlf; } $params = implode('', $params); } else { $params = ''; } $return = str_repeat($htab, $indent) . '<header>' . $crlf . str_repeat($htab, $indent) . $htab . '<headername>' . htmlspecialchars($new_hdr_name) . '</headername>' . $crlf . str_repeat($htab, $indent) . $htab . '<headervalue>' . htmlspecialchars($new_hdr_value['value']) . '</headervalue>' . $crlf . $params . str_repeat($htab, $indent) . '</header>' . $crlf; return $return; }
function workPopfetcher(&$eventData) { global $serendipity; static $debug = null; if ($debug === null) { $debug = $this->debug = serendipity_db_bool($this->get_config('debug')); } // updertEntry() will not function unless this is set: $serendipity['POST']['properties']['fake'] = 'fake'; $_SESSION['serendipityRightPublish'] = true; $this->out('<h3>' . PLUGIN_MF_NAME . ' v' . POPFETCHER_VERSION . ' @ ' . date("D M j G:i:s T Y") . '</h3>'); $debug_file = null; // DEVELOPERS: If set to a filename, you can bypass fetching POP and use a file instead. $debug_mail = $this->get_config('debug_mail'); if (strlen($debug_mail) != '' && file_exists($debug_mail)) { $debug_file = $debug_mail; } if ($debug_file != null) { $this->debug = true; } $authorid = $this->get_config('author'); if (empty($authorid) || $authorid == 'empty') { $authorid = isset($serendipity['authorid']) ? $serendipity['authorid'] : 1; } $mailserver = trim($this->get_config('mailserver')); $mailport = $this->get_config('mailport'); $mailuser = trim($this->get_config('mailuser')); $mailpass = trim($this->get_config('mailpass')); $timeout = $this->get_config('timeout'); $deleteflag = serendipity_db_bool($this->get_config('deleteflag')); $apopflag = serendipity_db_bool($this->get_config('apopflag')); $blogflag = serendipity_db_bool($this->get_config('blogflag')); $striptagsflag = serendipity_db_bool($this->get_config('striptagsflag')); $publishflag = serendipity_db_bool($this->get_config('publishflag')); $onlyfrom = $this->get_config('onlyfrom', ''); $maildir = trim($this->get_config('maildir')); $category = trim($this->get_config('category')); $adflag = serendipity_db_bool($this->get_config('adflag')); $plaintext_is_body_flag = serendipity_db_bool($this->get_config('plaintext_is_body')); $plaintext_use_extended_flag = serendipity_db_bool($this->get_config('plaintext_use_extended')); $list_virus = array('.pif', '.vbs', '.scr', '.bat', '.com', '.exe'); $list_imagetype = array('jpg', 'jpeg', 'gif', 'png', 'x-png', 'pjpeg'); $list_imageext = array('.gif', '.jpg', '.png', '.jpeg'); $list_ignore = array('.smil'); $output = ''; $dirpath = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $maildir; $dupcount = 0; // Upload directory must end with a slash character if (strrchr($dirpath, '/') != '/') { $output = MF_ERROR7; $this->out('<br />' . $output . '<br />'); return true; } // Upload directory must be writable if (!is_writable($dirpath)) { $output = MF_ERROR6; $this->out('<br />' . $output . '<br />'); return true; } if (serendipity_db_bool($this->get_config('subfolder'))) { $dirpath = $dirpath . '/' . date('Y'); if (!is_dir($dirpath)) { mkdir($dirpath); } $dirpath = $dirpath . '/' . date('m') . '/'; if (!is_dir($dirpath)) { mkdir($dirpath); } $maildir .= date('Y') . '/' . date('m') . '/'; } $maildir = str_replace('//', '/', $maildir); // Category (if specified) must exist if (!empty($category)) { $cid = serendipity_fetchCategoryInfo(null, $category); if ($cid == false) { $output = MF_ERROR8; $this->out('<br />' . $output . '<br />'); return true; } } if ($debug_file === null) { // Create new instance of POP3 connection $pop3 = new POP3($mailserver, $timeout); // Attempt to connect to mail server if (!$pop3->connect($mailserver, $mailport)) { $output = MF_ERROR1 . ': ' . $pop3->ERROR; $this->out('<br />' . $output . '<br />'); return true; } // Try APOP login if requested, otherwise, regular login if ($apopflag) { $Count = $pop3->apop($mailuser, $mailpass); } else { $Count = $pop3->login($mailuser, $mailpass); } // Check for error retrieving number of msgs in mailbox if ($Count === false or $Count == -1) { $output = MF_ERROR2 . ': ' . $pop3->ERROR; $this->out('<br />' . $output . '<br />'); return true; } // If no msgs in mailbox, exit if ($Count == 0) { $output = MF_MSG1; $this->out('<br />' . $output . '<br />'); return true; } // Get the list of email msgs $msglist = $pop3->uidl(); // Check for error in getting list of email msgs if (!is_array($msglist)) { $output = MF_ERROR3 . ': ' . $pop3->ERROR; $this->out('<br />' . $output . '<br />'); $pop3->quit(); return true; } } else { // Developer debug switch which reads from a file and not a POP3 connection. $dfiles = explode(':', $debug_file); $Count = count($dfiles); } $Message = array(); // ************************ // Fetch each email msg and attachments and put it into the $Message array // ************************ for ($i = 1; $i <= $Count; $i++) { // Messages are numbered starting with '1', not '0' if ($debug_file === null) { $MessArray = $pop3->get($i); } else { $MessArray = file($dfiles[$i - 1]); } // Should have an array. If not, there was an error if (!$MessArray or gettype($MessArray) != "array") { $output = MF_ERROR4 . ': ' . $pop3->ERROR; $this->out('<br />' . $output . '<br />'); $pop3->quit(); return true; } // Extract the msg from MessArray and store it in Message $Message[$i - 1] = ''; while (list($lineNum, $line) = each($MessArray)) { $Message[$i - 1] .= $line; } // Delete the msg if ($deleteflag && $debug_file === null) { $pop3->delete($i); } } if ($debug_file === null) { // Close the connection to the mail server $pop3->quit(); } // ************************ // Message processing section starts here // ************************ $this->out('<br />' . MF_MSG2 . ': ' . $Count . '<br />'); if ($deleteflag) { $this->out(MF_MSG11 . '<br />'); } else { $this->out(MF_MSG12 . '<br />'); } $params['include_bodies'] = true; $params['decode_bodies'] = true; $params['decode_headers'] = true; // Process each email msg foreach ($Message as $M) { $decode = new mimeDecode($M); #$this->out(print_r($M, true)); $s = $decode->decode($params); #$this->out(print_r($s, true)); if ($debug_file !== null) { // DEBUG Struct // echo '<pre>'; // print_r($s); // echo '</pre>'; } if ($s == null) { $this->out('<br />' . MF_ERROR9); return true; } $date = isset($s->headers['date']) ? $s->headers['date'] : MF_MSG3; $from = isset($s->headers['from']) ? $s->headers['from'] : MF_MSG4; if (!empty($onlyfrom) && trim($from) != trim($onlyfrom)) { $this->out('<br />' . sprintf(MF_ERROR_ONLYFROM, '"' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($from) : htmlspecialchars($from, ENT_COMPAT, LANG_CHARSET)) . '"', '"' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($onlyfrom) : htmlspecialchars($onlyfrom, ENT_COMPAT, LANG_CHARSET)) . '"')); continue; } if (empty($s->ctype_parameters['charset'])) { $s->ctype_parameters['charset'] = 'UTF-8'; } if (strtolower($s->ctype_parameters['charset']) == 'us-ascii') { $s->ctype_parameters['charset'] = 'ISO-8859-1'; } $subject = $this->decode(isset($s->headers['subject']) ? $s->headers['subject'] : MF_MSG17, $s->ctype_parameters['charset'], true); #$subject = $this->decode(isset($s->headers['subject']) ? $s->headers['subject'] : MF_MSG17, $s->ctype_parameters['charset']); #$subject = isset($s->headers['subject']) ? $s->headers['subject'] : MF_MSG17; $this->out('<hr />'); $this->out(MF_MSG5 . $date . '<br />'); $this->out(MF_MSG6 . (function_exists('serendipity_specialchars') ? serendipity_specialchars($from) : htmlspecialchars($from, ENT_COMPAT, LANG_CHARSET)) . '<br />'); $this->out(MF_MSG16 . $subject . '<br />'); // Find the author associated with the from address and // set them as the author of the post. $useAuthor = null; if ($authorid == 'byemail') { // We don't have tons of authors .. like two so this isn't a problem // If I wanted this to be "production" quality, I would have to add // a new s9y function that let you retrieve an author given an email address // I suppose I could go with a convention that the base name of the // email address had to be the author's name too. Lookup by name is // supported by s9y. $auths = serendipity_fetchUsers(); $vals = array(); $clean = strtolower($this->cleanEmail($from)); foreach ($auths as $auth) { if (isset($auth['email']) && strtolower($auth['email']) == $clean) { $useAuthor = $auth['authorid']; break; } } if (is_null($useAuthor)) { $this->out('<br />' . sprintf(MF_ERROR_NOAUTHOR, '"' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($clean) : htmlspecialchars($clean, ENT_COMPAT, LANG_CHARSET)) . '"')); continue; } } else { $useAuthor = $authorid; } $postattach = array(); $postbody = array(); $postex = array(); $verizonflag = false; $tmobileflag = false; $firstattachment = false; $firsttext = false; $o2flag = stristr($from, 'mms.o2online.de') !== FALSE; // A mail message with attachments is a series of "parts" if (isset($s->parts) and is_array($s->parts)) { if ($debug_file !== null || $debug) { $this->out('<pre>' . print_r($s->parts, true) . '</pre>'); } $textpref = $this->get_config('textpref'); if ($textpref != 'both') { $has_html = false; $has_text = false; $parts_html = array(); $parts_text = array(); foreach ($s->parts as $idx => $p) { if ($p->ctype_primary == 'text' && $p->ctype_secondary == 'html') { if ($debug_file !== null || $debug) { $this->out("This part is text/html.<br />\n"); } $has_html = true; $parts_html[] = $idx; } elseif ($p->ctype_primary == 'text' && $p->ctype_secondary == 'plain') { if ($debug_file !== null || $debug) { $this->out("This part is text/plain.<br />\n"); } $has_text = true; $parts_text[] = $idx; } } if ($debug_file !== null || $debug) { $this->out("Preference is: {$textpref}.<br />\n"); } if ($textpref == 'text' && $has_html) { if ($debug_file !== null || $debug) { $this->out("Preference is text/plain.<br />\n"); } foreach ($parts_html as $pidx) { if ($debug_file !== null || $debug) { $this->out("Stripping HTML part {$pidx}, because preference is plaintext.<br />\n"); } unset($s->parts[$pidx]); } } if ($textpref == 'html' && $has_text) { if ($debug_file !== null || $debug) { $this->out("Preference is text/html.<br />\n"); } foreach ($parts_text as $pidx) { if ($debug_file !== null || $debug) { $this->out("Stripping text part {$pidx}, because preference is html.<br />\n"); } unset($s->parts[$pidx]); } } } foreach ($s->parts as $p) { if ($debug_file !== null || $debug) { $this->out("Analyzing mail:<br />\n Disposition: {$p->disposition}<br />\n Body: " . (isset($p->body) ? 'Set' : 'Not Set') . "<br />\n Primary CType: {$p->ctype_primary}<br />\n Secondary CType: {$p->ctype_secondary}<br />\n Filename: {$p->d_parameters[filename]}\n .<br />\n"); } // Handle msgs with attachments and messages with images that are inlined if (isset($p->disposition) and $p->disposition == 'attachment' and isset($p->body) or isset($p->disposition) and $p->disposition == 'inline' and isset($p->body) and $p->ctype_primary == 'image' or !empty($p->body) and $p->ctype_primary == 'image') { $this->handleImage($p, $debug, $debug_file, $tmobileflag, $adflag, $dirpath, $list_virus, $list_ignore, $plaintext_is_body_flag, $firsttext, $plaintext_use_extended_flag, $postex, $postbody, $dupcount, $maildir, $authorid, $list_imagetype, $list_imageext, $subject); } elseif (strtolower($p->ctype_primary) == 'text' and isset($p->body)) { if ($debug_file !== null || $debug) { $this->out("<br />\nRecognized text part.<br />\n"); } if (trim($subject) == SPRINTPCS_IDENT_PICTURE) { $p->body = sprintpcs_pictureshare($maildir, $p->body, $authorid); if (strstr($p->body, ERROR_CHECK)) { $this->out('<br />' . $p->body); return true; } } if (trim($subject) == SPRINTPCS_IDENT_ALBUM) { $p->body = sprintpcs_albumshare($maildir, $p->body, $authorid); if (strstr($p->body, ERROR_CHECK)) { $this->out('<br />' . $p->body); return true; } } if (trim($subject) == SPRINTPCS_IDENT_VIDEO) { $p->body = sprintpcs_videoshare($maildir, $p->body, $authorid); if (strstr($p->body, ERROR_CHECK)) { $this->out('<br />' . $p->body); return true; } } if (stristr($subject, CINGULAR_IDENT_PICTURE)) { $p->body = cingular_photo($maildir, $p->body); if (strstr($p->body, ERROR_CHECK)) { $this->out('<br />' . $p->body); return true; } } if (stristr($p->body, VERIZON_IDENT_PICTURE)) { $p->body = verizon_photo($maildir, $p->body); $verizonflag = true; if (strstr($p->body, ERROR_CHECK)) { $this->out('<br />' . $p->body); return true; } } // Because text and HTML attachments get inlined // sometimes (notably Hotmail), // we want to collect them all and attach them to the // regular msg body $bodytext = trim($this->decode($p->body, $p->ctype_parameters['charset'])); if (empty($bodytext)) { continue; } // Strip evil HTML if (preg_match('@<body[^>]*>(.+)</body>@imsU', $bodytext, $m)) { if ($debug_file !== null || $debug) { $this->out("Reduced HTML text.<br />\n"); } $bodytext = $m[1]; } if ($adflag && preg_match('@T\\-Mobile MMS@', $bodytext) && preg_match('@http://www\\.T\\-Mobile\\.(de|nl|com)/mms@', $bodytext)) { if ($debug_file !== null || $debug) { $this->out("<br />\nSkipping T-Mobile ad.<br />\n"); } continue; } if ($firsttext && $plaintext_use_extended_flag) { $postex[] = $bodytext; } else { $postbody[] = $bodytext; $firsttext = true; } } elseif (is_array($p->parts)) { if ($debug_file !== null || $debug) { $this->out("<br />\nRecognized text/multipart.<br />\n"); } if ($textpref != 'both') { $has_html = false; $has_text = false; $parts_html = array(); $parts_text = array(); foreach ($p->parts as $idx => $subp) { if ($subp->ctype_primary == 'text' && $subp->ctype_secondary == 'html') { $has_html = true; $parts_html[] = $idx; } elseif ($subp->ctype_primary == 'text' && $subp->ctype_secondary == 'plain') { $has_text = true; $parts_text[] = $idx; } } if ($textpref == 'text' && $has_html) { foreach ($parts_html as $pidx) { if ($debug_file !== null || $debug) { $this->out("Stripping HTML part {$pidx}, because preference is plaintext.<br />\n"); } unset($p->parts[$pidx]); } } if ($textpref == 'html' && $has_text) { foreach ($parts_text as $pidx) { if ($debug_file !== null || $debug) { $this->out("Stripping text part {$pidx}, because preference is html.<br />\n"); } unset($p->parts[$pidx]); } } } foreach ($p->parts as $subpart) { if ($subpart->ctype_primary == 'text' && $subpart->ctype_secondary == 'html' && $o2flag) { $bodytext = trim($this->decode(popfetcher_provider_o2::getBody($subpart->body), $subpart->ctype_parameters['charset'])); if (empty($bodytext)) { continue; } if ($firsttext && $plaintext_use_extended_flag) { $postex[] = $bodytext; } else { $postbody[] = $bodytext; $firsttext = true; } } elseif ($subpart->ctype_primary == 'text') { $bodytext = trim($this->decode($subpart->body, $subpart->ctype_parameters['charset'])); if (preg_match('@<body[^>]*>(.+)</body>@imsU', $bodytext, $m)) { if ($debug_file !== null || $debug) { $this->out("Reduced HTML text.<br />\n"); } $bodytext = $m[1]; } if ($firsttext && $plaintext_use_extended_flag) { $postex[] = $bodytext; } else { $postbody[] = $bodytext; $firsttext = true; } } elseif ($subpart->ctype_primary == 'image') { // Handle inline multipart images $this->handleImage($subpart, $debug, $debug_file, $tmobileflag, $adflag, $dirpath, $list_virus, $list_ignore, $plaintext_is_body_flag, $firsttext, $plaintext_use_extended_flag, $postex, $postbody, $dupcount, $maildir, $authorid, $list_imagetype, $list_imageext, $subject); } } } else { if ($debug_file !== null || $debug) { $this->out("<br />\nRecognized unknown part.<br />\n"); } if ($p->disposition == 'inline' && isset($p->d_parameters['filename'])) { // Use makeFilename to get rid of spaces and other oddities $filename = serendipity_makeFilename($p->d_parameters['filename']); // if no file extension exists, add default .txt file extension if (!strrpos($filename, ".")) { $filename = $filename . 'txt'; } if ($debug_file !== null || $debug) { $this->out("<br />\nStoring attachment as {$filename}<br />\n"); } $this->out('<br />' . MF_MSG8 . $filename); $fullname = $dirpath . $filename; // Extract file extension and file name for various processing $ext = substr(strrchr($filename, "."), 0); $name = substr($filename, 0, strrpos($filename, ".")); // Skip message and all attachments if possible virus found $lext = strtolower($ext); if (in_array($lext, $list_virus)) { $output = MF_MSG19 . ': ' . $filename; $this->out('<br />' . $output . '<br />'); continue 2; } if (in_array($lext, $list_ignore)) { $this->out('<br />' . MF_MSG20 . '<br />'); continue; } // Check for duplicate filename. Give dup file name file.time().dup.ext if (is_file($fullname)) { $this->out('<br />' . MF_MSG14 . $filename); $name = $name . time() . $dupcount . 'dup'; $filename = $name . $ext; $fullname = $dirpath . $filename; $dupcount++; } $fp = fopen($fullname, 'w'); if (!$fp) { $this->out('<br />' . MF_ERROR5 . $fullname); return true; } fwrite($fp, $p->body); fclose($fp); serendipity_insertImageInDatabase($filename, $maildir, $authorid, NULL); $attlink = '<a class="popfetcherfile" href="' . $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $maildir . $filename . '" target="_blank">' . $filename . '</a>'; // Inline pictures to match the structure of the mail if ($plaintext_is_body_flag) { // Only the first image is embedded in body, or if no extended entry is used if (!$firstattachment || !$plaintext_use_extended_flag) { $postbody[] = $attlink; } else { $postex[] = $attlink; $firsttext = true; } } else { // Standard attachment mode $postattach[] = $attlink; } $firstattachment = true; $this->out('<br />' . MF_MSG13 . $filename); } $this->out('<br />' . MF_MSG9); // Tmobile sends a weird nested text and html // sub-attachment (at least the nokia does) if (isset($s->headers['x-operator']) and strtolower($s->headers['x-operator']) == TMOBILE_IDENT_PICTURE) { $p->body = tmobile_photo($maildir, $p->body); $tmobileflag = true; if (strstr($p->body, ERROR_CHECK)) { $this->out('<br />' . $p->body); return true; } } } } if ($blogflag) { if (trim($subject) == SPRINTPCS_IDENT_ALBUM || trim($subject) == SPRINTPCS_IDENT_PICTURE || trim($subject) == SPRINTPCS_IDENT_VIDEO || stristr($subject, CINGULAR_IDENT_PICTURE) || ($verizonflag and $subject == MF_MSG17) || ($tmobileflag and $subject == MF_MSG17)) { $time = strtotime($s->headers['date']); $stamp = $time == -1 ? date("l, F j, Y, g:ia") : date("l, F j, Y, g:ia", $time); $subject = MF_MSG23 . $stamp; } $msgbody = implode("<br />\n", $postbody); $msgbody .= implode("<br />\n", $postattach); //New draft post $entry = $this->workEntry($subject, $msgbody, $useAuthor, $postex, $cid, $s); } } elseif (strtolower($s->ctype_primary) == 'text') { // Email msg with no attachments if ($blogflag) { if (trim($subject) == SPRINTPCS_IDENT_ALBUM || trim($subject) == SPRINTPCS_IDENT_PICTURE || trim($subject) == SPRINTPCS_IDENT_VIDEO || stristr($subject, CINGULAR_IDENT_PICTURE) || (stristr($s->body, VERIZON_IDENT_PICTURE) and $subject == MF_MSG17) || ($tmobileflag and $subject == MF_MSG17)) { $time = strtotime($s->headers['date']); $stamp = $time == -1 ? date("l, F j, Y, g:ia") : date("l, F j, Y, g:ia", $time); $subject = MF_MSG23 . $stamp; } $bodytext = trim($this->decode($s->body, $s->ctype_parameters['charset'])); $entry = $this->workEntry($subject, $bodytext, $useAuthor, $postex, $cid, $s); } else { $this->out('<br />' . MF_MSG20); } } else { $this->out('<br />' . MF_MSG10 . '<br />'); } } echo '<br /><hr />'; }