diff --git a/client/Gallery3.php b/client/Gallery3.php index d1135ae9..83ed7b2d 100644 --- a/client/Gallery3.php +++ b/client/Gallery3.php @@ -129,10 +129,16 @@ class Gallery3 { * @return object Gallery3 */ public function save() { - $response = Gallery3_Helper::request( - "put", $this->url, $this->token, - array("entity" => array_diff((array)$this->data->entity, $this->original_entity), - "members" => $this->data->members)); + $data = array(); + $data["entity"] = array_diff((array)$this->data->entity, $this->original_entity); + if (isset($this->data->members)) { + $data["members"] = $this->data->members; + } + if ($this->file) { + $response = Gallery3_Helper::request("put", $this->url, $this->token, $data, $this->file); + } else { + $response = Gallery3_Helper::request("put", $this->url, $this->token, $data); + } return $this->load(); } diff --git a/client/example.php b/client/example.php index 1c96cd1b..5bfc49a2 100644 --- a/client/example.php +++ b/client/example.php @@ -39,13 +39,19 @@ for ($i = 0; $i < 2; $i++) { ->set("type", "photo") ->set("name", "Sample Photo.png") ->set("title", "Sample Photo") - ->set_file("gallery.png") + ->set_file("test1.png") ->create($album->url, $auth); alert("Uploaded photo: {$photo->url}"); } $album->load(); alert("Album members: " . join(", ", $album->data->members) . ""); + +alert("Replace the data file"); +$photo->set_file("test2.png") + ->save(); + + $comment = Gallery3::factory() ->set("item", $album->data->members[0]) ->set("type", "comment") @@ -93,7 +99,6 @@ $tag_relationship2->delete(); $tag->load(); alert("1 remaining tag: {$tag->data->relationships->items->members[0]}"); - alert("Delete the album and tag"); $album->delete(); $tag->delete(); diff --git a/client/gallery.png b/client/test1.png similarity index 100% rename from client/gallery.png rename to client/test1.png diff --git a/client/test2.png b/client/test2.png new file mode 100644 index 00000000..fdc97779 Binary files /dev/null and b/client/test2.png differ diff --git a/modules/ecard/controllers/admin_ecards.php b/modules/ecard/controllers/admin_ecard.php similarity index 71% rename from modules/ecard/controllers/admin_ecards.php rename to modules/ecard/controllers/admin_ecard.php index b2bde957..640ce40a 100644 --- a/modules/ecard/controllers/admin_ecards.php +++ b/modules/ecard/controllers/admin_ecard.php @@ -17,11 +17,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Admin_ecards_Controller extends Admin_Controller { +class Admin_ecard_Controller extends Admin_Controller { public function index() { $view = new Admin_View("admin.html"); $view->page_title = t("eCard settings"); - $view->content = new View("admin_ecards.html"); + $view->content = new View("admin_ecard.html"); $view->content->form = $this->_get_admin_form(); print $view; } @@ -31,31 +31,41 @@ class Admin_ecards_Controller extends Admin_Controller { $form = $this->_get_admin_form(); if ($form->validate()) { module::set_var("ecard", "sender", $form->ecard->sender->value); + module::set_var("ecard", "bcc", $form->ecard->bcc->value); module::set_var("ecard", "subject", $form->ecard->subject->value); module::set_var("ecard", "message", $form->ecard->message->value); module::set_var("ecard", "access_permissions", $form->ecard->access_permissions->value); + module::set_var("ecard", "location", $form->ecard->location->value); message::success(t("eCard settings updated")); - url::redirect("admin/ecards"); + url::redirect("admin/ecard"); } else { print $form; } } private function _get_admin_form() { - $form = new Forge("admin/ecards/save", "", "post", array("id" => "g-ecards-admin-form")); + $form = new Forge("admin/ecard/save", "", "post", array("id" => "g-ecard-admin-form")); $ecard_settings = $form->group("ecard")->label(t("eCard settings")); $ecard_settings->input("sender") ->label(t("E-mail sender (leave blank for a user-defined address)")) ->value(module::get_var("ecard", "sender", "")); - $ecard_settings->input("subject")->label(t("E-mail subject")) + $ecard_settings->input("bcc") + ->label(t("BCC (optional)")) + ->value(module::get_var("ecard", "bcc", "")); + $ecard_settings->input("subject")->label(t("E-mail subject")) ->value(module::get_var("ecard", "subject")); - $ecard_settings->textarea("message")->label(t("E-mail message")) + $ecard_settings->textarea("message")->label(t("E-mail message. Valid keywords are \"%toname\" (recipient's name) and \"%fromname\" (sender's name))")) ->value(module::get_var("ecard", "message")); $ecard_settings->dropdown("access_permissions") ->label(t("Who can send eCards?")) ->options(array("everybody" => t("Everybody"), "registered_users" => t("Only registered users"))) ->selected(module::get_var("ecard", "access_permissions")); + $ecard_settings->dropdown("location") + ->label(t("Where should the eCard link be displayed?")) + ->options(array("top" => t("At the top of the sidebar as an icon"), + "sidebar" => t("In the sidebar as a button"))) + ->selected(module::get_var("ecard", "location")); $ecard_settings->submit("save")->value(t("Save")); return $form; } diff --git a/modules/ecard/controllers/ecard.php b/modules/ecard/controllers/ecard.php new file mode 100644 index 00000000..6ca30df7 --- /dev/null +++ b/modules/ecard/controllers/ecard.php @@ -0,0 +1,95 @@ +validate(); + } catch (ORM_Validation_Exception $e) { + // Translate ORM validation errors into form error messages + foreach ($e->validation->errors() as $key => $error) { + $form->edit_item->inputs[$key]->add_error($error, 1); + } + $valid = false; + } + + if ($valid) { + $v = new View("ecard_email.html"); + $v->item = $item; + $v->subject = module::get_var("ecard", "subject"); + $to_name = $form->send_ecard->to_name->value; + $from_name = $form->send_ecard->from_name->value; + $bcc = module::get_var("ecard", "bcc"); + $v->message = t(module::get_var("ecard", "message"), array("toname" => $to_name, "fromname" => $from_name)); + $v->custom_message = $form->send_ecard->text->value; + $v->image = $item->name; + $to = $form->send_ecard->inputs["to_email"]->value; + $from = $form->send_ecard->inputs["from_email"]->value; + $headers = array("from" => $from_name."<".$from.">", "to" => $to, "subject" => module::get_var("ecard", "subject")); + require_once(MODPATH. "ecard/lib/mime.php"); + $mime = new Mail_mime("\n"); + $mime->setHTMLBody($v->render()); + $mime->addHTMLImage($item->resize_path(),$item->mime_type,$item->name); + $body = $mime->get(array('html_charset' => 'UTF-8', 'text_charset' => 'UTF-8','text_encoding' => '8bit','head_charset' => 'UTF-8')); + self::_notify($headers['to'], $headers['from'], $headers['subject'], $item, $body, $mime->headers(), $bcc); + message::success("eCard successfully sent"); + json::reply(array("result" => "success")); + } else { + json::reply(array("result" => "error", "html" => (string) $form)); + } + } + /** + * Present a form for sending a new ecard. + */ + public function form_send($item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + if (!ecard::can_send_ecard()) { + access::forbidden(); + } + print ecard::prefill_send_form(ecard::get_send_form($item)); + } + private static function _notify($to, $from, $subject, $item, $text, $headers, $bcc) { + $sendmail = Sendmail::factory(); + $sendmail + ->to($to) + ->from($from) + ->subject($subject); + if(isset($bcc)) { + $sendmail->header("bcc",$bcc); + } + foreach($headers as $key => $value) { + $sendmail->header($key,$value); + } + $sendmail + ->message($text) + ->send(); + return; + } +} diff --git a/modules/ecard/controllers/ecards.php b/modules/ecard/controllers/ecards.php deleted file mode 100644 index 6ea77a00..00000000 --- a/modules/ecard/controllers/ecards.php +++ /dev/null @@ -1,53 +0,0 @@ -validate()) { - Kohana_Log::add("error",print_r($form,1)); - // Send the ecard here, based on the form data - json::reply(array("result" => "success")); - } else { - json::reply(array("result" => "error", "html" => (string)$form)); - } - } - - /** - * Present a form for adding a new ecard to this item or editing an existing ecard. - */ - public function form_send($item_id) { - $item = ORM::factory("item", $item_id); - access::required("view", $item); - if (!ecard::can_send_ecard()) { - access::forbidden(); - } - - print ecard::prefill_send_form(ecard::get_send_form($item)); - } -} diff --git a/modules/ecard/css/ecard.css b/modules/ecard/css/ecard.css new file mode 100644 index 00000000..ddbf38c0 --- /dev/null +++ b/modules/ecard/css/ecard.css @@ -0,0 +1,7 @@ +.ui-icon-ecard { + width: 16px; + height: 16px; + float: left; + margin-right: .2em; + background-image: url(../images/email_go.png); +} diff --git a/modules/ecard/helpers/ecard.php b/modules/ecard/helpers/ecard.php index 0b4d63db..7fb79048 100644 --- a/modules/ecard/helpers/ecard.php +++ b/modules/ecard/helpers/ecard.php @@ -25,7 +25,7 @@ */ class ecard_Core { static function get_send_form($item) { - $form = new Forge("ecards/send/{$item->id}", "", "post", array("id" => "g-ecard-form")); + $form = new Forge("ecard/send/{$item->id}", "", "post", array("id" => "g-ecard-form")); $group = $form->group("send_ecard")->label(t("Send eCard")); $group->input("from_name") ->label(t("Your name")) diff --git a/modules/ecard/helpers/ecard_block.php b/modules/ecard/helpers/ecard_block.php new file mode 100644 index 00000000..23136d55 --- /dev/null +++ b/modules/ecard/helpers/ecard_block.php @@ -0,0 +1,39 @@ + t("eCard")); + } + + static function get($block_id, $theme) { + $block = ""; + switch ($block_id) { + case "ecard": + if ($theme->item() && $theme->item()->is_photo() && module::get_var("ecard", "location") == "sidebar") { + $block = new Block(); + $block->css_id = "g-send-ecard"; + $block->title = t("eCard"); + $block->content = new View("ecard_block.html"); + } + break; + } + return $block; + } +} \ No newline at end of file diff --git a/modules/ecard/helpers/ecard_event.php b/modules/ecard/helpers/ecard_event.php index b7517185..7b58b2bc 100644 --- a/modules/ecard/helpers/ecard_event.php +++ b/modules/ecard/helpers/ecard_event.php @@ -23,6 +23,18 @@ class ecard_event_Core { ->append(Menu::factory("link") ->id("ecard") ->label(t("eCard Settings")) - ->url(url::site("admin/ecards"))); + ->url(url::site("admin/ecard"))); + } + + static function photo_menu($menu, $theme) { + if (module::get_var("ecard", "location") == "top") { + $item = $theme->item(); + $menu->append(Menu::factory("link") + ->id("ecard") + ->label(t("Send as eCard")) + ->url(url::site("ecard/form_send/{$item->id}")) + ->css_class("g-dialog-link ui-icon-ecard") + ->css_id("g-send-ecard")); + } } } diff --git a/modules/ecard/helpers/ecard_installer.php b/modules/ecard/helpers/ecard_installer.php index 2f514b09..98d73702 100644 --- a/modules/ecard/helpers/ecard_installer.php +++ b/modules/ecard/helpers/ecard_installer.php @@ -21,9 +21,10 @@ class ecard_installer { static function install() { module::set_var("ecard", "subject", "You have been sent an eCard"); module::set_var("ecard", "message", - "Hello %toname%, \r\n%fromname% has sent you an eCard. " . + "Hello %toname, \r\n%fromname has sent you an eCard. " . "Click the image to be taken to the gallery."); + module::set_var("ecard", "bcc", ""); module::set_var("ecard", "access_permissions", "everybody"); - module::set_version("ecard", 1); + module::set_version("ecard", 2); } } diff --git a/modules/ecard/helpers/ecard_theme.php b/modules/ecard/helpers/ecard_theme.php index 9836d86f..dd3644e8 100644 --- a/modules/ecard/helpers/ecard_theme.php +++ b/modules/ecard/helpers/ecard_theme.php @@ -18,13 +18,7 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class ecard_theme_Core { - static function sidebar_bottom($theme) { - if (ecard::can_send_ecard()) { - $block = new Block; - $block->css_id = "g-ecards"; - $block->title = t("eCards"); - $block->content = new View("ecards.html"); - return $block; - } + static function head($theme) { + $theme->css("ecard.css"); } } \ No newline at end of file diff --git a/modules/ecard/images/email_go.png b/modules/ecard/images/email_go.png new file mode 100644 index 00000000..4a6c5d39 Binary files /dev/null and b/modules/ecard/images/email_go.png differ diff --git a/modules/ecard/lib/mime.php b/modules/ecard/lib/mime.php new file mode 100644 index 00000000..50616189 --- /dev/null +++ b/modules/ecard/lib/mime.php @@ -0,0 +1,912 @@ + | +// | Tomas V.V.Cox (port to PEAR) | +// +-----------------------------------------------------------------------+ +// + +if (!class_exists('Mail_mimePart')) { + require_once(MODPATH . "ecard/lib/mimePart.php"); +} +if (class_exists('Mail_mime')) return; + +/** + * Mime mail composer class. Can handle: text and html bodies, embedded html + * images and attachments. + * Documentation and examples of this class are avaible here: + * http://pear.php.net/manual/ + * + * @notes This class is based on HTML Mime Mail class from + * Richard Heyes which was based also + * in the mime_mail.class by Tobias Ratschiller and + * Sascha Schumann + * + * @author Richard Heyes + * @author Tomas V.V.Cox + * @package Mail + * @access public + */ +class Mail_mime +{ + /** + * Contains the plain text part of the email + * @var string + */ + var $_txtbody; + /** + * Contains the html part of the email + * @var string + */ + var $_htmlbody; + /** + * contains the mime encoded text + * @var string + */ + var $_mime; + /** + * contains the multipart content + * @var string + */ + var $_multipart; + /** + * list of the attached images + * @var array + */ + var $_html_images = array(); + /** + * list of the attachements + * @var array + */ + var $_parts = array(); + /** + * Build parameters + * @var array + */ + var $_build_params = array(); + /** + * Headers for the mail + * @var array + */ + var $_headers = array(); + /** + * End Of Line sequence (for serialize) + * @var string + */ + var $_eol; + + + /** + * Constructor function + * + * @access public + */ + function Mail_mime($crlf = "\r\n") + { + $this->_setEOL($crlf); + $this->_build_params = array( + 'head_encoding' => 'quoted-printable', + 'text_encoding' => '7bit', + 'html_encoding' => 'quoted-printable', + '7bit_wrap' => 998, + 'html_charset' => 'ISO-8859-1', + 'text_charset' => 'ISO-8859-1', + 'head_charset' => 'ISO-8859-1' + ); + } + + /** + * Wakeup (unserialize) - re-sets EOL constant + * + * @access private + */ + function __wakeup() + { + $this->_setEOL($this->_eol); + } + + /** + * Accessor function to set the body text. Body text is used if + * it's not an html mail being sent or else is used to fill the + * text/plain part that emails clients who don't support + * html should show. + * + * @param string $data Either a string or + * the file name with the contents + * @param bool $isfile If true the first param should be treated + * as a file name, else as a string (default) + * @param bool $append If true the text or file is appended to + * the existing body, else the old body is + * overwritten + * @return mixed true on success or PEAR_Error object + * @access public + */ + function setTXTBody($data, $isfile = false, $append = false) + { + if (!$isfile) { + if (!$append) { + $this->_txtbody = $data; + } else { + $this->_txtbody .= $data; + } + } else { + $cont = $this->_file2str($data); + if (!isset($cont) /*PEAR::isError($cont)*/) { + return $cont; + } + if (!$append) { + $this->_txtbody = $cont; + } else { + $this->_txtbody .= $cont; + } + } + return true; + } + + /** + * Adds a html part to the mail + * + * @param string $data Either a string or the file name with the + * contents + * @param bool $isfile If true the first param should be treated + * as a file name, else as a string (default) + * @return mixed true on success or PEAR_Error object + * @access public + */ + function setHTMLBody($data, $isfile = false) + { + if (!$isfile) { + $this->_htmlbody = $data; + } else { + $cont = $this->_file2str($data); + if (!isset($cont) /*PEAR::isError($cont)*/) { + return $cont; + } + $this->_htmlbody = $cont; + } + + return true; + } + + /** + * Adds an image to the list of embedded images. + * + * @param string $file The image file name OR image data itself + * @param string $c_type The content type + * @param string $name The filename of the image. + * Only use if $file is the image data + * @param bool $isfilename Whether $file is a filename or not + * Defaults to true + * @return mixed true on success or PEAR_Error object + * @access public + */ + function addHTMLImage($file, $c_type='application/octet-stream', + $name = '', $isfilename = true) + { + $filedata = ($isfilename === true) ? $this->_file2str($file) + : $file; + if ($isfilename === true) { + $filename = ($name == '' ? $file : $name); + } else { + $filename = $name; + } + if (!isset($filedata) /*PEAR::isError($filedata)*/) { + return $filedata; + } + $this->_html_images[] = array( + 'body' => $filedata, + 'name' => $filename, + 'c_type' => $c_type, + 'cid' => md5(uniqid(time())) + ); + return true; + } + + /** + * Adds a file to the list of attachments. + * + * @param string $file The file name of the file to attach + * OR the file contents itself + * @param string $c_type The content type + * @param string $name The filename of the attachment + * Only use if $file is the contents + * @param bool $isFilename Whether $file is a filename or not + * Defaults to true + * @param string $encoding The type of encoding to use. + * Defaults to base64. + * Possible values: 7bit, 8bit, base64, + * or quoted-printable. + * @param string $disposition The content-disposition of this file + * Defaults to attachment. + * Possible values: attachment, inline. + * @param string $charset The character set used in the filename + * of this attachment. + * @return mixed true on success or PEAR_Error object + * @access public + */ + function addAttachment($file, $c_type = 'application/octet-stream', + $name = '', $isfilename = true, + $encoding = 'base64', + $disposition = 'attachment', $charset = '') + { + $filedata = ($isfilename === true) ? $this->_file2str($file) + : $file; + if ($isfilename === true) { + // Force the name the user supplied, otherwise use $file + $filename = (!empty($name)) ? $name : $file; + } else { + $filename = $name; + } + if (empty($filename)) { + $err = null; /*PEAR::raiseError( + "The supplied filename for the attachment can't be empty" + );*/ + return $err; + } + $filename = basename($filename); + if (!isset($filedata) /*PEAR::isError($filedata)*/) { + return $filedata; + } + + $this->_parts[] = array( + 'body' => $filedata, + 'name' => $filename, + 'c_type' => $c_type, + 'encoding' => $encoding, + 'charset' => $charset, + 'disposition' => $disposition + ); + return true; + } + + /** + * Get the contents of the given file name as string + * + * @param string $file_name path of file to process + * @return string contents of $file_name + * @access private + */ + function &_file2str($file_name) + { + if (!is_readable($file_name)) { + $err = null; //PEAR::raiseError('File is not readable ' . $file_name); + return $err; + } + if (!$fd = fopen($file_name, 'rb')) { + $err = null; //PEAR::raiseError('Could not open ' . $file_name); + return $err; + } + $filesize = filesize($file_name); + if ($filesize == 0){ + $cont = ""; + }else{ + if ($magic_quote_setting = get_magic_quotes_runtime()){ + @set_magic_quotes_runtime(0); + } + $cont = fread($fd, $filesize); + if ($magic_quote_setting){ + @set_magic_quotes_runtime($magic_quote_setting); + } + } + fclose($fd); + return $cont; + } + + /** + * Adds a text subpart to the mimePart object and + * returns it during the build process. + * + * @param mixed The object to add the part to, or + * null if a new object is to be created. + * @param string The text to add. + * @return object The text mimePart object + * @access private + */ + function &_addTextPart(&$obj, $text) + { + $params['content_type'] = 'text/plain'; + $params['encoding'] = $this->_build_params['text_encoding']; + $params['charset'] = $this->_build_params['text_charset']; + if (is_object($obj)) { + $ret = $obj->addSubpart($text, $params); + return $ret; + } else { + $ret = new Mail_mimePart($text, $params); + return $ret; + } + } + + /** + * Adds a html subpart to the mimePart object and + * returns it during the build process. + * + * @param mixed The object to add the part to, or + * null if a new object is to be created. + * @return object The html mimePart object + * @access private + */ + function &_addHtmlPart(&$obj) + { + $params['content_type'] = 'text/html'; + $params['encoding'] = $this->_build_params['html_encoding']; + $params['charset'] = $this->_build_params['html_charset']; + if (is_object($obj)) { + $ret = $obj->addSubpart($this->_htmlbody, $params); + return $ret; + } else { + $ret = new Mail_mimePart($this->_htmlbody, $params); + return $ret; + } + } + + /** + * Creates a new mimePart object, using multipart/mixed as + * the initial content-type and returns it during the + * build process. + * + * @return object The multipart/mixed mimePart object + * @access private + */ + function &_addMixedPart() + { + $params['content_type'] = 'multipart/mixed'; + $ret = new Mail_mimePart('', $params); + return $ret; + } + + /** + * Adds a multipart/alternative part to a mimePart + * object (or creates one), and returns it during + * the build process. + * + * @param mixed The object to add the part to, or + * null if a new object is to be created. + * @return object The multipart/mixed mimePart object + * @access private + */ + function &_addAlternativePart(&$obj) + { + $params['content_type'] = 'multipart/alternative'; + if (is_object($obj)) { + return $obj->addSubpart('', $params); + } else { + $ret = new Mail_mimePart('', $params); + return $ret; + } + } + + /** + * Adds a multipart/related part to a mimePart + * object (or creates one), and returns it during + * the build process. + * + * @param mixed The object to add the part to, or + * null if a new object is to be created + * @return object The multipart/mixed mimePart object + * @access private + */ + function &_addRelatedPart(&$obj) + { + $params['content_type'] = 'multipart/related'; + if (is_object($obj)) { + return $obj->addSubpart('', $params); + } else { + $ret = new Mail_mimePart('', $params); + return $ret; + } + } + + /** + * Adds an html image subpart to a mimePart object + * and returns it during the build process. + * + * @param object The mimePart to add the image to + * @param array The image information + * @return object The image mimePart object + * @access private + */ + function &_addHtmlImagePart(&$obj, $value) + { + $params['content_type'] = $value['c_type'] . '; ' . + 'name="' . $value['name'] . '"'; + $params['encoding'] = 'base64'; + $params['disposition'] = 'inline'; + $params['dfilename'] = $value['name']; + $params['cid'] = $value['cid']; + $ret = $obj->addSubpart($value['body'], $params); + return $ret; + + } + + /** + * Adds an attachment subpart to a mimePart object + * and returns it during the build process. + * + * @param object The mimePart to add the image to + * @param array The attachment information + * @return object The image mimePart object + * @access private + */ + function &_addAttachmentPart(&$obj, $value) + { + $params['dfilename'] = $value['name']; + $params['encoding'] = $value['encoding']; + if ($value['disposition'] != "inline") { + $fname = array("fname" => $value['name']); + $fname_enc = $this->_encodeHeaders($fname); + $params['dfilename'] = $fname_enc['fname']; + } + if ($value['charset']) { + $params['charset'] = $value['charset']; + } + $params['content_type'] = $value['c_type'] . '; ' . + 'name="' . $params['dfilename'] . '"'; + $params['disposition'] = isset($value['disposition']) ? + $value['disposition'] : 'attachment'; + $ret = $obj->addSubpart($value['body'], $params); + return $ret; + } + + /** + * Returns the complete e-mail, ready to send using an alternative + * mail delivery method. Note that only the mailpart that is made + * with Mail_Mime is created. This means that, + * YOU WILL HAVE NO TO: HEADERS UNLESS YOU SET IT YOURSELF + * using the $xtra_headers parameter! + * + * @param string $separation The separation etween these two parts. + * @param array $build_params The Build parameters passed to the + * &get() function. See &get for more info. + * @param array $xtra_headers The extra headers that should be passed + * to the &headers() function. + * See that function for more info. + * @param bool $overwrite Overwrite the existing headers with new. + * @return string The complete e-mail. + * @access public + */ + function getMessage($separation = null, $build_params = null, $xtra_headers = null, $overwrite = false) + { + if ($separation === null) + { + $separation = MAIL_MIME_CRLF; + } + $body = $this->get($build_params); + $head = $this->txtHeaders($xtra_headers, $overwrite); + $mail = $head . $separation . $body; + return $mail; + } + + + /** + * Builds the multipart message from the list ($this->_parts) and + * returns the mime content. + * + * @param array Build parameters that change the way the email + * is built. Should be associative. Can contain: + * head_encoding - What encoding to use for the headers. + * Options: quoted-printable or base64 + * Default is quoted-printable + * text_encoding - What encoding to use for plain text + * Options: 7bit, 8bit, base64, or quoted-printable + * Default is 7bit + * html_encoding - What encoding to use for html + * Options: 7bit, 8bit, base64, or quoted-printable + * Default is quoted-printable + * 7bit_wrap - Number of characters before text is + * wrapped in 7bit encoding + * Default is 998 + * html_charset - The character set to use for html. + * Default is iso-8859-1 + * text_charset - The character set to use for text. + * Default is iso-8859-1 + * head_charset - The character set to use for headers. + * Default is iso-8859-1 + * @return string The mime content + * @access public + */ + function &get($build_params = null) + { + if (isset($build_params)) { + while (list($key, $value) = each($build_params)) { + $this->_build_params[$key] = $value; + } + } + + if (!empty($this->_html_images) AND isset($this->_htmlbody)) { + foreach ($this->_html_images as $key => $value) { + $regex = array(); + $regex[] = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' . + preg_quote($value['name'], '#') . '\3#'; + $regex[] = '#(?i)url(?-i)\(\s*(["\']?)' . + preg_quote($value['name'], '#') . '\1\s*\)#'; + $rep = array(); + $rep[] = '\1\2=\3cid:' . $value['cid'] .'\3'; + $rep[] = 'url(\1cid:' . $value['cid'] . '\2)'; + $this->_htmlbody = preg_replace($regex, $rep, + $this->_htmlbody + ); + $this->_html_images[$key]['name'] = basename($this->_html_images[$key]['name']); + } + } + + $null = null; + $attachments = !empty($this->_parts) ? true : false; + $html_images = !empty($this->_html_images) ? true : false; + $html = !empty($this->_htmlbody) ? true : false; + $text = (!$html AND !empty($this->_txtbody)) ? true : false; + + switch (true) { + case $text AND !$attachments: + $message =& $this->_addTextPart($null, $this->_txtbody); + break; + + case !$text AND !$html AND $attachments: + $message =& $this->_addMixedPart(); + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + case $text AND $attachments: + $message =& $this->_addMixedPart(); + $this->_addTextPart($message, $this->_txtbody); + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + case $html AND !$attachments AND !$html_images: + if (isset($this->_txtbody)) { + $message =& $this->_addAlternativePart($null); + $this->_addTextPart($message, $this->_txtbody); + $this->_addHtmlPart($message); + } else { + $message =& $this->_addHtmlPart($null); + } + break; + + case $html AND !$attachments AND $html_images: + if (isset($this->_txtbody)) { + $message =& $this->_addAlternativePart($null); + $this->_addTextPart($message, $this->_txtbody); + $related =& $this->_addRelatedPart($message); + } else { + $message =& $this->_addRelatedPart($null); + $related =& $message; + } + $this->_addHtmlPart($related); + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($related, $this->_html_images[$i]); + } + break; + + case $html AND $attachments AND !$html_images: + $message =& $this->_addMixedPart(); + if (isset($this->_txtbody)) { + $alt =& $this->_addAlternativePart($message); + $this->_addTextPart($alt, $this->_txtbody); + $this->_addHtmlPart($alt); + } else { + $this->_addHtmlPart($message); + } + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + case $html AND $attachments AND $html_images: + $message =& $this->_addMixedPart(); + if (isset($this->_txtbody)) { + $alt =& $this->_addAlternativePart($message); + $this->_addTextPart($alt, $this->_txtbody); + $rel =& $this->_addRelatedPart($alt); + } else { + $rel =& $this->_addRelatedPart($message); + } + $this->_addHtmlPart($rel); + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($rel, $this->_html_images[$i]); + } + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + } + + if (isset($message)) { + $output = $message->encode(); + $this->_headers = array_merge($this->_headers, + $output['headers']); + $body = $output['body']; + return $body; + + } else { + $ret = false; + return $ret; + } + } + + /** + * Returns an array with the headers needed to prepend to the email + * (MIME-Version and Content-Type). Format of argument is: + * $array['header-name'] = 'header-value'; + * + * @param array $xtra_headers Assoc array with any extra headers. + * Optional. + * @param bool $overwrite Overwrite already existing headers. + * @return array Assoc array with the mime headers + * @access public + */ + function &headers($xtra_headers = null, $overwrite = false) + { + // Content-Type header should already be present, + // So just add mime version header + $headers['MIME-Version'] = '1.0'; + if (isset($xtra_headers)) { + $headers = array_merge($headers, $xtra_headers); + } + if ($overwrite){ + $this->_headers = array_merge($this->_headers, $headers); + }else{ + $this->_headers = array_merge($headers, $this->_headers); + } + + $encodedHeaders = $this->_encodeHeaders($this->_headers); + return $encodedHeaders; + } + + /** + * Get the text version of the headers + * (usefull if you want to use the PHP mail() function) + * + * @param array $xtra_headers Assoc array with any extra headers. + * Optional. + * @param bool $overwrite Overwrite the existing heaers with new. + * @return string Plain text headers + * @access public + */ + function txtHeaders($xtra_headers = null, $overwrite = false) + { + $headers = $this->headers($xtra_headers, $overwrite); + $ret = ''; + foreach ($headers as $key => $val) { + $ret .= "$key: $val" . MAIL_MIME_CRLF; + } + return $ret; + } + + /** + * Sets the Subject header + * + * @param string $subject String to set the subject to + * access public + */ + function setSubject($subject) + { + $this->_headers['Subject'] = $subject; + } + + /** + * Set an email to the From (the sender) header + * + * @param string $email The email direction to add + * @access public + */ + function setFrom($email) + { + $this->_headers['From'] = $email; + } + + /** + * Add an email to the Cc (carbon copy) header + * (multiple calls to this method are allowed) + * + * @param string $email The email direction to add + * @access public + */ + function addCc($email) + { + if (isset($this->_headers['Cc'])) { + $this->_headers['Cc'] .= ", $email"; + } else { + $this->_headers['Cc'] = $email; + } + } + + /** + * Add an email to the Bcc (blank carbon copy) header + * (multiple calls to this method are allowed) + * + * @param string $email The email direction to add + * @access public + */ + function addBcc($email) + { + if (isset($this->_headers['Bcc'])) { + $this->_headers['Bcc'] .= ", $email"; + } else { + $this->_headers['Bcc'] = $email; + } + } + + /** + * Since the PHP send function requires you to specifiy + * recipients (To: header) separately from the other + * headers, the To: header is not properly encoded. + * To fix this, you can use this public method to + * encode your recipients before sending to the send + * function + * + * @param string $recipients A comma-delimited list of recipients + * @return string Encoded data + * @access public + */ + function encodeRecipients($recipients) + { + $input = array("To" => $recipients); + $retval = $this->_encodeHeaders($input); + return $retval["To"] ; + } + + /** + * Encodes a header as per RFC2047 + * + * @param array $input The header data to encode + * @return array Encoded data + * @access private + */ + function _encodeHeaders($input) + { + foreach ($input as $hdr_name => $hdr_value) { + if (function_exists('iconv_mime_encode') && preg_match('#[\x80-\xFF]{1}#', $hdr_value)){ + $imePref = array(); + if ($this->_build_params['head_encoding'] == 'base64'){ + $imePrefs['scheme'] = 'B'; + }else{ + $imePrefs['scheme'] = 'Q'; + } + $imePrefs['input-charset'] = $this->_build_params['head_charset']; + $imePrefs['output-charset'] = $this->_build_params['head_charset']; + $hdr_value = iconv_mime_encode($hdr_name, $hdr_value, $imePrefs); + $hdr_value = preg_replace("#^{$hdr_name}\:\ #", "", $hdr_value); + }elseif (preg_match('#[\x80-\xFF]{1}#', $hdr_value)){ + //This header contains non ASCII chars and should be encoded. + switch ($this->_build_params['head_encoding']) { + case 'base64': + //Base64 encoding has been selected. + + //Generate the header using the specified params and dynamicly + //determine the maximum length of such strings. + //75 is the value specified in the RFC. The -2 is there so + //the later regexp doesn't break any of the translated chars. + $prefix = '=?' . $this->_build_params['head_charset'] . '?B?'; + $suffix = '?='; + $maxLength = 75 - strlen($prefix . $suffix) - 2; + $maxLength1stLine = $maxLength - strlen($hdr_name); + + //Base64 encode the entire string + $hdr_value = base64_encode($hdr_value); + + //This regexp will break base64-encoded text at every + //$maxLength but will not break any encoded letters. + $reg1st = "|.{0,$maxLength1stLine}[^\=][^\=]|"; + $reg2nd = "|.{0,$maxLength}[^\=][^\=]|"; + break; + case 'quoted-printable': + default: + //quoted-printable encoding has been selected + + //Generate the header using the specified params and dynamicly + //determine the maximum length of such strings. + //75 is the value specified in the RFC. The -2 is there so + //the later regexp doesn't break any of the translated chars. + $prefix = '=?' . $this->_build_params['head_charset'] . '?Q?'; + $suffix = '?='; + $maxLength = 75 - strlen($prefix . $suffix) - 2; + $maxLength1stLine = $maxLength - strlen($hdr_name); + + //Replace all special characters used by the encoder. + $search = array("=", "_", "?", " "); + $replace = array("=3D", "=5F", "=3F", "_"); + $hdr_value = str_replace($search, $replace, $hdr_value); + + //Replace all extended characters (\x80-xFF) with their + //ASCII values. + $hdr_value = preg_replace( + '#([\x80-\xFF])#e', + '"=" . strtoupper(dechex(ord("\1")))', + $hdr_value + ); + //This regexp will break QP-encoded text at every $maxLength + //but will not break any encoded letters. + $reg1st = "|(.{0,$maxLength})[^\=]|"; + $reg2nd = "|(.{0,$maxLength})[^\=]|"; + break; + } + //Begin with the regexp for the first line. + $reg = $reg1st; + $output = ""; + while ($hdr_value) { + //Split translated string at every $maxLength + //But make sure not to break any translated chars. + $found = preg_match($reg, $hdr_value, $matches); + + //After this first line, we need to use a different + //regexp for the first line. + $reg = $reg2nd; + + //Save the found part and encapsulate it in the + //prefix & suffix. Then remove the part from the + //$hdr_value variable. + if ($found){ + $part = $matches[0]; + $hdr_value = substr($hdr_value, strlen($matches[0])); + }else{ + $part = $hdr_value; + $hdr_value = ""; + } + + //RFC 2047 specifies that any split header should be seperated + //by a CRLF SPACE. + if ($output){ + $output .= "\r\n "; + } + $output .= $prefix . $part . $suffix; + } + $hdr_value = $output; + } + $input[$hdr_name] = $hdr_value; + } + + return $input; + } + + /** + * Set the object's end-of-line and define the constant if applicable + * + * @param string $eol End Of Line sequence + * @access private + */ + function _setEOL($eol) + { + $this->_eol = $eol; + if (!defined('MAIL_MIME_CRLF')) { + define('MAIL_MIME_CRLF', $this->_eol, true); + } + } + + + +} // End of class +?> diff --git a/modules/ecard/lib/mimePart.php b/modules/ecard/lib/mimePart.php new file mode 100644 index 00000000..c0050d41 --- /dev/null +++ b/modules/ecard/lib/mimePart.php @@ -0,0 +1,351 @@ + | +// +-----------------------------------------------------------------------+ + +/** +* +* Raw mime encoding class +* +* What is it? +* This class enables you to manipulate and build +* a mime email from the ground up. +* +* Why use this instead of mime.php? +* mime.php is a userfriendly api to this class for +* people who aren't interested in the internals of +* mime mail. This class however allows full control +* over the email. +* +* Eg. +* +* // Since multipart/mixed has no real body, (the body is +* // the subpart), we set the body argument to blank. +* +* $params['content_type'] = 'multipart/mixed'; +* $email = new Mail_mimePart('', $params); +* +* // Here we add a text part to the multipart we have +* // already. Assume $body contains plain text. +* +* $params['content_type'] = 'text/plain'; +* $params['encoding'] = '7bit'; +* $text = $email->addSubPart($body, $params); +* +* // Now add an attachment. Assume $attach is +* the contents of the attachment +* +* $params['content_type'] = 'application/zip'; +* $params['encoding'] = 'base64'; +* $params['disposition'] = 'attachment'; +* $params['dfilename'] = 'example.zip'; +* $attach =& $email->addSubPart($body, $params); +* +* // Now build the email. Note that the encode +* // function returns an associative array containing two +* // elements, body and headers. You will need to add extra +* // headers, (eg. Mime-Version) before sending. +* +* $email = $message->encode(); +* $email['headers'][] = 'Mime-Version: 1.0'; +* +* +* Further examples are available at http://www.phpguru.org +* +* TODO: +* - Set encode() to return the $obj->encoded if encode() +* has already been run. Unless a flag is passed to specifically +* re-build the message. +* +* @author Richard Heyes +* @version $Revision: 1.13 $ +* @package Mail +*/ + +class Mail_mimePart { + + /** + * The encoding type of this part + * @var string + */ + var $_encoding; + + /** + * An array of subparts + * @var array + */ + var $_subparts; + + /** + * The output of this part after being built + * @var string + */ + var $_encoded; + + /** + * Headers for this part + * @var array + */ + var $_headers; + + /** + * The body of this part (not encoded) + * @var string + */ + var $_body; + + /** + * Constructor. + * + * Sets up the object. + * + * @param $body - The body of the mime part if any. + * @param $params - An associative array of parameters: + * content_type - The content type for this part eg multipart/mixed + * encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable + * cid - Content ID to apply + * disposition - Content disposition, inline or attachment + * dfilename - Optional filename parameter for content disposition + * description - Content description + * charset - Character set to use + * @access public + */ + function Mail_mimePart($body = '', $params = array()) + { + if (!defined('MAIL_MIMEPART_CRLF')) { + define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE); + } + + foreach ($params as $key => $value) { + switch ($key) { + case 'content_type': + $headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : ''); + break; + + case 'encoding': + $this->_encoding = $value; + $headers['Content-Transfer-Encoding'] = $value; + break; + + case 'cid': + $headers['Content-ID'] = '<' . $value . '>'; + break; + + case 'disposition': + $headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : ''); + break; + + case 'dfilename': + if (isset($headers['Content-Disposition'])) { + $headers['Content-Disposition'] .= '; filename="' . $value . '"'; + } else { + $dfilename = $value; + } + break; + + case 'description': + $headers['Content-Description'] = $value; + break; + + case 'charset': + if (isset($headers['Content-Type'])) { + $headers['Content-Type'] .= '; charset="' . $value . '"'; + } else { + $charset = $value; + } + break; + } + } + + // Default content-type + if (!isset($headers['Content-Type'])) { + $headers['Content-Type'] = 'text/plain'; + } + + //Default encoding + if (!isset($this->_encoding)) { + $this->_encoding = '7bit'; + } + + // Assign stuff to member variables + $this->_encoded = array(); + $this->_headers = $headers; + $this->_body = $body; + } + + /** + * encode() + * + * Encodes and returns the email. Also stores + * it in the encoded member variable + * + * @return An associative array containing two elements, + * body and headers. The headers element is itself + * an indexed array. + * @access public + */ + function encode() + { + $encoded =& $this->_encoded; + + if (!empty($this->_subparts)) { + srand((double)microtime()*1000000); + $boundary = '=_' . md5(rand() . microtime()); + $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"'; + + // Add body parts to $subparts + for ($i = 0; $i < count($this->_subparts); $i++) { + $headers = array(); + $tmp = $this->_subparts[$i]->encode(); + foreach ($tmp['headers'] as $key => $value) { + $headers[] = $key . ': ' . $value; + } + $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body']; + } + + $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . + implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) . + '--' . $boundary.'--' . MAIL_MIMEPART_CRLF; + + } else { + $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF; + } + + // Add headers to $encoded + $encoded['headers'] =& $this->_headers; + + return $encoded; + } + + /** + * &addSubPart() + * + * Adds a subpart to current mime part and returns + * a reference to it + * + * @param $body The body of the subpart, if any. + * @param $params The parameters for the subpart, same + * as the $params argument for constructor. + * @return A reference to the part you just added. It is + * crucial if using multipart/* in your subparts that + * you use =& in your script when calling this function, + * otherwise you will not be able to add further subparts. + * @access public + */ + function &addSubPart($body, $params) + { + $this->_subparts[] = new Mail_mimePart($body, $params); + return $this->_subparts[count($this->_subparts) - 1]; + } + + /** + * _getEncodedData() + * + * Returns encoded data based upon encoding passed to it + * + * @param $data The data to encode. + * @param $encoding The encoding type to use, 7bit, base64, + * or quoted-printable. + * @access private + */ + function _getEncodedData($data, $encoding) + { + switch ($encoding) { + case '8bit': + case '7bit': + return $data; + break; + + case 'quoted-printable': + return $this->_quotedPrintableEncode($data); + break; + + case 'base64': + return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF)); + break; + + default: + return $data; + } + } + + /** + * quoteadPrintableEncode() + * + * Encodes data to quoted-printable standard. + * + * @param $input The data to encode + * @param $line_max Optional max line length. Should + * not be more than 76 chars + * + * @access private + */ + function _quotedPrintableEncode($input , $line_max = 76) + { + $lines = preg_split("/\r?\n/", $input); + $eol = MAIL_MIMEPART_CRLF; + $escape = '='; + $output = ''; + + while(list(, $line) = each($lines)){ + + $linlen = strlen($line); + $newline = ''; + + for ($i = 0; $i < $linlen; $i++) { + $char = substr($line, $i, 1); + $dec = ord($char); + + if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only + $char = '=20'; + + } elseif(($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only + $char = '=09'; + } elseif($dec == 9) { + ; // Do nothing if a tab. + } elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) { + $char = $escape . strtoupper(sprintf('%02s', dechex($dec))); + } + + if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted + $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay + $newline = ''; + } + $newline .= $char; + } // end of for + $output .= $newline . $eol; + } + $output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf + return $output; + } +} // End of class +?> diff --git a/modules/ecard/module.info b/modules/ecard/module.info index bc50f729..3cc27a8a 100644 --- a/modules/ecard/module.info +++ b/modules/ecard/module.info @@ -1,3 +1,4 @@ name = "E-Card" description = "Send a photo as a postcard" -version = 1 +version = 2 + diff --git a/modules/ecard/views/admin_ecards.html.php b/modules/ecard/views/admin_ecard.html.php similarity index 100% rename from modules/ecard/views/admin_ecards.html.php rename to modules/ecard/views/admin_ecard.html.php diff --git a/modules/ecard/views/ecard_block.html.php b/modules/ecard/views/ecard_block.html.php new file mode 100644 index 00000000..3f307a1d --- /dev/null +++ b/modules/ecard/views/ecard_block.html.php @@ -0,0 +1,6 @@ + +id}") ?>" id="g-send-ecard" + class="g-dialog-link g-button ui-state-default ui-corner-all"> + + + diff --git a/modules/ecard/views/ecard_email.html.php b/modules/ecard/views/ecard_email.html.php new file mode 100644 index 00000000..0d676cf5 --- /dev/null +++ b/modules/ecard/views/ecard_email.html.php @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + description): ?> + + + + + +
title) ?>
+ + abs_url() ?> + +
description)) ?>
+ + diff --git a/modules/ecard/views/ecards.html.php b/modules/ecard/views/ecards.html.php deleted file mode 100644 index e655debb..00000000 --- a/modules/ecard/views/ecards.html.php +++ /dev/null @@ -1,6 +0,0 @@ - -id}") ?>" id="g-add-ecard" - class="g-button ui-corner-all ui-icon-left ui-state-default g-dialog-link"> - - -