223 lines
7.2 KiB
Bash
223 lines
7.2 KiB
Bash
|
#!/usr/bin/env php
|
||
|
<?php
|
||
|
/*
|
||
|
+-----------------------------------------------------------------------+
|
||
|
| export-contacts.sh |
|
||
|
| |
|
||
|
| This script permit to export Roundcube user's address book in vCard |
|
||
|
| format. |
|
||
|
| |
|
||
|
| Copyright (C) 2017, Easter-eggs |
|
||
|
| |
|
||
|
| Licensed under the GNU General Public License version 3 or |
|
||
|
| any later version with exceptions for skins & plugins. |
|
||
|
| See the LICENSE file for a full license statement. |
|
||
|
| |
|
||
|
+-----------------------------------------------------------------------+
|
||
|
| Author: Benjamin Renard <brenard@easter-eggs.com> |
|
||
|
+-----------------------------------------------------------------------+
|
||
|
*/
|
||
|
|
||
|
define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
|
||
|
ini_set('memory_limit', -1);
|
||
|
|
||
|
require_once INSTALL_PATH.'program/include/clisetup.php';
|
||
|
|
||
|
function print_usage()
|
||
|
{
|
||
|
print "Usage: export-contact.sh -u username -m mailhost.fqdn\n";
|
||
|
print "-u / --user User name\n";
|
||
|
print "-m / --mailhost Mailhost (optional)\n";
|
||
|
print "-o / --output Output file\n";
|
||
|
print "-v / --verbose Enable verbose mode\n";
|
||
|
print "-d / --debug Enable debug mode\n";
|
||
|
}
|
||
|
|
||
|
function vputs($str)
|
||
|
{
|
||
|
$out = $GLOBALS['args']['file'] ? STDOUT : STDERR;
|
||
|
fwrite($out, $str);
|
||
|
}
|
||
|
|
||
|
function progress_update($pos, $max)
|
||
|
{
|
||
|
$percent = round(100 * $pos / $max);
|
||
|
vputs(sprintf("%3d%% [%-51s] %d/%d\033[K\r", $percent, @str_repeat('=', $percent / 2) . '>', $pos, $max));
|
||
|
}
|
||
|
|
||
|
class rcmail_export extends rcmail_utils {
|
||
|
|
||
|
function get_userid($user,$mailhost=null) {
|
||
|
$db = self::db();
|
||
|
$sql = "SELECT user_id, mail_host, last_login FROM " . $db->table_name('users', true) . " WHERE username=?";
|
||
|
$sql_params = array($user);
|
||
|
if ($mailhost) {
|
||
|
$sql .= " AND mail_host=?";
|
||
|
$sql_params[] = $mailhost;
|
||
|
}
|
||
|
//$sql .= " ORDER BY last_login DESC";
|
||
|
$sql_result = $db->query($sql, $sql_params);
|
||
|
log_msg("DEBUG", "Search user $user SQL query : $sql / ".print_r($sql_params, 1));
|
||
|
if ($sql_result) {
|
||
|
if ($db -> num_rows($sql_result)==0) {
|
||
|
log_msg('FATAL',"User $user not found !");
|
||
|
}
|
||
|
elseif ($db -> num_rows($sql_result)>1) {
|
||
|
log_msg('FATAL', "More thant one user found for username $user. You need to specify mailhost !");
|
||
|
log_msg('INFO', "Users found :");
|
||
|
while($sql_arr = $db->fetch_assoc($sql_result)) {
|
||
|
log_msg('INFO', " - User : $user / ID : ".$sql_arr['user_id']." / Mailhost : ".$sql_arr['mail_host']." / Last login : ".$sql_arr['last_login']);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
$sql_arr = $db->fetch_assoc($sql_result);
|
||
|
return $sql_arr['user_id'];
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function get_user_address_book($user, $mailhost = null) {
|
||
|
$userid=$this -> get_userid($user, $mailhost);
|
||
|
if ($userid !== false) {
|
||
|
log_msg('DEBUG', "User $user ID : $userid");
|
||
|
$contacts = new rcube_contacts(self::db(), $userid);
|
||
|
return $contacts;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function export_user_contacts($user, $mailhost = null, $out = null) {
|
||
|
$CONTACTS = $this->get_user_address_book($user, $mailhost);
|
||
|
if ($CONTACTS === false) {
|
||
|
log_msg('WARNING', "No address book found for user $user");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$CONTACTS->set_page(1);
|
||
|
$CONTACTS->set_pagesize(99999);
|
||
|
$result = $CONTACTS->list_records(null, 0, true);
|
||
|
|
||
|
if (!$out) {
|
||
|
$out = $GLOBALS['args']['file'] ? STDOUT : STDERR;
|
||
|
}
|
||
|
|
||
|
$count=0;
|
||
|
while ($result && ($row = $result->next())) {
|
||
|
if ($CONTACTS) {
|
||
|
$this -> prepare_for_export($row, $CONTACTS);
|
||
|
}
|
||
|
|
||
|
// fix folding and end-of-line chars
|
||
|
$row['vcard'] = preg_replace('/\r|\n\s+/', '', $row['vcard']);
|
||
|
$row['vcard'] = preg_replace('/\n/', rcube_vcard::$eol, $row['vcard']);
|
||
|
fwrite($out, rcube_vcard::rfc2425_fold($row['vcard']) . rcube_vcard::$eol);
|
||
|
$count++;
|
||
|
}
|
||
|
log_msg("INFO","$count contact(s) found in address book of user $user");
|
||
|
}
|
||
|
|
||
|
function prepare_for_export(&$record, $source = null) {
|
||
|
$groups = $source && $source->groups && $source->export_groups ? $source->get_record_groups($record['ID']) : null;
|
||
|
$fieldmap = $source ? $source->vcard_map : null;
|
||
|
|
||
|
if (empty($record['vcard'])) {
|
||
|
$vcard = new rcube_vcard($record['vcard'], RCUBE_CHARSET, false, $fieldmap);
|
||
|
$vcard->reset();
|
||
|
|
||
|
foreach ($record as $key => $values) {
|
||
|
list($field, $section) = explode(':', $key);
|
||
|
// avoid unwanted casting of DateTime objects to an array
|
||
|
// (same as in rcube_contacts::convert_save_data())
|
||
|
if (is_object($values) && is_a($values, 'DateTime')) {
|
||
|
$values = array($values);
|
||
|
}
|
||
|
|
||
|
foreach ((array) $values as $value) {
|
||
|
if (is_array($value) || is_a($value, 'DateTime') || @strlen($value)) {
|
||
|
$vcard->set($field, $value, strtoupper($section));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// append group names
|
||
|
if ($groups) {
|
||
|
$vcard->set('groups', join(',', $groups), null);
|
||
|
}
|
||
|
|
||
|
$record['vcard'] = $vcard->export();
|
||
|
}
|
||
|
// patch categories to alread existing vcard block
|
||
|
else if ($record['vcard']) {
|
||
|
$vcard = new rcube_vcard($record['vcard'], RCUBE_CHARSET, false, $fieldmap);
|
||
|
|
||
|
// unset CATEGORIES entry, it might be not up-to-date (#1490277)
|
||
|
$vcard->set('groups', null);
|
||
|
$record['vcard'] = $vcard->export();
|
||
|
|
||
|
if (!empty($groups)) {
|
||
|
$vgroups = 'CATEGORIES:' . rcube_vcard::vcard_quote($groups, ',');
|
||
|
$record['vcard'] = str_replace('END:VCARD', $vgroups . rcube_vcard::$eol . 'END:VCARD', $record['vcard']);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// get arguments
|
||
|
$opts = array('u' => 'user', 'm' => 'mailhost', 'o' => 'output', 'd' => 'debug', 'v' => 'verbose', 'h' => 'help');
|
||
|
$args = rcube_utils::get_opt($opts);
|
||
|
|
||
|
if ($_SERVER['argv'][1] == 'help' || isset($args['help'])) {
|
||
|
print_usage();
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
$_log_levels=array(
|
||
|
'FATAL' => 0,
|
||
|
'WARNING' => 1,
|
||
|
'INFO' => 2,
|
||
|
'DEBUG' => 3
|
||
|
);
|
||
|
|
||
|
$log_level='WARNING';
|
||
|
if (isset($args['debug'])) {
|
||
|
$log_level='DEBUG';
|
||
|
}
|
||
|
elseif (isset($args['verbose'])) {
|
||
|
$log_level="INFO";
|
||
|
}
|
||
|
$_log_level=$_log_levels[$log_level];
|
||
|
|
||
|
function log_msg($level, $msg) {
|
||
|
global $_log_level, $_log_levels;
|
||
|
if (!isset($_log_levels[$level]))
|
||
|
$level='DEBUG';
|
||
|
$_level=$_log_levels[$level];
|
||
|
if ($_level <= $_log_level) {
|
||
|
echo "[$level] $msg\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// prompt for username if not set
|
||
|
if (empty($args['user'])) {
|
||
|
vputs("User: ");
|
||
|
$args['user'] = trim(fgets(STDIN));
|
||
|
}
|
||
|
|
||
|
$out=null;
|
||
|
if (!empty($args['output'])) {
|
||
|
$out=fopen($args['output'], 'w');
|
||
|
if ($out===false) {
|
||
|
print "Fail to open output file !\n";
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$export = new rcmail_export();
|
||
|
|
||
|
$export -> export_user_contacts( $args['user'], $args['mailhost'], $out);
|
||
|
|
||
|
if ($out)
|
||
|
fclose($out);
|