diff --git a/README.textile b/README.textile index 448c64947..6d199e56a 100644 --- a/README.textile +++ b/README.textile @@ -1,3 +1,8 @@ +h1. Modifizierte Version evtl. für GS 3.3 + +Eine Übersicht erhält man im Wiki unter https://github.com/marneu/GS3/wiki/Installation-der-Erweiterungen-auf-GS-3.2 +> Hinweis: Diese Version hat derzeit keinen Support von der GS3 Gemeinschaft und es kann nicht sichergestellt werden, ob die Änderungen in den GS 3 Master übernommen werden. + h1. Asterisk Version Gemeinschaft in der Version 3 ist die ältere Software mit einem Asterisk-Kern. Die aktuellere Version von Gemeinschaft hat Freeswitch als Kern. Weitere Informationen dazu finden Sie auf "https://www.alternative-solution.de/gs3":https://www.alternative-solution.de/gs3 diff --git a/etc/cron.d/gs-carddav-reader-to-db b/etc/cron.d/gs-carddav-reader-to-db new file mode 100644 index 000000000..4ade8a3a6 --- /dev/null +++ b/etc/cron.d/gs-carddav-reader-to-db @@ -0,0 +1,6 @@ +# Gemeinschaft +# $Revision$ + +# refresh cloud card phone books into the database + +*/17 * * * * root sleep 23; nice -n 15 /opt/gemeinschaft/sbin/gs-carddav-reader.php 1>>/dev/null 2>>/dev/null diff --git a/misc/scripts/upgrade-pb-3.2-3.3.sql b/misc/scripts/upgrade-pb-3.2-3.3.sql new file mode 100644 index 000000000..2a0fe8cf8 --- /dev/null +++ b/misc/scripts/upgrade-pb-3.2-3.3.sql @@ -0,0 +1,112 @@ +// gs 3.3 private phonebook modifications +DROP TABLE IF EXISTS `pb_prv_previous`; +RENAME TABLE `pb_prv` TO `pb_prv_previous`; + +CREATE TABLE IF NOT EXISTS `pb_prv` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL DEFAULT '0', + `firstname` varchar(40) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', + `lastname` varchar(40) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', + `number` varchar(25) CHARACTER SET ascii NOT NULL DEFAULT '', + `ptype` varchar(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'cell,work,home', + `pref` int(2) unsigned NOT NULL DEFAULT '9', + `card_id` int(10) unsigned NOT NULL, + `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `uid_vcard` (`user_id`,`card_id`), + KEY `uid_lastname_firstname_pref` (`user_id`,`lastname`(15),`firstname`(10),`pref`,`ptype`), + KEY `cloud_card_id` (`card_id`), + KEY `uid_number_pref` (`user_id`,`number`(10),`pref`,`ptype`), + KEY `uid_firstname_lastname_pref` (`user_id`,`firstname`(10),`lastname`(10),`pref`,`ptype`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +INSERT INTO `pb_prv` (`id`, `user_id`, `firstname`, `lastname`, `number`) + SELECT `id`, `user_id`, `firstname`, `lastname`, `number` FROM `pb_prv_previous`; + +ALTER TABLE `pb_prv` ADD CONSTRAINT `pb_prv_ibfk_1` FOREIGN KEY (`user_id`) + REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT ; + +// import voip phone book from cloud for preparing the xml to phone functionality +CREATE TABLE IF NOT EXISTS `pb_cloud` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL, + `url` varchar(256) COLLATE utf8_unicode_ci NOT NULL, + `login` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `pass` varbinary(64) NOT NULL, + `frequency` varchar(3) COLLATE utf8_unicode_ci NOT NULL DEFAULT '1d', + `ctag` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `last_remote_modified` datetime NOT NULL, + `next_poll` datetime NOT NULL, + `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `message` tinytext COLLATE utf8_unicode_ci NOT NULL, + `error_count` tinyint(1) unsigned NOT NULL DEFAULT '0', + `active` tinyint(1) unsigned NOT NULL DEFAULT '1', + `public` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `uid_url_login` (`user_id`,`url`(255),`login`), + KEY `next_poll` (`next_poll`), + KEY `uid_login_url` (`user_id`,`login`,`url`(255)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +ALTER TABLE `pb_cloud` ADD FOREIGN KEY ( `user_id` ) + REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT ; + +// holds the vcards +CREATE TABLE IF NOT EXISTS `pb_cloud_card` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `cloud_id` int(10) unsigned NOT NULL, + `vcard_id` varchar(36) COLLATE utf8_unicode_ci NOT NULL, + `etag` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `vcard` text COLLATE utf8_unicode_ci NOT NULL, + `last_modified` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `cloud_id_vcard_id` (`cloud_id`,`vcard_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +ALTER TABLE `pb_cloud_card` ADD FOREIGN KEY ( `cloud_id` ) + REFERENCES `pb_cloud` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_prv` ADD FOREIGN KEY ( `card_id` ) + REFERENCES `pb_cloud_card` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; + +// add categories (i.e like family, company etc.) +CREATE TABLE IF NOT EXISTS `pb_category` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL, + `category` varchar(24) COLLATE utf8_unicode_ci NOT NULL, + `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `uid_catid` (`user_id`,`category`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +ALTER TABLE `pb_category` ADD FOREIGN KEY ( `user_id` ) + REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; + +// connect a phone book entry to a category +CREATE TABLE IF NOT EXISTS `pb_prv_category` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL, + `cat_id` int(10) unsigned NOT NULL, + `card_id` int(10) unsigned NOT NULL, + `prv_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `uid_catid_cardid` (`user_id`,`cat_id`,`card_id`), + KEY `uid_prvid` (`user_id`,`prv_id`), + KEY `uid_cardid` (`user_id`,`card_id`), + KEY `card_id` (`card_id`), + KEY `prv_id` (`prv_id`), + KEY `catid_uid` (`cat_id`,`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +ALTER TABLE `pb_prv_category` ADD FOREIGN KEY ( `user_id` ) + REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_prv_category` ADD FOREIGN KEY ( `cat_id` ) + REFERENCES `pb_category` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_prv_category` ADD FOREIGN KEY ( `card_id` ) + REFERENCES `pb_cloud_card` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_prv_category` ADD FOREIGN KEY ( `prv_id` ) + REFERENCES `pb_prv` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; + +// set new modules active +INSERT INTO `group_members` VALUES (6, 3005); +// needed dependency for public cloud entries +INSERT INTO `users` VALUES ('1', 'public-abook', '', '', '', '', '', '1', '1', NULL, '', NULL, NULL, NULL, ''); diff --git a/opt/gemeinschaft/dialplan-scripts/dial-log-store b/opt/gemeinschaft/dialplan-scripts/dial-log-store index d7a972ad6..25a61f07b 100755 --- a/opt/gemeinschaft/dialplan-scripts/dial-log-store +++ b/opt/gemeinschaft/dialplan-scripts/dial-log-store @@ -76,7 +76,7 @@ $remote_user = $rs->fetchRow(); $is_from_phonebook = false; if (! $remote_user) { # if there is nothing in the ast_sipfriends, check the private phonebook - $rs = $db->execute('SELECT `firstname`, `lastname` FROM `pb_prv` WHERE `user_id`='.$uid.' AND `number`=\''. $db->escape($number) .'\''); + $rs = $db->execute('SELECT `firstname`, `lastname` FROM `pb_prv` WHERE (`user_id`='.$uid.' OR `user_id`=1) AND `number`=\''. $db->escape($number) .'\''); //FIXME - probably doesn't make much sense with uncanonized phone numbers $remote_user = $rs->fetchRow(); $is_from_phonebook = true; @@ -103,4 +103,4 @@ $db->execute( 'INSERT INTO `dial_log` (`user_id`, `type`, `timestamp`, `number`, -?> \ No newline at end of file +?> diff --git a/opt/gemeinschaft/dialplan-scripts/in-get-callername.agi b/opt/gemeinschaft/dialplan-scripts/in-get-callername.agi index 07b2a685a..2d9c272a8 100755 --- a/opt/gemeinschaft/dialplan-scripts/in-get-callername.agi +++ b/opt/gemeinschaft/dialplan-scripts/in-get-callername.agi @@ -37,7 +37,7 @@ ob_implicit_flush(1); function search_number ( $user_id, $source, $cid , $db ) { if ($source == 'private') - $query = 'SELECT `firstname`, `lastname`, `number` FROM `pb_prv` WHERE `user_id`=' . $user_id . ' AND `number`= \'' . $db->escape($cid) . '\''; + $query = 'SELECT `firstname`, `lastname`, `number`, `ptype` FROM `pb_prv` WHERE ( `user_id`=' . $user_id . ' OR `user_id`=1 ) AND `number`= \'' . $db->escape($cid) . '\''; else if ($source == 'public') $query = 'SELECT `firstname`, `lastname`, `number` FROM `pb_ldap` WHERE `number`=\''. $db->escape($cid) . '\''; @@ -49,7 +49,9 @@ function search_number ( $user_id, $source, $cid , $db ) { $firstname = $caller['firstname']; $lastname = $caller['lastname']; $number = $caller['number']; - $set = array( 'firstname' => $caller['firstname'], 'lastname' => $caller['lastname'], 'number' => $caller['number']); + if (isset($caller['ptype']) && !empty($caller['ptype']) ) $ptype = $caller['ptype']; + else $ptype = ''; + $set = array( 'firstname' => $caller['firstname'], 'lastname' => $caller['lastname'], 'number' => $caller['number'], 'ptype' => $ptype); $result[$number] = $set; } } @@ -57,14 +59,17 @@ function search_number ( $user_id, $source, $cid , $db ) { //direct match if ( isset($result[$cid]) ) { $hit = $result[$cid]; - print_name($hit['firstname'], $hit['lastname']); + print_name($hit['firstname'], $hit['lastname'], $hit['ptype']); } } -function print_name ( $firstname, $lastname ) { +function print_name ( $firstname, $lastname, $ptype='' ) { $fullname = ''; - if(strlen($firstname) > 0) - $fullname = strtoupper( substr($firstname, 0, 1) ) . '. ' . $lastname; + if(strlen($ptype) > 0) + $fullname = strtoupper( substr($firstname, 0, 1) ) . '. ' . $lastname . ' (' . $ptype .')'; +// else +// if(strlen($firstname) > 0) +// $fullname = strtoupper( substr($firstname, 0, 1) ) . '. ' . $lastname; else $fullname = $lastname; gs_agi_set_variable('CALLERID(name)' , $fullname); diff --git a/opt/gemeinschaft/dialplan-scripts/in-user-get-fw.agi b/opt/gemeinschaft/dialplan-scripts/in-user-get-fw.agi index 74b4bfb79..b06d5f6fe 100755 --- a/opt/gemeinschaft/dialplan-scripts/in-user-get-fw.agi +++ b/opt/gemeinschaft/dialplan-scripts/in-user-get-fw.agi @@ -147,6 +147,9 @@ foreach ($forwards as $source => $arr) { gs_agi_set_variable( '__fw_'.$source.'_'.$case, $fw['number'] ); + /* STD/MN Variable not set, so no content will be played - WORKAROUND */ + if ($fw['file'] === '') $fw['file']=$fw['number'].'-external.alaw'; + gs_agi_set_variable( '__fw_file_'.$source.'_'.$case, '/opt/gemeinschaft/vm-rec/'.$fw['file'] ); if (is_array($fw['number'])) { # this is an array if we are forwarding to parallel-call @@ -197,4 +200,4 @@ foreach ($msgs as $src => $file) { -?> \ No newline at end of file +?> diff --git a/opt/gemeinschaft/dialplan-scripts/out-route.agi b/opt/gemeinschaft/dialplan-scripts/out-route.agi index c2ed28fc4..4bf80507a 100755 --- a/opt/gemeinschaft/dialplan-scripts/out-route.agi +++ b/opt/gemeinschaft/dialplan-scripts/out-route.agi @@ -228,20 +228,22 @@ WHERE `id`='. $ggrp_id } } - $rs = $db->execute( + $rs = $db->execute( 'SELECT `type`, `name`, `dialstr`, `hw_port`, `host`, `user` FROM `gates` WHERE - `grp_id`='. $ggrp_id .' AND - `allow_out`=1 -ORDER BY RAND() + `grp_id`='. $ggrp_id .' AND + `allow_out`=1 +ORDER BY `title` LIKE CONCAT("%","'. $out_cid_num .'","%") DESC LIMIT 9' - ); + ); + //while ($gate = $rs->fetchRow()) $gates[] = $gate; while ($gate = $rs->fetchRow()) { $pos = 0; $dial_arr = array(); while ($pos < strLen($gate['dialstr'])) { +// gs_agi_verbose( $gate['dialstr'] ); $dial_vara = array(); diff --git a/opt/gemeinschaft/doc/de/docbook/datenbank-tabellen.xml b/opt/gemeinschaft/doc/de/docbook/datenbank-tabellen.xml index ca98ff48c..338baa823 100644 --- a/opt/gemeinschaft/doc/de/docbook/datenbank-tabellen.xml +++ b/opt/gemeinschaft/doc/de/docbook/datenbank-tabellen.xml @@ -17,19 +17,19 @@ Tabellenstruktur eingespielt wird, ist in beschrieben. - Die Datei asterisk.sql enth�lt hier alle zum - Erzeugen der Tabellen n�tigen SQL-Befehle. Einige Eintr�ge (z.B. IP-Adressen - etc.) m�ssen noch an die Installation angepa�t werden. + Die Datei asterisk.sql enthält hier alle zum + Erzeugen der Tabellen nötigen SQL-Befehle. Einige Einträge (z.B. IP-Adressen + etc.) müssen noch an die Installation angepaßt werden.
Datenbank-Struktur In der Datenbank asterisk werden zentral - Laufzeitkonfiguration und Logeintr�ge vorgehalten. Auf alle Tabellen, die + Laufzeitkonfiguration und Logeinträge vorgehalten. Auf alle Tabellen, die mit ast_ beginnen, wird direkt aus Asterisk zugegriffen, wodurch auch die Struktur und Spaltennamen vorgegeben sind. - Zus�tzliche Spalten, die f�r Asterisk keine Bedeutung haben, sind in - diesen Tabellen mit einem f�hrenden Unterstrich (_) + Zusätzliche Spalten, die für Asterisk keine Bedeutung haben, sind in + diesen Tabellen mit einem führenden Unterstrich (_) benannt.
@@ -37,7 +37,7 @@ Tabellenstruktur der Datenbank <quote>asterisk</quote> Die Tabellen der Datenbank werden hier alphabetisch - aufgef�hrt. + aufgeführt.
<literal>ast_cdr</literal> @@ -48,9 +48,9 @@ Konfigurationen dazu werden auf den Asterisk-Servern in der /opt/gemeinschaft/etc/asterisk/cdr_mysql.conf vorgenommen. Im Gegensatz zur Tabelle dial_log wird - diese Tabelle zur Auswertung von Gesp�chsdaten verwendet (z.B. + diese Tabelle zur Auswertung von Gespächsdaten verwendet (z.B. Statistik). Die Tabelle dial_log dient hingegen nur - der Anzeige f�r den Benutzer und wird von AGI-Skripten erstellt. + der Anzeige für den Benutzer und wird von AGI-Skripten erstellt. @@ -83,8 +83,8 @@ dst - Zuletzt f�r den Anruf im Dialplan ausgef�hrte - Ziel-Extension; Achtung: kann auch h (f�r + Zuletzt für den Anruf im Dialplan ausgeführte + Ziel-Extension; Achtung: kann auch h (für Hangup-Extension) sein! @@ -120,7 +120,7 @@ lastapp - Letzte ausgef�hrte Applikation im Dialplan, z.B.: + Letzte ausgeführte Applikation im Dialplan, z.B.: NoOp @@ -129,7 +129,7 @@ lastdata - Die dieser Applikation (s.o.) �bergebenen Argumente, z.B.: + Die dieser Applikation (s.o.) übergebenen Argumente, z.B.: Finish if-to-internal-users-self-79 @@ -147,7 +147,7 @@ billsec - Dauer des Gespr�chs in Sekunden, also ohne Klingeln o.�. + Dauer des Gesprächs in Sekunden, also ohne Klingeln o.ä. (die ggf. in Rechnung zu stellende Zeit), z.B.: 29 @@ -190,7 +190,7 @@ Fehlgeschlagen. - Unbekannte Rufnummer, Stau, - o.�. + o.ä. @@ -198,8 +198,8 @@ UNKNOWN - Unbekannt. - Keine Information �ber den Erfolg - verf�gbar. + Unbekannt. - Keine Information über den Erfolg + verfügbar. @@ -304,7 +304,7 @@ penalty - Legt die Priorit�t fest, nach der die Mitglieder einer + Legt die Priorität fest, nach der die Mitglieder einer Warteschlange (Agenten) angerufen werden. @@ -346,7 +346,7 @@ musicclass - Die Art der Wartemusik kann hiermit f�r die einzelne + Die Art der Wartemusik kann hiermit für die einzelne Warteschlange (z.B. nach Musikrichtung) definiert werden. @@ -366,7 +366,7 @@ Legt einen optionalen Kontext fest. Ein Anrufer wird durch - Dr�cken einer einzigen Ziffer zu der entsprechenden Extension in + Drücken einer einzigen Ziffer zu der entsprechenden Extension in diesem Kontext weitergeleitet. @@ -385,7 +385,7 @@ Legt fest, ob ein Agent automatisch auf "Pause" gesetzt - wird, wenn er einen Anruf nicht beantwortet. M�gliche Werte: + wird, wenn er einen Anruf nicht beantwortet. Mögliche Werte: yes|no @@ -396,7 +396,7 @@ Legt fest, ob das Interface des Mitglieds der Warteschlange, welches mit dem Anrufer verbunden wird, in der Variable - "MEMBERINTERFACE" gespeichert wird. M�gliche Werte: + "MEMBERINTERFACE" gespeichert wird. Mögliche Werte: yes|no @@ -405,9 +405,9 @@ monitor_join - Legt fest, ob bei einem Gespr�chsmitschnitt die Audiodateien + Legt fest, ob bei einem Gesprächsmitschnitt die Audiodateien der eIngehenden und der ausgehenden Richtung zu einer einzigen - Datei zusammengemischt werden. M�gliche Werte: + Datei zusammengemischt werden. Mögliche Werte: yes|no @@ -416,7 +416,7 @@ monitor_format - Legt fest ob und in welchem Audioformat Gespr�chsmitschnitte + Legt fest ob und in welchem Audioformat Gesprächsmitschnitte gespeichert werden sollen. @@ -424,7 +424,7 @@ NULL - Keine Aufzeichnung der Sprachkan�le wird durchgef�hrt, + Keine Aufzeichnung der Sprachkanäle wird durchgeführt, wenn kein Format definiert wurde. @@ -483,8 +483,8 @@ Sekunden, auf welche die Ansage der Wartezeit abgerundet - oder aufgerundet werden soll, um nicht unn�tige Pr�zision - vorzut�uschen. Sinnvolle Werte: 0 (keine Ansage + oder aufgerundet werden soll, um nicht unnötige Präzision + vorzutäuschen. Sinnvolle Werte: 0 (keine Ansage der Sekunden), 1, 5, 10, 15, 30. @@ -542,7 +542,7 @@ Zeit in Sekunden, die ein Mitglied der Warteschlange nicht - angerufen wird, nachdem er ein vorhergehendes Gespr�ch beendet + angerufen wird, nachdem er ein vorhergehendes Gespräch beendet hat. @@ -552,7 +552,7 @@ Maximale Anzahl der Anrufer, die in der Warteschlange - gehalten werden d�rfen. Der Wert 0 steht f�r + gehalten werden dürfen. Der Wert 0 steht für eine unbegrenzte Anzahl. @@ -600,8 +600,8 @@ Das Mitglied der Warteschlange wird angeklingelt, - dessen letztes Telefonat zeitlich am l�ngsten - zur�ckliegt. + dessen letztes Telefonat zeitlich am längsten + zurückliegt. @@ -618,7 +618,7 @@ random - Ein zuf�llig ausgew�hltes Mitglied der Warteschlange + Ein zufällig ausgewähltes Mitglied der Warteschlange wird angeklingelt. @@ -629,7 +629,7 @@ Alle Mitglieder der Warteschlange werden nacheinander angeklingelt, jedoch wird die Anfangsposition aus einem - vorhergehenden Durchlauf ber�cksichtigt. + vorhergehenden Durchlauf berücksichtigt. @@ -641,14 +641,14 @@ Legt fest ob Anrufer in eine Warteschlange aufgenommen - werden, die keine Mitglieder enth�lt. + werden, die keine Mitglieder enthält. yes - Anrufer k�nnen in die Warteschlange aufgenommen + Anrufer können in die Warteschlange aufgenommen werden, auch wenn diese keine Mitglieder definiert hat. @@ -658,8 +658,8 @@ no - Anrufer k�nnen nur in die Warteschlange aufgenommen - werden, mindestens ein Mitglied verf�gbar ist. + Anrufer können nur in die Warteschlange aufgenommen + werden, mindestens ein Mitglied verfügbar ist. @@ -667,8 +667,8 @@ strict - Anrufer k�nnen nur in die Warteschlange aufgenommen - werden, wenn mindestens ein Mitglied definiert ist, mu� aber + Anrufer können nur in die Warteschlange aufgenommen + werden, wenn mindestens ein Mitglied definiert ist, muß aber zu diesem Zeitpunkt nicht unbedingt eingeloggt sein. @@ -720,7 +720,7 @@ Legt fest, ob QueueMemberStatus-Events im Manager-Interface - erzeugt werden. M�gliche Werte: + erzeugt werden. Mögliche Werte: yes|no @@ -729,10 +729,10 @@ eventwhencalled - Legt fest, ob u.a. die folgenden Events f�r das + Legt fest, ob u.a. die folgenden Events für das Manager-Interface erzeugt werden: AgentCalled, AgentDump, AgentConnect, - AgentComplete. M�gliche Werte: + AgentComplete. Mögliche Werte: yes|no @@ -742,8 +742,8 @@ Legt fest ob dem Mitglied der Warteschlange, der das - Gespr�ch annimmt, die Wartezeit des Anrufers angesagt werden soll, - bevor dieser zu ihm durchgestellt wird. M�gliche Werte: + Gespräch annimmt, die Wartezeit des Anrufers angesagt werden soll, + bevor dieser zu ihm durchgestellt wird. Mögliche Werte: yes|no @@ -753,8 +753,8 @@ Legt fest, ob Mitglieder der Warteschlange auch dann - angeklingelt werden ,wenn sie sich in einem Gespr�ch befinden. - M�gliche Werte: + angeklingelt werden ,wenn sie sich in einem Gespräch befinden. + Mögliche Werte: yes|no @@ -774,7 +774,7 @@ Die relative Gewichtung der Warteschlangen. Ist ein Benutzer Mitglied in mehreren Warteschlangen, kann hiermit die Reihenfolge - der Wichtigkeit festgelegt werden. Schlangen mit h�herem Wert + der Wichtigkeit festgelegt werden. Schlangen mit höherem Wert werden bevorzugt. @@ -784,8 +784,8 @@ Bestimmt, ob der Antwort-Timeout eines Mitglieds der - Warteschlange bei einem Besetzt- oder Leitung-�berlastet-Signal - zur�ckgesetzt wird. + Warteschlange bei einem Besetzt- oder Leitung-überlastet-Signal + zurückgesetzt wird. @@ -794,9 +794,9 @@
<literal>ast_sipfriends</literal> - Die SIP Endger�te - Datenbankversion der - sip.conf. F�r diese Tabelle existiert der View ast_sipfriends_gs, - dieser wird von Asterisk ausgewertet, der view beschr�nkt die Tabelle um peers die f�r + Die SIP Endgeräte - Datenbankversion der + sip.conf. Für diese Tabelle existiert der View ast_sipfriends_gs, + dieser wird von Asterisk ausgewertet, der view beschränkt die Tabelle um peers die für Asterisk nicht relevant sind, so zb. User auf externen Hosts (Angenturen) @@ -813,7 +813,7 @@ name - Der Name des Endger�tes zur Identifikation z.B. im + Der Name des Endgerätes zur Identifikation z.B. im Dialplan. @@ -822,8 +822,8 @@ secret - Legt das Passwort fest, welches das SIP-Endger�t zur - Anmeldung benutzten mu�. + Legt das Passwort fest, welches das SIP-Endgerät zur + Anmeldung benutzten muß. @@ -831,7 +831,7 @@ type - Die Art, wie der SIP-Anschluss und damit das SIP-Endger�t + Die Art, wie der SIP-Anschluss und damit das SIP-Endgerät behandelt werden soll @@ -869,7 +869,7 @@ host - Legt fest, ob sich das SIP-Endger�t eine dynamische oder + Legt fest, ob sich das SIP-Endgerät eine dynamische oder eine statische IP-Adresse verwendet. @@ -877,7 +877,7 @@ dynamic - Die IP-Adresse des Endger�tes ist dynamisch, seine IP + Die IP-Adresse des Endgerätes ist dynamisch, seine IP ist dem System nicht bekannt. @@ -886,8 +886,8 @@ <IP>|<hostname> - Die IP-Adresse oder der Hostname des Endger�tes. Das - System kann hier�ber das Endger�t erreichen, ohne dass sich + Die IP-Adresse oder der Hostname des Endgerätes. Das + System kann hierüber das Endgerät erreichen, ohne dass sich dieses erst registrieren muss. @@ -900,7 +900,7 @@ Legt die IP-Adresse fest, unter der das System versucht ein - Endger�t zu erreichen, wenn es sich noch nicht registriert + Endgerät zu erreichen, wenn es sich noch nicht registriert hat. @@ -909,7 +909,7 @@ context - Der Kontext, zu welchem das SIP-Endger�t geh�ren + Der Kontext, zu welchem das SIP-Endgerät gehören soll. @@ -918,7 +918,7 @@ callerid - Die ID des Anrufers, die an die Gegenstelle �betragen + Die ID des Anrufers, die an die Gegenstelle übetragen wird. @@ -927,7 +927,7 @@ mailbox - Die Nummer der Mailbox, die dem Endger�t zugeordnet + Die Nummer der Mailbox, die dem Endgerät zugeordnet ist. @@ -936,8 +936,8 @@ callgroup - Liste numerischer IDs der Call-Groups, zu denen das Endger�t - geh�ren soll. + Liste numerischer IDs der Call-Groups, zu denen das Endgerät + gehören soll. @@ -945,8 +945,8 @@ pickupgroup - Liste numerischer IDs der Call-Groups, f�r die das - Heranholen von Gespr�chen an dieses Endger�t erlaubt ist. + Liste numerischer IDs der Call-Groups, für die das + Heranholen von Gesprächen an dieses Endgerät erlaubt ist. @@ -955,7 +955,7 @@ Legt fest, ob und welche Channelvariable bei Anrufen von - diesem Endger�t gesetzt werden soll. + diesem Endgerät gesetzt werden soll. @@ -963,8 +963,8 @@ call-limit - Legt die Maximale Anzahl von Gespr�chen fest, die �ber - dieses Endger�t gef�hrt werden k�nnen. + Legt die Maximale Anzahl von Gesprächen fest, die über + dieses Endgerät geführt werden können. @@ -973,8 +973,8 @@ Legt den Kontext fest, welcher zur Signalisierung z.B. von - LEDs an einem SIP-Endger�t verwendet wird. In diesem Kontext - befinden sich z.B. die "hint" Eintr�ge im Dialplan. + LEDs an einem SIP-Endgerät verwendet wird. In diesem Kontext + befinden sich z.B. die "hint" Einträge im Dialplan. @@ -983,7 +983,7 @@ Legt fest, welcher Kontest beim ersten Registrieren eines - SIP-Endger�tes automatisch aufgerufen wird. Als Extension wird der + SIP-Endgerätes automatisch aufgerufen wird. Als Extension wird der Inhalt des Feldes name verwendet. @@ -992,7 +992,7 @@ ipaddr - Die aktuelle IP-Adresse des SIP-Endger�tes wird vom + Die aktuelle IP-Adresse des SIP-Endgerätes wird vom Asterisk-Server in diesem Feld abgelegt. @@ -1001,7 +1001,7 @@ port - Die aktuelle Portnummer des SIP-Endger�tes wird vom + Die aktuelle Portnummer des SIP-Endgerätes wird vom Asterisk-Server in diesem Feld abgelegt. @@ -1010,7 +1010,7 @@ regseconds - Zeitstempel der Registrierung des SIP-Endger�tes wird vom + Zeitstempel der Registrierung des SIP-Endgerätes wird vom Asterisk-Server in diesem Feld abgelegt. @@ -1019,7 +1019,7 @@ username - Benutzername, wie er in der Konfiguration des SIP-Endger�tes + Benutzername, wie er in der Konfiguration des SIP-Endgerätes festgelegt wurde. @@ -1028,7 +1028,7 @@ regserver - Name des Servers, an dem das Endger�t registriert ist, wird + Name des Servers, an dem das Endgerät registriert ist, wird vom Asterisk-Server in diesem Feld abgelegt. @@ -1037,7 +1037,7 @@ fullcontact - Die Kontaktdaten des SIP-Endger�tes werden vom + Die Kontaktdaten des SIP-Endgerätes werden vom Asterisk-Server in diesem Feld abgelegt. @@ -1079,7 +1079,7 @@ context - Legt fest, zu welchem Kontext die Mailbox geh�rt. + Legt fest, zu welchem Kontext die Mailbox gehört. @@ -1104,7 +1104,7 @@ fullname - Vollst�ndiger Name des Benutzers der Mailbox. + Vollständiger Name des Benutzers der Mailbox. @@ -1121,8 +1121,8 @@ attach - Legt fest, ob an die Benachrichtigung �ber eMail, eine - Audiodatei mit der Aufnahme angeh�ngt werden soll. M�gliche Werte: + Legt fest, ob an die Benachrichtigung über eMail, eine + Audiodatei mit der Aufnahme angehängt werden soll. Mögliche Werte: yes|no @@ -1132,7 +1132,7 @@ Legt fest, ob nach der Benachrichtigung per eMail die - Audiodatei gel�scht werden soll. + Audiodatei gelöscht werden soll. @@ -1165,7 +1165,7 @@ regexp - Regul�rer Ausdruck zur Definition der + Regulärer Ausdruck zur Definition der Rufnummernsperre @@ -1199,7 +1199,7 @@ case - Legt fest, f�r welchen Fall die Anrufweiterleitung + Legt fest, für welchen Fall die Anrufweiterleitung aktiviert werden soll. @@ -1231,7 +1231,7 @@ offline - Wenn das Endger�t des Benutzers nicht angemeldet + Wenn das Endgerät des Benutzers nicht angemeldet ist. @@ -1319,8 +1319,8 @@ active - Legt fest, ob das Signal f�r einen weiteren, ankommenden - Anruf, w�hrend eines bestehenden Gespr�chs gesendet wird. + Legt fest, ob das Signal für einen weiteren, ankommenden + Anruf, während eines bestehenden Gesprächs gesendet wird. @@ -1330,7 +1330,7 @@ <literal>clir</literal> Konfiguration des Dienstmerkmals "CLIR" - (Rufnummernunterdr�ckung) + (Rufnummernunterdrückung) @@ -1346,8 +1346,8 @@ internal_restrict - Legt fest, ob bei ausgehenden, internen Gespr�chen die - eigene Rufnummer unterdr�ckt wird. M�gliche Werte: + Legt fest, ob bei ausgehenden, internen Gesprächen die + eigene Rufnummer unterdrückt wird. Mögliche Werte: yes|no @@ -1356,8 +1356,8 @@ external_restrict - Legt fest, ob bei ausgehenden, externen Gespr�chen die - eigene Rufnummer unterdr�ckt wird. M�gliche Werte: + Legt fest, ob bei ausgehenden, externen Gesprächen die + eigene Rufnummer unterdrückt wird. Mögliche Werte: yes|no @@ -1367,7 +1367,7 @@
<literal>conferences</literal> - Konferenzr�ume + Konferenzräume @@ -1392,9 +1392,9 @@
<literal>dial_log</literal> - Liste get�tigter, erhaltener oder verpasster Anrufe. Diese Tabelle - wird durch AGI-Skripte im Dialplan gef�llt, und die einzelnen Eintr�ge - k�nnen auch vom Benutzer gel�scht werden. + Liste getätigter, erhaltener oder verpasster Anrufe. Diese Tabelle + wird durch AGI-Skripte im Dialplan gefüllt, und die einzelnen Einträge + können auch vom Benutzer gelöscht werden. @@ -1425,7 +1425,7 @@ out - Get�tigter Anruf + Getätigter Anruf @@ -1480,7 +1480,7 @@
<literal>hosts</literal> - Zum System geh�rende Hosts + Zum System gehörende Hosts @@ -1597,14 +1597,14 @@
<literal>pb_prv</literal> - Die pers�nlichen Telefonb�cher der Benutzer. + Die persönlichen Telefonbücher der Benutzer. id - Fortlaufende Nummer der Eintr�ge. + Fortlaufende Nummer der Einträge. @@ -1613,7 +1613,7 @@ ID des Benutzers (aus der Tabelle users) - dem das Telefonbuch geh�rt. + dem das Telefonbuch gehört. @@ -1638,14 +1638,14 @@
<literal>phones</literal> - Die Endger�te. + Die Endgeräte. id - Eindeutige, numerische ID des Endger�tes. + Eindeutige, numerische ID des Endgerätes. @@ -1653,7 +1653,7 @@ type - Typ des Endger�tes, z.B. snom360 + Typ des Endgerätes, z.B. snom360 @@ -1661,7 +1661,7 @@ mac_addr - Die MAC-Adresse des Endger�tes. + Die MAC-Adresse des Endgerätes. @@ -1680,11 +1680,11 @@ Eindeutige, numerische ID eines Pseudo-Benutzers aus dem Feld nobody_index der Tabelle - users. Jedem Endger�t wird bei der Installation + users. Jedem Endgerät wird bei der Installation ein solcher Benutzer zugewiesen, um auch dann das Telefon - verwenden zu k�nnen, wenn sich noch kein Benutzer an diesem Ger�t - angemeldet hat. Dies erm�glicht Notrufe, kostenlose - Interngespr�che etc. direkt nach der Installation. + verwenden zu können, wenn sich noch kein Benutzer an diesem Gerät + angemeldet hat. Dies ermöglicht Notrufe, kostenlose + Interngespräche etc. direkt nach der Installation. @@ -1733,7 +1733,7 @@ Numerische ID der Pickup-Gruppe, zu welcher der Benutzer - geh�rt, aus der Tabelle pickupgroups. + gehört, aus der Tabelle pickupgroups. @@ -1776,7 +1776,7 @@ event - Ereignis, welches zum Eintrag ins Log gef�hrt hat. + Ereignis, welches zum Eintrag ins Log geführt hat. @@ -1810,8 +1810,8 @@ caller - Die Anrufer-ID, wie sie zum System �bertragen wurde oder - NULL, fals keine Rufnummern�bertragung aktiviert war. + Die Anrufer-ID, wie sie zum System übertragen wurde oder + NULL, fals keine Rufnummernübertragung aktiviert war. @@ -1861,7 +1861,7 @@ info - Zus�tzliche Informationen (z.B. + Zusätzliche Informationen (z.B. <extension>@<context>) bei einer Weiterleitung. @@ -1872,7 +1872,7 @@
<literal>ringtones</literal> - Die pro Benutzer eingestellten Klingelt�ne. + Die pro Benutzer eingestellten Klingeltöne. @@ -1888,7 +1888,7 @@ src - F�r Anrufe von welcher Quelle der Klingelton gelten soll. + Für Anrufe von welcher Quelle der Klingelton gelten soll. internal | external. @@ -1897,10 +1897,10 @@ bellcore - Die Nummer eines Standard-Klingeltons. �blicherweise - 1 - 10 f�r + Die Nummer eines Standard-Klingeltons. Üblicherweise + 1 - 10 für Bellcore-drX oder - 0 f�r Silent + 0 für Silent (lautlos). @@ -1942,10 +1942,10 @@ key - Telefon-Typ-spezifisches K�rzel der Taste. Wird aber vom + Telefon-Typ-spezifisches Kürzel der Taste. Wird aber vom Provisioning-System (z.B. - htdocs/prov/snom/settings.php) nochmal f�r - das Telefon �bersetzt. + htdocs/prov/snom/settings.php) nochmal für + das Telefon übersetzt. @@ -1956,6 +1956,38 @@ Eingestellte Rufnummer. + + + ptype + + + Lokation der Nummer (cell/work/home/fax etc.). + + + + + pref + + + Praeferenz der Nummer (1=highest, 99=lowest, default=9). + + + + + card_id + + + vCard ID Referenz. + + + + + modified + + + Zeitstemples letzter Aenderung. + +
@@ -1979,7 +2011,7 @@ Eindeutige alphanumerische Bezeichnung des Benutzers, z.B. - Personalnummer o.�. + Personalnummer o.ä. @@ -2020,8 +2052,8 @@ Eindeutige, numerische ID eines Pseudo-Benutzers. Diese - speziellen Benutzer werden verwendet, wenn an einem Endger�t noch - kein anderer Benutzer angemeldet ist. Dies erm�glicht z.B. + speziellen Benutzer werden verwendet, wenn an einem Endgerät noch + kein anderer Benutzer angemeldet ist. Dies ermöglicht z.B. Notrufe. @@ -2030,7 +2062,7 @@ host_id - Numerische ID des Asterisk-Servers, an dem sich das Endger�t + Numerische ID des Asterisk-Servers, an dem sich das Endgerät des Benutzer anmeldet. @@ -2039,7 +2071,7 @@ current_ip - Aktuelle IP des Endger�tes, welches der Benutzer aktuell + Aktuelle IP des Endgerätes, welches der Benutzer aktuell verwendet. @@ -2058,7 +2090,7 @@
<literal>users_external_numbers</literal> - M�gliche Ausgangsrufnummern pro Benutzer zur Initiierung von + Mögliche Ausgangsrufnummern pro Benutzer zur Initiierung von Anrufen. @@ -2100,8 +2132,8 @@ internal_active - Legt fest, ob die Anrufbeantworterfunktion f�r interne - Gespr�che aktiviert werden soll. + Legt fest, ob die Anrufbeantworterfunktion für interne + Gespräche aktiviert werden soll. @@ -2109,8 +2141,8 @@ external_active - Legt fest, ob die Anrufbeantworterfunktion f�r externe - Gespr�che aktiviert werden soll. + Legt fest, ob die Anrufbeantworterfunktion für externe + Gespräche aktiviert werden soll. diff --git a/opt/gemeinschaft/htdocs/gui/inc/modules.php b/opt/gemeinschaft/htdocs/gui/inc/modules.php index 3c1003123..00b75d963 100644 --- a/opt/gemeinschaft/htdocs/gui/inc/modules.php +++ b/opt/gemeinschaft/htdocs/gui/inc/modules.php @@ -71,7 +71,13 @@ 's' => array('title' => __('Intern' ), 'id' => 3001) ), 25=>array( 'k' => 'private', - 's' => array('title' => __('Persönlich' ), 'id' => 3002) ) + 's' => array('title' => __('Persönlich' ), 'id' => 3002) ), + 35=>array( + 'k' => 'category' , + 's' => array('title' => __('Kategorien' ), 'id' => 3006) ), + 45=>array( + 'k' => 'cloud' , + 's' => array('title' => __('Cloud Sync' ), 'id' => 3005) ) ); if (gs_get_conf('GS_PB_IMPORTED_ENABLED')) { $pos = (int)gs_get_conf('GS_PB_IMPORTED_ORDER', 9) * 10; diff --git a/opt/gemeinschaft/htdocs/gui/mod/home_home.php b/opt/gemeinschaft/htdocs/gui/mod/home_home.php index db74df080..6b45bf4f8 100644 --- a/opt/gemeinschaft/htdocs/gui/mod/home_home.php +++ b/opt/gemeinschaft/htdocs/gui/mod/home_home.php @@ -9,6 +9,8 @@ * Stefan Wintermeyer * Philipp Kempgen * Peter Kozak +* STD Markus Neubauer +* - added view for cloud books * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -297,6 +299,7 @@ ?> +
@@ -317,6 +320,59 @@
+ + + +
+ +
+ +
+ + execute( +'SELECT `url`, `login`, `message`, `active`, `error_count` +FROM + `pb_cloud` +WHERE + `user_id`='. (int)@$_SESSION['sudo_user']['info']['id'] . ' +ORDER BY `active`, `error_count` DESC +LIMIT 3' + ); + ?> + +
+    + +
+
+ ' ,"\n"; + echo '' ,"\n"; + $i=0; + while ($r = $rs->fetchRow()) { + echo '' ,"\n"; + echo '', htmlEnt($r['url']) ,', Status: '; + echo htmlEnt($r['message']) ,'' ,"\n"; + echo '' ,"\n"; + ++$i; + } + if ($i===0) { + echo '' ,"\n"; + echo '', __('keine') ,'' ,"\n"; + echo '' ,"\n"; + } + echo '' ,"\n"; + echo '' ,"\n"; + + ?> +
+ +
+
   diff --git a/opt/gemeinschaft/htdocs/gui/mod/pb_category.php b/opt/gemeinschaft/htdocs/gui/mod/pb_category.php new file mode 100644 index 000000000..9bd28e9de --- /dev/null +++ b/opt/gemeinschaft/htdocs/gui/mod/pb_category.php @@ -0,0 +1,270 @@ + +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +\*******************************************************************/ + +defined('GS_VALID') or die('No direct access.'); +include_once( GS_DIR .'lib/utf8-normalize/gs_utf_normal.php' ); + +echo '

'; +if (@$MODULES[$SECTION]['icon']) + echo ' '; +if (count( $MODULES[$SECTION]['sub'] ) > 1 ) + echo $MODULES[$SECTION]['title'], ' - '; +echo $MODULES[$SECTION]['sub'][$MODULE]['title']; +echo '

', "\n"; + + +echo '', "\n"; +echo '' ,"\n"; + +$per_page = (int)GS_GUI_NUM_RESULTS; + +$name = trim(@$_REQUEST['name' ]); +$category = trim(@$_REQUEST['category' ]); +$save_category = trim(@$_REQUEST['scategory']); +$page = (int) (@$_REQUEST['page' ]); +$delete_entry = (int)trim(@$_REQUEST['delete' ]); +$edit_entry = (int)trim(@$_REQUEST['edit' ]); +$save_entry = (int)trim(@$_REQUEST['save' ]); + +$user_id = (int)@$_SESSION['sudo_user']['info']['id']; + +if ($delete_entry > 0) { + # delete entry + + $rs = $DB->execute( +'DELETE FROM `pb_category` +WHERE `id`='. $delete_entry .' AND `user_id`='. $user_id + ); + +} + +if ( $save_category != '' ) { + # save entry + + if ($save_entry < 1) { + + $rs = $DB->execute( +'INSERT INTO `pb_category` (`id`, `user_id`, `category`) VALUES +(NULL, '. $user_id .', \''. $DB->escape($save_category) .'\')' + ); + + } else { + + $rs = $DB->execute( +'UPDATE `pb_category` SET `category`=\''. $DB->escape($save_category) .'\' + WHERE `id`='. $save_entry .' AND `user_id`='. $user_id + ); + + } + $save_category = ''; +} + + +# search by category + +$search_url = 'category='. urlEncode($category); + +$category_sql = '%' . str_replace( + array( '*', '?' ), + array( '%', '_' ), + $category +) .'%'; + +$rs = $DB->execute( + 'SELECT SQL_CALC_FOUND_ROWS '. + '`id`, `category` '. + 'FROM '. + '`pb_category` '. + 'WHERE '. + '`category` LIKE \''. $DB->escape($category_sql) .'\' '. + 'AND '. + '`user_id`='. $user_id .' '. + 'ORDER BY `category` ' . + 'LIMIT '. ($page*(int)$per_page) .','. (int)$per_page + ); +$num_total = @$DB->numFoundRows(); +$num_pages = ceil($num_total / $per_page); + + +?> + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ 0) { + echo + '', + '', __('zurück'), '', + '', "\n"; +} else { + echo + '', __('zurück'), '', "\n"; +} +if ($page < $num_pages-1) { + echo + '', + '', __('weiter'), '', + '', "\n"; +} else { + echo + '', __('weiter'), '', "\n"; +} + +?> +
+ $cs) { + echo '', htmlEnt($cd), '', "\n"; +} + +?> +
+ + + +', "\n"; +echo gs_form_hidden($SECTION, $MODULE), "\n"; +echo '', "\n"; +?> + + + + + + + + + +fetchRow()) { + echo '', "\n"; + + if ($r['id']==$edit_entry) { + + echo '', "\n"; + + echo ''; + + } else { + + echo '', "\n"; + + echo ''; + + } + + echo '', "\n"; + } +} + +?> + + + + + + + + + + +
> + +
'; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '', __('abbrechen'), ''; + + echo '', htmlEnt($r['category']); + echo ''; + $sudo_url = + (@$_SESSION['sudo_user']['name'] == @$_SESSION['real_user']['name']) + ? '' : ('&sudo='. @$_SESSION['sudo_user']['name']); + echo '', __('bearbeiten'), '   '; + echo '', __('entfernen'), ''; + echo '
+ + + + abbrechen';*/ ?> +
+ + +

