From 1391f17a521a19382c59ef9d4e93a8ced2f1a9e5 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Thu, 08 Aug 2013 09:49:11 -0400
Subject: [PATCH] Fix issue where uploaded photo was lost when contact form did not validate (#1489274)

---
 program/steps/addressbook/func.inc |  128 +++++++++++++++++++++++++++++++-----------
 1 files changed, 94 insertions(+), 34 deletions(-)

diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index 4d4bf22..f94d153 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -26,7 +26,7 @@
   'name'         => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'limit' => 1, 'label' => rcube_label('name'), 'category' => 'main'),
   'firstname'    => array('type' => 'text', 'size' => 19, 'maxlength' => 50, 'limit' => 1, 'label' => rcube_label('firstname'), 'category' => 'main'),
   'surname'      => array('type' => 'text', 'size' => 19, 'maxlength' => 50, 'limit' => 1, 'label' => rcube_label('surname'), 'category' => 'main'),
-  'email'        => array('type' => 'text', 'size' => 40, 'maxlength' => 50, 'label' => rcube_label('email'), 'subtypes' => array('home','work','other'), 'category' => 'main'),
+  'email'        => array('type' => 'text', 'size' => 40, 'maxlength' => 254, 'label' => rcube_label('email'), 'subtypes' => array('home','work','other'), 'category' => 'main'),
   'middlename'   => array('type' => 'text', 'size' => 19, 'maxlength' => 50, 'limit' => 1, 'label' => rcube_label('middlename'), 'category' => 'main'),
   'prefix'       => array('type' => 'text', 'size' => 8,  'maxlength' => 20, 'limit' => 1, 'label' => rcube_label('nameprefix'), 'category' => 'main'),
   'suffix'       => array('type' => 'text', 'size' => 8,  'maxlength' => 20, 'limit' => 1, 'label' => rcube_label('namesuffix'), 'category' => 'main'),
