Patch for improved vCard support

View: New views
3 Messages — Rating Filter:   Alert me  

Patch for improved vCard support

by Vincent Touchard-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

I have developed a patch for SquirrelMail 1.5.1 as available in debian.
This patch improves the support of vCard :
 - display of vcards attached to mail with more fields (including PHOTO
and LOGO), sorted by category (Personal, Work, Miscellaneous and
Security)
 - add vcards to identities in the options of the user's account
 - attach the vcard when sending a mail

The parsing of vcards is done using the pear module Contact_Vcard_Parse
which does a better job that the "parser" that is currently in
squirrelmail.

We did it as a patch and not a plugin to have it fully integrated into the
webmail and to replace the code already written to display vcards attached
to mails.

The next step would be to save the vcards received as mail attachments
into the address book.

As it is my first patch against SquirrelMail, it may be far from being
perfect. Any comments are welcome.

Best Regards,
Vincent Touchard

--
Vincent Touchard
First Choice Internet
[squirrelmail-vcard.diff]

diff -rbNu squirrelmail/functions/db_prefs.php /usr/share/squirrelmail/functions/db_prefs.php
--- squirrelmail/functions/db_prefs.php 2006-07-09 04:01:27.000000000 +0900
+++ /usr/share/squirrelmail/functions/db_prefs.php 2008-11-07 17:14:26.000000000 +0900
@@ -538,5 +538,45 @@
     return getPref($data_dir, $username, $key);
 }
 
+/**
+ * Writes the vCard
+ * @ignore
+ */
+function setVcard($data_dir, $username, $number, $tmp_file) {
+    if ($number == "d") {
+        $key = '___vcard___';
+    } else {
+        $key = sprintf('___vcar%s___', $number);
+ }
+
+ /* Open the file for reading, or else display an error to the user. */
+ if(!$file = @fopen($tmp_file, 'r')) {
+ logout_error( sprintf( _("vCard file, %s, could not be opened. Contact your system administrator to resolve this issue."), $tmp_file) );
+ exit;
+ }
+ if ( @fread($file, $value) == strlen($value) ) {
+ logout_error( sprintf( _("vCard file, %s, could not be written. Contact your system administrator to resolve this issue.") , $tmp_file));
+ exit;
+ }
+ fclose($file);
+
+
+ setPref($data_dir, $username, $key, $value);
+    return;
+}
+
+/**
+ * Gets the vCard
+ * @ignore
+ */
+function getVcard($data_dir, $username, $number) {
+    if ($number == "d") {
+        $key = '___vcard___';
+    } else {
+        $key = sprintf('___vcar%d___', $number);
+    }
+    return getPref($data_dir, $username, $key);
+}
+
 // vim: et ts=4
 ?>
\ No newline at end of file
diff -rbNu squirrelmail/functions/file_prefs.php /usr/share/squirrelmail/functions/file_prefs.php
--- squirrelmail/functions/file_prefs.php 2006-07-09 04:01:27.000000000 +0900
+++ /usr/share/squirrelmail/functions/file_prefs.php 2008-11-10 09:49:38.000000000 +0900
@@ -311,5 +311,52 @@
     return $sig;
 }
 
+/**
+ * Write the User vCard.
+ * @param string $data_dir data directory
+ * @param string $username user name
+ * @param integer $number identity number.
+ * @param string $tmp_file temporary file where the vcard is stored after upload
+ */
+function setVcard($data_dir, $username, $number, $tmp_file) {
+    $filename = getHashedFile($username, $data_dir, "$username.vcar$number");
+
+ if ($tmp_file == '') {
+ @unlink($filename);
+ } else {
+ if (! @copy($tmp_file, $filename) ) {
+   logout_error( sprintf( _("vCard file, %s, could not be copied from temporary file, %s. Contact your system administrator to resolve this issue."), $filename, $tmp_file) );
+   exit;
+ }
+ @unlink($tmp_file);
+ @chmod($filename, 0600);
+ }
+}
+
+/**
+ * Get the vCard.
+ * @param string $data_dir data directory
+ * @param string $username user name
+ * @param integer $number (since 1.2.5) identity number
+ * @return string signature
+ */
+function getVcard($data_dir, $username, $number) {
+    $filename = getHashedFile($username, $data_dir, "$username.vcar$number");
+    $vcard = '';
+    if (file_exists($filename)) {
+        /* Open the file, or else display an error to the user. */
+        if(!$file = @fopen($filename, 'r'))
+        {
+            logout_error( sprintf( _("vCard file, %s, could not be opened. Contact your system administrator to resolve this issue."), $filename) );
+            exit;
+        }
+        while (!feof($file)) {
+            $vcard .= fgets($file, 1024);
+        }
+        fclose($file);
+    }
+    return $vcard;
+}
+
 // vim: et ts=4
 ?>
\ No newline at end of file
diff -rbNu squirrelmail/functions/identity.php /usr/share/squirrelmail/functions/identity.php
--- squirrelmail/functions/identity.php 2006-07-09 04:01:27.000000000 +0900
+++ /usr/share/squirrelmail/functions/identity.php 2008-11-14 16:11:43.000000000 +0900
@@ -88,6 +88,7 @@
         removePref($data_dir, $username, 'email_address' . $i);
         removePref($data_dir, $username, 'reply_to' . $i);
         setSig($data_dir, $username, $i, '');
+        setVcard($data_dir, $username, $i, '');
     }
 
     foreach($identities as $id=>$ident) {
@@ -104,6 +105,15 @@
             setSig($data_dir, $username, $key, $ident['signature']);
         }
 
+ $vcard_file = check_vcard($id);
+ if ($vcard_file != FALSE) {
+ if ($id === 0) {
+ setVcard($data_dir, $username, 'd', $vcard_file);
+ } else {
+ setVcard($data_dir, $username, $key, $vcard_file);
+ }
+ }
+
     }
 
     setPref($data_dir, $username, 'identities', $cnt);
@@ -220,4 +230,63 @@
     }
 }
 
+/*
+ * Test if the vCard was correctly uploaded and if it is tagged as a being a vCard (text/x-vcard)
+ *
+ * mostly taken from
+ * plugins/abook_import_export/address_book_import.php
+ *
+ * @param  int    identity id
+ * @return mixte  FALSE if the file was not correctly uploaded or is not a vCard, otherwise the name of
+ *                the tempory file where the vCard related to the "identity id" is store
+ */
+function check_vcard($id) {
+    $vcards = $_FILES['newidentities'];
+
+    if ($vcards['tmp_name'][$id]['vcard'] == '' || $vcards['size'][$id]['vcard'] == 0) {
+        // Detect PHP 4.2.0+ upload error codes (http://www.php.net/features.file-upload.errors)
+        $upload_error = "";
+        if (isset($vcards['error'][$id]['vcard']) && $vcards['error'][$id]['vcard']!=0 ) {
+            switch($vcards['error'][$id]['vcard']) {
+            case 1:
+                $upload_error = _("The uploaded file exceeds PHP upload_max_filesize limits.");
+                break;
+            case 2:
+                $upload_error = _("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML.");
+                break;
+            case 3:
+                $upload_error = _("The uploaded file was only partially uploaded.");
+                break;
+            case 4:
+                break;
+            case 6:
+                $upload_error = _("Missing a temporary directory.");
+                break;
+            case 7:
+                $upload_error = _("Failed to write file to disk.");
+                break;
+            case 8:
+                // File upload stopped by extension. 'security library' is more user friendly.
+                $upload_error = _("File upload stopped by security library.");
+                break;
+            default:
+                $upload_error = _("Unknown upload error.");
+                break;
+            }
+ }
+ if (!empty($upload_error)) {
+ plain_error_message( $upload_error, $color);
+ }
+ return FALSE;
+ }
+ elseif (isset($vcards['type'][$id]['vcard']) && $vcards['type'][$id]['vcard'] != 'text/x-vcard') {
+ $upload_error = _("Please upload a vCard.");
+ plain_error_message( $upload_error, $color);
+ return FALSE;
+ }
+ else {
+ return $vcards['tmp_name'][$id]['vcard'];
+ }
+}
+
 ?>
\ No newline at end of file
diff -rbNu squirrelmail/functions/imap_messages.php /usr/share/squirrelmail/functions/imap_messages.php
--- squirrelmail/functions/imap_messages.php 2006-07-09 04:01:27.000000000 +0900
+++ /usr/share/squirrelmail/functions/imap_messages.php 2008-11-05 19:04:53.000000000 +0900
@@ -923,7 +923,7 @@
     if ($read) {
         if (preg_match('/.+FLAGS\s\((.*)\)\s/AUi',$read[0],$regs)) {
             if (trim($regs[1])) {
-                $flags = preg_split('/ /', $regs[1],-1,'PREG_SPLIT_NI_EMPTY');
+                $flags = preg_split('/ /', $regs[1],-1,PREG_SPLIT_NO_EMPTY);
             }
         }
     } else {
diff -rbNu squirrelmail/functions/options.php /usr/share/squirrelmail/functions/options.php
--- squirrelmail/functions/options.php 2006-07-09 04:01:27.000000000 +0900
+++ /usr/share/squirrelmail/functions/options.php 2008-11-17 09:21:01.000000000 +0900
@@ -26,6 +26,7 @@
 define('SMOPT_TYPE_HIDDEN', 6);
 define('SMOPT_TYPE_COMMENT', 7);
 define('SMOPT_TYPE_FLDRLIST', 8);
+define('SMOPT_TYPE_FILE', 9);
 
 /* Define constants for the options refresh levels. */
 define('SMOPT_REFRESH_NONE', 0);
@@ -314,6 +315,9 @@
             case SMOPT_TYPE_FLDRLIST:
                 $result = $this->createWidget_FolderList();
                 break;
+            case SMOPT_TYPE_FILE:
+                $result = $this->createWidget_File();
+                break;
             default:
                $result = '<font color="' . $color[2] . '">'
                        . sprintf(_("Option Type '%s' Not Found"), $this->type)
@@ -539,6 +543,19 @@
     }
 
     /**
+     * Creates file field
+     * @return string html formated file input field
+     */
+    function createWidget_File() {
+        $result = '<input type="file" name="new_' . $this->name
+                . '" />';
+        $result .= '<input type="hidden" name="MAX_FILE_SIZE'
+                . '" value="' . '500000000'
+                . '" />';
+        return ($result);
+    }
+
+    /**
      * Creates comment
      * @return string comment
      */