Hint: Categories are coming from the cloud and
+           must be changed within the cloud to really become active here.

diff --git a/opt/gemeinschaft/htdocs/gui/mod/pb_cloud.php b/opt/gemeinschaft/htdocs/gui/mod/pb_cloud.php new file mode 100644 index 000000000..c02164c55 --- /dev/null +++ b/opt/gemeinschaft/htdocs/gui/mod/pb_cloud.php @@ -0,0 +1,471 @@ + +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +\*******************************************************************/ + +defined('GS_VALID') or die('No direct access.'); +include_once( GS_DIR .'lib/utf8-normalize/gs_utf_normal.php' ); + +echo '

'; +if (@$MODULES[$SECTION]['icon']) + echo ' '; +if (count( $MODULES[$SECTION]['sub'] ) > 1 ) + echo $MODULES[$SECTION]['title'], ' - '; +echo $MODULES[$SECTION]['sub'][$MODULE]['title']; +echo '

', "\n"; + + +echo '', "\n"; +echo '' ,"\n"; + +$per_page = (int)GS_GUI_NUM_RESULTS; + +$name = trim(@$_REQUEST['name' ]); +$url = trim(@$_REQUEST['url' ]); +$login = trim(@$_REQUEST['login' ]); +$pass = trim(@$_REQUEST['pass' ]); +$frequency = trim(@$_REQUEST['frequency' ]); +$public = trim(@$_REQUEST['public' ]); +$save_url = trim(@$_REQUEST['surl' ]); +$save_login = trim(@$_REQUEST['slogin' ]); +$save_pass = trim(@$_REQUEST['spass' ]); +$save_frequency = trim(@$_REQUEST['sfrequency' ]); +$save_public = trim(@$_REQUEST['spublic' ]); +$page = (int) (@$_REQUEST['page' ]); +$delete_entry = (int)trim(@$_REQUEST['delete' ]); +$edit_entry = (int)trim(@$_REQUEST['edit' ]); +$save_entry = (int)trim(@$_REQUEST['save' ]); + +$user_id = (int)@$_SESSION['sudo_user']['info']['id']; + +if ($delete_entry > 0) { + // delete entry + + $rs = $DB->execute( +'DELETE FROM `pb_cloud` ' . + ' WHERE `id`='. $delete_entry . + ' AND `user_id`='. $user_id + ); + // remove cards + $rs2 = $DB->execute( +'DELETE FROM `pb_cloud_card` ' . + ' WHERE `cloud_id`='. $delete_entry + ); + // remove from phone book + $rs2 = $DB->execute( +'DELETE p FROM `pb_prv` AS p ' . + ' LEFT JOIN `pb_cloud_card` AS c ' . + ' ON c.id = p.card_id ' . + ' WHERE p.user_id = ' . $user_id . + ' AND p.card_id != 0 ' . + ' AND c.id IS NULL' + ); + // remove from categories xref + $rs2 = $DB->execute( +'DELETE p FROM `pb_prv_category` AS p ' . + ' LEFT JOIN `pb_cloud_card` AS c ' . + ' ON c.id = p.card_id' . + ' WHERE p.user_id = ' . $user_id . + ' AND p.card_id != 0 ' . + ' AND c.id IS NULL' + ); + // remove from categories + $rs2 = $DB->execute( +'DELETE c FROM `pb_category` AS c ' . + ' LEFT JOIN `pb_prv_category` AS p ' . + ' ON c.id = p.cat_id ' . + ' WHERE c.user_id = ' . $user_id . + ' AND p.id IS NULL' + ); + +} + +if ($save_url != '' && $save_login != '' && $save_pass != '') { + # save entry + + // check or correct frequency + if ( strlen($save_frequency) < 2 ) { + $save_frequency = '1d'; + } else { + $save_frequency = str_replace(' ', '', $save_frequency); + $p = substr($save_frequency, -1); + if ( ! ('h' == $p || 'd' == $p || 'm' == $p) ) + $save_frequency = substr($save_frequency, 0, -1) . 'd'; + if ( ! is_numeric(substr($save_frequency, 0, -1)) || substr($save_frequency, 0, -1) == '0' ) + $save_frequency = '1' . substr($save_frequency, -1); + } + + if ( $save_public != 1 ) $save_public = 0; + + if ($save_entry < 1) { + + $rs = $DB->execute( +'INSERT INTO `pb_cloud` ' . + ' (`id`, `user_id`, `url`, `login`, `pass`, `frequency`, `next_poll`, `message`, `public`) ' . + ' VALUES' . + '(NULL, '. $user_id .', \''. $DB->escape($save_url) .'\', \''. $DB->escape($save_login) .'\', des_encrypt(\''. $save_pass .'\',\'' . $save_login. '\'), \''. $DB->escape($save_frequency) .'\', NOW(), \'Scheduled\', ' . $save_public . ')' + ); + + } else { + // get old public status + $r = $DB->execute('SELECT `public` FROM `pb_cloud` WHERE `id`='. $save_entry . ' LIMIT 1')->fetchrow(); + + $rs = $DB->execute( +'UPDATE `pb_cloud` ' . + ' SET `url`=\''. $DB->escape($save_url) .'\', `login`=\''. $DB->escape($save_login) .'\', `pass`=des_encrypt(\''. $save_pass .'\',\'' . $save_login .'\'), ' . + ' `frequency`=\'' . $save_frequency . '\', `next_poll`=NOW(), `message`=\'Scheduled\', `last_remote_modified`=\'2000-01-01 00:00:00\', `active`=1, ' . + ' `public`=' . $save_public . +' WHERE `id`='. $save_entry .' AND `user_id`='. $user_id + ); + + // delete vcards if it was public and should not be anymore or vs + if ( $r['public'] != $save_public ) { + $DB->execute('DELETE FROM `pb_cloud_card` WHERE `cloud_id`=' . $save_entry); + } + + } + $save_url = ''; + $save_login = ''; + $save_pass = ''; + $save_frequency = ''; + $save_public = 0; +} + + + + + +if ($url != '') { + + # search by url + + $search_url = 'url='. urlEncode($url); + + $url_sql = '%' . str_replace( + array( '*', '?' ), + array( '%', '_' ), + $url + ) .'%'; + + $rs = $DB->execute( + 'SELECT SQL_CALC_FOUND_ROWS '. + '`id`, `url`, `login`, cast(des_decrypt(`pass`,`login`) as char(16)) as pass, `frequency`, `message`, `public` '. + 'FROM '. + '`pb_cloud` '. + 'WHERE '. + '`url` LIKE \''. $DB->escape($url_sql) .'\' '. + 'AND '. + '`user_id`='. $user_id .' '. + 'ORDER BY `url`, `login` '. + 'LIMIT '. ($page*(int)$per_page) .','. (int)$per_page + ); + $num_total = @$DB->numFoundRows(); + $num_pages = ceil($num_total / $per_page); + +} else { + + # search by login + + $search_url = 'login='. urlEncode($login); + + $login_sql = str_replace( + array( '*', '?' ), + array( '%', '_' ), + $login + ) .'%'; + + $rs = $DB->execute( + 'SELECT SQL_CALC_FOUND_ROWS '. + '`id`, `url`, `login`, cast(des_decrypt(`pass`,`login`) as char(16)) as pass, `frequency`, `message`, `public` '. + 'FROM '. + '`pb_cloud` '. + 'WHERE '. + '`login` LIKE \''. $DB->escape($login_sql) .'\' '. + 'AND '. + '`user_id`='. $DB->escape($user_id).' '. + 'ORDER BY `login`, `url` '. + 'LIMIT '. ($page*(int)$per_page) .','. (int)$per_page + ); + $num_total = @$DB->numFoundRows(); + $num_pages = ceil($num_total / $per_page); + +} + + +?> + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+
+ + + +
+
+ 0) { + echo + '', + '', __('zurück'), '', + '', "\n"; +} else { + echo + '', __('zurück'), '', "\n"; +} +if ($page < $num_pages-1) { + echo + '', + '', __('weiter'), '', + '', "\n"; +} else { + echo + '', __('weiter'), '', "\n"; +} + +?> +
+ $cs) { + echo '', htmlEnt($cd), '', "\n"; +} + +?> +
+ + + +', "\n"; +echo gs_form_hidden($SECTION, $MODULE), "\n"; +echo '', "\n"; +echo '', "\n"; +echo '', "\n"; +echo '', "\n"; +?> + + + + + + + + + + + + + + +fetchRow()) { + echo '', "\n"; + + if ($r['id']==$edit_entry) { + + echo '', "\n"; + + echo '', "\n"; + + echo '', "\n"; + + echo '', "\n"; + + echo '', "\n"; + + echo ''; + + } else { + + echo '', "\n"; + + echo '', "\n"; + + echo '', "\n"; + + echo '', "\n"; + + echo '', "\n"; + + echo ''; + if ( !empty($r['message']) ) { + echo ''; + echo ''; + } + + } + + echo '', "\n"; + } +} + +?> + + + + + + + + + + + + + + +
> + [1] + > + + + + + [2] + + +  
'; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + $checked = ($r['public']) ? 'checked' : ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '', __('abbrechen'), ''; + + echo '', htmlEnt($r['url']); + echo '', htmlEnt($r['login']), '', str_repeat('•', strLen($r['pass'])), '', htmlEnt($r['frequency']), '', ($r['public']) ? 'public' : ' ', ''; + $sudo_url = + (@$_SESSION['sudo_user']['name'] == @$_SESSION['real_user']['name']) + ? '' : ('&sudo='. @$_SESSION['sudo_user']['name']); + echo '', __('bearbeiten'), '   '; + echo '', __('entfernen'), ''; + echo '
'; + echo '       ' . __('Status') . ': '; + if ( 'OK' != substr($r['message'], 0, 2) ) { + if ( 'Scheduled' == $r['message'] ) $bg = '#FFFF00 '; + else $bg = '#FF0000'; + echo '' . $r['message'] . ''; + } else echo $r['message']; + echo '
+ + + + + + + + + + + + abbrechen';*/ ?> +
+ + +
+
+
Hints:
+
vCards are imported into your private phone book.
+
Updating vCards is based on changes within the cloud - the cloud always wins.
+
Matching local entries with an equal vCard entry will be removed to avoid duplicates.
+
An update should occur within ¾ of a hour.
+
To refresh locally all phone numbers of a cloud entry, you will have to delete and recreate an entry.
+
+

