Add support for .vcf vCard files
authorChristian Weiske <cweiske@cweiske.de>
Wed, 20 Dec 2023 20:49:43 +0000 (21:49 +0100)
committerChristian Weiske <cweiske@cweiske.de>
Wed, 20 Dec 2023 20:49:43 +0000 (21:49 +0100)
README.rst
composer.json
composer.lock
data/bdrem.config.php.dist
src/bdrem/Source/vCard.php [new file with mode: 0644]

index 81a729daaa8143012f92af3e5b9af690df84ea1f..1257d369118fb05555950c64cdad20d369cf34a6 100644 (file)
@@ -20,6 +20,8 @@ Data sources
 - An LDAP server with ``evolutionPerson`` records
 - `Birthday reminder <http://cweiske.de/birthday3.htm>`_ files (``.bdf``)
 - CSV files
+- A directory of .vcf vCard files
+
 
 Output formats
 ==============
index 25a5ba76736989f5bb45b3e6a4c0a91746dbcb5d..952411487401a1aba893a3b732ac20ca71893ec5 100644 (file)
@@ -4,6 +4,7 @@
         "pear/console_commandline": "^1.2",
         "pear/console_table": "^1.3",
         "pear/mail_mime": "^1.10",
-        "pear/net_ldap2": "^2.3"
+        "pear/net_ldap2": "^2.3",
+        "sabre/vobject": "^4.5"
     }
 }
index 3545e4981f7fad28425c2048bc580e035cb34d4d..7d7e616e5f2b4372200bc153e3b71d72adc42b2e 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "ecbd614a29db70e304521a06550a4326",
+    "content-hash": "39ce09afd7a686424abd7e671905368d",
     "packages": [
         {
             "name": "pear/console_color2",
                 "source": "https://github.com/pear/PEAR_Exception"
             },
             "time": "2021-03-21T15:43:46+00:00"
+        },
+        {
+            "name": "sabre/uri",
+            "version": "3.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sabre-io/uri.git",
+                "reference": "1774043c843f1db7654ecc93368a98be29b07544"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sabre-io/uri/zipball/1774043c843f1db7654ecc93368a98be29b07544",
+                "reference": "1774043c843f1db7654ecc93368a98be29b07544",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.4 || ^8.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^3.17",
+                "phpstan/extension-installer": "^1.3",
+                "phpstan/phpstan": "^1.10",
+                "phpstan/phpstan-phpunit": "^1.3",
+                "phpstan/phpstan-strict-rules": "^1.5",
+                "phpunit/phpunit": "^9.6"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/functions.php"
+                ],
+                "psr-4": {
+                    "Sabre\\Uri\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Evert Pot",
+                    "email": "me@evertpot.com",
+                    "homepage": "http://evertpot.com/",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Functions for making sense out of URIs.",
+            "homepage": "http://sabre.io/uri/",
+            "keywords": [
+                "rfc3986",
+                "uri",
+                "url"
+            ],
+            "support": {
+                "forum": "https://groups.google.com/group/sabredav-discuss",
+                "issues": "https://github.com/sabre-io/uri/issues",
+                "source": "https://github.com/fruux/sabre-uri"
+            },
+            "time": "2023-06-09T07:04:02+00:00"
+        },
+        {
+            "name": "sabre/vobject",
+            "version": "4.5.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sabre-io/vobject.git",
+                "reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sabre-io/vobject/zipball/a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
+                "reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "php": "^7.1 || ^8.0",
+                "sabre/xml": "^2.1 || ^3.0 || ^4.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "~2.17.1",
+                "phpstan/phpstan": "^0.12",
+                "phpunit/php-invoker": "^2.0 || ^3.1",
+                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
+            },
+            "suggest": {
+                "hoa/bench": "If you would like to run the benchmark scripts"
+            },
+            "bin": [
+                "bin/vobject",
+                "bin/generate_vcards"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Sabre\\VObject\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Evert Pot",
+                    "email": "me@evertpot.com",
+                    "homepage": "http://evertpot.com/",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Dominik Tobschall",
+                    "email": "dominik@fruux.com",
+                    "homepage": "http://tobschall.de/",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Ivan Enderlin",
+                    "email": "ivan.enderlin@hoa-project.net",
+                    "homepage": "http://mnt.io/",
+                    "role": "Developer"
+                }
+            ],
+            "description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects",
+            "homepage": "http://sabre.io/vobject/",
+            "keywords": [
+                "availability",
+                "freebusy",
+                "iCalendar",
+                "ical",
+                "ics",
+                "jCal",
+                "jCard",
+                "recurrence",
+                "rfc2425",
+                "rfc2426",
+                "rfc2739",
+                "rfc4770",
+                "rfc5545",
+                "rfc5546",
+                "rfc6321",
+                "rfc6350",
+                "rfc6351",
+                "rfc6474",
+                "rfc6638",
+                "rfc6715",
+                "rfc6868",
+                "vCalendar",
+                "vCard",
+                "vcf",
+                "xCal",
+                "xCard"
+            ],
+            "support": {
+                "forum": "https://groups.google.com/group/sabredav-discuss",
+                "issues": "https://github.com/sabre-io/vobject/issues",
+                "source": "https://github.com/fruux/sabre-vobject"
+            },
+            "time": "2023-11-09T12:54:37+00:00"
+        },
+        {
+            "name": "sabre/xml",
+            "version": "4.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sabre-io/xml.git",
+                "reference": "99caa5dd248776ca6a1e1d2cfdef556a3fa63456"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sabre-io/xml/zipball/99caa5dd248776ca6a1e1d2cfdef556a3fa63456",
+                "reference": "99caa5dd248776ca6a1e1d2cfdef556a3fa63456",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-xmlreader": "*",
+                "ext-xmlwriter": "*",
+                "lib-libxml": ">=2.6.20",
+                "php": "^7.4 || ^8.0",
+                "sabre/uri": ">=2.0,<4.0.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^3.38",
+                "phpstan/phpstan": "^1.10",
+                "phpunit/phpunit": "^9.6"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/Deserializer/functions.php",
+                    "lib/Serializer/functions.php"
+                ],
+                "psr-4": {
+                    "Sabre\\Xml\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Evert Pot",
+                    "email": "me@evertpot.com",
+                    "homepage": "http://evertpot.com/",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Markus Staab",
+                    "email": "markus.staab@redaxo.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "sabre/xml is an XML library that you may not hate.",
+            "homepage": "https://sabre.io/xml/",
+            "keywords": [
+                "XMLReader",
+                "XMLWriter",
+                "dom",
+                "xml"
+            ],
+            "support": {
+                "forum": "https://groups.google.com/group/sabredav-discuss",
+                "issues": "https://github.com/sabre-io/xml/issues",
+                "source": "https://github.com/fruux/sabre-xml"
+            },
+            "time": "2023-11-09T10:47:15+00:00"
         }
     ],
     "packages-dev": [],