diff -rbNu squirrelmail/functions/vcard.php /usr/share/squirrelmail/functions/vcard.php
--- squirrelmail/functions/vcard.php 1970-01-01 09:00:00.000000000 +0900
+++ /usr/share/squirrelmail/functions/vcard.php 2008-11-17 09:23:58.000000000 +0900
@@ -0,0 +1,323 @@
+<?php
+
+/*
+ * Vincent Touchard
+ * 2008/11/12
+ *
+ * set of a functions to render a vcard
+ *
+ * You can use it calling vcard_fromFile or vcard_fromText
+ *
+ * Needs the pear class Contact_Vcard_Parse
+ */
+
+require_once 'Contact_Vcard_Parse.php';
+
+/*
+ * display each field
+ *
+ * name     string   name of the field
+ * value    array    values to display
+ * url      boolean  is the value is an url
+ * charset  string   charset of the text to render
+ */
+function vcard_format_text($name, $value, $url = 0, $charset = '') {
+ $ret = "";
+ foreach ($value as $t) {
+ if (isset($t[0]) && $t[0]) {
+ $text = $t[0];
+
+ // convert to utf-8 if needed
+ if (!empty($charset)) {
+ $res = iconv($charset, "UTF-8", $text);
+ // check if conversion didn't fail - keep the unconverted text if it failed
+ if($res != FALSE) {
+ $text = $res;
+ }
+ }
+
+ $ret .= ', ' . ($url ? '<a href="' . $text . '" >' . $text . '</a>' : $text);
+ }
+ }
+ return '  <tr><td align="right" valign="top" style="width:15%">' . $name . ':</td>' .
+ '<td>' . nl2br(ltrim($ret, ", ")) . "</td></tr>\n";
+}
+
+/*
+ * Generate a table for each topic
+ *
+ * name        string  name of the topic
+ * fields      array   fields to display
+ * vcard_data  array   data extracted from the vcard
+ */
+function vcard_data_to_table($name, $fields, $vcard_data) {
+
+ echo '<table border="0" cellpadding="2" cellspacing="0" align="center" style="width:100%">' . "\n" .
+ '  <tr><td colspan="2"><b>' . $name . '</b></td></tr>' . "\n";
+
+ // read all attributes with the wanted keyword (TEL, PHOTO, ...)
+ foreach ($fields as $k => $v) {
+ if (isset($vcard_data[0][$k]) && $vcard_data[0][$k]) {
+
+ // read all the attributes with the same keyword
+ foreach ($vcard_data[0][$k] as $values) {
+
+ // go to all the wanted attributes with the same keyword
+ foreach ($v as $w) {
+
+ // is an url?
+ $url = isset($values['param']['VALUE']) && $values['param']['VALUE'][0] == 'URL' || $k == 'URL';
+
+ // which charset ?
+ $charset = isset($values['param']['CHARSET'][0]) ? $values['param']['CHARSET'][0] : '';
+
+ // if a parameter is given, keep only if it matches
+ if (isset($w["param"]) && $w["param"][1] != "DEFAULT" && !empty($values['param'][$w["param"][0]])) {
+ foreach ($values['param'][$w["param"][0]] as $param) {
+ if ($param == $w["param"][1]) {
+ echo vcard_format_text($w["name"], $values['value'], $url, $charset);
+ }
+ }
+ } elseif (isset($w["param"]) && $w["param"][1] == "DEFAULT" && empty($values['param'][$w["param"][0]])) {
+ echo vcard_format_text($w["name"], $values['value'], $url, $charset);
+
+ // else, print it
+ } elseif (!isset($w["param"])) {
+ echo vcard_format_text($w["name"], $values['value'], $url, $charset);
+ }
+ }
+ }
+ }
+ }
+ echo "</table>\n";
+}
+
+/*
+ * Display an image
+ *
+ * Used by PHOTO and LOGO keywords
+ *
+ * Can handle base64 images and url ones
+ *
+ *
+ */
+function vcard_display_image($image_info) {
+ $data = $image_info[0]['value'][0][0];
+
+ // default values
+ $x = 120;
+ $y = 160;
+
+ // check if it is an URL or not
+ if (!isset($image_info[0]['param']['VALUE']) || $image_info[0]['param']['VALUE'][0] != 'URL') {
+
+ // find size
+ $im = imagecreatefromstring(base64_decode($data));
+ if ($im != FALSE) {
+ $x = imagesx($im);
+ $y = imagesy($im);
+
+ $ratio_x = $x / 160.0;
+ $ratio_y = $y / 160.0;
+
+ // reduce size to stay in the limit of 160x160
+ if ($ratio_x > 1.0 || $ratio_y > 1.0) {
+ $ratio = max($ratio_x, $ratio_y);
+ $x = $x / $ratio;
+ $y = $y / $ratio;
+ }
+
+ }
+
+ $data = "data:image/jpg;base64," . $data;
+ } else {
+ // find size
+ $a = getimagesize($data);
+ $x = $a[0];
+ $y = $a[1];
+
+ $ratio_x = $x / 160.0;
+ $ratio_y = $y / 160.0;
+
+ // reduce size to stay in the limit of 160x160
+ if ($ratio_x > 1.0 || $ratio_y > 1.0) {
+ $ratio = max($ratio_x, $ratio_y);
+ $x = $x / $ratio;
+ $y = $y / $ratio;
+ }
+ }
+ return "<img src=\"" . $data . "\" height=\"$y\" width=\"$x\" \>";
+}
+
+/*
+ * Generate the vcard display
+ *
+ * cardinfo  array  nested array containing the vcard data
+ */
+function vcard_generate_vcard($cardinfo) {
+ echo '<table width="100%" border="0" cellspacing="0" cellpadding="2" align="center">' . "\n";
+
+
+ $fn = $cardinfo[0]['FN'][0]['value'][0][0];
+ if (isset($cardinfo[0]['FN'][0]['param']['CHARSET'][0])) {
+ $fn2 = iconv($cardinfo[0]['FN'][0]['param']['CHARSET'][0], "UTF-8", $fn);
+ // if iconv failed, keep the old text
+ if ($fn2 != FALSE) {
+ $fn = $fn2;
+ }
+ }
+
+ echo '<tr><td><div style="text-align: center;"><b>' . $fn . '</b></div></td></tr>';
+
+?>
+
+<!-- Personal Data -->
+<tr><td>
+
+<?php
+ $ShowValues = array(
+ 'N' =>             array(array("name" => _("Name"))),
+ 'NICKNAME' =>             array(array("name" => _("Nickname"))),
+ 'EMAIL' =>         array(array("name" => _("E-mail"), "param" => array("TYPE", "DEFAULT")),
+ array("name" => _("E-mail"), "param" => array("TYPE", "INTERNET")),
+ array("name" => _("E-mail"), "param" => array("TYPE", "HOME"))),
+ 'TEL' =>           array(array("name" => _("Phone"), "param" => array("TYPE", "DEFAULT")),
+ array("name" => _("Phone"), "param" => array("TYPE", "HOME")),
+ array("name" => _("Cell Phone"), "param" => array("TYPE", "CELL"))),
+ 'LABEL' =>         array(array("name" => _("Address"), "param" => array("TYPE", "DEFAULT")),
+ array("name" => _("Address"), "param" => array("TYPE", "DOM")),
+ array("name" => _("Address"), "param" => array("TYPE", "HOME"))),
+ 'ADR' =>         array(array("name" => _("Address"), "param" => array("TYPE", "DEFAULT")),
+ array("name" => _("Address"), "param" => array("TYPE", "HOME"))),
+ 'BDAY' => array(array("name" => _("Birthday")))
+ );
+
+ vcard_data_to_table("Personal Data", $ShowValues, $cardinfo);
+
+?>
+
+</td>
+<td>
+
+<?php
+ // display only the first photo
+ if (isset($cardinfo[0]['PHOTO']) && $cardinfo[0]['PHOTO'])     {
+ echo vcard_display_image($cardinfo[0]['PHOTO']);
+ }
+?>
+
+</td></tr>
+<!-- Personal Data -->
+
+<tr><td colspan="2"><hr /></td></tr>
+
+<!-- Work -->
+<tr><td>
+
+<?php
+ $ShowValues = array(
+ 'ORG' =>             array(array("name" => _("Organisation"))),
+ 'TITLE' =>             array(array("name" => _("Title"))),
+ 'ROLE' =>             array(array("name" => _("Role"))),
+ 'EMAIL' =>         array(array("name" => _("E-mail"), "param" => array("TYPE", "WORK"))),
+ 'TEL' =>           array(array("name" => _("Phone"), "param" => array("TYPE", "WORK")),
+ array("name" => _("Fax"), "param" => array("TYPE", "FAX"))),
+ 'LABEL' =>         array(array("name" => _("Address"), "param" => array("TYPE", "WORK"))),
+ 'ADR' =>         array(array("name" => _("Address"), "param" => array("TYPE", "WORK")))
+ );
+
+ vcard_data_to_table("Work", $ShowValues, $cardinfo);
+
+?>
+
+</td>
+<td>
+
+<?php
+ // display only the first logo
+ if (isset($cardinfo[0]['LOGO']) && $cardinfo[0]['LOGO'])     {
+ echo vcard_display_image($cardinfo[0]['LOGO']);
+ }
+?>
+
+</td></tr>
+<!-- Work -->
+
+<tr><td colspan="2"><hr /></td></tr>
+
+<!-- Miscelleaneous -->
+<tr><td>
+
+<?php
+ $ShowValues = array(
+ 'NOTE' =>          array(array("name" => _("Note"))),
+ 'URL' =>          array(array("name" => _("Website")))
+ );
+
+ vcard_data_to_table("Miscelleaneous", $ShowValues, $cardinfo);
+?>
+
+</td></tr>
+<!-- Miscelleaneous -->
+
+<tr><td colspan="2"><hr /></td></tr>
+
+<!-- Security -->
+<tr><td>
+
+<?php
+ $ShowValues = array(
+ 'KEY' =>           array(array("name" => _("PGP Public Key"), "param" => array("TYPE", "PGP")),
+ array("name" => _("X509 Public Key"), "param" => array("TYPE", "X509"))),
+ );
+
+ vcard_data_to_table("Security", $ShowValues, $cardinfo);
+?>
+
+</td></tr>
+<!-- Security -->
+
+</table>
+<?php
+
+}
+
+/*
+ * Function to extract some basic information from the vcard
+ *
+ * returns an array with the information extracted
+ */
+function vcard_extractBasicInfo($cardinfo) {
+ // Key "N", mandatory in all current vcard version (2.1 and 3.0)
+ $info['firstname'] = $cardinfo[0]['N'][0]['value'][0][0];
+ $info['lastname'] = $cardinfo[0]['N'][0]['value'][1][0];
+
+ // Key "Nickname", optional
+ if (isset($cardinfo[0]['NICKNAME'])) {
+ $info['nickname'] = $cardinfo[0]['NICKNAME'][0]['value'][0][0];
+ }
+ return $info;
+}
+
+/*
+ * Display a vcard taking the data in a file
+ */
+function vcard_fromFile($file) {
+ $parse = new Contact_Vcard_Parse();
+ $cardinfo = $parse->fromFile($file);
+//print_r($cardinfo[0]);
+ vcard_generate_vcard($cardinfo);
+ return vcard_extractBasicInfo($cardinfo);
+}
+
+/*
+ * Display a vcard taking the data from the text given as an argument
+ */
+function vcard_fromText($text) {
+ $parse = new Contact_Vcard_Parse();
+ $cardinfo = $parse->fromText($text);
+ vcard_generate_vcard($cardinfo);
+ return vcard_extractBasicInfo($cardinfo);
+}
+
+?>
diff -rbNu squirrelmail/include/load_prefs.php /usr/share/squirrelmail/include/load_prefs.php
--- squirrelmail/include/load_prefs.php 2007-05-10 20:24:16.000000000 +0900
+++ /usr/share/squirrelmail/include/load_prefs.php 2008-11-07 17:17:51.000000000 +0900
@@ -180,6 +180,7 @@
 $editor_height = getPref($data_dir, $username, 'editor_height', 20 );
 $use_signature = getPref($data_dir, $username, 'use_signature', SMPREF_OFF );
 $prefix_sig = getPref($data_dir, $username, 'prefix_sig');
+$use_vcard = getPref($data_dir, $username, 'use_vcard', SMPREF_OFF );
 
 /* Load timezone preferences */
 $timezone = getPref($data_dir, $username, 'timezone', SMPREF_NONE );