[1] vCard URL: Any valid URL from your cloud provider, starting with scheme (http/https)://.
+Naiv Examples: +

+
ownCloud
https://example.com/remote.php/carddav/addressbooks/{resource|principal|username}/{collection}/
+
SabreDAV
https://example.com/addressbooks/{resource|principal|username}/{collection}/
+
radicale
https://example.com/radicale/{resource|principal|username}/{collection}/
+
SOGo
https://example.com/SOGo/dav/{resource|principal|username}/Contacts/{collection}/
+
DAViCal
https://example.com/{resource|principal|username}/{collection}/
+
Apple Adrbook Server
https://example.com/addressbooks/users/{resource|principal|username}/{collection}/
+
+

+

[2] Schedule: Defaults to '1d', also see hints before.
+       Where h=hour, d=day, m=month (Max. 2 digits plus 1 char, no blank/minutes allowed).
+       Example: 12h =~ refresh every 12 hours (~ also during night), starting with the saved time.
+       You can simply trigger a refresh using edit and save with no other changes.

+

diff --git a/opt/gemeinschaft/htdocs/gui/mod/pb_private.php b/opt/gemeinschaft/htdocs/gui/mod/pb_private.php index de3984d11..6a80ebee9 100644 --- a/opt/gemeinschaft/htdocs/gui/mod/pb_private.php +++ b/opt/gemeinschaft/htdocs/gui/mod/pb_private.php @@ -10,6 +10,10 @@ * Philipp Kempgen * Peter Kozak * Soeren Sprenger +* Markus Neubauer - 2015 +* - extending db and preparing for vcards +* you need to alter the db for this version to work: +* * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -52,9 +56,12 @@ function confirm_delete() { $name = trim(@$_REQUEST['name' ]); $number = trim(@$_REQUEST['number' ]); +$ptype = trim(@$_REQUEST['ptype' ]); +$catid = trim(@$_REQUEST['catid' ]); $save_lname = trim(@$_REQUEST['slname' ]); $save_fname = trim(@$_REQUEST['sfname' ]); $save_number = trim(@$_REQUEST['snumber']); +$save_ptype = trim(@$_REQUEST['sptype']); $page = (int) (@$_REQUEST['page' ]); $delete_entry = (int)trim(@$_REQUEST['delete' ]); $edit_entry = (int)trim(@$_REQUEST['edit' ]); @@ -78,84 +85,90 @@ function confirm_delete() { if ($save_entry < 1) { $rs = $DB->execute( -'INSERT INTO `pb_prv` (`id`, `user_id`, `lastname`, `firstname`, `number`) VALUES -(NULL, '. $user_id .', \''. $DB->escape($save_lname) .'\', \''. $DB->escape($save_fname) .'\', \''. $DB->escape($save_number) .'\')' +'INSERT INTO `pb_prv` (`id`, `user_id`, `lastname`, `firstname`, `number`, `ptype`) VALUES +(NULL, '. $user_id .', \''. $DB->escape($save_lname) .'\', \''. $DB->escape($save_fname) .'\', \''. $DB->escape($save_number) .'\', \''. $DB->escape($save_ptype) .'\')' ); } else { $rs = $DB->execute( -'UPDATE `pb_prv` SET `lastname`=\''. $DB->escape($save_lname) .'\', `firstname`=\''. $DB->escape($save_fname) .'\', `number`=\''. $DB->escape($save_number) .'\' +'UPDATE `pb_prv` SET `lastname`=\''. $DB->escape($save_lname) .'\', `firstname`=\''. $DB->escape($save_fname) .'\', `number`=\''. $DB->escape($save_number) .'\', `ptype`=\''. $DB->escape($save_ptype) .'\' WHERE `id`='. $save_entry .' AND `user_id`='. $user_id ); - $save_number = ''; - $save_name = ''; } + $save_number = ''; + $save_name = ''; + $save_ptype = ''; } +if ( empty($catid) && isset($SESSION['catid']) ) $catid=(int)@$SESSION['catid']; +elseif ( empty($catid) ) $catid=0; + +$sel = ( $catid == 0 ) ? ' selected="selected"' : ''; +$ac = array(''); + +$cs = $DB->execute( + 'SELECT `c`.`id`, `c`.`category` '. + 'FROM `pb_category` `c` '. + 'LEFT JOIN `pb_prv_category` `p` ON `c`.`id` = `p`.`cat_id` ' . + 'WHERE '. + '`p`.`id` IS NOT NULL AND ' . + '( `c`.`user_id`='. $DB->escape($user_id).' OR `c`.`user_id`=1 )'. + 'GROUP BY `c`.`category` '. + 'ORDER BY `c`.`category`' + ); +while ( $r = $cs->fetchRow() ) { + $sel = ($catid == @$r['id']) ? ' selected="selected"' : ''; + $ac[] = ''; +} - - +$query = 'SELECT SQL_CALC_FOUND_ROWS '. + '`p`.`id`, `p`.`lastname`, `p`.`firstname`, `p`.`number` , `p`.`ptype`, `p`.`card_id`, `p`.`user_id`'. + ' FROM `pb_prv` `p`'; +$where = ' WHERE ( `p`.`user_id`='. $user_id . ' OR `p`.`user_id`=1 ) '; if ($number != '') { - + # search by number - + $name = ''; $search_url = 'number='. urlEncode($number); - $number_sql = str_replace( array( '*', '?' ), array( '%', '_' ), $number ) .'%'; - - $rs = $DB->execute( - 'SELECT SQL_CALC_FOUND_ROWS '. - '`id`, `lastname`, `firstname`, `number` '. - 'FROM '. - '`pb_prv` '. - 'WHERE '. - '`number` LIKE \''. $DB->escape($number_sql) .'\' '. - 'AND '. - '`user_id`='. $user_id .' '. - 'ORDER BY `lastname`, `firstname` '. - 'LIMIT '. ($page*(int)$per_page) .','. (int)$per_page - ); - $num_total = @$DB->numFoundRows(); - $num_pages = ceil($num_total / $per_page); - + $where .= ' AND `p`.`number` LIKE \''. $DB->escape($number_sql) .'\' '; + } else { - + # search by name - $number = ''; $search_url = 'name='. urlEncode($name); - $name_sql = str_replace( array( '*', '?' ), array( '%', '_' ), $name ) .'%'; - - $rs = $DB->execute( - 'SELECT SQL_CALC_FOUND_ROWS '. - '`id`, `lastname`, `firstname`, `number` '. - 'FROM '. - '`pb_prv` '. - 'WHERE '. - '( `lastname` LIKE _utf8\''. $DB->escape($name_sql) .'\' COLLATE utf8_unicode_ci OR '. - ' `firstname` LIKE _utf8\''. $DB->escape($name_sql) .'\' COLLATE utf8_unicode_ci ) '. - 'AND '. - '`user_id`='. $DB->escape($user_id).' '. - 'ORDER BY `lastname`, `firstname` '. - 'LIMIT '. ($page*(int)$per_page) .','. (int)$per_page - ); - $num_total = @$DB->numFoundRows(); - $num_pages = ceil($num_total / $per_page); - + $where .= ' AND ( `p`.`lastname` LIKE _utf8\''. $DB->escape($name_sql) .'\' COLLATE utf8_unicode_ci OR '. + ' `p`.`firstname` LIKE _utf8\''. $DB->escape($name_sql) .'\' COLLATE utf8_unicode_ci ) '; } +if ( $catid != 0 ) { + $search_url .= '&catid='. $catid; + $search_cat = '&catid='. $catid; + $query .= ' LEFT JOIN `pb_prv_category` `pc` ON `p`.`id` = `pc`.`prv_id` '; + $where .= ' AND `pc`.`cat_id` = ' . $catid; +} else $search_cat = ''; +$SESSION['catid']=$catid; + +$order = ' ORDER BY `p`.`lastname`, `p`.`firstname`, `p`.`pref`, `p`.`ptype` '; +$limit = ' LIMIT '. ($page*(int)$per_page) .','. (int)$per_page; + +$rs = $DB->execute( $query . $where . $order . $limit); + +$num_total = @$DB->numFoundRows(); +$num_pages = ceil($num_total / $per_page); ?> @@ -163,7 +176,8 @@ function confirm_delete() { - + + [1] @@ -172,6 +186,7 @@ function confirm_delete() {
+
+ + '; + echo gs_form_hidden($SECTION, $MODULE); + echo ''; + } else echo ' '; + ?> + - + $cs) { - echo '', htmlEnt($cd), '', "\n"; + echo '', htmlEnt($cd), '', "\n"; } ?> @@ -237,6 +266,8 @@ function confirm_delete() { echo gs_form_hidden($SECTION, $MODULE), "\n"; echo '', "\n"; echo '', "\n"; +echo '', "\n"; +echo '', "\n"; ?> @@ -245,9 +276,12 @@ function confirm_delete() { - + @@ -257,6 +291,7 @@ function confirm_delete() { if (@$rs) { $i = 0; + $last_seen = ''; while ($r = $rs->fetchRow()) { echo '', "\n"; @@ -270,6 +305,10 @@ function confirm_delete() { echo ''; echo '', "\n"; + echo '', "\n"; + echo ''; } else { - echo '', "\n"; echo '', "\n"; + + echo '', "\n"; echo ''; } @@ -320,6 +368,9 @@ function confirm_delete() { +
> > + > > + [2] +  
'; + echo ''; + echo ''; echo ''; echo ''; @@ -279,26 +318,35 @@ function confirm_delete() { echo ''; - echo '', __('abbrechen'), ''; + echo '', __('abbrechen'), ''; echo '', htmlEnt($r['lastname']); - if ($r['firstname'] != '') - echo ', ', htmlEnt($r['firstname']); + $show_name = trim( $r['lastname'] . ', ' . $r['firstname'], " ," ); + if ( $last_seen != $show_name ) { + echo ''; + $last_seen = htmlEnt($show_name); + } + else echo ''; + echo $last_seen; echo '', htmlEnt($r['number']), '', htmlEnt($r['ptype']), ''; $sudo_url = (@$_SESSION['sudo_user']['name'] == @$_SESSION['real_user']['name']) ? '' : ('&sudo='. @$_SESSION['sudo_user']['name']); echo '', __('wählen'), '   '; - echo '', __('bearbeiten'), '   '; - echo '', __('entfernen'), ''; + if ( $r['user_id'] != 1 ) { // edit only own recordset, other's within the cloud + echo '', __('bearbeiten'), '   '; + echo '', __('entfernen'), ''; + } + if ( $r['card_id'] ) echo ' [1]'; echo ' + +
+
+

[1] is only shown for cloud records. You can loose local changes on a cloud record with a refresh,
+       rather modify/delete this entry within your cloud. Public entries can not be edited here.

+

[2] Type of phone number: cell/work/home etc.

diff --git a/opt/gemeinschaft/htdocs/gui/styles/original.css b/opt/gemeinschaft/htdocs/gui/styles/original.css index bfdb92782..01a69f2cc 100644 --- a/opt/gemeinschaft/htdocs/gui/styles/original.css +++ b/opt/gemeinschaft/htdocs/gui/styles/original.css @@ -142,9 +142,9 @@ q:after { content: close-quote; } .r {text-align: right;} .c {text-align: center;} -.t {text-align: top;} -.m {text-align: middle;} -.b {text-align: bottom;} +.t {vertical-align: top;} +.m {vertical-align: middle;} +.b {vertical-align: bottom;} .m, tr.m td, diff --git a/opt/gemeinschaft/htdocs/prov/aastra/pb.php b/opt/gemeinschaft/htdocs/prov/aastra/pb.php index c543a70cd..dbf7fb009 100644 --- a/opt/gemeinschaft/htdocs/prov/aastra/pb.php +++ b/opt/gemeinschaft/htdocs/prov/aastra/pb.php @@ -269,7 +269,7 @@ function _get_userid() FROM `pb_prv` WHERE - `user_id`='. $user_id .' AND ( + (`user_id`='. $user_id . 'OR `user_id`=1 ) AND ( `lastname` LIKE _utf8\''. $db->escape($name_sql) .'\' COLLATE utf8_unicode_ci ) ORDER BY `lastname`, `firstname` @@ -446,4 +446,4 @@ function _get_userid() aastra_transmit_str( $xml ); -?> \ No newline at end of file +?> diff --git a/opt/gemeinschaft/htdocs/prov/grandstream/gs_phonebook.php b/opt/gemeinschaft/htdocs/prov/grandstream/gs_phonebook.php index d60b39881..a7cad3a48 100644 --- a/opt/gemeinschaft/htdocs/prov/grandstream/gs_phonebook.php +++ b/opt/gemeinschaft/htdocs/prov/grandstream/gs_phonebook.php @@ -169,7 +169,7 @@ function _err( $msg='' ) 'query' => 'SELECT `pb`.`lastname` `ln`, `pb`.`firstname` `fn`, `pb`.`number` `ext` FROM `pb_prv` `pb` -WHERE `pb`.`user_id`='.$user_id.' +WHERE (`pb`.`user_id`='. $user_id . 'OR `pb`.`user_id`=1 ) ORDER BY `pb`.`lastname`, `pb`.`firstname` LIMIT 100' ); diff --git a/opt/gemeinschaft/htdocs/prov/private-phonebook-xml.inc b/opt/gemeinschaft/htdocs/prov/private-phonebook-xml.inc new file mode 100644 index 000000000..fd2c89730 --- /dev/null +++ b/opt/gemeinschaft/htdocs/prov/private-phonebook-xml.inc @@ -0,0 +1,155 @@ + +* Philipp Kempgen +* Peter Kozak +* Soeren Sprenger +* Markus Neubauer - 2015 +* - extending db and preparing for vcards +* you need to alter the db for this version to work: +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +\*******************************************************************/ + +defined('GS_VALID') or die('No direct access.'); + +require_once( dirName(__FILE__) .'/../../inc/conf.php' ); +include_once( GS_DIR .'lib/yadb/yadb.php' ); +include_once( GS_DIR .'inc/gs-lib.php' ); +require_once( GS_DIR .'inc/db_connect.php' ); +include_once( GS_DIR .'lib/utf8-normalize/gs_utf_normal.php' ); +require_once( GS_DIR .'inc/db_connect.php' ); + +header('Content-type: application/xml'); + +if ( empty($_REQUEST) && !empty($argv) ) parse_str(implode('&', array_slice($argv, 1)), $_REQUEST); +if ( empty($_REQUEST) && !empty($_GET) ) $_REQUEST = $_GET; + +$name = trim(@$_REQUEST['name' ]); +$number = trim(@$_REQUEST['number' ]); +$catid = trim(@$_REQUEST['catid' ]); +$cat = trim(@$_REQUEST['cat' ]); + +$user_id = (int)@$_REQUEST['id']; +$user = @$_REQUEST['user']; + +if ( empty($catid) && isset($SESSION['catid']) ) $catid=(int)@$SESSION['catid']; +elseif ( empty($catid) ) $catid=0; + +$query = 'SELECT `id`, `user` FROM `users` WHERE '; +if ( !empty($user) ) { + $query .= '`user`=' . $user; +} +elseif ( !empty( $user_id ) ) { + $query .= '`id`=' . $user_id; +} +elseif ( empty( $user ) && empty( $user_id ) ) die(); + +$DB = gs_db_master_connect(); + +$rs = $DB->execute( $query . ' LIMIT 1' ); +if ( $r = $rs->fetchRow() ) { + $user = $r['user']; + $user_id = $r['id']; +} else die(); + +if ( empty($catid) && ! empty($cat) ) { + $query = 'SELECT `id` FROM `pb_category` WHERE `category`=\'' . $cat . '\' LIMIT 1'; + $catid = (int)$DB->executeGetOne( $query ); +} + + +$query = 'SELECT SQL_CALC_FOUND_ROWS '. + '`p`.`id`, `p`.`lastname`, `p`.`firstname`, `p`.`number` , `p`.`ptype`, `p`.`card_id`'. + ' FROM `pb_prv` `p`'; +$where = ' WHERE ( `p`.`user_id`='. $user_id . ' OR `p`.`user_id`=1 ) '; + +if ($number != '') { + + # search by number + $name = ''; + $search_url = 'number='. urlEncode($number); + $number_sql = str_replace( + array( '*', '?' ), + array( '%', '_' ), + $number + ) .'%'; + $where .= ' AND `p`.`number` LIKE \''. $DB->escape($number_sql) .'\' '; + +} else { + + # search by name + $number = ''; + $search_url = 'name='. urlEncode($name); + $name_sql = str_replace( + array( '*', '?' ), + array( '%', '_' ), + $name + ) .'%'; + $where .= ' AND ( `p`.`lastname` LIKE _utf8\''. $DB->escape($name_sql) .'\' COLLATE utf8_unicode_ci OR '. + ' `p`.`firstname` LIKE _utf8\''. $DB->escape($name_sql) .'\' COLLATE utf8_unicode_ci ) '; +} + +if ( $catid != 0 ) { + $search_url .= '&catid='. $catid; + $query .= ' LEFT JOIN `pb_prv_category` `pc` ON `p`.`id` = `pc`.`prv_id` '; + $where .= ' AND `pc`.`cat_id` = ' . $catid; +} + +$order = ' ORDER BY `p`.`lastname`, `p`.`firstname`, `p`.`pref`, `p`.`ptype` '; + +$rs = $DB->execute( $query . $where . $order); + +$cs = $DB->execute( + 'SELECT `c`.`category` '. + ' FROM `pb_category` `c` '. + ' WHERE `c`.`id` =' . $catid + ); +if ( $r = $cs->fetchRow() ) $sel = $r['category']; +else $sel = __('Alle Kategorien'); + +?> +<?php echo $sel ?> +Prompt +fetchRow()) { + echo '' . PHP_EOL; + echo '' . trim( $r['lastname'] . ', ' . $r['firstname'], " ," ); + if ( ! empty($r['ptype']) ) echo ' (' . $r['ptype'] . ')'; + echo '' . PHP_EOL; + echo '' . $r['number'] . '' . PHP_EOL; + echo '' . PHP_EOL; + } +} + +if ( $sel != __('Alle Kategorien') ) { + echo '' . PHP_EOL; + echo '*' . PHP_EOL; + echo 'http://' . $_SERVER['SERVER_NAME'] . '/gemeinschaft/prov/snom/private-phonebook-xml.php?user=' . $user . '' . PHP_EOL; + echo '' . PHP_EOL; +} +?> diff --git a/opt/gemeinschaft/htdocs/prov/siemens/pb/pb.php b/opt/gemeinschaft/htdocs/prov/siemens/pb/pb.php index a9ee3a70b..6bd5b7ef0 100644 --- a/opt/gemeinschaft/htdocs/prov/siemens/pb/pb.php +++ b/opt/gemeinschaft/htdocs/prov/siemens/pb/pb.php @@ -283,7 +283,7 @@ function write_alert( $message, $alert_type='ERROR' ) $image = $img_url.'contents.png'; break; case 'prv': - $c = (int)$db->executeGetOne( 'SELECT COUNT(*) FROM `pb_prv` WHERE `user_id`='. $user_id ); + $c = (int)$db->executeGetOne( 'SELECT COUNT(*) FROM `pb_prv` WHERE (`user_id`='. $user_id . 'OR `user_id`=1 )' ); $image = $img_url.'yast_sysadmin.png'; break; case 'imported': diff --git a/opt/gemeinschaft/htdocs/prov/snom/pb.php b/opt/gemeinschaft/htdocs/prov/snom/pb.php index fc83adb56..958acb4dc 100644 --- a/opt/gemeinschaft/htdocs/prov/snom/pb.php +++ b/opt/gemeinschaft/htdocs/prov/snom/pb.php @@ -161,7 +161,7 @@ function getUserID( $ext ) switch ($t) { case 'gs' : $cq .= '`users` WHERE `id` IN ('.implode(',',$group_members).') AND `id`!='.$user_id; break; case 'imported': $cq .= '`pb_ldap`' ; break; - case 'prv' : $cq .= '`pb_prv` WHERE `user_id`='. $user_id ; break; + case 'prv' : $cq .= '`pb_prv` WHERE (`user_id`='. $user_id . 'OR `user_id`=1 )' ; break; default : $cq = false; } $c = $cq ? (' ('. (int)@$db->executeGetOne( $cq ) .')') : ''; diff --git a/opt/gemeinschaft/htdocs/prov/snom/private-phonebook-xml.php b/opt/gemeinschaft/htdocs/prov/snom/private-phonebook-xml.php new file mode 100644 index 000000000..0d6f2f4a1 --- /dev/null +++ b/opt/gemeinschaft/htdocs/prov/snom/private-phonebook-xml.php @@ -0,0 +1,43 @@ + +* Philipp Kempgen +* Peter Kozak +* Soeren Sprenger +* Markus Neubauer - 2015 +* - extending db and preparing for vcards +* you need to alter the db for this version to work: +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +\*******************************************************************/ + +define('GS_VALID', true); // arriving nativ here + +header('Content-type: application/xml'); + +?> + + + diff --git a/opt/gemeinschaft/htdocs/prov/tiptel/pb.php b/opt/gemeinschaft/htdocs/prov/tiptel/pb.php index 64e09bd23..570a50131 100644 --- a/opt/gemeinschaft/htdocs/prov/tiptel/pb.php +++ b/opt/gemeinschaft/htdocs/prov/tiptel/pb.php @@ -174,7 +174,7 @@ function getUserID( $ext ) switch ($t) { case 'gs' : $cq .= '`users` WHERE `id` IN ('.implode(',',$group_members).') AND `id`!='.$user_id; break; case 'imported': $cq .= '`pb_ldap`' ; break; - case 'prv' : $cq .= '`pb_prv` WHERE `user_id`='. $user_id ; break; + case 'prv' : $cq .= '`pb_prv` WHERE (`user_id`='. $user_id . 'OR `user_id`=1 )' ; break; default : $cq = false; } $c = $cq ? (' ('. (int)@$db->executeGetOne( $cq ) .')') : ''; @@ -324,4 +324,4 @@ function getUserID( $ext ) #################################### PHONEBOOK } -?> \ No newline at end of file +?> diff --git a/opt/gemeinschaft/htdocs/prov/tiptel/pb_on_phone.php b/opt/gemeinschaft/htdocs/prov/tiptel/pb_on_phone.php index bbf54bf89..3026aabf8 100644 --- a/opt/gemeinschaft/htdocs/prov/tiptel/pb_on_phone.php +++ b/opt/gemeinschaft/htdocs/prov/tiptel/pb_on_phone.php @@ -125,7 +125,7 @@ function _err( $msg='' ) 'query' => 'SELECT `pb`.`lastname` `ln`, `pb`.`firstname` `fn`, `pb`.`number` `ext` FROM `pb_prv` `pb` - WHERE `pb`.`user_id`='.$user_id.' + WHERE (`pb`.`user_id`='. $user_id . 'OR `pb`.`user_id`=1 ) ORDER BY `pb`.`lastname`, `pb`.`firstname`' ); } @@ -172,4 +172,4 @@ function _err( $msg='' ) } @ob_end_flush(); -?> \ No newline at end of file +?> diff --git a/opt/gemeinschaft/lib/carddav/CardDAV.php b/opt/gemeinschaft/lib/carddav/CardDAV.php new file mode 100644 index 000000000..aae5fd23b --- /dev/null +++ b/opt/gemeinschaft/lib/carddav/CardDAV.php @@ -0,0 +1,679 @@ +set_auth('username', 'password'); + * echo $carddav->get(); + * + * + * Simple vCard query + * ------------------ + * $carddav = new carddav_backend('https://davical.example.com/user/contacts/'); + * $carddav->set_auth('username', 'password'); + * echo $carddav->get_vcard('0126FFB4-2EB74D0A-302EA17F'); + * + * + * XML vCard query + * ------------------ + * $carddav = new carddav_backend('https://davical.example.com/user/contacts/'); + * $carddav->set_auth('username', 'password'); + * echo $carddav->get_xml_vcard('0126FFB4-2EB74D0A-302EA17F'); + * + * + * Check CardDAV server connection + * ------------------------------- + * $carddav = new carddav_backend('https://davical.example.com/user/contacts/'); + * $carddav->set_auth('username', 'password'); + * var_dump($carddav->check_connection()); + * + * + * CardDAV delete query + * -------------------- + * $carddav = new carddav_backend('https://davical.example.com/user/contacts/'); + * $carddav->set_auth('username', 'password'); + * $carddav->delete('0126FFB4-2EB74D0A-302EA17F'); + * + * + * CardDAV add query + * -------------------- + * $vcard = 'BEGIN:VCARD + * VERSION:3.0 + * UID:1f5ea45f-b28a-4b96-25as-ed4f10edf57b + * FN:Christian Putzke + * N:Christian;Putzke;;; + * EMAIL;TYPE=OTHER:christian.putzke@graviox.de + * END:VCARD'; + * + * $carddav = new carddav_backend('https://davical.example.com/user/contacts/'); + * $carddav->set_auth('username', 'password'); + * $vcard_id = $carddav->add($vcard); + * + * + * CardDAV update query + * -------------------- + * $vcard = 'BEGIN:VCARD + * VERSION:3.0 + * UID:1f5ea45f-b28a-4b96-25as-ed4f10edf57b + * FN:Christian Putzke + * N:Christian;Putzke;;; + * EMAIL;TYPE=OTHER:christian.putzke@graviox.de + * END:VCARD'; + * + * $carddav = new carddav_backend('https://davical.example.com/user/contacts/'); + * $carddav->set_auth('username', 'password'); + * $carddav->update($vcard, '0126FFB4-2EB74D0A-302EA17F'); + * + * + * CardDAV debug + * ------------- + * $carddav = new carddav_backend('https://davical.example.com/user/contacts/'); + * $carddav->enable_debug(); + * $carddav->set_auth('username', 'password'); + * $carddav->get(); + * var_dump($carddav->get_debug()); + * + * + * CardDAV server list + * ------------------- + * DAViCal: https://example.com/{resource|principal|username}/{collection}/ + * Apple Addressbook Server: https://example.com/addressbooks/users/{resource|principal|username}/{collection}/ + * memotoo: https://sync.memotoo.com/cardDAV/ + * SabreDAV: https://example.com/addressbooks/{resource|principal|username}/{collection}/ + * ownCloud: https://example.com/apps/contacts/carddav.php/addressbooks/{resource|principal|username}/{collection}/ + * SOGo: https://example.com/SOGo/dav/{resource|principal|username}/Contacts/{collection}/ + * + * + * @author Christian Putzke + * @copyright Christian Putzke + * @link http://www.graviox.de/ + * @link https://twitter.com/cputzke/ + * @since 20.07.2011 + * @version 0.6 + * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + * + */ + +class carddav_backend +{ + /** + * CardDAV PHP Version + * + * @constant string + */ + const VERSION = '0.6'; + + /** + * User agent displayed in http requests + * + * @constant string + */ + const USERAGENT = 'CardDAV PHP/'; + + /** + * CardDAV server url + * + * @var string + */ + private $url = null; + + /** + * CardDAV server url_parts + * + * @var array + */ + private $url_parts = null; + + /** + * Authentication string + * + * @var string + */ + private $auth = null; + + /** + * Authentication: username + * + * @var string + */ + private $username = null; + + /** + * Authentication: password + * + * @var string + */ + private $password = null; + + /** + * Characters used for vCard id generation + * + * @var array + */ + private $vcard_id_chars = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F'); + + /** + * CardDAV server connection (curl handle) + * + * @var resource + */ + private $curl; + + /** + * Debug on or off + * + * @var boolean + */ + private $debug = false; + + /** + * All available debug information + * + * @var array + */ + private $debug_information = array(); + + /** + * Exception codes + */ + const EXCEPTION_WRONG_HTTP_STATUS_CODE_GET = 1000; + const EXCEPTION_WRONG_HTTP_STATUS_CODE_GET_VCARD = 1001; + const EXCEPTION_WRONG_HTTP_STATUS_CODE_GET_XML_VCARD = 1002; + const EXCEPTION_WRONG_HTTP_STATUS_CODE_DELETE = 1003; + const EXCEPTION_WRONG_HTTP_STATUS_CODE_ADD = 1004; + const EXCEPTION_WRONG_HTTP_STATUS_CODE_UPDATE = 1005; + const EXCEPTION_MALFORMED_XML_RESPONSE = 1006; + const EXCEPTION_COULD_NOT_GENERATE_NEW_VCARD_ID = 1007; + + + /** + * Constructor + * Sets the CardDAV server url + * + * @param string $url CardDAV server url + */ + public function __construct($url = null) + { + if ($url !== null) + { + $this->set_url($url); + } + } + + /** + * Sets debug information + * + * @param array $debug_information Debug information + * @return void + */ + public function set_debug(array $debug_information) + { + $this->debug_information[] = $debug_information; + } + + /** + * Sets the CardDAV server url + * + * @param string $url CardDAV server url + * @return void + */ + public function set_url($url) + { + $this->url = $url; + + if (substr($this->url, -1, 1) !== '/') + { + $this->url = $this->url . '/'; + } + + $this->url_parts = parse_url($this->url); + } + + /** + * Sets authentication information + * + * @param string $username CardDAV server username + * @param string $password CardDAV server password + * @return void + */ + public function set_auth($username, $password) + { + $this->username = $username; + $this->password = $password; + $this->auth = $username . ':' . $password; + } + + /** + * Gets all available debug information + * + * @return array $this->debug_information All available debug information + */ + public function get_debug() + { + return $this->debug_information; + } + + /** + * Gets all vCards including additional information from the CardDAV server + * + * @param boolean $include_vcards Include vCards within the response (simplified only) + * @param boolean $raw Get response raw or simplified + * @return string Raw or simplified XML response + */ + public function get($include_vcards = true, $raw = false) + { + $result = $this->query($this->url, 'PROPFIND'); + + switch ($result['http_code']) + { + case 200: + case 207: + if ($raw === true) + { + return $result['response']; + } + else + { + return $this->simplify($result['response'], $include_vcards); + } + break; + + default: + throw new Exception('Woops, something\'s gone wrong! The CardDAV server returned the http status code ' . $result['http_code'] . '.', self::EXCEPTION_WRONG_HTTP_STATUS_CODE_GET); + break; + } + } + + /** + * Gets a clean vCard from the CardDAV server + * + * @param string $vcard_id vCard id on the CardDAV server + * @return string vCard (text/vcard) + */ + public function get_vcard($vcard_id) + { + $vcard_id = str_replace('.vcf', null, $vcard_id); + $result = $this->query($this->url . $vcard_id . '.vcf', 'GET'); + + switch ($result['http_code']) + { + case 200: + case 207: + return $result['response']; + break; + + default: + throw new Exception('Woops, something\'s gone wrong! The CardDAV server returned the http status code ' . $result['http_code'] . '.', self::EXCEPTION_WRONG_HTTP_STATUS_CODE_GET_VCARD); + break; + } + } + + /** + * Gets a vCard + XML from the CardDAV Server + * + * @param string $vcard_id vCard id on the CardDAV Server + * @return string Raw or simplified vCard (text/xml) + */ + public function get_xml_vcard($vcard_id) + { + $vcard_id = str_replace('.vcf', null, $vcard_id); + + $xml = new XMLWriter(); + $xml->openMemory(); + $xml->setIndent(4); + $xml->startDocument('1.0', 'utf-8'); + $xml->startElement('C:addressbook-multiget'); + $xml->writeAttribute('xmlns:D', 'DAV:'); + $xml->writeAttribute('xmlns:C', 'urn:ietf:params:xml:ns:carddav'); + $xml->startElement('D:prop'); + $xml->writeElement('D:getetag'); + $xml->writeElement('D:getlastmodified'); + $xml->endElement(); + $xml->writeElement('D:href', $this->url_parts['path'] . $vcard_id . '.vcf'); + $xml->endElement(); + $xml->endDocument(); + + $result = $this->query($this->url, 'REPORT', $xml->outputMemory(), 'text/xml'); + + switch ($result['http_code']) + { + case 200: + case 207: + return $this->simplify($result['response'], true); + break; + + default: + throw new Exception('Woops, something\'s gone wrong! The CardDAV server returned the http status code ' . $result['http_code'] . '.', self::EXCEPTION_WRONG_HTTP_STATUS_CODE_GET_XML_VCARD); + break; + } + } + + /** + * Enables the debug mode + * + * @return void + */ + public function enable_debug() + { + $this->debug = true; + } + + /** + * Checks if the CardDAV server is reachable + * + * @return boolean + */ + public function check_connection() + { + $result = $this->query($this->url, 'OPTIONS'); + + if ($result['http_code'] === 200) + { + return true; + } + else + { + return false; + } + } + + /** + * Cleans the vCard + * + * @param string $vcard vCard + * @return string $vcard vCard + */ + private function clean_vcard($vcard) + { + $vcard = str_replace("\t", null, $vcard); + + return $vcard; + } + + /** + * Deletes an entry from the CardDAV server + * + * @param string $vcard_id vCard id on the CardDAV server + * @return boolean + */ + public function delete($vcard_id) + { + $result = $this->query($this->url . $vcard_id . '.vcf', 'DELETE'); + + switch ($result['http_code']) + { + case 204: + return true; + break; + + default: + throw new Exception('Woops, something\'s gone wrong! The CardDAV server returned the http status code ' . $result['http_code'] . '.', self::EXCEPTION_WRONG_HTTP_STATUS_CODE_DELETE); + break; + } + } + + /** + * Adds an entry to the CardDAV server + * + * @param string $vcard vCard + * @param string $vcard_id vCard id on the CardDAV server + * @return string The new vCard id + */ + public function add($vcard, $vcard_id = null) + { + if ($vcard_id === null) + { + $vcard_id = $this->generate_vcard_id(); + } + $vcard = $this->clean_vcard($vcard); + $result = $this->query($this->url . $vcard_id . '.vcf', 'PUT', $vcard, 'text/vcard'); + + switch($result['http_code']) + { + case 201: + return $vcard_id; + break; + + default: + throw new Exception('Woops, something\'s gone wrong! The CardDAV server returned the http status code ' . $result['http_code'] . '.', self::EXCEPTION_WRONG_HTTP_STATUS_CODE_ADD); + break; + } + } + + /** + * Updates an entry to the CardDAV server + * + * @param string $vcard vCard + * @param string $vcard_id vCard id on the CardDAV server + * @return boolean + */ + public function update($vcard, $vcard_id) + { + try + { + return $this->add($vcard, $vcard_id); + } + catch (Exception $e) + { + throw new Exception($e->getMessage(), self::EXCEPTION_WRONG_HTTP_STATUS_CODE_UPDATE); + } + } + + /** + * Simplify CardDAV XML response + * + * @param string $response CardDAV XML response + * @param boolean $include_vcards Include vCards or not + * @return string Simplified CardDAV XML response + */ + private function simplify($response, $include_vcards = true) + { + $response = $this->clean_response($response); + + try + { + $xml = new SimpleXMLElement($response); + } + catch(Exception $e) + { + throw new Exception('The XML response seems to be malformed and can\'t be simplified!', self::EXCEPTION_MALFORMED_XML_RESPONSE, $e); + } + + $simplified_xml = new XMLWriter(); + $simplified_xml->openMemory(); + $simplified_xml->setIndent(4); + + $simplified_xml->startDocument('1.0', 'utf-8'); + $simplified_xml->startElement('response'); + + if (!empty($xml->response)) + { + foreach ($xml->response as $response) + { + if (preg_match('/vcard/', $response->propstat->prop->getcontenttype) || preg_match('/vcf/', $response->href)) + { + $id = basename($response->href); + $id = str_replace('.vcf', null, $id); + + if (!empty($id)) + { + $simplified_xml->startElement('element'); + $simplified_xml->writeElement('id', $id); + $simplified_xml->writeElement('etag', str_replace('"', null, $response->propstat->prop->getetag)); + $simplified_xml->writeElement('last_modified', $response->propstat->prop->getlastmodified); + + if ($include_vcards === true) + { + $simplified_xml->writeElement('vcard', $this->get_vcard($id)); + } + $simplified_xml->endElement(); + } + } + else if (preg_match('/unix-directory/', $response->propstat->prop->getcontenttype)) + { + if (isset($response->propstat->prop->href)) + { + $href = $response->propstat->prop->href; + } + else if (isset($response->href)) + { + $href = $response->href; + } + else + { + $href = null; + } + + $url = str_replace($this->url_parts['path'], null, $this->url) . $href; + $simplified_xml->startElement('addressbook_element'); + $simplified_xml->writeElement('display_name', $response->propstat->prop->displayname); + $simplified_xml->writeElement('url', $url); + $simplified_xml->writeElement('last_modified', $response->propstat->prop->getlastmodified); + $simplified_xml->endElement(); + } + } + } + + $simplified_xml->endElement(); + $simplified_xml->endDocument(); + + return $simplified_xml->outputMemory(); + } + + /** + * Cleans CardDAV XML response + * + * @param string $response CardDAV XML response + * @return string $response Cleaned CardDAV XML response + */ + private function clean_response($response) + { + $response = utf8_encode($response); + $response = str_replace('D:', null, $response); + $response = str_replace('d:', null, $response); + $response = str_replace('C:', null, $response); + $response = str_replace('c:', null, $response); + + return $response; + } + + /** + * Curl initialization + * + * @return void + */ + public function curl_init() + { + if (empty($this->curl)) + { + $this->curl = curl_init(); + curl_setopt($this->curl, CURLOPT_HEADER, true); + curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($this->curl, CURLOPT_USERAGENT, self::USERAGENT.self::VERSION); + + if ($this->auth !== null) + { + curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_setopt($this->curl, CURLOPT_USERPWD, $this->auth); + } + } + } + + /** + * Query the CardDAV server via curl and returns the response + * + * @param string $url CardDAV server URL + * @param string $method HTTP method like (OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE) + * @param string $content Content for CardDAV queries + * @param string $content_type Set content type + * @return array Raw CardDAV Response and http status code + */ + private function query($url, $method, $content = null, $content_type = null) + { + $this->curl_init(); + + curl_setopt($this->curl, CURLOPT_URL, $url); + curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $method); + + if ($content !== null) + { + curl_setopt($this->curl, CURLOPT_POST, true); + curl_setopt($this->curl, CURLOPT_POSTFIELDS, $content); + } + else + { + curl_setopt($this->curl, CURLOPT_POST, false); + curl_setopt($this->curl, CURLOPT_POSTFIELDS, null); + } + + if ($content_type !== null) + { + curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('Content-type: '.$content_type)); + } + else + { + curl_setopt($this->curl, CURLOPT_HTTPHEADER, array()); + } + + $complete_response = curl_exec($this->curl); + $header_size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE); + $http_code = curl_getinfo($this->curl, CURLINFO_HTTP_CODE); + $header = trim(substr($complete_response, 0, $header_size)); + $response = substr($complete_response, $header_size); + + $return = array( + 'response' => $response, + 'http_code' => $http_code + ); + + if ($this->debug === true) + { + $debug = $return; + $debug['url'] = $url; + $debug['method'] = $method; + $debug['content'] = $content; + $debug['content_type'] = $content_type; + $debug['header'] = $header; + $this->set_debug($debug); + } + + return $return; + } + + /** + * Returns a valid and unused vCard id + * + * @return$carddav->query($this->url . $vcard_id . '.vcf', 'GET'); + + if ($result['http_code'] !== 404) + { + $vcard_id = $this->generate_vcard_id(); + } + + return $vcard_id; + } + catch (Exception $e) + { + throw new Exception($e->getMessage(), self::EXCEPTION_COULD_NOT_GENERATE_NEW_VCARD_ID); + } + } + + /** + * Destructor + * Close curl connection if it's open + * + * @return void + */ + public function __destruct() + { + if (!empty($this->curl)) + { + curl_close($this->curl); + } + } +} diff --git a/opt/gemeinschaft/lib/xml/xml2array.php b/opt/gemeinschaft/lib/xml/xml2array.php new file mode 100644 index 000000000..165405134 --- /dev/null +++ b/opt/gemeinschaft/lib/xml/xml2array.php @@ -0,0 +1,142 @@ +rawXML = $xml; + } + + function parse($xml = NULL) + { + if (!is_null($xml)) + { + $this->rawXML = $xml; + } + + $this->isError = false; + + if (!$this->parse_init()) + { + return false; + } + + $this->index = 0; + $this->parsed = $this->parse_recurse(); + $this->status = 'parsing complete'; + + return $this->parsed; + } + + function parse_recurse() + { + $found = array(); + $tagCount = array(); + + while (isset($this->valueArray[$this->index])) + { + $tag = $this->valueArray[$this->index]; + $this->index++; + + if ($tag['type'] == 'close') + { + return $found; + } + + if ($tag['type'] == 'cdata') + { + $tag['tag'] = $this->cdataKey; + $tag['type'] = 'complete'; + } + + $tagName = $tag['tag']; + + if (isset($tagCount[$tagName])) + { + if ($tagCount[$tagName] == 1) + { + $found[$tagName] = array($found[$tagName]); + } + + $tagRef =& $found[$tagName][$tagCount[$tagName]]; + $tagCount[$tagName]++; + } + else + { + $tagCount[$tagName] = 1; + $tagRef =& $found[$tagName]; + } + + switch ($tag['type']) + { + case 'open': + $tagRef = $this->parse_recurse(); + + if (isset($tag['attributes'])) + { + $tagRef[$this->attribKey] = $tag['attributes']; + } + + if (isset($tag['value'])) + { + if (isset($tagRef[$this->cdataKey])) + { + $tagRef[$this->cdataKey] = (array)$tagRef[$this->cdataKey]; + array_unshift($tagRef[$this->cdataKey], $tag['value']); + } + else + { + $tagRef[$this->cdataKey] = $tag['value']; + } + } + break; + + case 'complete': + if (isset($tag['attributes'])) + { + $tagRef[$this->attribKey] = $tag['attributes']; + $tagRef =& $tagRef[$this->valueKey]; + } + + if (isset($tag['value'])) + { + $tagRef = $tag['value']; + } + break; + } + } + + return $found; + } + + function parse_init() + { + $this->parser = xml_parser_create(); + + $parser = $this->parser; + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + if (!$res = (bool)xml_parse_into_struct($parser, $this->rawXML, $this->valueArray, $this->keyArray)) + { + $this->isError = true; + $this->error = 'error: '.xml_error_string(xml_get_error_code($parser)).' at line '.xml_get_current_line_number($parser); + } + xml_parser_free($parser); + + return $res; + } +} + +?> diff --git a/opt/gemeinschaft/sbin/gs-carddav-reader-to-db b/opt/gemeinschaft/sbin/gs-carddav-reader-to-db new file mode 100644 index 000000000..4abc25c88 --- /dev/null +++ b/opt/gemeinschaft/sbin/gs-carddav-reader-to-db @@ -0,0 +1,394 @@ +#!/usr/bin/php -q + +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301, USA. +\*******************************************************************/ + + +define('GS_VALID', true); // arriving nativ here + +require_once( dirName(__FILE__) .'/../inc/conf.php' ); +$CARDDAV_LOG = 'cloud_connector.log'; +$FIFO = ''; +$process_name = 'vcard-checker'; +include_once( GS_DIR .'inc/log.php' ); + +if (defined('STDIN' )) @fClose(STDIN ); +if (defined('STDOUT')) @fClose(STDOUT); +if (defined('STDERR')) @fClose(STDERR); + +include_once( GS_DIR .'lib/yadb/yadb.php' ); +include_once( GS_DIR .'inc/gs-lib.php' ); +require_once( GS_DIR .'lib/carddav/CardDAV.php' ); +require_once( GS_DIR .'lib/XML/xml2array.php' ); +require_once( GS_DIR .'inc/db_connect.php' ); + +$CLOUD_MSG = ''; + +// vCard DAV connect +function gs_vcards_connect( $url=null, $login=null, $pass=null ) { + global $CARDDAV_LOG, $FIFO, $CLOUD_MSG, $sudo_user; + + if (! class_exists('carddav_backend')) { + $CLOUD_MSG = 'This system does not support carddav (lib CardDav.php missing)!'; + gs_log( GS_LOG_FATAL, getmypid() . ': ' . $CLOUD_MSG, $CARDDAV_LOG, $FIFO ); + return false; + } + + $carddav_conn = new carddav_backend($url); + $carddav_conn->set_auth($login, $pass); + + if ( $carddav_conn->check_connection() ) { + $CLOUD_MSG = $sudo_user . ': connected to CardDAV '. $url .' for user ' . $login; + gs_log(GS_LOG_DEBUG, getmypid() . ': ' . $CLOUD_MSG, $CARDDAV_LOG, $FIFO ); + return $carddav_conn; + } else { + $CLOUD_MSG = $sudo_user . ': Can not connect to cloud, check url, and login/password.'; + gs_log(GS_LOG_FATAL, getmypid() . ': ' . $CLOUD_MSG, $CARDDAV_LOG, $FIFO ); + return false; + } +} + +// update gs records +function gs_vcard_update( $vcr, $head, $vcard, $lvc=array() ) { + global $CARDDAV_LOG, $FIFO, $DB, $CANONIZE_INTL_PREFIX, $CANONIZE_COUNTRY_CODE, $CANONIZE_NATL_PREFIX, $USER_ID; + + $last_modified = date("Y-m-d H:i:s", strtotime( $head['d:propstat']['d:prop']['d:getlastmodified'] )); + $etag = str_replace('"', '', $head['d:propstat']['d:prop']['d:getetag']); + + // remove phone numbers on existing vcards -> update is difficult due to aligment with name/phone number + if ( ! empty($lvc) ) { + $DB->execute('DELETE FROM `pb_prv` WHERE `card_id`=' . $lvc['id']); + $DB->execute('DELETE FROM `pb_prv_category` WHERE `card_id`=' . $lvc['id']); + } + else { + $DB->execute('INSERT INTO `pb_cloud_card` ' . + ' (`cloud_id`,`vcard_id`,`etag`,`vcard`,`last_modified`) ' . + ' VALUES(' . $vcr['id'] . ',\'' . $head['vcard_id'] . '\',\'' . $etag . '\',\'' . mysql_real_escape_string($vcard) . '\',\'' . $last_modified . '\')'); + $lvc = $DB->execute( 'SELECT `id`,`cloud_id`,`vcard_id`,`etag`,`last_modified`' . + ' FROM `pb_cloud_card` ' . + ' WHERE `cloud_id`=' . $vcr['id'] . + ' and `vcard_id`=\'' . $head['vcard_id'] . '\' LIMIT 1' + )->fetchRow(); + } + + $tmp_vcard = explode("\n", $vcard); + + $n = array(); + $acat = array(); + $aparam = array(); + $fn = ''; + $ln = ''; + foreach ( $tmp_vcard as $value ) { + if ( empty( $value ) ) continue; + + + $pos = strpos($value, ':'); + $elem = trim(substr($value, $pos + 1 )); + $aparam = explode(';', substr($value, 0, $pos)); + $key = strtoupper( array_shift( $aparam ) ); + + // we need only name, category and tel type records for the phone book + if ( 'N' != $key && 'TEL' != $key && 'CATEGORIES' != $key ) continue; + + if ( 'N' == $key ) { + // reverse the array N for the phones display + $aname = explode(';', $elem); + $ln = array_shift( $aname ); + for ($i = count($aname); $i >= 0; $i--) { + if ( empty($aname[$i]) ) continue; + $fn .= ' ' . $aname[$i]; + } + $fn = ltrim( $fn ); + if ( empty( $ln) ) { $ln = $fn; $fn=''; } + } + + elseif ( 'TEL' == $key ) { + + // do not canonize on sip strings + if ( strpos($elem, '@') === false ) { + + if ( '+' == substr($elem, 0, 1) ) + $elem = GS_CANONIZE_INTL_PREFIX . substr($elem, 1); + + $number = preg_replace('/\D/', '', $elem); + + if ( GS_CANONIZE_INTL_PREFIX . GS_CANONIZE_COUNTRY_CODE == substr($number, 0, strlen(GS_CANONIZE_INTL_PREFIX . GS_CANONIZE_COUNTRY_CODE) ) ) + $number = GS_CANONIZE_NATL_PREFIX . substr($number, strlen(GS_CANONIZE_INTL_PREFIX . GS_CANONIZE_COUNTRY_CODE)); + } + else $number = $elem; + + // add number to array, making it singular + if ( ! isset($n[$number]) ) $n[$number] = array( 'type' => '', 'pref' => 99 ); + + // add attributes to the number + foreach ( $aparam as $param ) { + if ( empty($param) ) continue; + $k2 = explode('=', strtoupper( $param )); + $k2[1] = str_replace('"', '', $k2[1]); + if ( 'TYPE' == $k2[0] ) { + if ( strpos($k2[1], 'PREF' ) !== false ) $n[$number]['pref'] = 1; + elseif ( $k2[1] == 'MAIN' ) $n[$number]['pref'] = 1; + elseif ( $k2[1] == 'PREF' ) $n[$number]['pref'] = 1; + $n[$number]['type'] .= strtolower( $k2[1] ) . ','; + } + elseif ( 'PREF' == $k2[0] ) $n[$number]['pref'] = (int)$k2[1]; + } + $n[$number]['type'] = rtrim($n[$number]['type'], ','); + if ( $n[$number]['pref'] < 1 ) $n[$number]['pref'] = 1; + } + elseif ( 'CATEGORIES' == $key ) $acat = explode( ',', $elem ); + } + + // loop over phone numbers + foreach ( $n as $number => $param ) { + + $prc=false; + // check_duplicates from within a vcard -> try to avoid duplicates, the latest wins + if ( $prc = $DB->execute('SELECT `id` FROM `pb_prv` WHERE `user_id`=' . $USER_ID . ' AND `firstname`=\'' . $fn . '\' AND `lastname`=\'' . $ln . '\' AND `number`=\'' . $number . '\' AND `card_id`=0 LIMIT 1')->fetchRow() ) + $DB->execute('DELETE FROM `pb_prv` WHERE `id`=' . $prc['id']); + // net could probably changed to an update + elseif ( $prc = $DB->execute('SELECT `id` FROM `pb_prv` WHERE `user_id`=' . $USER_ID . ' AND `firstname`=\'' . $fn . '\' AND `lastname`=\'' . $ln . '\' AND `number`=\'' . $number . '\' LIMIT 1')->fetchRow() ) + $DB->execute('DELETE FROM `pb_prv` WHERE `id`=' . $prc['id']); + + // add a phone record + $DB->execute('INSERT INTO `pb_prv` ' . + ' (`user_id`,`firstname`,`lastname`,`number`,`ptype`,`pref`,`card_id`) ' . + ' VALUES(' . $USER_ID .',\'' . $fn .'\',\'' . $ln .'\',\'' . $number .'\',\'' . $param['type'] .'\',' . $param['pref'] . ',' . $lvc['id'] . ')'); + + // loop over categories + if ( ! empty( $acat) ) { + $prc = $DB->execute( 'SELECT `id` FROM `pb_prv` WHERE `user_id`=' . $USER_ID . ' and `firstname`=\'' . $fn . '\' and `lastname`=\'' . $ln . '\' and `number`=\'' . $number . '\' and `ptype`=\'' . $param['type'] . '\' and `card_id`=' . $lvc['id'] . ' LIMIT 1')->fetchRow(); + foreach ( $acat as $cat ) { + if ( empty($cat) ) continue; + if ( ! $crc = $DB->execute( 'SELECT `id` FROM `pb_category` WHERE `user_id`=' . $USER_ID . ' and `category`=\'' . $cat . '\'')->fetchRow() ) { + // insert rec + $DB->execute('INSERT INTO `pb_category` ' . + ' (`user_id`,`category`) ' . + ' VALUES(' . $USER_ID .',\'' . $cat .'\')'); + $crc = $DB->execute( 'SELECT `id` FROM `pb_category` WHERE `user_id`=' . $USER_ID . ' and `category`=\'' . $cat . '\' LIMIT 1')->fetchRow(); + } + // correct xref + $DB->execute('INSERT INTO `pb_prv_category` ' . + ' (`user_id`,`cat_id`,`card_id`,`prv_id`) ' . + ' VALUES(' . $USER_ID .',' . $crc['id'] .',' . $lvc['id'] .',' . $prc['id'] . ')'); + } + } + } + +} + + +// fetch vcards for a cloud entry +function gs_user_vcards_update( $vcr ) { + global $CARDDAV_LOG, $FIFO, $DB, $CLOUD_MSG, $USER_ID; + $vc_add = 0; + $vc_mod = 0; + $vc_del = 0; + $vc_seen = 0; + + $carddav_conn = gs_vcards_connect( $vcr['url'], $vcr['login'], $vcr['pass'] ); + if ( ! is_object( $carddav_conn ) || $carddav_conn === false ) { + return false; + } + + $a = new XMLThing(); + $vchead = $a->parse($carddav_conn->get(false,true)); + $vchead = $vchead['d:multistatus']['d:response']; + $head = array_shift ( $vchead ); + $CLOUD_MSG = ''; + + // skip rest if not modified between, depending on header etag or lastmodified + if ( isset( $head['d:propstat']['d:prop']['cs:getctag'] ) ) { + // ref etag: https://tools.ietf.org/html/rfc6352 + $last_ctag = str_replace('"', '', $head['d:propstat']['d:prop']['cs:getctag']); + if ( $last_ctag == $vcr['last_ctag'] ) { + $CLOUD_MSG = 'no update, cloud last ctag: '. $last_ctag; + gs_log(GS_LOG_DEBUG, getmypid() . ': ' . $CLOUD_MSG, $CARDDAV_LOG, $FIFO ); + return true; + } + } else $last_ctag = ''; + + if ( isset($head['d:propstat']['d:prop']['d:getlastmodified']) ) { + $last_modified = date("Y-m-d H:i:s", strtotime( $head['d:propstat']['d:prop']['d:getlastmodified'] )); + if ( $last_modified <= $vcr['last_remote_modified'] ) { + $CLOUD_MSG = 'no update, cloud last modified: '. $last_modified; + gs_log(GS_LOG_DEBUG, getmypid() . ': ' . $CLOUD_MSG, $CARDDAV_LOG, $FIFO ); + return true; + } + } else $last_modified = $vcr['modified']; + + gs_log(GS_LOG_DEBUG, getmypid() .': updating..., last modified='. $last_modified, $CARDDAV_LOG, $FIFO ); + // update ctag and last_modified immed + $DB->execute('UPDATE `pb_cloud` SET `ctag`=\'' . $last_ctag . '\', `last_remote_modified`=\'' . $last_modified . '\' WHERE `id`=' . $vcr['id']); + + // get unseen records + gs_log(GS_LOG_DEBUG, getmypid() .': fetch unseen', $CARDDAV_LOG, $FIFO ); + $unseen=array(); + $unrc = $DB->execute('SELECT `id`, `vcard_id`,`etag`, `last_modified` FROM `pb_cloud_card` WHERE `cloud_id`=' . $vcr['id']); + while ( $urc = $unrc->fetchRow() ) { + $unseen[$urc['vcard_id']] = array( + 'id' => $urc['id'], + 'etag' => $urc['etag'], + 'last_modified' => $urc['last_modified'] + ); + } + if ( empty($unseen) ) gs_log(GS_LOG_DEBUG, getmypid() .': no unseen, adding ...', $CARDDAV_LOG, $FIFO ); + + gs_log(GS_LOG_DEBUG, getmypid() .': updating vcards...', $CARDDAV_LOG, $FIFO ); + + // iterate through all of them + for ($i = 0; $i < count($vchead); $i++) { + + $vcard_id=str_replace('.vcf', null, substr($vchead[$i]['d:href'], strrpos($vchead[$i]['d:href'], '/') + 1) ); + + $vchead[$i]['vcard_id'] = $vcard_id; + + $vc_seen += 1; + // check for existing vcard + if ( isset($unseen[$vcard_id]) ) { + $lvc = $unseen[$vcard_id]; + // avoid deleting + unset($unseen["$vcard_id"]); + + // skip if not modified + $last_modified = date("Y-m-d H:i:s", strtotime( $vchead[$i]['d:propstat']['d:prop']['d:getlastmodified'] )); + $last_etag = str_replace('"', '', $vchead[$i]['d:propstat']['d:prop']['d:getetag']); + if ( $last_etag == $lvc['etag'] && $last_modified == $lvc['last_modified'] ) continue; + + $vc_mod += 1; + gs_log(GS_LOG_DEBUG, getmypid() .': updating '. $vcard_id, $CARDDAV_LOG, $FIFO ); + + $vchead[$i]['d:propstat']['d:prop']['d:getlastmodified'] = $last_modified; + + // modified remote get the new vcard + $vcard = $carddav_conn->get_vcard($vcard_id . '.vcf'); + gs_vcard_update( $vcr, $vchead[$i], $vcard, $lvc ); + + } else { + // missing local add new vcard + $vc_add += 1; + gs_log(GS_LOG_DEBUG, getmypid() .': adding '. $vcard_id, $CARDDAV_LOG, $FIFO ); + $vcard = $carddav_conn->get_vcard($vcard_id . '.vcf'); + gs_vcard_update( $vcr, $vchead[$i], $vcard ); + } + } + + // delete no more existing recs + foreach ($unseen as $vcard_id => $value) { + $vc_del += 1; + gs_log(GS_LOG_DEBUG, getmypid() .': deleting '. $vcard_id, $CARDDAV_LOG, $FIFO ); + $DB->execute('DELETE FROM `pb_prv_category` WHERE `user_id`=' . $USER_ID . ' and `card_id`=' . $value['id']); + $DB->execute('DELETE FROM `pb_prv` WHERE `user_id`=' . $USER_ID . ' and `card_id`=' . $value['id']); + $DB->execute('DELETE FROM `pb_cloud_card` WHERE `id`=' . $value['id']); + } + + // clean up categories + $rs2 = $DB->execute( 'DELETE c FROM `pb_category` AS c ' . + ' LEFT JOIN `pb_prv_category` AS p ' . + ' ON c.id = p.cat_id ' . + ' WHERE c.user_id = ' . $USER_ID . + ' AND p.id IS NULL' + ); + $CLOUD_MSG = $vc_seen . ' seen, ' . $vc_mod . ' modified, ' . $vc_add . ' added, ' . $vc_del . ' deleted'; + gs_log(GS_LOG_DEBUG, getmypid() . ': ' . $CLOUD_MSG, $CARDDAV_LOG, $FIFO ); + + return true; +} + +$DB = gs_db_master_connect(); + + +// remain in loop, doing a record time by time (avoid race cond in dup exec) +while ( true ) { + $CLOUD_MSG = ''; + $vcrc = @ $DB->execute( + 'SELECT + `id`, `user_id`, `url`, `login`, cast(des_decrypt(`pass`,`login`) as char(16)) as pass, `frequency`, `ctag`, + `last_remote_modified`, `modified`, `error_count`, `public` + FROM `pb_cloud` + WHERE `next_poll` < NOW() AND `active`=1 ORDER BY `next_poll` + LIMIT 1' + ); + if ( $vcr = $vcrc->fetchRow() ) { + $usrc = $DB->execute('SELECT `user` FROM `users` WHERE `id`=' . $vcr['user_id'] . ' LIMIT 1'); + $urc = $usrc->fetchRow(); + $sudo_user = $urc['user']; + gs_log(GS_LOG_NOTICE, getmypid() .': Checking vCards for ' . $sudo_user . ': '. $vcr['login'] . ': ' . $vcr['url'], $CARDDAV_LOG, $FIFO ); + + } else break; // the loop, nothing to be done anymore + + + // update next check immediately to avoid concurrent execs in timeout situations + $hdm2text = array( + 'h' => 'hour', + 'd' => 'day', + 'm' => 'month' + ); + $period = substr($vcr['frequency'], -1); + $freq = substr($vcr['frequency'], 0, -1); + if ( $freq > 1 ) $more = 's'; + else $more = ''; + + $next_poll = date_format(date_add( date_create(), DateInterval::createFromDateString("$freq $hdm2text[$period]" . "$more") ), "Y-m-d H:i:s"); + + $DB->execute('UPDATE `pb_cloud` SET `next_poll`=\'' . $next_poll . '\', `message`=\'Update in progress...\' WHERE `id`=' . $vcr['id']); + + // if its a public record we are goig to write for user_id = 0 (which should(!) not exist) + if ( $vcr['public'] ) $USER_ID = 1; + else $USER_ID = $vcr['user_id']; + + $unset_active=''; + + if ( gs_user_vcards_update( $vcr ) === true ) { + + // all went ok + gs_log(GS_LOG_NOTICE, getmypid() .': Check vCards completed normal for ' . $sudo_user . '.', $CARDDAV_LOG, $FIFO ); + $CLOUD_MSG = 'OK - ' . $CLOUD_MSG; + $error_counter = ', `error_count`=0 '; + + } else { + + // any failure + $error_counter=', `error_count`=`error_count`+1 '; + $CLOUD_MSG = getmypid() . ': '; + if ( $vcr['error_count'] = 4 ) { + // deactivate record + $unset_active = ', `active`=0 '; + $CLOUD_MSG .= 'Set inactive. '; + }; + $CLOUD_MSG .= 'Check vCards failed for ' . $vcr['login'] . ': ' . $vcr['url']; + gs_log(GS_LOG_WARNING, $sudo_user . ': ' . $CLOUD_MSG, $CARDDAV_LOG, $FIFO ); + // increment error counter + } + + // inform on user display + $DB->execute('UPDATE `pb_cloud` SET `message` = CONCAT_WS(\' \', ' . + '\'' . $CLOUD_MSG . '\',\', last check: \', `modified` ) ' . + $error_counter . $unset_active . + ' WHERE `id` = ' . $vcr['id']); +} + +?> diff --git a/usr/share/doc/gemeinschaft/asterisk.sql b/usr/share/doc/gemeinschaft/asterisk.sql index f647c5ab0..beb337b92 100644 --- a/usr/share/doc/gemeinschaft/asterisk.sql +++ b/usr/share/doc/gemeinschaft/asterisk.sql @@ -6180,6 +6180,7 @@ INSERT INTO `group_members` VALUES (6,3001); INSERT INTO `group_members` VALUES (6,3002); INSERT INTO `group_members` VALUES (6,3003); INSERT INTO `group_members` VALUES (6,3004); +INSERT INTO `group_members` VALUES (6,3005); INSERT INTO `group_members` VALUES (6,4000); INSERT INTO `group_members` VALUES (6,4001); INSERT INTO `group_members` VALUES (6,4002); @@ -6672,6 +6673,62 @@ INSERT INTO `pb_ldap` VALUES ('012345','TEST','HANS','123','2007-05-24 07:28:28' /*!40000 ALTER TABLE `pb_ldap` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Tabellenstruktur für Tabelle `pb_category` +-- +DROP TABLE IF EXISTS `pb_category`; +CREATE TABLE IF NOT EXISTS `pb_category` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL, + `category` varchar(24) COLLATE utf8_unicode_ci NOT NULL, + `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `uid_catid` (`user_id`,`category`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Tabellenstruktur für Tabelle `pb_cloud` +-- +DROP TABLE IF EXISTS `pb_cloud`; +CREATE TABLE IF NOT EXISTS `pb_cloud` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL, + `url` varchar(256) COLLATE utf8_unicode_ci NOT NULL, + `login` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `pass` varbinary(64) NOT NULL, + `frequency` varchar(3) COLLATE utf8_unicode_ci NOT NULL DEFAULT '1d', + `ctag` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `last_remote_modified` datetime NOT NULL, + `next_poll` datetime NOT NULL, + `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `message` tinytext COLLATE utf8_unicode_ci NOT NULL, + `error_count` tinyint(1) unsigned NOT NULL DEFAULT '0', + `active` tinyint(1) unsigned NOT NULL DEFAULT '1', + `public` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `uid_url_login` (`user_id`,`url`(255),`login`), + KEY `next_poll` (`next_poll`), + KEY `uid_login_url` (`user_id`,`login`,`url`(255)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +ALTER TABLE `pb_cloud` ADD FOREIGN KEY ( `user_id` ) + REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT ; + +-- +-- Tabellenstruktur für Tabelle `pb_cloud_card` +-- +DROP TABLE IF EXISTS `pb_cloud_card`; +CREATE TABLE IF NOT EXISTS `pb_cloud_card` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `cloud_id` int(10) unsigned NOT NULL, + `vcard_id` varchar(36) COLLATE utf8_unicode_ci NOT NULL, + `etag` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `vcard` text COLLATE utf8_unicode_ci NOT NULL, + `last_modified` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `cloud_id_vcard_id` (`cloud_id`,`vcard_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + -- -- Table structure for table `pb_prv` -- @@ -6679,18 +6736,23 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `pb_prv`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `pb_prv` ( +CREATE TABLE IF NOT EXISTS `pb_prv` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `user_id` int(10) unsigned NOT NULL DEFAULT '0', `firstname` varchar(40) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `lastname` varchar(40) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `number` varchar(25) CHARACTER SET ascii NOT NULL DEFAULT '', + `ptype` varchar(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'cell,work,home', + `pref` int(2) unsigned NOT NULL DEFAULT '9', + `card_id` int(10) unsigned NOT NULL, + `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), - KEY `uid_lastname_firstname` (`user_id`,`lastname`(15),`firstname`(10)), - KEY `uid_firstname_lastname` (`user_id`,`firstname`(10),`lastname`(10)), - KEY `uid_number` (`user_id`,`number`(10)), - CONSTRAINT `pb_prv_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + KEY `uid_vcard` (`user_id`,`card_id`), + KEY `uid_lastname_firstname_pref` (`user_id`,`lastname`(15),`firstname`(10),`pref`,`ptype`), + KEY `cloud_card_id` (`card_id`), + KEY `uid_number_pref` (`user_id`,`number`(10),`pref`,`ptype`), + KEY `uid_firstname_lastname_pref` (`user_id`,`firstname`(10),`lastname`(10),`pref`,`ptype`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -6702,6 +6764,37 @@ LOCK TABLES `pb_prv` WRITE; /*!40000 ALTER TABLE `pb_prv` ENABLE KEYS */; UNLOCK TABLES; +-- connect a phone book entry to a category +CREATE TABLE IF NOT EXISTS `pb_prv_category` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL, + `cat_id` int(10) unsigned NOT NULL, + `card_id` int(10) unsigned NOT NULL, + `prv_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `uid_catid_cardid` (`user_id`,`cat_id`,`card_id`), + KEY `uid_prvid` (`user_id`,`prv_id`), + KEY `uid_cardid` (`user_id`,`card_id`), + KEY `card_id` (`card_id`), + KEY `prv_id` (`prv_id`), + KEY `cat_id` (`cat_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +ALTER TABLE `pb_cloud_card` ADD FOREIGN KEY ( `cloud_id` ) + REFERENCES `pb_cloud` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_prv` ADD FOREIGN KEY ( `card_id` ) + REFERENCES `pb_cloud_card` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_category` ADD FOREIGN KEY ( `user_id` ) + REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_prv_category` ADD FOREIGN KEY ( `user_id` ) + REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_prv_category` ADD FOREIGN KEY ( `cat_id` ) + REFERENCES `pb_category` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_prv_category` ADD FOREIGN KEY ( `card_id` ) + REFERENCES `pb_cloud_card` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; +ALTER TABLE `pb_prv_category` ADD FOREIGN KEY ( `prv_id` ) + REFERENCES `pb_prv` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ; + -- -- Table structure for table `penalties` -- @@ -7451,6 +7544,7 @@ CREATE TABLE `users` ( LOCK TABLES `users` WRITE; /*!40000 ALTER TABLE `users` DISABLE KEYS */; +INSERT INTO `users` VALUES ('1', 'public-abook', '', '', '', '', '', '1', '1', NULL, '', NULL, NULL, NULL, '') INSERT INTO `users` VALUES (5,'nobody-00001','','','','','',1,1,NULL,'',NULL,NULL,NULL,''); INSERT INTO `users` VALUES (6,'nobody-00002','','','','','',2,1,NULL,'',NULL,NULL,NULL,''); INSERT INTO `users` VALUES (7,'nobody-00003','','','','','',3,1,NULL,'',NULL,NULL,NULL,''); @@ -7655,4 +7749,3 @@ USE `asterisk`; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2010-10-19 19:30:00 -