@@ -167,7 +167,7 @@
     // get address book name (for display)
     if ($abook && $_SESSION['addressbooks_count'] > 1) {
         $name = $abook->get_name();
-        if (!$name && $source == 0) {
+        if (!$name) {
             $name = rcube_label('personaladrbook');
         }
         $OUTPUT->set_env('sourcename', html_entity_decode($name, ENT_COMPAT, 'UTF-8'));
@@ -183,7 +183,6 @@
         $attrib['id'] = 'rcmdirectorylist';
 
     $out = '';
-    $local_id = '0';
     $jsdata = array();
 
     $line_templ = html::tag('li', array(
@@ -268,8 +267,8 @@
 {
     global $RCMAIL;
 
+    $groups_html = '';
     $groups = $RCMAIL->get_address_book($args['source'])->list_groups();
-    $js_id = $RCMAIL->JQ($args['source']);
 
     if (!empty($groups)) {
         $line_templ = html::tag('li', array(
@@ -282,8 +281,6 @@
         $is_collapsed = strpos($RCMAIL->config->get('collapsed_abooks',''), '&'.rawurlencode($args['source']).'&') !== false;
         $args['out'] .= html::div('treetoggle ' . ($is_collapsed ? 'collapsed' : 'expanded'), '&nbsp;');
 
-        $jsdata = array();
-        $groups_html = '';
         foreach ($groups as $group) {
             $groups_html .= sprintf($line_templ,
                 rcube_utils::html_identifier('G' . $args['source'] . $group['ID'], true),
@@ -297,7 +294,7 @@
     }
 
     $args['out'] .= html::tag('ul',
-      array('class' => 'groups', 'style' => ($is_collapsed ? "display:none;" : null)),
+      array('class' => 'groups', 'style' => ($is_collapsed || empty($groups) ? "display:none;" : null)),
       $groups_html);
 
     return $args;
@@ -325,7 +322,7 @@
     $OUTPUT->include_script('list.js');
 
     // add some labels to client
-    $OUTPUT->add_label('deletecontactconfirm', 'copyingcontact', 'contactdeleting');
+    $OUTPUT->add_label('deletecontactconfirm', 'copyingcontact', 'movingcontact', 'contactdeleting');
 
     return $out;
 }
@@ -372,6 +369,8 @@
                             'onclick' => sprintf("return %s.command('pushgroup',{'source':'%s','id':'%s'},this,event)", JS_OBJECT_NAME, $source_id, $row['CID']),
                         ), '&raquo;');
                     }
+                    else
+                        $val = '&nbsp;';
                     break;
 
                 default:
@@ -594,22 +593,13 @@
                     // iterate over possible subtypes and collect values with their subtype
                     if (is_array($colprop['subtypes'])) {
                         $values = $subtypes = array();
-                        foreach ($colprop['subtypes'] as $i => $st) {
-                            $newval = false;
-                            if ($record[$field.':'.$st]) {
-                                $subtypes[count($values)] = $st;
-                                $newval = $record[$field.':'.$st];
+                        foreach (rcube_addressbook::get_col_values($field, $record) as $st => $vals) {
+                            foreach((array)$vals as $value) {
+                                $i = count($values);
+                                $subtypes[$i] = $st;
+                                $values[$i] = $value;
                             }
-                            else if ($i == 0 && $record[$field]) {
-                                $subtypes[count($values)] = $st;
-                                $newval = $record[$field];
-                            }
-                            if ($newval !== false) {
-                                if (is_array($newval) && isset($newval[0]))
-                                    $values = array_merge($values, $newval);
-                                else
-                                    $values[] = $newval;
-                            }
+                            // TODO: add $st to $select_subtype if missing ?
                         }
                     }
                     else {
@@ -761,12 +751,28 @@
 
     $plugin = $RCMAIL->plugins->exec_hook('contact_photo', array('record' => $record, 'data' => $record['photo']));
 
+    // check if we have photo data from contact form
+    if ($GLOBALS['EDIT_RECORD']) {
+        $rec = $GLOBALS['EDIT_RECORD'];
+        if ($rec['photo'] == '-del-') {
+            $record['photo'] = '';
+        }
+        else if ($_SESSION['contacts']['files'][$rec['photo']]) {
+            $record['photo'] = $file_id = $rec['photo'];
+        }
+    }
+
     if ($plugin['url'])
         $photo_img = $plugin['url'];
     else if (preg_match('!^https?://!i', $record['photo']))
         $photo_img = $record['photo'];
-    else if ($record['photo'])
-        $photo_img = $RCMAIL->url(array('_action' => 'photo', '_cid' => $record['ID'], '_source' => $SOURCE_ID));
+    else if ($record['photo']) {
+        $url = array('_action' => 'photo', '_cid' => $record['ID'], '_source' => $SOURCE_ID);
+        if ($file_id) {
+            $url['_photo'] = $ff_value = $file_id;
+        }
+        $photo_img = $RCMAIL->url($url);
+    }
     else
         $ff_value = '-del-'; // will disable delete-photo action
 
@@ -789,6 +795,54 @@
     return format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d'), false);
 }
 
+/**
+ * Updates saved search after data changed
+ */
+function rcmail_search_update($return = false)
+{
+    global $RCMAIL;
+
+    if (($search_request = $_REQUEST['_search']) && isset($_SESSION['search'][$search_request])) {
+        $search   = (array)$_SESSION['search'][$search_request];
+        $sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name');
+        $afields  = $return ? $RCMAIL->config->get('contactlist_fields') : array('name', 'email');
+        $records  = array();
+
+        foreach ($search as $s => $set) {
+            $source = $RCMAIL->get_address_book($s);
+
+            // reset page
+            $source->set_page(1);
+            $source->set_pagesize(9999);
+            $source->set_search_set($set);
+
+            // get records
+            $result = $source->list_records($afields);
+
+            if (!$result->count) {
+                unset($search[$s]);
+                continue;
+            }
+
+            if ($return) {
+                while ($row = $result->next()) {
+                    $row['sourceid'] = $s;
+                    $key = rcube_addressbook::compose_contact_key($row, $sort_col);
+                    $records[$key] = $row;
+                }
+                unset($result);
+            }
+
+            $search[$s] = $source->get_search_set();
+        }
+
+        $_SESSION['search'][$search_request] = $search;
+
+        return $records;
+    }
+
+    return false;
+}
 
 /**
  * Returns contact ID(s) and source(s) from GET/POST data
@@ -812,20 +866,27 @@
         return array();
     }
 
-    $cid    = explode(',', $cid);
-    $result = array();
+    $cid        = explode(',', $cid);
+    $got_source = strlen($source);
+    $result     = array();
 
     // create per-source contact IDs array
     foreach ($cid as $id) {
-        // get source from decoded ID
-        if ($sep = strrpos($id, '-')) {
-            $contact_id = substr($id, 0, $sep);
-            $source_id  = substr($id, $sep+1);
-            if (strlen($source_id)) {
-                $result[(string)$source_id][] = $contact_id;
+        // extract source ID from contact ID (it's there in search mode)
+        // see #1488959 and #1488862 for reference
+        if (!$got_source) {
+            if ($sep = strrpos($id, '-')) {
+                $contact_id = substr($id, 0, $sep);
+                $source_id  = (string) substr($id, $sep+1);
+                if (strlen($source_id)) {
+                    $result[$source_id][] = $contact_id;
+                }
             }
         }
         else {
+            if (substr($id, -($got_source+1)) === "-$source") {
+                $id = substr($id, 0, -($got_source+1));
+            }
             $result[$source][] = $id;
         }
     }
@@ -848,7 +909,6 @@
 // register action aliases
 $RCMAIL->register_action_map(array(
     'add' => 'edit.inc',
-    'photo' => 'show.inc',
     'group-create' => 'groups.inc',
     'group-rename' => 'groups.inc',
     'group-delete' => 'groups.inc',

--
Gitblit v1.9.1