diff -rbNu squirrelmail/include/options/personal.php /usr/share/squirrelmail/include/options/personal.php
--- squirrelmail/include/options/personal.php 2006-07-09 04:04:05.000000000 +0900
+++ /usr/share/squirrelmail/include/options/personal.php 2008-11-17 09:25:50.000000000 +0900
@@ -117,6 +117,29 @@
         'save'    => 'save_option_signature'
     );
 
+ $optvals[SMOPT_GRP_CONTACT][] = array(
+ 'name'    => 'vcard',
+ 'caption' => _("Upload vCard"),
+ 'type'    => SMOPT_TYPE_FILE,
+ 'refresh' => SMOPT_REFRESH_NONE,
+ 'value'   => '10485760',
+ 'save'    => 'save_option_vcard'
+ );
+
+    $filename = getHashedFile($username, $data_dir, "$username.vcard");
+ if (file_exists($filename)) {
+ $view_vard_link_value = '<a href="view_personal_vcard.php">'
+ . _("View vCard")
+ . '</a> ';
+ $optvals[SMOPT_GRP_CONTACT][] = array(
+ 'name'    => 'vcard',
+ 'caption' => _("Current vCard"),
+ 'type'    => SMOPT_TYPE_COMMENT,
+ 'refresh' => SMOPT_REFRESH_NONE,
+ 'comment' =>  $view_vard_link_value
+ );
+ }
+
     if ($edit_identity) {
         $identities_link_value = '<a href="options_identities.php">'
                                . _("Edit Advanced Identities")
@@ -237,6 +260,13 @@
         'refresh' => SMOPT_REFRESH_NONE
     );
 
+    $optvals[SMOPT_GRP_SIG][] = array(
+        'name'    => 'use_vcard',
+        'caption' => _("Use vCard"),
+        'type'    => SMOPT_TYPE_BOOLEAN,
+        'refresh' => SMOPT_REFRESH_NONE
+    );
+
     /* Assemble all this together and return it as our result. */
     $result = array(
         'grps' => $optgrps,
@@ -257,4 +287,59 @@
     setSig($data_dir, $username, 'g', $option->new_value);
 }
 
+/**
+ * Saves the vcard option.
+ *
+ * mostly taken from
+ * plugins/abook_import_export/address_book_import.php
+ *
+ */
+function save_option_vcard($option) {
+    global $data_dir, $username;
+
+    $vcard = $_FILES['new_' . $option->name];
+
+    if ($vcard['tmp_name'] == '' || $vcard['size'] == 0) {
+        // Detect PHP 4.2.0+ upload error codes (http://www.php.net/features.file-upload.errors)
+        $upload_error = _("Please select a file for uploading.");
+        if (isset($vcard['error']) && $vcard['error']!=0 ) {
+            switch($vcard['error']) {
+            case 1:
+                $upload_error = _("The uploaded file exceeds PHP upload_max_filesize limits.");
+                break;
+            case 2:
+                $upload_error = _("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML.");
+                break;
+            case 3:
+                $upload_error = _("The uploaded file was only partially uploaded.");
+                break;
+            case 4:
+                $upload_error = _("No file was uploaded.");
+                break;
+            case 6:
+                $upload_error = _("Missing a temporary directory.");
+                break;
+            case 7:
+                $upload_error = _("Failed to write file to disk.");
+                break;
+            case 8:
+                // File upload stopped by extension. 'security library' is more user friendly.
+                $upload_error = _("File upload stopped by security library.");
+                break;
+            default:
+                $upload_error = _("Unknown upload error.");
+                break;
+            }
+        }
+ plain_error_message( $upload_error, $color);
+ }
+ elseif (isset($vcard['type']) && $vcard['type'] != 'text/x-vcard') {
+ $upload_error = _("Please upload a vCard.");
+ plain_error_message( $upload_error, $color);
+ }
+ else {
+    setVcard($data_dir, $username, 'd', $vcard['tmp_name']);
+ }
+}
+
 ?>
\ No newline at end of file
diff -rbNu squirrelmail/src/compose.php /usr/share/squirrelmail/src/compose.php
--- squirrelmail/src/compose.php 2007-05-10 20:22:51.000000000 +0900
+++ /usr/share/squirrelmail/src/compose.php 2008-11-10 16:29:11.000000000 +0900
@@ -80,6 +80,7 @@
 sqgetGlobalVar('mail_sent',$mail_sent, $SQ_GLOBAL);
 sqgetGlobalVar('passed_id',$passed_id, $SQ_GLOBAL);
 sqgetGlobalVar('passed_ent_id',$passed_ent_id, $SQ_GLOBAL);
+sqgetGlobalVar('usevcard',$usevcard, $SQ_GLOBAL);
 
 sqgetGlobalVar('attach',$attach, SQ_POST);
 sqgetGlobalVar('draft',$draft, SQ_POST);
@@ -333,7 +334,7 @@
             'passed_body','use_signature','signature','attachments','subject','newmail',
             'send_to_bcc', 'passed_id', 'mailbox', 'from_htmladdr_search', 'identity',
             'draft_id', 'delete_draft', 'mailprio', 'edit_as_new', 'compose_messsages',
