Как программно импортировать данные в контакты Gnome?

Я хочу импортировать свои контакты в Контакты Gnome через Python или командную строку. Я готов заняться программированием, но не могу найти необходимую документацию.

Gnome Contacts использует библиотеку libfolks, которая включает утилиту folks-import, но нет справочной страницы и вывод folks-import --help не очень полезен:

Usage:
  folks-import [OPTION…] — import meta-contact information to libfolks

Help Options:
  -h, --help            Show help options

Application Options:
  -s, --source=name     Source backend name (default: ‘pidgin’)
  --source-filename     Source filename (default: specific to source backend)

Контакты хранятся локально в ~/.local/share/evolution/addressbook/system/contacts.db, которая является базой данных SQLite3, поэтому я мог писать прямо в этот файл. Однако я бы предпочел обойтись без хорошей документации, особенно потому, что в базу данных встроены двоичные файлы и vCard. данные.

В Ubuntu 18.04 вы можете установить контакты Gnome и инструменты libfolks через:

sudo apt install gnome-contacts folks-tools

Вы можете проверить локальную базу данных контактов через:

sqlite3 ~/.local/share/evolution/addressbook/system/contacts.db .dump

Связанные ответы, которые не решили мою проблему:


person bitinerant    schedule 19.10.2019    source источник
comment
Мне просто интересно, откуда берутся контакты? Каков формат контактной информации?   -  person Kevin Ng    schedule 03.11.2019
comment
@KevinNg - как описано выше, контакты хранятся в ~/.local/share/evolution/addressbook/system/contacts.db, которая представляет собой базу данных SQLite со встроенными данными vCard. Запустите указанную выше команду sqlite3, чтобы просмотреть ее.   -  person bitinerant    schedule 03.11.2019
comment
Из быстрого поиска в Google я обнаружил, что контакты Gnome обмениваются информацией с сервером данных Evolution, поэтому вы можете обновить ее через почтовый клиент Evolution и позволить контактам синхронизироваться. Вот ссылка. Я лично не проверял это, поэтому я не уверен, что это сработает.   -  person curiousMinded    schedule 04.11.2019
comment
Также здесь находится справочное руководство по серверу данных Evolution, которое может оказаться полезным, поскольку оно содержит документация по программным интерфейсам, взаимодействующим, помимо прочего, с контактами.   -  person curiousMinded    schedule 04.11.2019
comment
@curiousMinded - спасибо! Я проверю их. Кстати, что вы искали в Google? Я, видимо, не то же самое искал.   -  person bitinerant    schedule 04.11.2019
comment
Я искал импортировать данные в контакты gnome, а затем сервер данных эволюции.   -  person curiousMinded    schedule 04.11.2019


Ответы (1)


На мой взгляд, кроме использования Evolution есть два способа импортировать контакты. Без Evolution для этого не существует автоматического инструмента.

Сделайте резервную копию ваших контактов.db перед внесением каких-либо изменений!

  1. Первый способ — это простой способ импорта контактов с помощью folks-import. Я проверил источник, и, похоже, это импортер из файла blist.xml пиджина.

    • blist.xml - A local copy of your buddy lists, for use in keeping locally applied aliases and group and buddy ordering between. I have tried it, out of curiosity, on my blist.xml and it worked for some contacts.

Для вас создать 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>[email protected]</email>
      <address>Berlin</address>
    </buddy>
  </contact>
  </group>
</blist>
<privacy>
</privacy>
</purple>

Когда я проверил созданный контакт, я обнаружил, что было импортировано только имя alias.

Итак, я создал 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'>[email protected]</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.

  1. Второй способ сложнее, и вам нужно правильно заполнить таблицы в 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','[email protected]');
INSERT INTO "folder_id_email_list" VALUES ('pas-id-5DBFDF5A00000000','[email protected]');
INSERT INTO "folder_id_email_list" VALUES ('pas-id-5DBFE7F200000001','[email protected]');
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:[email protected]

EMAIL;TYPE=HOME:[email protected]

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:[email protected]

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, выполнять запросы и даже редактировать рукой, если нужно.

person tukan    schedule 04.11.2019
comment
Я очень ценю ваше время и исследования. Жаль, что импорт данных требует копаться в исходном коде, но, по крайней мере, это является вариантом (спасибо, открытый исходный код). Вариант 1 может быть тем, к чему я пришел, но я хотел бы узнать больше о вашем комментарии, это сработало для некоторых контактов. Есть ли у вас информация о том, почему у некоторых это не сработало? - person bitinerant; 05.11.2019
comment
Вариант 2 вызывает у меня дискомфорт, потому что его несовершенное выполнение может привести к повреждению, которое не будет обнаружено позже. Как я сказал в своем OP, база данных, кажется, встраивает двоичные данные (о которых вы не упомянули) и данные vCard (о которых вы упомянули, но я думаю, что vCard намного сложнее, чем просто замена текста в шаблоне). - person bitinerant; 05.11.2019
comment
Объявление @bitinerant 1) Я использовал свой реальный blist.xml, которому более 10 лет (предыдущий у меня только отключен), и я подключался ко многим различным сетям, поэтому есть много дополнительной информации. Я вернулся к исходному коду import-pidgin.vala и прочитал его еще раз - я отредактирую ответ с выводами. - person tukan; 06.11.2019
comment
@bitinerant как для Варианта 2. Исходя из структуры базы данных, не должно быть никаких двоичных данных (BLOB), а есть только ТЕКСТОВЫЕ. Вы правы в том, что некоторые атрибуты, такие как given_name_localized, имеют двоичное значение. Однако не должно быть никаких проблем, если это NULL или ''. Вы можете проверить исходный код, что там сделано. Если возникнут какие-либо проблемы, вы всегда можете создать UPDATE. - person tukan; 06.11.2019