index 3689d1bb4a916c526570d3e6080d61d04c33c40f..1e877e8e3d219135e8abd8b90bcf1f559608dee3 100644 (file)
@@ -53,6 +53,14 @@ $source = array(
     )
 );
 
+//Source: Directory of .vcf vCard files (2 subfolder levels supported)
+$source = [
+    'vCard',
+    [
+        'folder' => '/home/cweiske/dev/contacts-backup/contacts'
+    ]
+];
+
 
 $daysPrev = 3;
 $daysNext = 14;
diff --git a/src/bdrem/Source/vCard.php b/src/bdrem/Source/vCard.php
new file mode 100644 (file)
index 0000000..98b8e00
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Part of bdrem
+ *
+ * PHP version 7
+ *
+ * @category  Tools
+ * @package   Bdrem
+ * @author    Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2023 Christian Weiske
+ * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link      http://cweiske.de/bdrem.htm
+ */
+namespace bdrem;
+
+use Sabre\VObject;
+use Sabre\VObject\Component\VCard;
+
+/**
+ * Read a folder of vcard files
+ * 2 subfolder levels are supported.
+ *
+ * @category  Tools
+ * @package   Bdrem
+ * @author    Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2023 Christian Weiske
+ * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link      http://cweiske.de/bdrem.htm
+ */
+class Source_vCard
+{
+    /**
+     * Full path to a folder with .vcf files
+     */
+    protected string $folder;
+
+    /**
+     * Set the VCard folder path
+     */
+    public function __construct(array $config)
+    {
+        $this->folder = $config['folder'];
+        if (!is_dir($this->folder)) {
+            throw new \Exception(
+                'VCard folder does not exist: ' . $this->folder
+            );
+        }
+    }
+
+    /**
+     * Return all events for the given date range
+     *
+     * @param string  $strDate       Date the events shall be found for,
+     *                               YYYY-MM-DD
+     * @param integer $nDaysPrevious Include number of days before $strDate
+     * @param integer $nDaysNext     Include number of days after $strDate
+     *
+     * @return Event[] Array of matching event objects
+     */
+    public function getEvents($strDate, $nDaysPrevious, $nDaysNext)
+    {
+        $vcfFiles = glob($this->folder . '/{*,*/*,*/*/*}.vcf', GLOB_BRACE);
+        if (count($vcfFiles) == 0) {
+            throw new \Exception('No .vcf files found in folder');
+        }
+
+        $arEvents = [];
+        foreach ($vcfFiles as $vcfFile) {
+            $vcard = VObject\Reader::read(file_get_contents($vcfFile));
+
+            if (isset($vcard->BDAY)) {
+                $event = new Event(
+                    $this->getName($vcard),
+                    'Birthday',
+                    $vcard->BDAY->getDateTime()->format('Y-m-d')
+                );
+                if ($event->isWithin($strDate, $nDaysPrevious, $nDaysNext)) {
+                    $arEvents[] = $event;
+                }
+            }
+
+            if (isset($vcard->{'X-ANNIVERSARY'})) {
+                $event = new Event(
+                    $this->getName($vcard),
+                    'Anniversary',
+                    $vcard->{'X-ANNIVERSARY'}->getDateTime()->format('Y-m-d')
+                );
+                if ($event->isWithin($strDate, $nDaysPrevious, $nDaysNext)) {
+                    $arEvents[] = $event;
+                }
+            }
+        }
+
+        return $arEvents;
+    }
+
+    protected function getName(VCard $vcard)
+    {
+        return (string) $vcard->FN;
+    }
+}
+?>