-            'composesession', 'request_mdn', 'request_dr');
+            'composesession', 'request_mdn', 'request_dr', 'usevcard');
 
         foreach ($compo_var_list as $var) {
             if ( isset($session_expired_post[$var]) && !isset($$var) ) {
@@ -701,6 +702,8 @@
     if (isset($subject)) {
         $values['subject'] = $subject;
     }
+
+ $usevcard = $use_vcard;
     showInputForm($session, $values);
 }
 
@@ -1400,7 +1403,7 @@
     global $use_javascript_addr_book, $save_as_draft,
         $default_use_priority, $mailprio, $default_use_mdn,
         $request_mdn, $request_dr,
-        $data_dir, $username;
+        $data_dir, $username, $usevcard;
 
     echo '   <tr>' . "\n" .
         '      <td></td>' . "\n" .
@@ -1430,6 +1433,7 @@
         '      <td></td>' . "\n" .
         '      <td>' . "\n" .
         '         <input type="submit" name="sigappend" value="' . _("Signature") . '" />' . "\n";
+ echo addCheckBox('usevcard',  $usevcard  == '1', '1'). _("Use vCard");
     if ($use_javascript_addr_book) {
         echo "         <script type=\"text/javascript\"><!--\n document.write(\"".
             "            <input type=button value=\\\""._("Addresses").
@@ -1549,6 +1553,7 @@
         $request_mdn, $request_dr, $default_charset, $color, $useSendmail,
         $domain, $action, $default_move_to_sent, $move_to_sent;
     global $imapServerAddress, $imapPort, $sent_folder, $key;
+ global $usevcard;
 
     $rfc822_header = $composeMessage->rfc822_header;
 
@@ -1570,6 +1575,19 @@
     }
     $composeMessage->setBody($body);
 
+ if (isset($usevcard) && $usevcard) {
+ if ($identity == 0) {
+ $vcard_path = getHashedFile($username, $data_dir, "$username.vcard");
+ } else {
+ $vcard_path = getHashedFile($username, $data_dir, "$username.vcar$identity");
+ }
+ if (file_exists($vcard_path)) {
+ $vcard_attached = tempnam(getHashedDir($username, $attachment_dir), $username . ".vcf");
+ copy($vcard_path, $vcard_attached);
+ $composeMessage->initAttachment('text/x-vcard', $username . ".vcf", $vcard_attached);
+ }
+    }
+
     if (ereg("^([^@%/]+)[@%/](.+)$", $username, $usernamedata)) {
         $popuser = $usernamedata[1];
         $domain  = $usernamedata[2];
diff -rbNu squirrelmail/src/options_identities.php /usr/share/squirrelmail/src/options_identities.php
--- squirrelmail/src/options_identities.php 2006-07-09 04:05:34.000000000 +0900
+++ /usr/share/squirrelmail/src/options_identities.php 2008-11-14 11:42:02.000000000 +0900
@@ -65,7 +65,7 @@
 do_hook('options_identities_top');
 
 $td_str = '';
-$td_str .= '<form name="f" action="options_identities.php" method="post"><br />' . "\n";
+$td_str .= '<form name="f" action="options_identities.php" method="post" enctype="multipart/form-data"><br />' . "\n";
 $td_str .= '<table border="0" cellspacing="0" cellpadding="0" width="100%">' . "\n";
 $cnt = count($identities);
 foreach( $identities as $iKey=>$ident ) {
@@ -128,7 +128,7 @@
  * @since 1.5.1 and 1.4.5 (was called ShowTableInfo() in 1.1.3-1.4.4 and 1.5.0)
  */
 function ShowIdentityInfo($title, $identity, $id ) {
-    global $color;
+    global $color, $username, $data_dir;
 
     if (empty($identity['full_name']) && empty($identity['email_address']) && empty($identity['reply_to']) && empty($identity['signature'])) {
         $bg = '';
@@ -150,6 +150,21 @@
     $return_str .= sti_input( _("E-Mail Address") , sprintf($name, $id, 'email_address'), $identity['email_address'], $bg);
     $return_str .= sti_input( _("Reply To"), sprintf($name, $id, 'reply_to'), $identity['reply_to'], $bg);
     $return_str .= sti_textarea( _("Signature"), sprintf($name, $id, 'signature'), $identity['signature'], $bg);
+    $return_str .= sti_file( _("Upload vCard"), sprintf($name, $id, 'vcard'), $bg);
+
+ if ($id == 0) {
+ $filename = getHashedFile($username, $data_dir, "$username.vcard");
+ } else {
+ $filename = getHashedFile($username, $data_dir, "$username.vcar" . $id);
+ }
+ if (file_exists($filename)) {
+ $return_str .= '';
+ $return_str .= '<tr' . $bg . ">\n";
+ $return_str .= '  <td style="white-space: nowrap;text-align:right;">' . _("Current vCard") . ' </td>' . "\n";
+ $return_str .= '  <td> <a href="view_personal_vcard.php?identity=' . $id .'">' . _("View vCard") . '</a> </td>' . "\n";
+ $return_str .= '</tr>';
+ }
+
     $return_str .= concat_hook_function('options_identities_table', array($bg, $empty, $id));
     $return_str .= '<tr' . $bg . '> ' . "\n";
     $return_str .= '  <td>   </td>' . "\n";
@@ -221,4 +236,24 @@
 
 }
 
+/**
+ * Creates html formated table row with upload file input field
+ * @param string $title Name displayed next to input field
+ * @param string $name Name of textarea field
+ * @param string $bgcolor html attributes added to row element (tr)
+ * @return string html formated table row with textarea
+ * @todo check right-to-left language issues
+ * @access private
+ */
+function sti_file( $title, $name, $bgcolor ) {
+    $str = '';
+    $str .= '<tr' . $bgcolor . ">\n";
+    $str .= '  <td style="white-space: nowrap;text-align:right;">' . $title . ' </td>' . "\n";
+ $str .= '  <td> <input type="file" name="' . $name . '" /> </td>' . "\n";
+    $str .= '</tr>';
+
+    return $str;
+
+}
+
 ?>
\ No newline at end of file
diff -rbNu squirrelmail/src/options.php /usr/share/squirrelmail/src/options.php
--- squirrelmail/src/options.php 2006-07-09 04:05:34.000000000 +0900
+++ /usr/share/squirrelmail/src/options.php 2008-11-13 09:38:22.000000000 +0900
@@ -58,7 +58,8 @@
                . "new_value = '$option->new_value'\n";
             echo "<br />";
             */
-            if ($option->changed()) {
+ // error = 4 == file not uploaded
+ if ($option->changed() || isset($_FILES['new_'.$option->name]['error']) && $_FILES['new_'.$option->name]['error'] != 4) {
                 $option->save();
                 $max_refresh = max($max_refresh, $option->refresh_level);
             }
@@ -425,7 +426,7 @@
 /* If we are not looking at the main option page, display the page here. */
 /*************************************************************************/
 } else {
-    echo addForm('options.php', 'post', 'f')
+    echo addForm('options.php', 'post', 'f', 'multipart/form-data')
        . create_optpage_element($optpage)
        . create_optmode_element(SMOPT_MODE_SUBMIT)
        . html_tag( 'table', '', '', '', 'width="100%" cellpadding="2" cellspacing="0" border="0"' ) . "\n";
diff -rbNu squirrelmail/src/vcard.php /usr/share/squirrelmail/src/vcard.php
--- squirrelmail/src/vcard.php 2006-07-09 04:05:34.000000000 +0900
+++ /usr/share/squirrelmail/src/vcard.php 2008-11-14 15:41:56.000000000 +0900
@@ -21,6 +21,7 @@
 include_once(SM_PATH . 'include/validate.php');
 require_once(SM_PATH . 'functions/mime.php');
 require_once(SM_PATH . 'functions/url_parser.php');
+require_once(SM_PATH . 'functions/vcard.php');
 
 /* globals */
 sqgetGlobalVar('username', $username, SQ_SESSION);
@@ -40,7 +41,7 @@
 
 echo '<br /><table width="100%" border="0" cellspacing="0" cellpadding="2" ' .
         'align="center">' . "\n" .
-     '<tr><td bgcolor="' . $color[0] . '"><b><div style="text-align: center;">' .
+     '<tr><td colspan="2" bgcolor="' . $color[0] . '"><b><div style="text-align: center;">' .
      _("Viewing a Business Card") . " - ";
 
 $msg_url = 'read_body.php?mailbox='.urlencode($mailbox).
@@ -58,86 +59,14 @@
 
 $vcard = mime_fetch_body($imapConnection, $passed_id, $ent_id);
 $vcard = decodeBody($vcard, $entity_vcard->header->encoding);
-$vcard = explode ("\n",$vcard);
-foreach ($vcard as $l) {
-    $k = substr($l, 0, strpos($l, ':'));
-    $v = substr($l, strpos($l, ':') + 1);
-    $attributes = explode(';', $k);
-    $k = strtolower(array_shift($attributes));
-    foreach ($attributes as $attr)     {
-        if ($attr == 'quoted-printable')
-        $v = quoted_printable_decode($v);
-        else
-            $k .= ';' . strtolower($attr);
-    }
-
-    $v = str_replace(';', "\n", $v);
-    $vcard_nice[$k] = $v;
-}
-
-if ($vcard_nice['version'] == '2.1') {
-    // get firstname and lastname for sm addressbook
-    $vcard_nice['firstname'] = substr($vcard_nice['n'],
-    strpos($vcard_nice['n'], "\n") + 1, strlen($vcard_nice['n']));
-    $vcard_nice['lastname'] = substr($vcard_nice['n'], 0,
-        strpos($vcard_nice['n'], "\n"));
-    // workaround for Outlook, should be fixed in a better way,
-    // maybe in new 'vCard' class.
-    if (isset($vcard_nice['email;pref;internet'])) {
-       $vcard_nice['email;internet'] = $vcard_nice['email;pref;internet'];
-    }
-} else {
-    echo '<tr><td align="center">' .
-         sprintf(_("vCard Version %s is not supported. Some information might not be converted correctly."),
-                 htmlspecialchars($vcard_nice['version'])) .
-         "</td></tr>\n";
-    $vcard_nice['firstname'] = '';
-    $vcard_nice['lastname'] = '';
-}
-
-foreach ($vcard_nice as $k => $v) {
-    $v = htmlspecialchars($v);
-    $v = trim($v);
-    $vcard_safe[$k] = trim(nl2br($v));
-}
-
-$ShowValues = array(
-    'fn' =>             _("Name"),
-    'title' =>          _("Title"),
-    'email;internet' => _("E-mail"),
-    'url' =>            _("Web Page"),
-    'org' =>            _("Organization / Department"),
-    'adr' =>            _("Address"),
-    'tel;work' =>       _("Work Phone"),
-    'tel;home' =>       _("Home Phone"),
-    'tel;cell' =>       _("Cellular Phone"),
-    'tel;fax' =>        _("Fax"),
-    'note' =>           _("Note"));
-
-echo '<tr><td><br />' .
-     '<table border="0" cellpadding="2" cellspacing="0" align="center">' . "\n";
-
-if (isset($vcard_safe['email;internet'])) {
-    $vcard_safe['email;internet'] = makeComposeLink('src/compose.php?send_to='.urlencode($vcard_safe['email;internet']),
-        $vcard_safe['email;internet']);
-}
-
-if (isset($vcard_safe['url'])) {
-    $vcard_safe['url'] = '<a href="' . $vcard_safe['url'] . '">' .
-        $vcard_safe['url'] . '</a>';
-}
-
-foreach ($ShowValues as $k => $v) {
-    if (isset($vcard_safe[$k]) && $vcard_safe[$k])     {
-        echo "<tr><td align=\"right\" valign=\"top\"><b>$v:</b></td><td>" .
-            $vcard_safe[$k] . "</td><tr>\n";
-    }
-}
 
+echo "<tr><td><br />";
+$vcard_safe = vcard_fromText($vcard);
+echo "</td></tr>";
 ?>
-</table>
-<br />
-</td></tr></table>
+
+
+
 <table width="100%" border="0" cellspacing="0" cellpadding="2" align="center">
 <tr><td bgcolor="<?php echo $color[0]; ?>">
 <div style="text-align: center;"><b><?php echo _("Add to address book"); ?></b></div>
diff -rbNu squirrelmail/src/view_personal_vcard.php /usr/share/squirrelmail/src/view_personal_vcard.php
--- squirrelmail/src/view_personal_vcard.php 1970-01-01 09:00:00.000000000 +0900
+++ /usr/share/squirrelmail/src/view_personal_vcard.php 2008-11-14 16:18:38.000000000 +0900
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * view_personal_vcard.php
+ *
+ * This file shows an vcard defined is the user's options
+ *
+ * Vincent Touchard - 14/11/2008
+ *
+ */
+
+/**
+ * Path for SquirrelMail required files.
+ * @ignore
+ */
+Define('SM_PATH','../');
+
+/* SquirrelMail required files. */
+include_once(SM_PATH . 'include/validate.php');
+require_once(SM_PATH . 'functions/url_parser.php');
+require_once(SM_PATH . 'functions/vcard.php');
+
+/* globals */
+sqgetGlobalVar('username', $username, SQ_SESSION);
+sqgetGlobalVar('key', $key, SQ_COOKIE);
+sqgetGlobalVar('onetimepad', $onetimepad, SQ_SESSION);
+
+sqgetGlobalVar('identity',     $identity);
+/* end globals */
+
+displayPageHeader($color, 'None');
+
+echo '<table width="100%" border="0" cellspacing="0" cellpadding="2" ' .
+ 'align="center">' . "\n";
+
+
+// title bar + url to go back to options
+$options_url = ($identity == "") ? "options.php?optpage=personal" : "options_identities.php";
+echo '<tr><td colspan="2" bgcolor="' . $color[0] . '"><b><div style="text-align: center;">' .
+     _("Viewing a Business Card") . " - ";
+echo '<a href="' . $options_url . '">' . _("Go back to account options") . '</a>';
+echo '</td></tr>' . "\n";
+
+// display vcard
+echo "<tr><td><br />";
+// 0 and "" considered as empty
+if (empty($identity)) {
+ $vcard = getHashedFile($username, $data_dir, "$username.vcard");
+} else {
+ $vcard = getHashedFile($username, $data_dir, "$username.vcar$identity");
+}
+vcard_fromFile($vcard);
+echo "</td></tr>" . "\n";
+
+echo "</table>";
+
+$oTemplate->display('footer.tpl');
+?>


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
-----
squirrelmail-devel mailing list
Posting guidelines: http://squirrelmail.org/postingguidelines
List address: squirrelmail-devel@...
List archives: http://news.gmane.org/gmane.mail.squirrelmail.devel
List info (subscribe/unsubscribe/change options): https://lists.sourceforge.net/lists/listinfo/squirrelmail-devel

Re: Patch for improved vCard support

by Paul Lesniewski :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Vincent,

> I have developed a patch for SquirrelMail 1.5.1 as available in debian.

When submitting patches to any project, you should always base it on
the code directly from that project.  1.5.1 is years old now and very
much deprecated (and I have no idea whether or not Debian modified the
code for their purposes).  Our current development stream is
1.5.2(svn), and any patches should be based on it (either do a SVN
checkout or grab a snapshot from our downloads page).

> This patch improves the support of vCard :
>  - display of vcards attached to mail with more fields (including PHOTO
> and LOGO), sorted by category (Personal, Work, Miscellaneous and
> Security)
>  - add vcards to identities in the options of the user's account
>  - attach the vcard when sending a mail
>
> The parsing of vcards is done using the pear module Contact_Vcard_Parse
> which does a better job that the "parser" that is currently in
> squirrelmail.

One of SquirrelMail's goals is to be easily installable and have an
extremely small set of requirements.  I'm not sure we'd want to add
this kind of requirement to our core.  You might investigate if any of
it can be done with a plugin or see if the built-in parser can be
extended.

> We did it as a patch and not a plugin to have it fully integrated into the
> webmail and to replace the code already written to display vcards attached
> to mails.
>
> The next step would be to save the vcards received as mail attachments
> into the address book.
>
> As it is my first patch against SquirrelMail, it may be far from being
> perfect. Any comments are welcome.

I haven't looked at it, but will see if I can find the time...  no
matter what ends up happening with it, your contribution is HIGHLY
appreciated!

Thanks!

  - Paul

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
-----
squirrelmail-devel mailing list
Posting guidelines: http://squirrelmail.org/postingguidelines
List address: squirrelmail-devel@...
List archives: http://news.gmane.org/gmane.mail.squirrelmail.devel
List info (subscribe/unsubscribe/change options): https://lists.sourceforge.net/lists/listinfo/squirrelmail-devel

Re: Patch for improved vCard support

by Vincent Touchard-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, November 20, 2008 10:30 am, Paul Lesniewski wrote:

> Vincent,
>
>
>> I have developed a patch for SquirrelMail 1.5.1 as available in debian.
>>
>
> When submitting patches to any project, you should always base it on
> the code directly from that project.  1.5.1 is years old now and very much
> deprecated (and I have no idea whether or not Debian modified the code for
> their purposes).  Our current development stream is 1.5.2(svn), and any
> patches should be based on it (either do a SVN checkout or grab a snapshot
> from our downloads page).
I did a checkout of the SVN and updated my patch so that it can now work
with the latest version.
Some parts need to be reworked (I tagged some of them as TODO) but I
wanted to sent this patch before the week-end.

>>
>> The parsing of vcards is done using the pear module Contact_Vcard_Parse
>>  which does a better job that the "parser" that is currently in
>> squirrelmail.
>
> One of SquirrelMail's goals is to be easily installable and have an
> extremely small set of requirements.  I'm not sure we'd want to add this
> kind of requirement to our core.  You might investigate if any of it can
> be done with a plugin or see if the built-in parser can be extended.
This module is quite easy to install but I understand that you want to
limit the dependencies of SquirrelMail. I used it because it works pretty
well and it avoids duplicated code. vCard being so flexible it's really
hard to write a good parser so I won't write a new one during the coming
days but why not once the other parts of the code are finished.

>>
>> As it is my first patch against SquirrelMail, it may be far from being
>> perfect. Any comments are welcome.
>
> I haven't looked at it, but will see if I can find the time...  no
> matter what ends up happening with it, your contribution is HIGHLY
> appreciated!
Thanks. I hope we can finalize this in the near future as vCards are more
and more common.
>
> Thanks!
>
>
> - Paul
Vincent
[squirrelmail-svn-vcard-20081121.diff]

Index: include/constants.php
===================================================================
--- include/constants.php (revision 13325)
+++ include/constants.php (working copy)
@@ -235,6 +235,7 @@
 define('SMOPT_TYPE_BOOLEAN_RADIO', 13);
 define('SMOPT_TYPE_STRLIST_RADIO', 14);
 define('SMOPT_TYPE_SUBMIT', 15);
+define('SMOPT_TYPE_FILE', 16);
 
 // Define constants for the layout scheme for edit lists
 define('SMOPT_EDIT_LIST_LAYOUT_LIST', 0);
Index: include/load_prefs.php
===================================================================
--- include/load_prefs.php (revision 13325)
+++ include/load_prefs.php (working copy)
@@ -137,6 +137,7 @@
 $editor_height = getPref($data_dir, $username, 'editor_height', 20 );
 $use_signature = getPref($data_dir, $username, 'use_signature', SMPREF_OFF );
 $prefix_sig = getPref($data_dir, $username, 'prefix_sig');
+$use_vcard = getPref($data_dir, $username, 'use_vcard', SMPREF_OFF );
 
 /* Load timezone preferences */
 $timezone = getPref($data_dir, $username, 'timezone', SMPREF_NONE );
Index: include/options/personal.php
===================================================================
--- include/options/personal.php (revision 13325)
+++ include/options/personal.php (working copy)
@@ -125,6 +125,28 @@
         'save'    => 'save_option_signature'
     );
 
+ $optvals[SMOPT_GRP_CONTACT][] = array(
+ 'name'    => 'vcard',
+ 'caption' => _("Upload vCard"),
+ 'type'    => SMOPT_TYPE_FILE,
+ 'refresh' => SMOPT_REFRESH_NONE,
+ 'save'    => 'save_option_vcard'
+ );
+
+    $filename = getHashedFile($username, $data_dir, "$username.vcard");
+ if (file_exists($filename)) {
+ $view_vard_link_value = '<a href="view_personal_vcard.php">'
+ . _("View vCard")
+ . '</a> ';
+ $optvals[SMOPT_GRP_CONTACT][] = array(
+ 'name'    => 'vcard',
+ 'caption' => _("Current vCard"),
+ 'type'    => SMOPT_TYPE_COMMENT,
+ 'refresh' => SMOPT_REFRESH_NONE,
+ 'comment' =>  $view_vard_link_value
+ );
+ }
+
     if ($edit_identity) {
         $identities_link_value = '<a href="options_identities.php">'
                                . _("Edit Advanced Identities")
@@ -245,6 +267,13 @@
         'refresh' => SMOPT_REFRESH_NONE
     );
 
+    $optvals[SMOPT_GRP_SIG][] = array(
+        'name'    => 'use_vcard',
+        'caption' => _("Use vCard"),
+        'type'    => SMOPT_TYPE_BOOLEAN,
+        'refresh' => SMOPT_REFRESH_NONE
+    );
+
     /* Assemble all this together and return it as our result. */
     $result = array(
         'grps' => $optgrps,
@@ -265,3 +294,59 @@
     setSig($data_dir, $username, 'g', $option->new_value);
 }
 
+/**
+ * Saves the vcard option.
+ *
+ * mostly taken from
+ * plugins/abook_import_export/address_book_import.php
+ *
+ */
+function save_option_vcard($option) {
+    global $data_dir, $username;
+
+    $vcard = $_FILES['new_' . $option->name];
+
+    if ($vcard['tmp_name'] == '' || $vcard['size'] == 0) {
+        // Detect PHP 4.2.0+ upload error codes (http://www.php.net/features.file-upload.errors)
+        $upload_error = _("Please select a file for uploading.");
+        if (isset($vcard['error']) && $vcard['error']!=0 ) {
+            switch($vcard['error']) {
+            case 1:
+                $upload_error = _("The uploaded file exceeds PHP upload_max_filesize limits.");
+                break;
+            case 2:
+                $upload_error = _("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML.");
+                break;
+            case 3:
+                $upload_error = _("The uploaded file was only partially uploaded.");
+                break;
+            case 4:
+                $upload_error = _("No file was uploaded.");
+                break;
+            case 6:
+                $upload_error = _("Missing a temporary directory.");
+                break;
+            case 7:
+                $upload_error = _("Failed to write file to disk.");
+                break;
+            case 8:
+                // File upload stopped by extension. 'security library' is more user friendly.
+                $upload_error = _("File upload stopped by security library.");
+                break;
+            default:
+                $upload_error = _("Unknown upload error.");
+                break;
+            }
+        }
+ // TODO: use something else
+ plain_error_message( $upload_error, $color);
+ }
+ elseif (isset($vcard['type']) && $vcard['type'] != 'text/x-vcard') {
+ $upload_error = _("Please upload a vCard.");
+ // TODO: use something else
+ plain_error_message( $upload_error, $color);
+ }
+ else {
+    setVcard($data_dir, $username, 'd', $vcard['tmp_name']);
+ }
+}
Index: src/options_identities.php
===================================================================
--- src/options_identities.php (revision 13325)
+++ src/options_identities.php (working copy)
@@ -79,6 +79,15 @@
     $a['Email'] = htmlspecialchars($ident['email_address']);
     $a['ReplyTo'] = htmlspecialchars($ident['reply_to']);
     $a['Signature'] = htmlspecialchars($ident['signature']);
+    // $username, $data_dir;
+    if ($key == 0) {
+        $filename = getHashedFile($username, $data_dir, "$username.vcard");
+    } else {
+        $filename = getHashedFile($username, $data_dir, "$username.vcar" . $key);
+    }
+    if (file_exists($filename)) {
+        $a['DisplayVcard'] = true;
+    }
     $i[$key] = $a;
 }
 
@@ -93,7 +102,7 @@
 $i[count($i)] = $a;
 
 //FIXME: NO HTML IN THE CORE
-echo '<form name="f" action="options_identities.php" method="post">' . "\n";
+echo '<form name="f" action="options_identities.php" method="post" enctype="multipart/form-data">' . "\n";
 
 $oTemplate->assign('identities', $i);
 $oTemplate->display('options_advidentity_list.tpl');
Index: src/options.php
===================================================================
--- src/options.php (revision 13325)
+++ src/options.php (working copy)
@@ -81,7 +81,8 @@
 //FIXME: NO HTML IN THE CORE!
             echo "<br />";
             */
-            if ($option->changed()) {
+ // error = 4 == file not uploaded
+ if ($option->changed() || isset($_FILES['new_'.$option->name]['error']) && $_FILES['new_'.$option->name]['error'] != 4) {
                 $option->save();
                 $max_refresh = max($max_refresh, $option->refresh_level);
             }
@@ -425,7 +426,7 @@
     }
 
     // Begin output form
-    echo addForm('options.php', 'post', 'option_form')
+    echo addForm('options.php', 'post', 'option_form', 'multipart/form-data')
        . create_optpage_element($optpage)
        . create_optmode_element(SMOPT_MODE_SUBMIT);
 
Index: src/view_personal_vcard.php
===================================================================
--- src/view_personal_vcard.php (revision 0)
+++ src/view_personal_vcard.php (revision 0)
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * view_personal_vcard.php
+ *
+ * Displays the vcard defined for a given identity.
+ * If no identity given, use the default one
+ *
+ * @copyright © 1999-2007 The SquirrelMail Project Team
+ * @license http://opensource.org/licenses/gpl-license.php GNU Public License
+ * @package squirrelmail
+ * @subpackage prefs
+ */
+
+/** This is the options page */
+define('PAGE_NAME', 'view_personal_vcard');
+
+/**
+ * Include the SquirrelMail initialization file.
+ */
+require('../include/init.php');
+
+/* SquirrelMail required files. */
+
+require_once(SM_PATH . 'functions/vcard.php');
+
+/*********************************/
+/*** Build the resultant page. ***/
+/*********************************/
+
+/* ---------------------------- main ---------------------------- */
+
+/* get the globals that we may need */
+sqgetGlobalVar('identity',     $identity);
+/* end of getting globals */
+
+$options_url = ($identity == "") ? "options.php?optpage=personal" : "options_identities.php";
+$oTemplate->assign('link', $options_url);
+$oTemplate->assign('link_label', _("Go back to account options"));
+
+
+
+// 0 and "" considered as empty
+if (empty($identity)) {
+ $vcard = getHashedFile($username, $data_dir, "$username.vcard");
+} else {
+ $vcard = getHashedFile($username, $data_dir, "$username.vcar$identity");
+}
+$vcard = vcard_fromFile($vcard);
+
+$oTemplate->assign('vcard', $vcard['vcard']);
+
+displayPageHeader($color);
+
+$oTemplate->display('vcard.tpl');
+
+$oTemplate->display('footer.tpl');
Index: src/vcard.php
===================================================================
--- src/vcard.php (revision 13325)
+++ src/vcard.php (working copy)
@@ -33,6 +33,8 @@
 include_once(SM_PATH . 'functions/imap_general.php');
 include_once(SM_PATH . 'functions/imap_messages.php');
 
+include_once(SM_PATH . 'functions/vcard.php');
+
 /* globals */
 
 sqgetGlobalVar('passed_id', $passed_id, SQ_GET);
@@ -57,6 +59,8 @@
 
 $vcard = mime_fetch_body($imapConnection, $passed_id, $ent_id);
 $vcard = decodeBody($vcard, $entity_vcard->header->encoding);
+
+/*
 $vcard = explode ("\n",$vcard);
 foreach ($vcard as $l) {
     $k = substr($l, 0, strpos($l, ':'));
@@ -129,20 +133,25 @@
     }
 }
 
+ */
+
+$vcard = vcard_fromText($vcard);
+
 $dl = '../src/download.php?absolute_dl=true&passed_id=' .
      urlencode($passed_id) . '&mailbox=' . urlencode($mailbox) .
      '&ent_id=' . urlencode($ent_id);
 
-if (isset($vcard_nice['email;internet'])) {
-    $email = $vcard_nice['email;internet'];
-} else {
+////if (isset($vcard_nice['email;internet'])) {
+////    $email = $vcard_nice['email;internet'];
+////} else {
     $message = sqimap_get_message($imapConnection, $passed_id, $mailbox);
     $header = $message->rfc822_header;
     $from_name = $header->getAddr_s('from');
 
     $email = getEmail(decodeHeader($from_name));
-}
+////}
 
+/*
 $opts = array();
 if (isset($vcard_nice['url'])) {
     $opts[$vcard_nice['url']] = _("Web Page");
@@ -174,17 +183,27 @@
 if (isset($vcard_nice['note'])) {
     $opts[$vcard_nice['note']] = _("Note");
 }
+ */
 
-$oTemplate->assign('view_message_link', $msg_url);
+$oTemplate->assign('link', $msg_url);
+$oTemplate->assign('link_label', _("View message"));
 $oTemplate->assign('download_link', $dl);
-$oTemplate->assign('vcard', $vcard);
+$oTemplate->assign('vcard', $vcard['vcard']);
 
-$oTemplate->assign('nickname', $vcard_nice['firstname'].'-'.$vcard_safe['lastname']);
-$oTemplate->assign('firstname', $vcard_safe['firstname']);
-$oTemplate->assign('lastname', $vcard_safe['lastname']);
+$nickname = (isset($vcard['basicinfo']['nickname'])) ? $vcard['basicinfo']['nickname'] : $vcard['basicinfo']['firstname'] . ' - ' . $vcard['basicinfo']['lastname'];
+$oTemplate->assign('nickname', $nickname);
+$oTemplate->assign('firstname', $vcard['basicinfo']['firstname']);
+$oTemplate->assign('lastname', $vcard['basicinfo']['lastname']);
 $oTemplate->assign('email', $email);
-$oTemplate->assign('info', $opts);
+// TODO: fill in opts
+//$oTemplate->assign('info', $opts);
+$oTemplate->assign('info', array());
 
+
+// display vcard
 $oTemplate->display('vcard.tpl');
 
+// display box to import the vcard in the address book
+$oTemplate->display('vcard2abook.tpl');
+
 $oTemplate->display('footer.tpl');
Index: src/compose.php
===================================================================
--- src/compose.php (revision 13325)
+++ src/compose.php (working copy)
@@ -85,6 +85,7 @@
 sqgetGlobalVar('mail_sent',$mail_sent, $SQ_GLOBAL);
 sqgetGlobalVar('passed_id',$passed_id, $SQ_GLOBAL);
 sqgetGlobalVar('passed_ent_id',$passed_ent_id, $SQ_GLOBAL);
+sqgetGlobalVar('usevcard',$usevcard, $SQ_GLOBAL);
 
 sqgetGlobalVar('attach',$attach, SQ_POST);
 sqgetGlobalVar('draft',$draft, SQ_POST);
@@ -334,7 +335,7 @@
             'subject', 'newmail', 'send_to_bcc', 'passed_id', 'mailbox',
             'from_htmladdr_search', 'identity', 'draft_id', 'delete_draft',
             'mailprio', 'edit_as_new', 'attachments', 'composesession',
-            'request_mdn', 'request_dr');
+            'request_mdn', 'request_dr', 'usevcard');
 
         foreach ($compo_var_list as $var) {
             if ( isset($session_expired_post[$var]) && !isset($$var) ) {
@@ -711,6 +712,8 @@
     if (isset($subject)) {
         $values['subject'] = $subject;
     }
+
+ $usevcard = $use_vcard;
     showInputForm($session, $values);
 }
 
@@ -735,7 +738,7 @@
         $key, $imapServerAddress, $imapPort,
         $composeMessage, $body_quote, $request_mdn, $request_dr,
         $mdn_user_support, $languages, $squirrelmail_language,
-        $default_charset;
+        $default_charset, $usevcard;
 
     /*
      * Set $default_charset to correspond with the user's selection
@@ -1350,7 +1353,7 @@
     global $use_javascript_addr_book, $save_as_draft,
         $default_use_priority, $mailprio, $default_use_mdn,
         $request_mdn, $request_dr,
-        $data_dir, $username;
+        $data_dir, $username, $usevcard;
 
     global $oTemplate, $buffer_hook;
 
@@ -1378,6 +1381,8 @@
     $oTemplate->assign('read_receipt', $request_mdn=='1');
     $oTemplate->assign('delivery_receipt', $request_dr=='1');
 
+ $oTemplate->assign('usevcard', $usevcard=='1');
+
     $oTemplate->assign('drafts_enabled', $save_as_draft);
     $oTemplate->assign('address_book_button', $addr_book);
 
@@ -1483,7 +1488,8 @@
         $username, $identity, $idents, $data_dir,
         $request_mdn, $request_dr, $default_charset, $useSendmail,
         $domain, $action, $default_move_to_sent, $move_to_sent,
-        $imapServerAddress, $imapPort, $sent_folder, $key;
+ $imapServerAddress, $imapPort, $sent_folder, $key, $usevcard,
+ $attachment_dir;
 
     $rfc822_header = $composeMessage->rfc822_header;
 
@@ -1505,6 +1511,18 @@
     }
     $composeMessage->setBody($body);
 
+    if (!$draft && isset($usevcard) && $usevcard) {
+        if ($identity == 0) {
+            $vcard_path = getHashedFile($username, $data_dir, "$username.vcard");
+        } else {
+            $vcard_path = getHashedFile($username, $data_dir, "$username.vcar$identity");
+        }
+        if (file_exists($vcard_path)) {
+            $vcard_attached = tempnam(getHashedDir($username, $attachment_dir), $username . ".vcf");
+            copy($vcard_path, $vcard_attached);
+            $composeMessage->initAttachment('text/x-vcard', $username . ".vcf", basename($vcard_attached));
+        }
+    }
     $reply_to = '';
     $reply_to  = $idents[$identity]['reply_to'];
     
Index: templates/default/compose_buttons.tpl
===================================================================
--- templates/default/compose_buttons.tpl (revision 13325)
+++ templates/default/compose_buttons.tpl (working copy)
@@ -60,6 +60,14 @@
     }
  ?>
  <tr>
+  <td class="fieldName">
+   <?php echo _("vCard"); ?>:
+  </td>
+  <td class="fieldValue">
+   <input type="checkbox" name="usevcard" id="usevcard" value="1" <?php if ($usevcard) echo ' checked="checked"'; ?> /><label for="usevcard"><?php echo _("Attach vCard"); ?></label>
+  </td>
+ </tr>
+ <tr>
   <td colspan="2" class="buttons">
    <input type="submit" name="sigappend" value="<?php echo _("Signature"); ?>" /> 
    <?php echo $address_book_button; ?> 
Index: templates/default/options_advidentity_list.tpl
===================================================================
--- templates/default/options_advidentity_list.tpl (revision 13325)
+++ templates/default/options_advidentity_list.tpl (working copy)
@@ -85,6 +85,24 @@
       <textarea name="newidentities[<?php echo $index; ?>][signature]" cols="50" rows="5"><?php echo $identity['Signature']; ?></textarea>
      </td>
     </tr>
+    <tr>
+     <td class="fieldName">
+      <?php echo _("Upload vCard"); ?>
+     </td>
+     <td class="fieldValue">
+      <input type="file" name="newidentities[<?php echo $index; ?>][vcard]" cols="50" rows="5" />
+     </td>
+    </tr>
+ <?php if (isset($identity['DisplayVcard'])) { ?>
+    <tr>
+     <td class="fieldName">
+      <?php echo _("Current vCard"); ?>
+     </td>
+     <td class="fieldValue">
+      <a href="view_personal_vcard.php?identity=<?php echo $index; ?>"><?php echo _("View vCard")?></a>
+     </td>
+    </tr>
+ <?php } ?>
     <?php /* FIXME: No hooks in templates! */ $temp = array('', &$identity['New'], &$index); echo concat_hook_function('options_identities_table', $temp); ?>
     <tr>
      <td colspan="2" class="actionButtons">
Index: templates/default/vcard2abook.tpl
===================================================================
--- templates/default/vcard2abook.tpl (revision 0)
+++ templates/default/vcard2abook.tpl (revision 0)
@@ -0,0 +1,96 @@
+<?php
+/**
+ * vcard2abook.tpl
+ *
+ * Template to add a vCard to the address book
+ *
+ * The following variables are available in this template:
+ *      $nickname           - Default nickname for the address book add form
+ *      $firstname          - First name for the address book add from
+ *      $last name          - Last name for the add form
+ *      $email              - Email for the add form
+ *      $info               - array of Additional info for the add form.  May be
+ *                            empty if no additional info is provided by the
+ *                            card.  Index of each element is the value for the
+ *                            option, value of each element is the name.
+ *
+ * @copyright © 1999-2006 The SquirrelMail Project Team
+ * @license http://opensource.org/licenses/gpl-license.php GNU Public License
+ * @version $Id: vcard.tpl 11653 2006-08-28 15:33:36Z stevetruckstuff $
+ * @package squirrelmail
+ * @subpackage templates
+ */
+
+/** add required includes **/
+
+/** extract template variables **/
+extract($t);
+
+/** Begin template **/
+?>
+<div id="vCard">
+<form action="../src/addressbook.php" method="post" name="f_add">
+<input type="hidden" name="addaddr[firstname]" value="<?php echo $firstname; ?>" />
+<input type="hidden" name="addaddr[lastname]" value="<?php echo $lastname; ?>" />
+<table cellspacing="0" class="table1">
+ <tr>
+  <td class="header1">
+   <?php echo _("Add to address book"); ?>
+  </td>
+ </tr>
+ <tr>
+  <td>
+   <table cellspacing="0">
+    <tr>
+     <td class="fieldName">
+      <?php echo _("Nickname"); ?>
+     </td>
+     <td class="fieldValue">
+      <input type="text" name="addaddr[nickname]" value="<?php echo $nickname; ?>" size="20" />
+     </td>
+    </tr>
+    <tr>
+     <td class="fieldName">
+      <?php echo _("Email"); ?>
+     </td>
+     <td class="fieldValue">
+      <input type="text" name="addaddr[email]" value="<?php echo $email; ?>" size="20" />
+     </td>
+    </tr>
+    <tr>
+     <td class="fieldName">
+      <?php echo _("Additional Info"); ?>
+     </td>
+     <td class="fieldValue">
+      <?php
+        if (count($info) == 0) {
+            ?>
+      <input type="text" name="addaddr[label]" value="" size="20" />
+            <?php
+        } else {
+            ?>
+      <select name="addaddr[label]">
+            <?php
+            foreach ($info as $value=>$field) {
+                ?>
+        <option value="<?php echo $value; ?>"><?php echo $field; ?></option>
+                <?php
+            }
+            ?>
+      </select>
+            <?php
+        }
+      ?>
+     </td>
+    </tr>
+   </table>
+  </td>
+ </tr>
+ <tr>
+  <td>
+   <input type="submit" value="<?php echo _("Add to address book"); ?>" name="addaddr[SUBMIT]" id="addaddr_SUBMIT_" />
+  </td>
+ </tr>
+</table>
+</form>
+</div>
Index: templates/default/vcard.tpl
===================================================================
--- templates/default/vcard.tpl (revision 13325)
+++ templates/default/vcard.tpl (working copy)
@@ -7,14 +7,6 @@
  * The following variables are available in this template:
  *      $view_message_link  - URL to go back to the message
  *      $download_link      - URL to download the vCard
- *      $nickname           - Default nickname for the address book add form
- *      $firstname          - First name for the address book add from
- *      $last name          - Last name for the add form
- *      $email              - Email for the add form
- *      $info               - array of Additional info for the add form.  May be
- *                            empty if no additional info is provided by the
- *                            card.  Index of each element is the value for the
- *                            option, value of each element is the name.
  *      $vcard              - array containing vCard data, scrubbed and i-18-n'ed.
  *                            Index of each element is the field name, value of
  *                            each element is the field value.
@@ -37,97 +29,55 @@
 <table cellspacing="0" class="table1">
  <tr>
   <td class="header1">
-   <?php echo _("Viewing a Business Card") ; ?> - <a href="<?php echo $view_message_link; ?>"><?php echo _("View message"); ?></a>
+   <?php echo _("Viewing a Business Card") ; ?> - <a href="<?php echo $link; ?>"><?php echo $link_label; ?></a>
   </td>
  </tr>
- <tr>
-  <td>
-   <table cellspacing="0">
     <?php
-        foreach ($vcard as $field=>$value) {
-            ?>
+    foreach ($vcard as $field=>$values) {
+    ?>
+ <tr><td><strong><?php echo $field; ?></strong></td></tr>
     <tr>
-     <td class="fieldName">
-      <?php echo $field; ?>:
-     </td>
-     <td class="fieldValue">
-      <?php echo $value; ?>
-     </td>
-    </tr>
-            <?php
-        }
-    ?>
+     <td>
+      <table cellspacing="0">
+   <tr>
+    <td>
+         <table cellspacing="0">
+          <?php
+            foreach ($values['data'] as $value) {
+          ?>
+          <tr>
+           <td class="fieldName">
+            <?php echo $value['name']; ?>:
+           </td>
+           <td class="fieldValue">
+            <?php echo $value['value']; ?>
+           </td>
+          </tr>
+           <?php } ?>
+     </td>
+    </tr>
+   </table>
+  </td>
+ <td>
+ <?php
+   if (isset($values['picture'])) {
+    echo '<img src="' . $values['picture']['src'] . '" width="' . $values['picture']['width'] . '" height="' . $values['picture']['height'] . '" \>';
+   }
+ ?>
+ </td>
+ </tr>
    </table>
   </td>
  </tr>
+    <?php
+      }
+      if (isset($download_link)) {
+    ?>
  <tr>
   <td>
    <a href="<?php echo $download_link; ?>"><?php echo _("Download this as a file"); ?></a>
   </td>
  </tr>
+   <?php } ?>
 </table>
-<form action="../src/addressbook.php" method="post" name="f_add">
-<input type="hidden" name="addaddr[firstname]" value="<?php echo $firstname; ?>" />
-<input type="hidden" name="addaddr[lastname]" value="<?php echo $lastname; ?>" />
-<table cellspacing="0" class="table1">
- <tr>
-  <td class="header1">
-   <?php echo _("Add to address book"); ?>
-  </td>
- </tr>
- <tr>
-  <td>
-   <table cellspacing="0">
-    <tr>
-     <td class="fieldName">
-      <?php echo _("Nickname"); ?>
-     </td>
-     <td class="fieldValue">
-      <input type="text" name="addaddr[nickname]" value="<?php echo $nickname; ?>" size="20" />
-     </td>
-    </tr>
-    <tr>
-     <td class="fieldName">
-      <?php echo _("Email"); ?>
-     </td>
-     <td class="fieldValue">
-      <input type="text" name="addaddr[email]" value="<?php echo $email; ?>" size="20" />
-     </td>
-    </tr>
-    <tr>
-     <td class="fieldName">
-      <?php echo _("Additional Info"); ?>
-     </td>
-     <td class="fieldValue">
-      <?php
-        if (count($info) == 0) {
-            ?>
-      <input type="text" name="addaddr[label]" value="" size="20" />
-            <?php
-        } else {
-            ?>
-      <select name="addaddr[label]">
-            <?php
-            foreach ($info as $value=>$field) {
-                ?>
-        <option value="<?php echo $value; ?>"><?php echo $field; ?></option>
-                <?php
-            }
-            ?>
-      </select>
-            <?php
-        }
-      ?>
-     </td>
-    </tr>
-   </table>
-  </td>
- </tr>
- <tr>
-  <td>
-   <input type="submit" value="<?php echo _("Add to address book"); ?>" name="addaddr[SUBMIT]" id="addaddr_SUBMIT_" />
-  </td>
- </tr>
-</table>
-</form>
-</div>
\ No newline at end of file
+</div>
Index: functions/db_prefs.php
===================================================================
--- functions/db_prefs.php (revision 13325)
+++ functions/db_prefs.php (working copy)
@@ -599,3 +599,43 @@
     }
     return getPref($data_dir, $username, $key);
 }
