From 67cb017b0cdda3c2dcc7d9434fdbaca5f4ead938 Mon Sep 17 00:00:00 2001
From: Thomas Bruederli <thomas@roundcube.net>
Date: Sun, 20 Jan 2013 10:28:02 -0500
Subject: [PATCH] Extend archive plugin with user-configurable options to move messages into subfolders according to their date, sender or originating folder

---
 /dev/null                              |   21 -----
 plugins/archive/package.xml            |   42 +++++++++-
 plugins/archive/archive.php            |  136 ++++++++++++++++++++++++++++++++-
 plugins/archive/localization/en_US.inc |   11 ++
 plugins/archive/archive.js             |   23 +++++
 5 files changed, 199 insertions(+), 34 deletions(-)

diff --git a/plugins/archive/archive.js b/plugins/archive/archive.js
index af2b0d2..eee41d3 100644
--- a/plugins/archive/archive.js
+++ b/plugins/archive/archive.js
@@ -1,6 +1,6 @@
 /*
  * Archive plugin script
- * @version @package_version@
+ * @version 2.0
  */
 
 function rcmail_archive(prop)
@@ -8,8 +8,19 @@
   if (!rcmail.env.uid && (!rcmail.message_list || !rcmail.message_list.get_selection().length))
     return;
   
-  if (rcmail.env.mailbox != rcmail.env.archive_folder)
-    rcmail.command('moveto', rcmail.env.archive_folder);
+  if (rcmail.env.mailbox.indexOf(rcmail.env.archive_folder) != 0) {
+    if (!rcmail.env.archive_type) {
+      // simply move to archive folder (if no partition type is set)
+      rcmail.command('moveto', rcmail.env.archive_folder);
+    }
+    else {
+      // let the server sort the messages to the according subfolders
+      rcmail.http_post(
+        'plugin.move2archive',
+        { _uid: rcmail.message_list.get_selection().join(','), _mbox: rcmail.env.mailbox }
+      );
+    }
+  }
 }
 
 // callback for app-onload event
@@ -29,6 +40,12 @@
     var li;
     if (rcmail.env.archive_folder && (li = rcmail.get_folder_li(rcmail.env.archive_folder, '', true)))
       $(li).addClass('archive');
+
+    // callback for server response
+    rcmail.addEventListener('plugin.move2archive_response', function(result) {
+      if (result.update)
+        rcmail.command('checkmail');  // refresh list
+    });
   })
 }
 
diff --git a/plugins/archive/archive.php b/plugins/archive/archive.php
index 9b03cb1..38b4f9f 100644
--- a/plugins/archive/archive.php
+++ b/plugins/archive/archive.php
@@ -6,7 +6,7 @@
  * Plugin that adds a new button to the mailbox toolbar
  * to move messages to a (user selectable) archive folder.
  *
- * @version @package_version@
+ * @version 2.0
  * @license GNU GPLv3+
  * @author Andre Rodier, Thomas Bruederli
  */
@@ -45,14 +45,19 @@
       // register hook to localize the archive folder
       $this->add_hook('render_mailboxlist', array($this, 'render_mailboxlist'));
 
-      // set env variable for client
+      // set env variables for client
       $rcmail->output->set_env('archive_folder', $archive_folder);
+      $rcmail->output->set_env('archive_type', $rcmail->config->get('archive_type',''));
 
       // add archive folder to the list of default mailboxes
       if (($default_folders = $rcmail->config->get('default_folders')) && !in_array($archive_folder, $default_folders)) {
         $default_folders[] = $archive_folder;
         $rcmail->config->set('default_folders', $default_folders);
-      }  
+      }
+    }
+    else if ($rcmail->task == 'mail') {
+      // handler for ajax request
+      $this->register_action('plugin.move2archive', array($this, 'move_messages'));
     }
     else if ($rcmail->task == 'settings') {
       $dont_override = $rcmail->config->get('dont_override', array());
@@ -62,7 +67,10 @@
       }
     }
   }
-  
+
+  /**
+   * Hook to give the archive folder a localized name in the mailbox list
+   */
   function render_mailboxlist($p)
   {
     $rcmail = rcmail::get_instance();
@@ -80,7 +88,10 @@
     return $p;
   }
 
