На мой взгляд, кроме использования Evolution есть два способа импорта контактов. Для Evolution нет автоматического инструмента.
Сделайте резервную копию ваших contacts.db перед внесением любых изменений!
Первый способ - это простой способ использования folks-import
для импорта ваших контактов. Я проверил источник, и он, похоже, является импортером из файла blist.xml
pidgin.
blist.xml
- Локальная копия ваших списков друзей, для использования влокально применяемые псевдонимы и групповое и дружеское упорядочение между. Я попробовал это из любопытства на своем blist.xml
, и он работал для некоторых контактов.
Для вас необходимо создать blist.xml
(здесь blist.h и источник для него) вы можете использовать чью-то работу, например vcftoxml.py и настроить ее.
Редактировать - пробоватьсоздать фиктивный XML для импорта
Я пытался создать простой XML (blist.xml) для импорта через импортер.
XML, вдохновленный blist.xml
пример:
<?xml version="1.0" encoding="UTF-8" ?>
<purple version="1.0">
<blist>
<group name='GroupName'>
<contact>
<buddy account='test' proto='prpl-hangouts'>
<name>1131313213446</name>
<alias>Jakto Tomos</alias>
<phone>+6568309312</phone>
<email>testing@yahoo.com</email>
<address>Berlin</address>
</buddy>
</contact>
</group>
</blist>
<privacy>
</privacy>
</purple>
Когда я проверил созданный контакт, я обнаружил, что было импортировано только имя alias
.
Итак, у меня есть create blist.xml
, который имитирует реальную жизньодин:
<?xml version="1.0" encoding="UTF-8" ?>
<purple version="1.0">
<blist>
<group name='GroupName'>
<contact>
<buddy account='test' proto='prpl-hangouts'>
<name>1131313213446</name>
<alias>Jakto Tomos</alias>
<setting name='phone' type='string'>+6568309312</setting>
<setting name='email' type='string'>testing@yahoo.com</setting>
<setting name='address' type='string'>Lesser strasse, Berlin</setting>
</buddy>
</contact>
</group>
</blist>
<privacy>
</privacy>
</purple>
Когда я импортировал его снова, я снова получил только имя alias
. Итак, я пошел к исходному коду import-pidgin.vala
и обнаружил, что он действительно импортирует только имя (contact ID
) и псевдоним как имя:
...
/* Parse the <name> and <alias> elements beneath <buddy> */
for (Xml.Node *subiter = iter->children; subiter != null;
subiter = subiter->next)
{
if (subiter->type != ElementType.ELEMENT_NODE)
continue;
if (subiter->name == "alias")
alias = subiter->get_content ();
else if (subiter->name == "name")
{
/* The <name> element seems to give the contact ID, which
* we need to insert into the Persona's im-addresses property
* for the linking to work. */
string im_address = subiter->get_content ();
im_addresses.set (tp_protocol,
new ImFieldDetails (im_address));
im_address_string += " %s\n".printf (im_address);
}
}
...
Так что этот способ возможен, но вы должныдобавьте разбор узлов, которые вы хотите импортировать. Вы можете сделать PR
для такого патча, чтобы другие могли использовать его (я рекомендую использовать нотацию <setting name...
, поскольку именно так форматируется файл blist.xml.
Второй способ намного сложнее, и вы должны правильно заполнить таблицы в sqlite. Это структура БД:
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "folder_id_phone_list" (
"uid" TEXT NOT NULL,
"value" TEXT,
FOREIGN KEY("uid") REFERENCES "folder_id"("uid")
);
CREATE TABLE IF NOT EXISTS "folder_id_email_list" (
"uid" TEXT NOT NULL,
"value" TEXT,
FOREIGN KEY("uid") REFERENCES "folder_id"("uid")
);
CREATE TABLE IF NOT EXISTS "folder_id" (
"uid" TEXT,
"Rev" TEXT,
"file_as" TEXT,
"file_as_localized" TEXT,
"nickname" TEXT,
"full_name" TEXT,
"given_name" TEXT,
"given_name_localized" TEXT,
"family_name" TEXT,
"family_name_localized" TEXT,
"is_list" INTEGER,
"list_show_addresses" INTEGER,
"wants_html" INTEGER,
"x509Cert" INTEGER,
"vcard" TEXT,
"bdata" TEXT,
PRIMARY KEY("uid")
);
CREATE TABLE IF NOT EXISTS "keys" (
"key" TEXT,
"value" TEXT,
"folder_id" TEXT,
PRIMARY KEY("key"),
FOREIGN KEY("folder_id") REFERENCES "folders"
);
CREATE TABLE IF NOT EXISTS "folders" (
"folder_id" TEXT,
"version" INTEGER,
"multivalues" TEXT,
"lc_collate" TEXT,
"countrycode" VARCHAR(2),
PRIMARY KEY("folder_id")
);
INSERT INTO "keys" VALUES ('eds-reserved-namespace-is-populated','1','folder_id');
INSERT INTO "keys" VALUES ('revision','2019-11-04T07:28:25Z(0)','folder_id');
INSERT INTO "folders" VALUES ('folder_id',11,'email;prefix:phone','en_US.UTF-8','US');
CREATE INDEX IF NOT EXISTS "UID_INDEX_phone_folder_id" ON "folder_id_phone_list" (
"uid"
);
CREATE INDEX IF NOT EXISTS "INDEX_email_folder_id" ON "folder_id_email_list" (
"value"
);
CREATE INDEX IF NOT EXISTS "UID_INDEX_email_folder_id" ON "folder_id_email_list" (
"uid"
);
CREATE INDEX IF NOT EXISTS "SINDEX_family_name_folder_id" ON "folder_id" (
"family_name_localized"
);
CREATE INDEX IF NOT EXISTS "INDEX_family_name_folder_id" ON "folder_id" (
"family_name"
);
CREATE INDEX IF NOT EXISTS "SINDEX_given_name_folder_id" ON "folder_id" (
"given_name_localized"
);
CREATE INDEX IF NOT EXISTS "INDEX_given_name_folder_id" ON "folder_id" (
"given_name"
);
CREATE INDEX IF NOT EXISTS "INDEX_full_name_folder_id" ON "folder_id" (
"full_name"
);
CREATE INDEX IF NOT EXISTS "INDEX_nickname_folder_id" ON "folder_id" (
"nickname"
);
CREATE INDEX IF NOT EXISTS "SINDEX_file_as_folder_id" ON "folder_id" (
"file_as_localized"
);
CREATE INDEX IF NOT EXISTS "INDEX_file_as_folder_id" ON "folder_id" (
"file_as"
);
CREATE INDEX IF NOT EXISTS "keysindex" ON "keys" (
"folder_id"
);
COMMIT;
Затем вам нужно будет создать группу вставок, которые следуют логике структуры следующим образом:
INSERT INTO "folder_id_phone_list" VALUES ('pas-id-5DBFDF5A00000000','+0000000000');
INSERT INTO "folder_id_phone_list" VALUES ('pas-id-5DBFDF5A00000000','+131545678');
INSERT INTO "folder_id_phone_list" VALUES ('pas-id-5DBFE7F200000001','+45646546565465');
INSERT INTO "folder_id_email_list" VALUES ('pas-id-5DBFDF5A00000000','first_mail@gmal.com');
INSERT INTO "folder_id_email_list" VALUES ('pas-id-5DBFDF5A00000000','home_email@gmail.com');
INSERT INTO "folder_id_email_list" VALUES ('pas-id-5DBFE7F200000001','asdf@fasdf.com');
INSERT INTO "folder_id" VALUES ('pas-id-5DBFDF5A00000000','2019-11-04T08:28:52Z(15)','a header mail, this','001-)71)/1KA)9?O79M��',NULL,'john smith','this','020-O79M�','a header mail','001-)71)/1KA)9?',0,0,0,0,'BEGIN:VCARD
VERSION:3.0
UID:pas-id-5DBFDF5A00000000
X-URIS:www.testing.com
FN:John Smith
N:a header mail;This;is;;
X-EVOLUTION-FILE-AS:a header mail\, This
REV:2019-11-04T08:28:52Z(15)
TEL;TYPE=VOICE,HOME:+0000000000
TEL;TYPE=CELL:+131545678
EMAIL;TYPE=PERSONAL:first_mail@gmal.com
EMAIL;TYPE=HOME:home_email@gmail.com
ADR;TYPE=WORK:p.o. box;456;Stree work;New York;New York;456465;USA
ADR;TYPE=HOME:p.o. box;456;Street;City;New York State;13676;USA
BDAY:2019-11-04
PHOTO;VALUE=uri:file:///home/osboxes/.local/share/evolution/addressbook/sys
tem/photos/pas_id_5DBFDF5A00000000_photo-file0.image%252Fpng
END:VCARD',NULL);
INSERT INTO "folder_id" VALUES ('pas-id-5DBFE7F200000001','2019-11-04T08:57:22Z(17)','sdaf','019-M/)3',NULL,'sdaf','sdaf','019-M/)3','','000-',0,0,0,0,'BEGIN:VCARD
VERSION:3.0
EMAIL;TYPE=PERSONAL:asdf@fasdf.com
TEL;TYPE=CELL:+45646546565465
ADR;TYPE=HOME:asdf;;asdfsdfasdf;;sadf;;asdf
FN:sdaf
N:;sdaf;;;
X-EVOLUTION-FILE-AS:sdaf
UID:pas-id-5DBFE7F200000001
REV:2019-11-04T08:57:22Z(17)
END:VCARD',NULL);
INSERT INTO "folder_id" VALUES ('pas-id-5DBFE7F800000002','2019-11-04T08:57:28Z(19)','next','014-C1WO',NULL,'next','next','014-C1WO','','000-',0,0,0,0,'BEGIN:VCARD
VERSION:3.0
FN:next
N:;next;;;
X-EVOLUTION-FILE-AS:next
UID:pas-id-5DBFE7F800000002
REV:2019-11-04T08:57:28Z(19)
END:VCARD',NULL);
INSERT INTO "keys" VALUES ('eds-reserved-namespace-is-populated','1','folder_id');
INSERT INTO "keys" VALUES ('revision','2019-11-04T08:57:28Z(20)','folder_id');
INSERT INTO "folders" VALUES ('folder_id',11,'email;prefix:phone','en_US.UTF-8','US');
Что важно отметитьUID, например, для первой записи: pas-id-5DBFDF5A00000000
(определяется как new HashMap<string, Field?>
). Я вижу это как фиксированную строку pas-id-
, затем шестнадцатеричное число 5DBFDF5A
(кажется случайным), а последним является счетчик 00000000
(следующий будет 00000001
).
Я бы лично пошел наПервый вариант, но второй, если у вас возникнут проблемы с созданием файла xml
. Если вы используете ручные вставки, не забудьте соответствовать данным.
Редактировать - комментировать экспортированные данные
Кажется, что атрибуты похожи на file_as_localized
, given_name_localized
и family_name_localized
содержат некоторые "мусорные" данные. Однако эти атрибуты определены как TEXT
, поэтому должны быть какие-то читаемые данные, но это не так (пробовал с другой кодировкой, но это не помогло). Я рекомендую прочитать исходный код для этих атрибутов. Возможно, есть возможность ввести пустое значение, как будто это было сделано для некоторого аккаунта на family_name_localized
только с 000-
. Вы также можете попробовать его со значением NULL в начале, а когда вы его узнаете, вы можете обновить его позже.
Заключение
После выполнения тестов с импортером, я думаю, что более простой вариантфактически вариант 2. Вариант 1 будет включать в себя некоторые программы в vala
, если вы не хотите импортировать только имена, которые есть.
Что касается инструмента SQLite, я рекомендую Браузер БД для SQLite , где вы можете запрашивать базу данных SQLite, выполнять запросы и даже редактировать вручную, если это необходимо.