+
+/**
+ * Writes the vCard
+ * @ignore
+ */
+function setVcard($data_dir, $username, $number, $tmp_file) {
+    if ($number == "d") {
+        $key = '___vcard___';
+    } else {
+        $key = sprintf('___vcar%s___', $number);
+ }
+
+ /* Open the file for reading, or else display an error to the user. */
+ if(!$file = @fopen($tmp_file, 'r')) {
+ logout_error( sprintf( _("vCard file, %s, could not be opened. Contact your system administrator to resolve this issue."), $tmp_file) );
+ exit;
+ }
+ if ( @fread($file, $value) == strlen($value) ) {
+ logout_error( sprintf( _("vCard file, %s, could not be written. Contact your system administrator to resolve this issue.") , $tmp_file));
+ exit;
+ }
+ fclose($file);
+
+
+ setPref($data_dir, $username, $key, $value);
+    return;
+}
+
+/**
+ * Gets the vCard
+ * @ignore
+ */
+function getVcard($data_dir, $username, $number) {
+    if ($number == "d") {
+        $key = '___vcard___';
+    } else {
+        $key = sprintf('___vcar%d___', $number);
+    }
+    return getPref($data_dir, $username, $key);
+}
Index: functions/forms.php
===================================================================
--- functions/forms.php (revision 13325)
+++ functions/forms.php (working copy)
@@ -158,6 +158,22 @@
 }
 
 /**
+ * File input field
+ * @param string $sName field name
+ * @param array $aAttribs (since 1.5.1) extra attributes
+ * @return string html formated file field
+ */
+function addFileUpload($sName, $aAttribs=array()) {
+    $aAttribs['name']  = $sName;
+    $aAttribs['value'] = '';
+    // add default css
+ // TODO: CSS class
+    if (! isset($aAttribs['class'])) $aAttribs['class'] = 'sqmpwfield';
+    return addInputField('file',$aAttribs);
+}
+
+
+/**
  * Function to create a selectlist from an array.
  * @param string  $sName     Field name
  * @param array   $aValues   Field values array(key => value) results in:
Index: functions/identity.php
===================================================================
--- functions/identity.php (revision 13325)
+++ functions/identity.php (working copy)
@@ -80,6 +80,7 @@
         removePref($data_dir, $username, 'email_address' . $i);
         removePref($data_dir, $username, 'reply_to' . $i);
         setSig($data_dir, $username, $i, '');
+        setVcard($data_dir, $username, $i, '');
     }
 
     foreach($identities as $id=>$ident) {
@@ -96,6 +97,15 @@
             setSig($data_dir, $username, $key, $ident['signature']);
         }
 
+        $vcard_file = check_vcard($id);
+        if ($vcard_file != FALSE) {
+            if ($id === 0) {
+                setVcard($data_dir, $username, 'd', $vcard_file);
+            } else {
+                setVcard($data_dir, $username, $key, $vcard_file);
+            }
+        }
+
     }
 
     setPref($data_dir, $username, 'identities', $cnt);
@@ -274,3 +284,64 @@
     }
     return 0;
 }
+
+/*
+ * Test if the vCard was correctly uploaded and if it is tagged as a being a vCard (text/x-vcard)
+ *
+ * mostly taken from
+ * plugins/abook_import_export/address_book_import.php
+ *
+ * @param  int    identity id
+ * @return mixte  FALSE if the file was not correctly uploaded or is not a vCard, otherwise the name of
+ *                the tempory file where the vCard related to the "identity id" is store
+ */
+function check_vcard($id) {
+    $vcards = $_FILES['newidentities'];
+
+    if ($vcards['tmp_name'][$id]['vcard'] == '' || $vcards['size'][$id]['vcard'] == 0) {
+        // Detect PHP 4.2.0+ upload error codes (http://www.php.net/features.file-upload.errors)
+        $upload_error = "";
+        if (isset($vcards['error'][$id]['vcard']) && $vcards['error'][$id]['vcard']!=0 ) {
+            switch($vcards['error'][$id]['vcard']) {
+            case 1:
+                $upload_error = _("The uploaded file exceeds PHP upload_max_filesize limits.");
+                break;
+            case 2:
+                $upload_error = _("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML.");
+                break;
+            case 3:
+                $upload_error = _("The uploaded file was only partially uploaded.");
+                break;
+            case 4:
+                break;
+            case 6:
+                $upload_error = _("Missing a temporary directory.");
+                break;
+            case 7:
+                $upload_error = _("Failed to write file to disk.");
+                break;
+            case 8:
+                // File upload stopped by extension. 'security library' is more user friendly.
+                $upload_error = _("File upload stopped by security library.");
+                break;
+            default:
+                $upload_error = _("Unknown upload error.");
+                break;
+            }
+ }
+ if (!empty($upload_error)) {
+ // TODO: use something else
+ plain_error_message( $upload_error, $color);
+ }
+ return FALSE;
+ }
+ elseif (isset($vcards['type'][$id]['vcard']) && $vcards['type'][$id]['vcard'] != 'text/x-vcard') {
+ $upload_error = _("Please upload a vCard.");
+ // TODO: use something else
+ plain_error_message( $upload_error, $color);
+ return FALSE;
+ }
+ else {
+ return $vcards['tmp_name'][$id]['vcard'];
+ }
+}
Index: functions/options.php
===================================================================
--- functions/options.php (revision 13325)
+++ functions/options.php (working copy)
@@ -410,6 +410,9 @@
             case SMOPT_TYPE_SUBMIT:
                 $result = $this->createWidget_Submit();
                 break;