-  function _mod_folder_name(&$list, $folder, $new_name)
+  /**
+   * Helper method to find the archive folder in the mailbox tree
+   */
+  private function _mod_folder_name(&$list, $folder, $new_name)
   {
     foreach ($list as $idx => $item) {
       if ($item['id'] == $folder) {
@@ -93,6 +104,100 @@
     return false;
   }
 
+  /**
+   * Plugin action to move the submitted list of messages to the archive subfolders
+   * according to the user settings and their headers.
+   */
+  function move_messages()
+  {
+    $rcmail = rcmail::get_instance();
+    $this->add_texts('localization');
+
+    $storage = $rcmail->get_storage();
+    $storage->set_folder(($current_mbox = rcube_utils::get_input_value('_mbox', RCUBE_INPUT_POST)));
+
+    $delimiter = $storage->get_hierarchy_delimiter();
+    $archive_folder = $rcmail->config->get('archive_mbox');
+    $archive_type = $rcmail->config->get('archive_type', '');
+
+    $result = array('reload' => false, 'update' => false, 'errors' => array());
+
+    $uids = explode(',', rcube_utils::get_input_value('_uid', RCUBE_INPUT_POST));
+    foreach ($uids as $uid) {
+      if (!$archive_folder || !($message = $rcmail->storage->get_message($uid))) {
+        continue;
+      }
+
+      $subfolder = null;
+      switch ($archive_type) {
+        case 'year':
+          $subfolder = $rcmail->format_date($message->timestamp, 'Y');
+          break;
+
+        case 'month':
+          $subfolder = $rcmail->format_date($message->timestamp, 'Y') . $delimiter . $rcmail->format_date($message->timestamp, 'm');
+          break;
+
+        case 'folder':
+          $subfolder = $current_mbox;
+          break;
+
+        case 'sender':
+          $from = $message->get('from');
+          if (preg_match('/[\b<](.+@.+)[\b>]/i', $from, $m)) {
+            $subfolder = $m[1];
+          }
+          else {
+            $subfolder = $this->gettext('unkownsender');
+          }
+
+          // replace reserved characters in folder name
+          $repl = $delimiter == '-' ? '_' : '-';
+          $replacements[$delimiter] = $repl;
+          $replacements['.'] = $repl;  // some IMAP server do not allow . characters
+          $subfolder = strtr($subfolder, $replacements);
+          break;
+
+        default:
+          $subfolder = '';
+          break;
+      }
+
+      // compose full folder path
+      $folder =  $archive_folder . ($subfolder ? $delimiter . $subfolder : '');
+
+      // create archive subfolder if it doesn't yet exist
+      if (!$storage->folder_exists($folder, false)) {
+        if ($storage->create_folder($folder, true))
+          $result['reload'] = true;
+      }
+
+      // move message to target folder
+      if ($storage->move_message(array($uid), $folder)) {
+        $result['update'] = true;
+      }
+      else {
+        $result['errors'][] = $uid;
+      }
+    }  // end for
+
+    // send response
+    if ($result['errors']) {
+      $rcmail->output->show_message($this->gettext('archiveerror'), 'warning');
+    }
+    if ($result['reload']) {
+      $rcmail->output->show_message($this->gettext('archivedreload'), 'confirmation');
+    }
+    else if ($result['update']) {
+      $rcmail->output->show_message($this->gettext('archived'), 'confirmation');
+    }
+
+    $rcmail->output->command('plugin.move2archive_response', $result);
+  }
+
+  /**
+   * Hook to inject plugin-specific user settings
+   */
   function prefs_table($args)
   {
     global $CURR_SECTION;
@@ -113,15 +218,36 @@
           'title' => $this->gettext('archivefolder'),
           'content' => $select->show($rcmail->config->get('archive_mbox'), array('name' => "_archive_mbox"))
       );
+
+      // add option for structuring the archive folder
+      $archive_type = new html_select(array('name' => '_archive_type', 'id' => 'ff_archive_type'));
+      $archive_type->add($this->gettext('none'), '');
+      $archive_type->add($this->gettext('archivetypeyear'), 'year');
+      $archive_type->add($this->gettext('archivetypemonth'), 'month');
+      $archive_type->add($this->gettext('archivetypesender'), 'sender');
+      $archive_type->add($this->gettext('archivetypefolder'), 'folder');
+
+      $args['blocks']['archive'] = array(
+        'name' => Q(rcube_label('settingstitle', 'archive')),
+        'options' => array('archive_type' => array(
+            'title' => $this->gettext('archivetype'),
+            'content' => $archive_type->show($rcmail->config->get('archive_type'))
+          )
+        )
+      );
     }
 
     return $args;
   }
 
