mirror of
https://codeberg.org/streams/streams.git
synced 2024-09-22 22:35:16 +00:00
745515b11f
We use composer already to install SabreDAV. Include config composer.(json|lock) to install and manage more dependencies in future. Also provide PSR-4 autoloading for our namespaced classes, e.g. "Zotlabs\". To regenerate autoloader maps use: $ composer install --optimize-autoloader --no-dev We could also remove the whole vendor/ folder from our repository, but that would need changes in deployment and how to install hubs and needs more discussion first.
184 lines
4.6 KiB
PHP
Executable file
184 lines
4.6 KiB
PHP
Executable file
#!/usr/bin/env php
|
|
<?php
|
|
|
|
namespace Sabre\VObject;
|
|
|
|
// This sucks.. we have to try to find the composer autoloader. But chances
|
|
// are, we can't find it this way. So we'll do our bestest
|
|
$paths = [
|
|
__DIR__ . '/../vendor/autoload.php', // In case vobject is cloned directly
|
|
__DIR__ . '/../../../autoload.php', // In case vobject is a composer dependency.
|
|
];
|
|
|
|
foreach ($paths as $path) {
|
|
if (file_exists($path)) {
|
|
include $path;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!class_exists('Sabre\\VObject\\Version')) {
|
|
fwrite(STDERR, "Composer autoloader could not be loaded.\n");
|
|
die(1);
|
|
}
|
|
|
|
echo "sabre/vobject ", Version::VERSION, " duplicate contact merge tool\n";
|
|
|
|
if ($argc < 3) {
|
|
|
|
echo "\n";
|
|
echo "Usage: ", $argv[0], " input.vcf output.vcf [debug.log]\n";
|
|
die(1);
|
|
|
|
}
|
|
|
|
$input = fopen($argv[1], 'r');
|
|
$output = fopen($argv[2], 'w');
|
|
$debug = isset($argv[3]) ? fopen($argv[3], 'w') : null;
|
|
|
|
$splitter = new Splitter\VCard($input);
|
|
|
|
// The following properties are ignored. If they appear in some vcards
|
|
// but not in others, we don't consider them for the sake of finding
|
|
// differences.
|
|
$ignoredProperties = [
|
|
"PRODID",
|
|
"VERSION",
|
|
"REV",
|
|
"UID",
|
|
"X-ABLABEL",
|
|
];
|
|
|
|
|
|
$collectedNames = [];
|
|
|
|
$stats = [
|
|
"Total vcards" => 0,
|
|
"No FN property" => 0,
|
|
"Ignored duplicates" => 0,
|
|
"Merged values" => 0,
|
|
"Error" => 0,
|
|
"Unique cards" => 0,
|
|
"Total written" => 0,
|
|
];
|
|
|
|
function writeStats() {
|
|
|
|
global $stats;
|
|
foreach ($stats as $name => $value) {
|
|
echo str_pad($name, 23, " ", STR_PAD_RIGHT), str_pad($value, 6, " ", STR_PAD_LEFT), "\n";
|
|
}
|
|
// Moving cursor back a few lines.
|
|
echo "\033[" . count($stats) . "A";
|
|
|
|
}
|
|
|
|
function write($vcard) {
|
|
|
|
global $stats, $output;
|
|
|
|
$stats["Total written"]++;
|
|
fwrite($output, $vcard->serialize() . "\n");
|
|
|
|
}
|
|
|
|
while ($vcard = $splitter->getNext()) {
|
|
|
|
$stats["Total vcards"]++;
|
|
writeStats();
|
|
|
|
$fn = isset($vcard->FN) ? (string)$vcard->FN : null;
|
|
|
|
if (empty($fn)) {
|
|
|
|
// Immediately write this vcard, we don't compare it.
|
|
$stats["No FN property"]++;
|
|
$stats['Unique cards']++;
|
|
write($vcard);
|
|
$vcard->destroy();
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!isset($collectedNames[$fn])) {
|
|
|
|
$collectedNames[$fn] = $vcard;
|
|
$stats['Unique cards']++;
|
|
continue;
|
|
|
|
} else {
|
|
|
|
// Starting comparison for all properties. We only check if properties
|
|
// in the current vcard exactly appear in the earlier vcard as well.
|
|
foreach ($vcard->children() as $newProp) {
|
|
|
|
if (in_array($newProp->name, $ignoredProperties)) {
|
|
// We don't care about properties such as UID and REV.
|
|
continue;
|
|
}
|
|
$ok = false;
|
|
foreach ($collectedNames[$fn]->select($newProp->name) as $compareProp) {
|
|
|
|
if ($compareProp->serialize() === $newProp->serialize()) {
|
|
$ok = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$ok) {
|
|
|
|
if ($newProp->name === 'EMAIL' || $newProp->name === 'TEL') {
|
|
|
|
// We're going to make another attempt to find this
|
|
// property, this time just by value. If we find it, we
|
|
// consider it a success.
|
|
foreach ($collectedNames[$fn]->select($newProp->name) as $compareProp) {
|
|
|
|
if ($compareProp->getValue() === $newProp->getValue()) {
|
|
$ok = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$ok) {
|
|
|
|
// Merging the new value in the old vcard.
|
|
$collectedNames[$fn]->add(clone $newProp);
|
|
$ok = true;
|
|
$stats['Merged values']++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!$ok) {
|
|
|
|
// echo $newProp->serialize() . " does not appear in earlier vcard!\n";
|
|
$stats['Error']++;
|
|
if ($debug) fwrite($debug, "Missing '" . $newProp->name . "' property in duplicate. Earlier vcard:\n" . $collectedNames[$fn]->serialize() . "\n\nLater:\n" . $vcard->serialize() . "\n\n");
|
|
|
|
$vcard->destroy();
|
|
continue 2;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$vcard->destroy();
|
|
$stats['Ignored duplicates']++;
|
|
|
|
}
|
|
|
|
foreach ($collectedNames as $vcard) {
|
|
|
|
// Overwriting any old PRODID
|
|
$vcard->PRODID = '-//Sabre//Sabre VObject ' . Version::VERSION . '//EN';
|
|
write($vcard);
|
|
writeStats();
|
|
|
|
}
|
|
|
|
echo str_repeat("\n", count($stats)), "\nDone.\n";
|