+            case SMOPT_TYPE_FILE:
+                $result = $this->createWidget_FileUpload();
+                break;
             default:
                 error_box (
                     sprintf(_("Option Type '%s' Not Found"), $this->type)
@@ -691,6 +694,14 @@
     }
 
     /**
+     * Creates file field
+     * @return string html formated file field
+     */
+    function createWidget_FileUpload() {
+        return addFileUpload('new_' . $this->name, $this->aExtraAttribs);
+    }
+
+    /**
      * Creates comment
      * @return string comment
      */
Index: functions/vcard.php
===================================================================
--- functions/vcard.php (revision 0)
+++ functions/vcard.php (revision 0)
@@ -0,0 +1,289 @@
+<?php
+
+/*
+ * Vincent Touchard
+ * 2008/11/12
+ *
+ * set of a functions to render a vcard
+ *
+ * You can use it calling vcard_fromFile or vcard_fromText
+ *
+ * Needs the pear class Contact_Vcard_Parse
+ */
+
+require_once 'Contact_Vcard_Parse.php';
+
+/*
+ * format each field
+ *
+ * value    array    values to display
+ * url      boolean  is the value is an url
+ * charset  string   charset of the text to render
+ */
+function vcard_format_text($value, $url = 0, $charset = '') {
+ $ret = "";
+ foreach ($value as $t) {
+ if (isset($t[0]) && $t[0]) {
+ $text = $t[0];
+
+ // convert to utf-8 if needed
+ if (!empty($charset)) {
+ $res = iconv($charset, "UTF-8", $text);
+ // check if conversion didn't fail - keep the unconverted text if it failed
+ if($res != FALSE) {
+ $text = $res;
+ }
+ }
+ $ret = htmlspecialchars($ret);
+
+ $ret .= ', ' . ($url ? '<a href="' . $text . '" >' . $text . '</a>' : $text);
+ }
+ }
+ return nl2br(ltrim($ret, ", "));
+}
+
+/*
+ * Generate a table for each topic
+ *
+ * name        string  name of the topic
+ * fields      array   fields to display
+ * vcard_data  array   data extracted from the vcard
+ */
+function vcard_data_to_table($fields, $vcard_data) {
+
+ $ret = array();
+
+ // read all attributes with the wanted keyword (TEL, PHOTO, ...)
+ foreach ($fields as $k => $v) {
+ if (isset($vcard_data[0][$k]) && $vcard_data[0][$k]) {
+
+ // read all the attributes with the same keyword
+ foreach ($vcard_data[0][$k] as $values) {
+
+ // go to all the wanted attributes with the same keyword
+ foreach ($v as $w) {
+
+ // is an url?
+ $url = isset($values['param']['VALUE']) && $values['param']['VALUE'][0] == 'URL' || $k == 'URL';
+
+ // which charset ?
+ $charset = isset($values['param']['CHARSET'][0]) ? $values['param']['CHARSET'][0] : '';
+
+ // if a parameter is given, keep only if it matches
+ if (isset($w["param"]) && $w["param"][1] != "DEFAULT" && !empty($values['param'][$w["param"][0]])) {
+ foreach ($values['param'][$w["param"][0]] as $param) {
+ if ($param == $w["param"][1]) {
+ $ret[] = array('name' => $w["name"], 'value' => vcard_format_text($values['value'], $url, $charset));
+ }
+ }
+ } elseif (isset($w["param"]) && $w["param"][1] == "DEFAULT" && empty($values['param'][$w["param"][0]])) {
+ $ret[] = array('name' => $w["name"], 'value' => vcard_format_text($values['value'], $url, $charset));
+
+ // else, print it
+ } elseif (!isset($w["param"])) {
+ $ret[] = array('name' => $w["name"], 'value' => vcard_format_text($values['value'], $url, $charset));
+ }
+ }
+ }
+ }
+ }
+
+ return $ret;
+}
+
+/*
+ * Pictures
+ * Return the source (URL or base64), the width and the height
+ *
+ * The width and height are limited to 160x160. If the picture is bigger,
+ * new width & height parameters are computed to keep the x/y ratio and stay
+ * in the 160x160 bounding box
+ *
+ * Used by PHOTO and LOGO keywords
+ *
+ * Can handle base64 images and url ones
+ *
+ *
+ */
+function vcard_display_image($image_info) {
+ $data = $image_info[0]['value'][0][0];
+
+ // default values
+ $x = 120;
+ $y = 160;
+
+ // check if it is an URL or not
+ if (!isset($image_info[0]['param']['VALUE']) || $image_info[0]['param']['VALUE'][0] != 'URL') {
+
+ // find size
+ $im = imagecreatefromstring(base64_decode($data));
+ if ($im != FALSE) {
+ $x = imagesx($im);
+ $y = imagesy($im);
+
+ $ratio_x = $x / 160.0;
+ $ratio_y = $y / 160.0;
+
+ // reduce size to stay in the limit of 160x160
+ if ($ratio_x > 1.0 || $ratio_y > 1.0) {
+ $ratio = max($ratio_x, $ratio_y);
+ $x = $x / $ratio;
+ $y = $y / $ratio;
+ }
+
+ }
+
+ $data = "data:image/jpg;base64," . $data;
+ } else {
+ // find size
+ $a = getimagesize($data);
+ $x = $a[0];
+ $y = $a[1];
+
+ $ratio_x = $x / 160.0;
+ $ratio_y = $y / 160.0;
+
+ // reduce size to stay in the limit of 160x160
+ if ($ratio_x > 1.0 || $ratio_y > 1.0) {
+ $ratio = max($ratio_x, $ratio_y);
+ $x = $x / $ratio;
+ $y = $y / $ratio;
+ }
+ }
+ return array('src' => $data, 'height' => $y, 'width' => $x);
+}
+
+/*
+ * Generate the vcard display
+ *
+ * cardinfo  array  nested array containing the vcard data
+ */
+function vcard_generate_vcard($cardinfo) {
+
+// TODO: FN
+ $fn = $cardinfo[0]['FN'][0]['value'][0][0];
+ if (isset($cardinfo[0]['FN'][0]['param']['CHARSET'][0])) {
+ $fn2 = iconv($cardinfo[0]['FN'][0]['param']['CHARSET'][0], "UTF-8", $fn);
+ // if iconv failed, keep the old text
+ if ($fn2 != FALSE) {
+ $fn = $fn2;
+ }
+ }
+
+ // Personal Information
+ $ShowValues = array(
+ 'N' =>             array(array("name" => _("Name"))),
+ 'NICKNAME' =>             array(array("name" => _("Nickname"))),
+ 'EMAIL' =>         array(array("name" => _("E-mail"), "param" => array("TYPE", "DEFAULT")),
+ array("name" => _("E-mail"), "param" => array("TYPE", "INTERNET")),
+ array("name" => _("E-mail"), "param" => array("TYPE", "HOME"))),
+ 'TEL' =>           array(array("name" => _("Phone"), "param" => array("TYPE", "DEFAULT")),
+ array("name" => _("Phone"), "param" => array("TYPE", "HOME")),
+ array("name" => _("Cell Phone"), "param" => array("TYPE", "CELL"))),
+ 'LABEL' =>         array(array("name" => _("Address"), "param" => array("TYPE", "DEFAULT")),
+ array("name" => _("Address"), "param" => array("TYPE", "DOM")),
+ array("name" => _("Address"), "param" => array("TYPE", "HOME"))),
+ 'ADR' =>         array(array("name" => _("Address"), "param" => array("TYPE", "DEFAULT")),
+ array("name" => _("Address"), "param" => array("TYPE", "HOME"))),
+ 'BDAY' => array(array("name" => _("Birthday")))
+ );
+ $data = vcard_data_to_table($ShowValues, $cardinfo);
+
+ // display only the first photo
+ if (isset($cardinfo[0]['PHOTO']) && $cardinfo[0]['PHOTO'])     {
+ $picture = vcard_display_image($cardinfo[0]['PHOTO']);
+ }
+ if (!empty($data) || !empty($picture)) {
+ $vcard['Personal Data']['data'] = $data;
+ $vcard['Personal Data']['picture'] = $picture;
+ }
+
+ // Work
+ $ShowValues = array(
+ 'ORG' =>             array(array("name" => _("Organisation"))),
+ 'TITLE' =>             array(array("name" => _("Title"))),
+ 'ROLE' =>             array(array("name" => _("Role"))),
+ 'EMAIL' =>         array(array("name" => _("E-mail"), "param" => array("TYPE", "WORK"))),
+ 'TEL' =>           array(array("name" => _("Phone"), "param" => array("TYPE", "WORK")),
+ array("name" => _("Fax"), "param" => array("TYPE", "FAX"))),
+ 'LABEL' =>         array(array("name" => _("Address"), "param" => array("TYPE", "WORK"))),
+ 'ADR' =>         array(array("name" => _("Address"), "param" => array("TYPE", "WORK")))
+ );
+ $data = vcard_data_to_table($ShowValues, $cardinfo);
+ $picture = '';
+
+ // display only the first logo
+ if (isset($cardinfo[0]['LOGO']) && $cardinfo[0]['LOGO'])     {
+ $picture = vcard_display_image($cardinfo[0]['LOGO']);
+ }
+ if (!empty($data) || !empty($picture)) {
+ $vcard['Work']['data'] = $data;
+ $vcard['Work']['picture'] = $picture;
+ }
+
+ // Miscelleaneous
+ $ShowValues = array(
+ 'NOTE' =>          array(array("name" => _("Note"))),
+ 'URL' =>          array(array("name" => _("Website")))
+ );
+ $data = vcard_data_to_table($ShowValues, $cardinfo);
+ if (!empty($data)) {
+ $vcard['Miscelleaneous']['data'] = $data;
+ }
+
+
+ // Security
+ $ShowValues = array(
+ 'KEY' =>           array(array("name" => _("PGP Public Key"), "param" => array("TYPE", "PGP")),
+ array("name" => _("X509 Public Key"), "param" => array("TYPE", "X509"))),
+ );
+ $data = vcard_data_to_table($ShowValues, $cardinfo);
+ if (!empty($data)) {
+ $vcard['Security']['data'] = $data;
+ }
+
+
+ return $vcard;
+}
+
+/*
+ * Function to extract some basic information from the vcard
+ *
+ * returns an array with the information extracted
+ */
+function vcard_extractBasicInfo($cardinfo) {
+ // Key "N", mandatory in all current vcard versions (2.1 and 3.0)
+ $info['firstname'] = $cardinfo[0]['N'][0]['value'][0][0];
+ $info['lastname'] = $cardinfo[0]['N'][0]['value'][1][0];
+
+ // Key "Nickname", optional
+ if (isset($cardinfo[0]['NICKNAME'])) {
+ $info['nickname'] = $cardinfo[0]['NICKNAME'][0]['value'][0][0];
+ }
+ return $info;
+}
+
+/*
+ * Display a vcard taking the data in a file
+ */
+function vcard_fromFile($file) {
+ $parse = new Contact_Vcard_Parse();
+ $cardinfo = $parse->fromFile($file);
+//print_r($cardinfo[0]);
+ $ret['vcard'] = vcard_generate_vcard($cardinfo);
+ $ret['basicinfo'] = vcard_extractBasicInfo($cardinfo);
+ return $ret;
+}
+
+/*
+ * Display a vcard taking the data from the text given as an argument
+ */
+function vcard_fromText($text) {
+ $parse = new Contact_Vcard_Parse();
+ $cardinfo = $parse->fromText($text);
+ $ret['vcard'] = vcard_generate_vcard($cardinfo);
+ $ret['basicinfo'] = vcard_extractBasicInfo($cardinfo);
+ return $ret;
+}
+
+?>
Index: functions/file_prefs.php
===================================================================
--- functions/file_prefs.php (revision 13325)
+++ functions/file_prefs.php (working copy)
@@ -338,4 +338,51 @@
     return $sig;
 }
 