+  /**
+   * Hook to save plugin-specific user settings
+   */
   function save_prefs($args)
   {
     if ($args['section'] == 'folders') {
       $args['prefs']['archive_mbox'] = rcube_utils::get_input_value('_archive_mbox', rcube_utils::INPUT_POST);
+      $args['prefs']['archive_type'] = rcube_utils::get_input_value('_archive_type', rcube_utils::INPUT_POST);
       return $args;
     }
   }
diff --git a/plugins/archive/localization/en_US.inc b/plugins/archive/localization/en_US.inc
index fade708..d3714c1 100644
--- a/plugins/archive/localization/en_US.inc
+++ b/plugins/archive/localization/en_US.inc
@@ -5,7 +5,7 @@
  | plugins/archive/localization/<lang>.inc                                |
  |                                                                       |
  | Localization file of the Roundcube Webmail Archive plugin             |
- | Copyright (C) 2012, The Roundcube Dev Team                            |
+ | Copyright (C) 2013, The Roundcube Dev Team                            |
  |                                                                       |
  | Licensed under the GNU General Public License version 3 or            |
  | any later version with exceptions for skins & plugins.                |
@@ -20,6 +20,15 @@
 $labels['buttontext'] = 'Archive';
 $labels['buttontitle'] = 'Archive this message';
 $labels['archived'] = 'Successfully archived';
+$labels['archivedreload'] = 'Successfully archived. Reload the page to see the new archive folders.';
+$labels['archiveerror'] = 'Some messages could not be archived';
 $labels['archivefolder'] = 'Archive';
+$labels['settingstitle'] = 'Archive';
+$labels['archivetype'] = 'Divide archive by';
+$labels['archivetypeyear'] = 'Year (e.g. Archive/2012)';
+$labels['archivetypemonth'] = 'Month (e.g. Archive/2012/06)';
+$labels['archivetypefolder'] = 'Original folder';
+$labels['archivetypesender'] = 'Sender email';
+$labels['unkownsender'] = 'unknown';
 
 ?>
diff --git a/plugins/archive/localization/nb_NB.inc b/plugins/archive/localization/nb_NB.inc
deleted file mode 100644
index 46e49ab..0000000
--- a/plugins/archive/localization/nb_NB.inc
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | localization/nb_NB/labels.inc                                         |
- |                                                                       |
- | Language file of the Roundcube Webmail client                         |
- | Copyright (C) 2012, The Roundcube Dev Team                            |
- | Licensed under the GNU General Public License                         |
- |                                                                       |
- +-----------------------------------------------------------------------+
- | Author: Tobias V. Langhoff <spug@thespug.net>                         |
- +-----------------------------------------------------------------------+
-*/
-
-$labels = array();
-$labels['buttontext'] = 'Arkiv';
-$labels['archivefolder'] = 'Arkiv';
-$labels['buttontitle'] = 'Arkiver meldingen';
-$labels['archived'] = 'Arkivert';
-
diff --git a/plugins/archive/package.xml b/plugins/archive/package.xml
index 1aeffaf..62a009a 100644
--- a/plugins/archive/package.xml
+++ b/plugins/archive/package.xml
@@ -6,17 +6,17 @@
 	<name>archive</name>
 	<channel>pear.roundcube.net</channel>
 	<summary>Archive feature for Roundcube</summary>