+/**
+ * Write the User vCard.
+ * @param string $data_dir data directory
+ * @param string $username user name
+ * @param integer $number identity number.
+ * @param string $tmp_file temporary file where the vcard is stored after upload
+ */
+function setVcard($data_dir, $username, $number, $tmp_file) {
+    $filename = getHashedFile($username, $data_dir, "$username.vcar$number");
+
+ if ($tmp_file == '') {
+ @unlink($filename);
+ } else {
+ if (! @copy($tmp_file, $filename) ) {
+   logout_error( sprintf( _("vCard file, %s, could not be copied from temporary file, %s. Contact your system administrator to resolve this issue."), $filename, $tmp_file) );
+   exit;
+ }
+ @unlink($tmp_file);
+ @chmod($filename, 0600);
+ }
+}
+
+/**
+ * Get the vCard.
+ * @param string $data_dir data directory
+ * @param string $username user name
+ * @param integer $number (since 1.2.5) identity number
+ * @return string signature
+ */
+function getVcard($data_dir, $username, $number) {
+    $filename = getHashedFile($username, $data_dir, "$username.vcar$number");
+    $vcard = '';
+    if (file_exists($filename)) {
+        /* Open the file, or else display an error to the user. */
+        if(!$file = @fopen($filename, 'r'))
+        {
+            logout_error( sprintf( _("vCard file, %s, could not be opened. Contact your system administrator to resolve this issue."), $filename) );
+            exit;
+        }
+        while (!feof($file)) {
+            $vcard .= fgets($file, 1024);
+        }
+        fclose($file);
+    }
+    return $vcard;
+}
+
 // vim: et ts=4


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
-----
squirrelmail-devel mailing list
Posting guidelines: http://squirrelmail.org/postingguidelines
List address: squirrelmail-devel@...
List archives: http://news.gmane.org/gmane.mail.squirrelmail.devel
List info (subscribe/unsubscribe/change options): https://lists.sourceforge.net/lists/listinfo/squirrelmail-devel