-	<description>This adds a button to move the selected messages to an archive folder. The folder can be selected in the settings panel.</description>
+	<description>This adds a button to move the selected messages to an archive folder. The folder (and the optional structure of subfolders) can be selected in the settings panel.</description>
 	<lead>
 		<name>Thomas Bruederli</name>
 		<user>thomasb</user>
 		<email>roundcube@gmail.com</email>
 		<active>yes</active>
 	</lead>
-	<date>2011-11-23</date>
+	<date>2013-01-20</date>
 	<version>
-		<release>1.6</release>
-		<api>1.6</api>
+		<release>2.0</release>
+		<api>2.0</api>
 	</version>
 	<stability>
 		<release>stable</release>
@@ -34,21 +34,55 @@
 				<tasks:replace from="@name@" to="name" type="package-info"/>
 				<tasks:replace from="@package_version@" to="version" type="package-info"/>
 			</file>
+			<file name="localization/ar_SA.inc" role="data"></file>
+			<file name="localization/az_AZ.inc" role="data"></file>
+			<file name="localization/be_BE.inc" role="data"></file>
+			<file name="localization/bg_BG.inc" role="data"></file>
+			<file name="localization/bs_BA.inc" role="data"></file>
+			<file name="localization/ca_ES.inc" role="data"></file>
 			<file name="localization/cs_CZ.inc" role="data"></file>
+			<file name="localization/cy_GB.inc" role="data"></file>
+			<file name="localization/da_DK.inc" role="data"></file>
 			<file name="localization/de_CH.inc" role="data"></file>
 			<file name="localization/de_DE.inc" role="data"></file>
+			<file name="localization/el_GR.inc" role="data"></file>
+			<file name="localization/eb_GB.inc" role="data"></file>
 			<file name="localization/en_US.inc" role="data"></file>
 			<file name="localization/es_AR.inc" role="data"></file>
 			<file name="localization/es_ES.inc" role="data"></file>
 			<file name="localization/et_EE.inc" role="data"></file>
+			<file name="localization/fa_IR.inc" role="data"></file>
+			<file name="localization/fi_FI.inc" role="data"></file>
 			<file name="localization/fr_FR.inc" role="data"></file>
 			<file name="localization/gl_ES.inc" role="data"></file>
+			<file name="localization/he_IL.inc" role="data"></file>
+			<file name="localization/hr_HR.inc" role="data"></file>
+			<file name="localization/hu_HU.inc" role="data"></file>
+			<file name="localization/hy_AM.inc" role="data"></file>
+			<file name="localization/id_ID.inc" role="data"></file>
+			<file name="localization/it_IT.inc" role="data"></file>
 			<file name="localization/ja_JP.inc" role="data"></file>
+			<file name="localization/km_KH.inc" role="data"></file>
+			<file name="localization/ko_KR.inc" role="data"></file>
+			<file name="localization/lt_LT.inc" role="data"></file>
+			<file name="localization/lv_LV.inc" role="data"></file>
+			<file name="localization/ml_IN.inc" role="data"></file>
+			<file name="localization/nb_NO.inc" role="data"></file>
 			<file name="localization/nl_NL.inc" role="data"></file>
+			<file name="localization/nn_NO.inc" role="data"></file>
 			<file name="localization/pl_PL.inc" role="data"></file>
 			<file name="localization/pt_BR.inc" role="data"></file>
+			<file name="localization/pt_PT.inc" role="data"></file>
 			<file name="localization/ru_RU.inc" role="data"></file>
+			<file name="localization/si_LK.inc" role="data"></file>
+			<file name="localization/sk_SK.inc" role="data"></file>
+			<file name="localization/sl_SI.inc" role="data"></file>
+			<file name="localization/sr_CS.inc" role="data"></file>
 			<file name="localization/sv_SE.inc" role="data"></file>
+			<file name="localization/tr_TR.inc" role="data"></file>
+			<file name="localization/uk_UA.inc" role="data"></file>
+			<file name="localization/vi_VN.inc" role="data"></file>
+			<file name="localization/zh_CN.inc" role="data"></file>
 			<file name="localization/zh_TW.inc" role="data"></file>
 			<file name="skins/classic/archive_act.png" role="data"></file>
 			<file name="skins/classic/archive_pas.png" role="data"></file>

--
Gitblit v1.9.1