pax_global_header00006660000000000000000000000064136367416010014521gustar00rootroot0000000000000052 comment=ca42dcf0e6bebe2d0f818e1221db9518561dd8a0 telegram-purple/000077500000000000000000000000001363674160100141725ustar00rootroot00000000000000telegram-purple/.gitignore000066400000000000000000000002511363674160100161600ustar00rootroot00000000000000/objs/ /autom4te.cache/ /config.h *~ /dep/ /libs/ /bin/ /config.log /config.status /Makefile /commit.h /telegram-purple.nsi /win32/ /contrib/ /telegram-adium/Frameworks telegram-purple/.gitmodules000066400000000000000000000001231363674160100163430ustar00rootroot00000000000000[submodule "tgl"] path = tgl branch = test url = https://github.com/majn/tgl telegram-purple/.travis.yml000066400000000000000000000063331363674160100163100ustar00rootroot00000000000000language: c # Select Trusty Tahr. sudo: required dist: trusty # Travis' git submodule support is ... broken? half-broken? Maybe intentional? git: submodules: false depth: 3 before_install: - git submodule update --init --recursive - sudo apt-get update -qq - sudo apt-get install -qq libssl-dev libgcrypt20-dev libpurple-dev libwebp-dev script: - ./configure $CONFIGURE_FLAGS - make -j2 - make check # Test both installation routines: - sudo make install - make local_install compiler: - clang - gcc env: # Try to be nice to the builder - CONFIGURE_FLAGS="" - CONFIGURE_FLAGS="--disable-gcrypt" - CONFIGURE_FLAGS=" --disable-libwebp" # - CONFIGURE_FLAGS="--disable-gcrypt --disable-libwebp" - CONFIGURE_FLAGS=" --disable-translation" # - CONFIGURE_FLAGS="--disable-gcrypt --disable-translation" # - CONFIGURE_FLAGS=" --disable-libwebp --disable-translation" - CONFIGURE_FLAGS="--disable-gcrypt --disable-libwebp --disable-translation" - CONFIGURE_FLAGS="--disable-png" # - CONFIGURE_FLAGS="--disable-png --disable-gcrypt" - CONFIGURE_FLAGS="--disable-png --disable-libwebp" # - CONFIGURE_FLAGS="--disable-png --disable-gcrypt --disable-libwebp" # - CONFIGURE_FLAGS="--disable-png --disable-translation" # - CONFIGURE_FLAGS="--disable-png --disable-gcrypt --disable-translation" # - CONFIGURE_FLAGS="--disable-png --disable-libwebp --disable-translation" # - CONFIGURE_FLAGS="--disable-png --disable-gcrypt --disable-libwebp --disable-translation" matrix: # Be even nicer by excluding half of the combinations exclude: - compiler: clang env: CONFIGURE_FLAGS="" - compiler: gcc env: CONFIGURE_FLAGS="--disable-gcrypt" - compiler: clang env: CONFIGURE_FLAGS=" --disable-libwebp" # - compiler: XXX # env: CONFIGURE_FLAGS="--disable-gcrypt --disable-libwebp" - compiler: gcc env: CONFIGURE_FLAGS=" --disable-translation" # - compiler: XXX # env: CONFIGURE_FLAGS="--disable-gcrypt --disable-translation" # - compiler: XXX # env: CONFIGURE_FLAGS=" --disable-libwebp --disable-translation" - compiler: clang env: CONFIGURE_FLAGS="--disable-gcrypt --disable-libwebp --disable-translation" - compiler: clang env: CONFIGURE_FLAGS="--disable-png" # - compiler: XXX # env: CONFIGURE_FLAGS="--disable-png --disable-gcrypt" - compiler: gcc env: CONFIGURE_FLAGS="--disable-png --disable-libwebp" # - compiler: XXX # env: CONFIGURE_FLAGS="--disable-png --disable-gcrypt --disable-libwebp" # - compiler: XXX # env: CONFIGURE_FLAGS="--disable-png --disable-translation" # - compiler: XXX # env: CONFIGURE_FLAGS="--disable-png --disable-gcrypt --disable-translation" # - compiler: XXX # env: CONFIGURE_FLAGS="--disable-png --disable-libwebp --disable-translation" # - compiler: XXX # env: CONFIGURE_FLAGS="--disable-png --disable-gcrypt --disable-libwebp --disable-translation" telegram-purple/AUTHORS000066400000000000000000000002521363674160100152410ustar00rootroot00000000000000Matthias Jentsch Ben Wiederhake Vitaly Valtman Christopher Althaus telegram-purple/AppStream/000077500000000000000000000000001363674160100160665ustar00rootroot00000000000000telegram-purple/AppStream/Makefile000066400000000000000000000043561363674160100175360ustar00rootroot00000000000000# This file is part of telegram-purple # # 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 02111-1301 USA # # Copyright Ben Wiederhake 2016 # This file is NOT meant for inclusion into the main Makefile. LOCALES=$(shell cat po/LINGUAS) LOCALE_MOS=$(addprefix po/,$(addsuffix .mo,$(LOCALES))) # Hardcoded, since this should only be run on very few machines anyway, # which are expected to have msgfmt on their $PATH MSGFMT_PATH=msgfmt all: translate # I fucked up some of the language codes. # Fixing it in Transifex would require me to recreate these groups, # deleting all old translations and potentially losing the translators. # This is ugly, but better than losing translators. # The space in the matching pattern excludes the "Language-Team:" field. po/de.po: po/de_DE.po sed -re 's/ de_DE/ de/' $< > $@ po/it.po: po/it_IT.po sed -re 's/ it_IT/ it/' $< > $@ po/pl.po: po/pl_PL.po sed -re 's/ pl_PL/ pl/' $< > $@ po/ru.po: po/ru_RU.po sed -re 's/ ru_RU/ ru/' $< > $@ po/%.mo: po/%.po ${MSGFMT_PATH} -cf -o $@ $< po/telegram-purple.metainfo.xml.pot: telegram-purple.metainfo.untranslated.xml as-metainfo.its itstool -i as-metainfo.its -o $@ $< # CAREFUL WHEN EDITING! # "-j raw.xml *.mo" must be the last options! telegram-purple.metainfo.xml: as-metainfo.its telegram-purple.metainfo.untranslated.xml $(LOCALE_MOS) po/LINGUAS itstool -i as-metainfo.its -o $@ \ -j telegram-purple.metainfo.untranslated.xml $(LOCALE_MOS) .PHONY: potfile potfile: po/telegram-purple.metainfo.xml.pot .PHONY: translate translate: telegram-purple.metainfo.xml .PHONY: clean clean: rm -rf po/*.mo po/de.po po/it.po po/pl.po po/ru.po telegram-purple/AppStream/as-metainfo.its000066400000000000000000000017151363674160100210160ustar00rootroot00000000000000 telegram-purple/AppStream/po/000077500000000000000000000000001363674160100165045ustar00rootroot00000000000000telegram-purple/AppStream/po/.gitignore000066400000000000000000000001671363674160100205000ustar00rootroot00000000000000/*.mo # I fucked up the locale names on Transifex; these are actually just intermediates: /de.po /it.po /pl.po /ru.po telegram-purple/AppStream/po/LINGUAS000066400000000000000000000000631363674160100175300ustar00rootroot00000000000000bg cs_CZ de es es_AR fr it nl nn pl pt_BR ru sq uk telegram-purple/AppStream/po/LINGUAS.BAD000066400000000000000000000004001363674160100201100ustar00rootroot00000000000000# This file lists translations that are too bad or incomplete for installation. # If you would like to improve the state of this, please see the translation page: # https://www.transifex.com/telegram-purple-developers/telegram-purple/ da # not translated telegram-purple/AppStream/po/bg.po000066400000000000000000000015421363674160100174360ustar00rootroot00000000000000# # Translators: # Любомир Василев, 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-23 03:49+0000\n" "Last-Translator: Любомир Василев\n" "Language-Team: Bulgarian (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/bg/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: bg\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Добавка, която добавя поддръжка на Telegram" telegram-purple/AppStream/po/cs_CZ.po000066400000000000000000000016651363674160100200550ustar00rootroot00000000000000# # Translators: # Jan Breuer , 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-22 19:10+0000\n" "Last-Translator: Jan Breuer \n" "Language-Team: Czech (Czech Republic) (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/cs_CZ/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: cs_CZ\n" "Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Zásuvný modul, který přidá podporu pro Telegram" telegram-purple/AppStream/po/da.po000066400000000000000000000013451363674160100174330ustar00rootroot00000000000000# # Translators: msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2016-01-09 13:13+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: Danish (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: da\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "" telegram-purple/AppStream/po/de_DE.po000066400000000000000000000015531363674160100200100ustar00rootroot00000000000000# # Translators: # Ben Wiederhake , 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-22 19:10+0000\n" "Last-Translator: Ben Wiederhake \n" "Language-Team: German (Germany) (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/de_DE/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: de_DE\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Plugin zur Unterstützung von Telegram" telegram-purple/AppStream/po/es.po000066400000000000000000000015061363674160100174550ustar00rootroot00000000000000# # Translators: # aguador , 2017 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-23 13:29+0000\n" "Last-Translator: aguador \n" "Language-Team: Spanish (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Un plugin que añade soporte para Telegram" telegram-purple/AppStream/po/es_AR.po000066400000000000000000000015301363674160100200340ustar00rootroot00000000000000# # Translators: # ᏦᏁᎢᎵᏫ , 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-22 19:10+0000\n" "Last-Translator: ᏦᏁᎢᎵᏫ \n" "Language-Team: Spanish (Argentina) (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/es_AR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: es_AR\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Un plugin que agrega soporte para Telegram" telegram-purple/AppStream/po/fr.po000066400000000000000000000014451363674160100174570ustar00rootroot00000000000000# # Translators: # Javier Sixto, 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-22 19:10+0000\n" "Last-Translator: Javier Sixto\n" "Language-Team: French (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Une extension qui ajoute le support pour Telegram" telegram-purple/AppStream/po/it_IT.po000066400000000000000000000015471363674160100200630ustar00rootroot00000000000000# # Translators: # Giuseppe Pignataro , 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-22 19:10+0000\n" "Last-Translator: Giuseppe Pignataro \n" "Language-Team: Italian (Italy) (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/it_IT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: it_IT\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Un plugin che aggiunge il supporto per Telegram" telegram-purple/AppStream/po/nl.po000066400000000000000000000015741363674160100174640ustar00rootroot00000000000000# # Translators: # justin [notsupplied] , 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-23 04:04+0000\n" "Last-Translator: justin [notsupplied] \n" "Language-Team: Dutch (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Een plug-in die ondersteuning voor Telegram toevoegt" telegram-purple/AppStream/po/nn.po000066400000000000000000000015401363674160100174570ustar00rootroot00000000000000# # Translators: # Yngve Spjeld-Landro , 2020 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2020-01-26 03:13+0000\n" "Last-Translator: Yngve Spjeld-Landro \n" "Language-Team: Norwegian Nynorsk (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/nn/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: nn\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Eit programtillegg for å kunna nytta Telegram" telegram-purple/AppStream/po/pl_PL.po000066400000000000000000000017571363674160100200640ustar00rootroot00000000000000# # Translators: # Piotr Drąg , 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-22 19:10+0000\n" "Last-Translator: Piotr Drąg \n" "Language-Team: Polish (Poland) (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/pl_PL/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pl_PL\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Wtyczka dodająca obsługę protokołu Telegram" telegram-purple/AppStream/po/pt_BR.po000066400000000000000000000015351363674160100200560ustar00rootroot00000000000000# # Translators: # Denis Brandl , 2018 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2018-12-04 18:25+0000\n" "Last-Translator: Denis Brandl \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Um plugin que adiciona suporte para o Telegram" telegram-purple/AppStream/po/ru_RU.po000066400000000000000000000017731363674160100201100ustar00rootroot00000000000000# # Translators: # Vladimir , 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-22 19:10+0000\n" "Last-Translator: Vladimir \n" "Language-Team: Russian (Russia) (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/ru_RU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru_RU\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Плагин, добавляющий поддержку Telegram" telegram-purple/AppStream/po/sq.po000066400000000000000000000015201363674160100174650ustar00rootroot00000000000000# # Translators: # Besnik , 2016 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-22 19:10+0000\n" "Last-Translator: Besnik \n" "Language-Team: Albanian (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/sq/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sq\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Telegram" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Një shtojcë që shton mbulim për Telegram-in" telegram-purple/AppStream/po/telegram-purple.metainfo.xml.pot000066400000000000000000000011171363674160100247350ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "" telegram-purple/AppStream/po/uk.po000066400000000000000000000021511363674160100174620ustar00rootroot00000000000000# # Translators: # Самохвалов Антон , 2017 msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2016-01-07 23:23+0100\n" "PO-Revision-Date: 2017-09-22 19:10+0000\n" "Last-Translator: Самохвалов Антон \n" "Language-Team: Ukrainian (http://www.transifex.com/telegram-purple-developers/telegram-purple/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" #. (itstool) path: component/name #: telegram-purple.metainfo.untranslated.xml:9 msgid "Telegram" msgstr "Телеграм" #. (itstool) path: component/summary #: telegram-purple.metainfo.untranslated.xml:10 msgid "A plugin that adds support for Telegram" msgstr "Плагін, що дає підтримку Телеграм" telegram-purple/AppStream/telegram-purple.metainfo.untranslated.xml000066400000000000000000000013031363674160100262160ustar00rootroot00000000000000 telegram-purple pidgin.desktop Telegram A plugin that adds support for Telegram https://github.com/majn/telegram-purple https://github.com/majn/telegram-purple/issues/ GFDL-1.3 GPL-2.0+ eischmann_at_redhat.com telegram-purple/AppStream/telegram-purple.metainfo.xml000066400000000000000000000047421363674160100235250ustar00rootroot00000000000000 telegram-purple pidgin.desktop Telegram Telegram Telegram Telegram Telegram Telegram Telegram Telegram Telegram Telegram Telegram Telegram Telegram Telegram Телеграм A plugin that adds support for Telegram Добавка, която добавя поддръжка на Telegram Zásuvný modul, který přidá podporu pro Telegram Plugin zur Unterstützung von Telegram Un plugin que añade soporte para Telegram Un plugin que agrega soporte para Telegram Une extension qui ajoute le support pour Telegram Un plugin che aggiunge il supporto per Telegram Een plug-in die ondersteuning voor Telegram toevoegt Eit programtillegg for å kunna nytta Telegram Wtyczka dodająca obsługę protokołu Telegram Um plugin que adiciona suporte para o Telegram Плагин, добавляющий поддержку Telegram Një shtojcë që shton mbulim për Telegram-in Плагін, що дає підтримку Телеграм https://github.com/majn/telegram-purple https://github.com/majn/telegram-purple/issues/ GFDL-1.3 GPL-2.0+ eischmann_at_redhat.com telegram-purple/CHANGELOG.md000066400000000000000000000153251363674160100160110ustar00rootroot00000000000000Changelog --------- ##### 1.4.3 - Bitlbee: Write files to /tmp instead (See #513) - Windows: Automatically adapt installer filename - Binaries should be "somewhat" reproducible now - Update translations. Thanks to the following people: * oɹʇuʞ (es_AR) * Yngve Spjeld-Landro (nn) * Piotr Drąg (pl_PL) * Denis Brandl (pt_BR) * Besnik (sq) * Самохвалов Антон (uk) - Fix: Don't crash on immediately-finished transfers (See #530) Thanks Vladimir Panteleev ! - Fix: Don't crash on photos with geolocation (See https://github.com/majn/tgl/pull/30 ) Thanks to himselfv ! ##### 1.4.2 - Still no support for Adium. We just don't know how! Help wanted! PLEASE! - Update Windows dependencies - Support ancient glib (See #501) - Update translations. Thanks to the following people: * Eduardo Trápani (es) * Olesya Gerasimenko (ru) - Fix: Handle forwarded messages and captioned images better - Fix: Handle replies better - Fix: Images in own messages - Fix: Remove *some* of the duplicate messages seen (Maybe fixes #258?) ##### 1.4.1 - *REMOVED* active support for Adium. We just don't know how! Help wanted! - Had to skip 1.4.0 as someone distributed an intermediate version as "1.4.0" - Import awesomeness from kenorb's mega-merge: * Support for pinned and other action types. * Stability improvements in general - Better build support: * No `-Werror` * Compatibility with LibreSSL * Compatibility with C++ - Simplify: Only one level of submodules - Add support for replies/forwarded messages - Add support for IPv6-only - Add windows cross-compilation script ##### 1.3.1 - Stability improvements - Support auto-loading for documents - Add support for "typing" in group chats (using group-typing-notifications plugin) - Add support for /kick command in group chats ##### 1.3.0 - channel/supergroup support - support sending code tags in markdown "backtick" format (see README for example) - reduce amount of file-transfer popups in Pidgin, auto-load media in the background - fix stability issues for the win32 build - fix multiple crashes in libtgl ##### 1.2.6 - Include libtgl bugfix "use-after-not-created for photos" - Fix Adium bundle version incompatibillity for newest version ##### 1.2.5 - Include libtgl fix to prevent crashes on certain channel messages - Improve error handling to be more graceful ##### 1.2.4 - Fix crash on unknown media type - Fix crash on logout after cancelling a file transfer ##### 1.2.3 - Build: Allow compilation on Windows #52 Thanks Eion! - Build: Drop dependency on LodePNG, Thanks Ben! - Build: Gettext is now optional - Fix issue that prevented to send messages to deleted users in certain cases (#174) - Fix own user being added to the buddy list in certain cases - Fix that read recipes of own messages are being displayed (#139) - Fix encoding inconsistencies with Unicode characters (#177) - Fix auto-joining for chats (#179) - Fix client not reconnecting anymore under certain circumstances (#173) - Fix crash on compat-verification (PullRequest #183) - Remove pointless "create chat" confirmation dialogue - Improve logging messages - Always send read recipes when the user is typing or sending a message - Improve translation and user messages (#139) - Use native password prompts (Adium) ##### 1.2.2 - fix some licensing issues by not depending on OpenSSL any longer (thanks Ben!) - add tons of translations (thanks to anyone helping!) - fix issue that caused empty files - fix pidgin not reconnecting after hibernation - fix adium not reconnecting after hibernation - fix secret chat fingerprint not being displayed after restart - fix secret chat name not being displayed after restart ##### 1.2.1 ##### Bugfixes - Fix buggy group chat handling * Assure that foreign users are always listed by their full name instead of the user ID * Don't automatically add group chats to buddy list to prevent incompatibillities with some libpurple clients * Fix issue that caused the buddy list to not be correctly updated on joining / leaving participants * Fix an issue that caused the user list to be printed on every group chat message in Finch - Fetch chat information lazily to reduce traffic and prevent flood errors - Improve input validation for phone numbers ###### Features - Support leaving chats - Implement the roomlist-API to allow listing of all active chats ##### Version 1.2.0 (Beta 3) ##### Bugfixes - Fix error in incoming message handling that caused segmentation faults - Fix failing audio and video transfers - Mark messages read on other devices as 'deferred' to avoid needless notifications - Improved buddy list handling (should avoid "unknown" contacts popping up) - Many small issues (see commit history) - Fix issues that caused audio and video downloads to not have a proper file ending - Fix issue that caused very old unused chats to not be available ###### Features - Allow creation of new group chats - Allow joining chats by invite link - Allow exporting chats by invite link - Support displaying and sending GIFs - Support joining chats by invite link ##### Version 1.1.0 (Beta 2) - update to libtgl 2 - support two-factor authentication - improve sticker support - add option to control message read recipes - many bugfixes ##### Version 1.0.0 (Beta 1) - Move state files into .purple/telegram-purple directory - Add extended account settings for controlling history and read notifications - Improved support for Adium * fix chat bookmarking * add custom views for account settings and chat joining ##### Version 0.7 - Support uploads and downloads (with some caveats though): * Uploads wont contain the current file name but a generic one * Every file is uploaded as a document or picture, so unfortunately no embedded videos and audio (right now) * Group chats only support picture uploads since nothing else is supported by the UI - Fix HTML escaping issues ##### Version 0.6.1 - Fix many stability issues - Do not readd left chats on login ##### Version 0.6 - Support for secret chats - Receiving geo messages ##### Version 0.5 - Display incoming photos - Respect received user and chat property updates - Support changing own profile picture - Support adding new contacts - Display service messages - Works with libpurple proxy settings ##### TODO: - Picture Uploads - Audio, Video and File Transfers telegram-purple/COPYING000066400000000000000000000432541363674160100152350ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. telegram-purple/HACKING.BUILD.md000066400000000000000000000065701363674160100164260ustar00rootroot00000000000000# Hacking on the build system This list was previously maintained as [issue #242](https://github.com/majn/telegram-purple/issues/242), until we realized that this needs proper version-control. (Duh!) ## Exhaustive list of requirements on the build system: 1. `commit.h` must change whenever it disagrees with the current git commit 1. `commit.h` must not change whenever it agrees with the current git commit 1. Must call `cd tgl && ./configure` with appropriate options whenever `tgl/Makefile` is missing, or notices that `./configure` was run. ("Too often" is acceptable as long as `make && make` isn't violated.) 1. Must call `make -C tgl` whenever this might have any effect. ("Too often" is acceptable as long as `make && make` isn't violated.) 1. Any changes due to `make -C tgl` must cause all necessary rebuilds in telegram-purple during the same invocation of make. ("Too often" is acceptable as long as `make && make` isn't violated.) 1. If `tgl/Makefile.in` is missing, explain that we need submodules, and stop. 1. `make -j12` must work fine 1. Must support out-of-CVS builds. ## While ensuring that: - Must not `-include tgl/Makefile` as it doesn't really support that, and I'm not going to try and convince @vysheng to do that. Also, it's too fragile. You know how he ticks. - `make && make` must not create any files in the second run (otherwise, `sudo make install` would become hairy) - Compatibility with other makes ## Approach: - `commit.h` is a regular file which depends on a .PHONY target `commit`. Building `commit.h` *only* touches `commit.h` if necessary and possible. (=> 1, 2, half of 8) - Have a target `tgl/Makefile` which depends on `Makefile`. (=> 3) - The central target `${PRPL_LIBNAME}` shall depend on the .PHONY `submade`, which depends on `tgl/Makefile`, and essentially executes `make -C tgl`. (=> 4, time constraint of 5) - All objects of telegram-purple depend on `tgl/libs/libtgl.a`. Rationale: if `tgl/libs/libtgl.a` stays the same, then nothing in tgl changed. If `tgl/libs/libtgl.a` changes, then due to lots of black preprocessor magic within tgl, it can't be safely determined which, if any, objects of telegram-purple can be re-used. Also, if tgl got recompiled (~ 1 minute), then tgp can be recompiled, too (~ 5 seconds). (=> dependency constraint of 5) - Let `tgl/Makefile` depend on `tgl/Makefile.in`, and put the warning into the rule for the latter. (=> 6) - The above already implies a dependency DAG that is completely known to make; except at one point: let `tgl/libs/libtgl.a` depend on `submade`, without any own code. Now make ensure thread-safety on it's own. (=> 7) - Bundle commit.h into the origtar (=> other half of 8) ## Side effects: - Should be ultimately robust. Then again, that's what I thought about the last few attempts, and they didn't last long. - This reduces the number of .PHONYs drastically, making it easier to read, and making it easier to prove that `make && make` doesn't change anything. - Even though `submade` should trigger once and only once, this can handle multiple invocations just fine, too. - All files dependent on `commit.h` need to be mentioned explicitly as dependents in the Makefile. This is ugly, but (as far as I can see) unavoidable. Thankfully, any errors here will get detected by automated testing. - We currently use only one GNU make specific extension. See https://github.com/majn/telegram-purple/issues/137#issuecomment-167970054 telegram-purple/HACKING.md000066400000000000000000000070151363674160100155630ustar00rootroot00000000000000# Contributing This is Open Source Software. We realized that we didn't pass the Patch Test ## What to contribute Here's a few places to start: - Report any bugs you find. - No, seriously! Most of the bugs don't even get reported, or the reporter only writes "Doesn't work for me" and then vanishes. - ["help wanted" issues](https://github.com/majn/telegram-purple/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+-label%3A%22in-pipeline%22), especially automated testing - ["secret chat" issues](https://github.com/majn/telegram-purple/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3A%22secret+chats%22+-label%3A%22in-pipeline%22+) - Portability (especially endianness) of tgl (external project) - [Issues of tgl](https://github.com/vysheng/tgl/issues) -- lots and lots of false or obsolete reports - Slim down the size of the generated files in `tgl/auto`, as this currently dominates the build time. Yuk! - Make sure that the libpurple-devs don't break libpurple any further. ## How to contribute Write [an issue](https://github.com/majn/telegram-purple/issues/new), shoot us a mail (scrape the address from the git history), or contact us in dev chat (changing URL, see README for that). ## How to release #### Translations Ideally, do a string freeze beforehand; however, this has proven to be too impractical for this project. Go to the [translation site](https://www.transifex.com/telegram-purple-developers/telegram-purple/content/), and close the current resource for new translations. Rename and re-prioritize it appropriately. Download the zip-file, extract it, remove the annoying prefix. Move all files to `po/`, except `en.po`. While waiting for the download link, create the new resource with the new potfile, then re-upload all the old translations there. Run `make po/*.po` to fix the filenames. Do not delete any files. Rationale see `Makefile`. Adjust `po/LINGUAS*` as you see fit. Also import the translations for `AppStream/po/`, and run `make -C Appstream translate`. #### Increment version Attempt to use semver. Adjust `configure.ac`, in macro `AC_INIT`. Remember to run `autoreconf`. Adjust `telegram-adium/telegram-adium/telegram-adium-Info.plist`. Adjust `rpm/purple-telegram.spec`, in version at the top and "changelog" below. Don't update debian: It's abandoned anyway. AppStream: Nothing to do. Update `CHANGELOG.md`. #### Run some tests First locally, then on Travis. Also, install it locally. Don't forget to `./configure` first. #### Prepare release files Fetch/pull recent changes. Merge into `master`. Make a tag: `git tag v1.something` Remember to push the tag to github. Make a dist-bundle: `make dist` Keep the resulting `telegram-purple_1.something.orig.tar.gz` safe. Make the windows installer: `./mkwindows.sh` Keep the resulting `telegram-purple-1.something+gcafebabe5.exe` safe. #### Create release on github See the [release page](https://github.com/majn/telegram-purple/releases/). Feel free to be inspired by the previous release-messages. Remember to upload the origtar *and* Windows installer. #### Close associated issues All relevant issues are marked with `in-pipeline`, but sadly too many are marked this way. #### Organize branches Create a new branch `dev-1.nextsomething`, delete the old branch. #### Create new translation goal on transifex Be pessimistic in the slug-name. Run `./autogen.sh` to make all string changes available. Also, create an announcement that yes there is a new resource, but this resource may change significantly until the next string freeze. telegram-purple/Makefile.in000066400000000000000000000320651363674160100162450ustar00rootroot00000000000000# This file is part of telegram-purple # # 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 02111-1301 USA # # Copyright Matthias Jentsch, Vitaly Valtman, Christopher Althaus, Markus Endres 2014-2017 srcdir=@srcdir@ prefix=@prefix@ datarootdir=@datarootdir@ localedir=@localedir@ gettext_package=@GETTEXT_PACKAGE@ # Also update mkwindows.sh PIDGIN_VERSION=2.13.0 WIN32_GTK_BUNDLE_DIR=win32/gtk+-bundle_2.24.10-20120208_win32 WIN32_GTK_BUNDLE_URL=http://ftp.acc.umu.se/pub/gnome/binaries/win32/gtk+/2.24/gtk+-bundle_2.24.10-20120208_win32.zip WIN32_GTK_BUNDLE_FILE=win32/gtk+-bundle_2.24.10-20120208_win32.zip WIN32_PIDGIN_SRC_URL=http://sourceforge.net/projects/pidgin/files/Pidgin/${PIDGIN_VERSION}/pidgin-${PIDGIN_VERSION}.tar.gz/download WIN32_PIDGIN_SRC_FILE=win32/pidgin-${PIDGIN_VERSION}.tar.gz WIN32_PIDGIN_SRC_DIR=win32/pidgin-${PIDGIN_VERSION} WIN32_PIDGIN_BIN_URL=http://sourceforge.net/projects/pidgin/files/Pidgin/${PIDGIN_VERSION}/pidgin-${PIDGIN_VERSION}-win32-bin.zip/download WIN32_PIDGIN_BIN_FILE=win32/pidgin-${PIDGIN_VERSION}-win32-bin.zip WIN32_PIDGIN_BIN_DIR=win32/pidgin-${PIDGIN_VERSION}-win32bin WIN32_WEBP_URL=https://github.com/webmproject/libwebp/archive/v1.0.2.tar.gz WIN32_WEBP_FILE=win32/libwebp-1.0.2.tar.gz WIN32_WEBP_DIR=win32/libwebp-1.0.2 WIN32_DIRS=${WIN32_GTK_BUNDLE_DIR} ${WIN32_PIDGIN_SRC_DIR} ${WIN32_PIDGIN_BIN_DIR} ${WIN32_WEBP_DIR} # Not directly used here, but the usage will be injected via the CFLAGS configure var. # Note on webp: locally cross-built! That's why it violates the pattern. WIN32_INC=-I${WIN32_PIDGIN_SRC_DIR}/pidgin \ -I${WIN32_PIDGIN_SRC_DIR}/pidgin/win32 \ -I${WIN32_PIDGIN_SRC_DIR}/libpurple \ -I${WIN32_PIDGIN_SRC_DIR}/libpurple/win32 \ -I${WIN32_GTK_BUNDLE_DIR}/include \ -I${WIN32_GTK_BUNDLE_DIR}/include/glib-2.0 \ -I${WIN32_GTK_BUNDLE_DIR}/lib/glib-2.0/include \ -I${WIN32_GTK_BUNDLE_DIR}/include/gtk-2.0 \ -I${WIN32_GTK_BUNDLE_DIR}/lib/gtk-2.0/include \ -Iobjs/webp/install/include WIN32_CONTRIB_FILES=contrib/libgcrypt-20.dll contrib/libgpg-error-0.dll contrib/libgcc_s_sjlj-1.dll CFLAGS_INTL=-DENABLE_NLS -DLOCALEDIR='"$(localedir)"' CFLAGS_WARN=-Wall -Wextra -Wno-deprecated-declarations -Wno-unused-parameter CFLAGS_EXTRA=-I${srcdir} -I. -fno-strict-aliasing -fPIC -D_FORTIFY_SOURCE=2 CFLAGS=@CFLAGS@ @PURPLE_CFLAGS@ @DEFS@ ${CFLAGS_INTL} ${CFLAGS_WARN} ${CFLAGS_EXTRA} LDFLAGS_EXTRA=-rdynamic -ggdb LDFLAGS=@LDFLAGS@ @OPENSSL_LIBS@ @PURPLE_LIBS@ @LIBS@ ${LDFLAGS_EXTRA} DIR_PERM=0755 FILE_PERM=0644 CC=@CC@ PKG_CONFIG=@PKG_CONFIG@ MSGFMT_PATH=@MSGFMT_PATH@ # Check if -fstack-protector-strong is supported before enabling it STACK_PROTECTOR_UNSUPPORTED = $(shell $(CC) -fstack-protector-strong 2>&1 | grep -c 'stack-protector-strong') ifeq "$(STACK_PROTECTOR_UNSUPPORTED)" "0" CFLAGS += -fstack-protector-strong endif # Check if -frandom-seed is supported before enabling it RANDOM_SEED_UNSUPPORTED = $(shell $(CC) -frandom-seed=77e0418a98676b76729b50fe91cc1f250c14fd8f664f8430649487a6f918926d 2>&1 | grep -c 'random-seed') ifeq "$(RANDOM_SEED_UNSUPPORTED)" "0" CFLAGS += -frandom-seed=0x$$(sha256sum $< | cut -f1 -d" ") endif # Check if -ffile-prefix-map is supported before enabling it FILE_PREFIX_MAP_UNSUPPORTED = $(shell $(CC) -ffile-prefix-map=/foo/bar/baz=/quux 2>&1 | grep -c 'file-prefix-map') ifeq "$(FILE_PREFIX_MAP_UNSUPPORTED)" "0" # FIXME CFLAGS += "-ffile-prefix-map=$(realpath ${srcdir})=telegram-purple" endif DEP=dep EXE=bin OBJ=objs DIR_LIST=${DEP} ${EXE} ${OBJ} contrib PLUGIN_OBJECTS=${OBJ}/tgp-net.o ${OBJ}/tgp-timers.o ${OBJ}/msglog.o ${OBJ}/telegram-base.o ${OBJ}/telegram-purple.o ${OBJ}/tgp-2prpl.o ${OBJ}/tgp-structs.o ${OBJ}/tgp-utils.o ${OBJ}/tgp-chat.o ${OBJ}/tgp-ft.o ${OBJ}/tgp-msg.o ${OBJ}/tgp-request.o ${OBJ}/tgp-blist.o ${OBJ}/tgp-info.o ALL_OBJS=${PLUGIN_OBJECTS} ${EXTRA_OBJECTS} ifdef MSGFMT_PATH LOCALES=$(shell cat po/LINGUAS) LOCALE_MOS=$(addprefix po/,$(addsuffix .mo,$(LOCALES))) endif .SUFFIXES: .SUFFIXES: .c .h .o PRPL_NAME=telegram-purple.so PRPL_LIBNAME=${EXE}/${PRPL_NAME} all: ${PRPL_LIBNAME} $(LOCALE_MOS) PLUGIN_DIR_PURPLE=$(shell ${PKG_CONFIG} --variable=plugindir purple) DATA_ROOT_DIR_PURPLE=$(shell ${PKG_CONFIG} --variable=datarootdir purple) CRYPTO_FLAG=@CRYPTO_FLAG@ ### == 'Magic' targets and infrastructure. == ### # Here be dragons! See HACKING.BUILD.md # for the full list of requirements, goals, and rationale. .PHONY: create_dirs create_dirs: ${DIR_LIST} ${DIR_LIST}: @test -d $@ || mkdir -p $@ DEPENDENCE=$(subst ${OBJ}/,${DEP}/,$(patsubst %.o,%.d,${ALL_OBJS})) DEPENDENCE_LIST=${DEPENDENCE} -include ${DEPENDENCE_LIST} tgl/Makefile.in: @echo "tgl/Makefile.in not found. Maybe you need to 'git submodule update --init --recursive' ?" && exit 1 tgl/Makefile: tgl/Makefile.in Makefile cd tgl && ./configure -q ${CRYPTO_FLAG} --disable-extf CFLAGS="@CFLAGS@" LDFLAGS="@LDFLAGS@" tgl/libs/libtgl.a: tgl/Makefile +${MAKE} -C tgl libs/libtgl.a .PHONY: commit commit: # The *commands* for commit.h shall always be executed, but the # *file* commit.h should only be considered to have changed in rare cases. GIT_COMMIT=$(shell git rev-parse HEAD | cut -c1-10) commit.h: commit @./commit.h.gen # Ugly, but necessary, because otherwise commit.h would not get generated: test/loadtest.c: commit.h # Ugly, but necessary, because otherwise commit.h would not get generated: telegram-purple.c: commit.h ### == 'Normal' build. == ### ${PLUGIN_OBJECTS}: ${OBJ}/%.o: ${srcdir}/%.c tgl/libs/libtgl.a | create_dirs echo $@ && ${CC} ${CFLAGS} ${CPPFLAGS} -I ${srcdir}/tgl -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $< po/%.mo: po/%.po ${MSGFMT_PATH} -cf -o $@ $< >/dev/null 2>&1 ${PRPL_LIBNAME}: ${ALL_OBJS} tgl/libs/libtgl.a | create_dirs ${CC} -shared -o $@ $^ ${LDFLAGS} ### == Translation fixes == ### # I fucked up some of the language codes. # Fixing it in Transifex would require me to recreate these groups, # deleting all old translations and potentially losing the translators. # This is ugly, but better than losing translators. # The space in the matching pattern excludes the "Language-Team:" field. po/de.po: po/de_DE.po sed -re 's/ de_DE/ de/' $< > $@ po/it.po: po/it_IT.po sed -re 's/ it_IT/ it/' $< > $@ po/pl.po: po/pl_PL.po sed -re 's/ pl_PL/ pl/' $< > $@ po/ru.po: po/ru_RU.po sed -re 's/ru_RU/ru/' $< > $@ ### == noicon_{,un}install targets. Use only if you know that you don't need icons. Note that pidgin uses those files. == ### .PHONY: noicon_install noicon_install: $(PRPL_LIBNAME) $(LOCALE_MOS) mkdir -m $(DIR_PERM) -p $(DESTDIR)$(PLUGIN_DIR_PURPLE) install -m $(FILE_PERM) $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_NAME) mkdir -m $(DIR_PERM) -p $(DESTDIR)/etc/telegram-purple # Assume that the user does not use AppStream if she doesn't want icons @for lang in $(LOCALES); do \ mkdir -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES; \ echo "installing po/$$lang.mo to $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(gettext_package).mo"; \ install -m $(FILE_PERM) po/$$lang.mo $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(gettext_package).mo; \ done .PHONY: noicon_uninstall noicon_uninstall: rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_NAME) rm -f $(DESTDIR)/etc/telegram-purple/server.pub # TODO: Remove this in later versions rm -f $(DESTDIR)/etc/telegram-purple/server.tglpub # TODO: Remove this in later versions # TODO: Delete all installed .mo's, no matter what LINGUAS says. @for lang in $(LOCALES); do \ echo "removing $(localedir)/$$lang/LC_MESSAGES/$(gettext_package).mo"; \ rm -f $(localedir)/$$lang/LC_MESSAGES/$(gettext_package).mo; \ done ### == Main {,un}install targets. This should satisfy most needs. == ### .PHONY: install install: noicon_install mkdir -m $(DIR_PERM) -p $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16 install -m $(FILE_PERM) imgs/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png mkdir -m $(DIR_PERM) -p $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22 install -m $(FILE_PERM) imgs/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png mkdir -m $(DIR_PERM) -p $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48 install -m $(FILE_PERM) imgs/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png mkdir -m $(DIR_PERM) -p $(DESTDIR)$(datarootdir)/appdata install -m $(FILE_PERM) AppStream/telegram-purple.metainfo.xml $(DESTDIR)$(datarootdir)/appdata/telegram-purple.metainfo.xml .PHONY: uninstall uninstall: noicon_uninstall rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png rm -f $(DESTDIR)$(datarootdir)/appdata/telegram-purple.metainfo.xml ### == The local_{,un}install targets, in case you're not root. == ### .PHONY: local_install local_install: mkdir -m $(DIR_PERM) -p $(DESTDIR)$(HOME)/.purple/plugins install -m $(FILE_PERM) $(PRPL_LIBNAME) $(DESTDIR)$(HOME)/.purple/plugins/$(PRPL_NAME) .PHONY: local_uninstall local_uninstall: rm -f $(DESTDIR)$(HOME)/.purple/plugins/$(PRPL_NAME) rm -f $(DESTDIR)$(HOME)/.purple/telegram-purple/server.tglpub # TODO: Remove this in later versions ### == Windows sources downloads == ### .PHONY: download_win32_sources download_win32_sources: | ${WIN32_DIRS} win32: @mkdir -p $@ ${WIN32_GTK_BUNDLE_DIR}: | ${WIN32_GTK_BUNDLE_FILE} unzip -q $| -d $@ ${WIN32_GTK_BUNDLE_FILE}: | win32 wget -q -O $@ ${WIN32_GTK_BUNDLE_URL} ${WIN32_PIDGIN_SRC_DIR}: | ${WIN32_PIDGIN_SRC_FILE} tar xf $| -C win32/ ${WIN32_PIDGIN_SRC_FILE}: | win32 wget -q -O $@ ${WIN32_PIDGIN_SRC_URL} ${WIN32_PIDGIN_BIN_DIR}: | ${WIN32_PIDGIN_BIN_FILE} unzip -q $| -d win32/ ${WIN32_PIDGIN_BIN_FILE}: | win32 wget -q -O $@ ${WIN32_PIDGIN_BIN_URL} ${WIN32_WEBP_DIR}: | ${WIN32_WEBP_FILE} tar xf $| -C win32/ ${WIN32_WEBP_FILE}: | win32 wget -q -O $@ ${WIN32_WEBP_URL} .PHONY: win-installer-deps win-installer-deps: telegram-purple.nsi $(PRPL_LIBNAME) $(LOCALE_MOS) ${WIN32_CONTRIB_FILES} @[ "x${PRPL_NAME}" = "xlibtelegram.dll" ] || { \ echo "WARNING: Bad PRPL_NAME. This probably won't work." ; \ echo " (The DLL file cannot be just renamed!)" ; } /usr/%: @echo "You're missing the file $@" @echo "Try installing the appropriate of the following packages:" @echo " libgcrypt-mingw-w64-dev" @echo " libgpg-error-mingw-w64-dev" @echo " gcc-mingw-w64-i686" @echo "Also, please file a bug report *EVEN IF THIS SOLVES THE ISSUE*," @echo "as it should have been detected earlier." contrib/libgcrypt-20.dll: /usr/i686-w64-mingw32/bin/libgcrypt-20.dll | contrib cp $< "$@" contrib/libgpg-error-0.dll: /usr/i686-w64-mingw32/bin/libgpg-error-0.dll | contrib cp $< "$@" contrib/libgcc_s_sjlj-1.dll: /usr/lib/gcc/i686-w64-mingw32/*-win32/libgcc_s_sjlj-1.dll | contrib cp $< "$@" ### == Handling and maintenance. Subject to rapid change, shouldn't be used in scripts. == ### .PHONY: plugin plugin: $(PRPL_LIBNAME) .PHONY: strip strip: $(PRPL_LIBNAME) $(STRIP) --strip-unneeded $(PRPL_LIBNAME) .PHONY: build-nsi build-nsi: telegram-purple.nsi config.h: @echo "How did you manage to do that?" @echo "You probably want to call ./config.status first." @exit 1 telegram-purple.nsi: telegram-purple.nsi.awk telegram-purple.nsi.awk-in po/LINGUAS config.h awk -f telegram-purple.nsi.awk telegram-purple.nsi.awk-in > telegram-purple.nsi .PHONY: run run: pidgin -d | grep 'telegram\|plugin\|proxy' .PHONY: debug debug: install ddd pidgin DIST_ERR_MSG="Working directory is not git clean.\ Run 'git status' to show what files are causing this.\ Please note that 'make dist' packages the state in git, not the one on your disk." SUBMOD_ERR_MSG="Submodule tgl looks weird.\ Are all submodules properly initialized and updated?" # Not PHONY .git: @echo "Not in a git folder. Features that require git are disabled."; exit 1 .PHONY: check-clean check-clean: .git @test "x" = x"$(git status --porcelain)" || (echo ${DIST_ERR_MSG}; exit 1) @test -r tgl/.git || (echo ${SUBMOD_ERR_MSG}; exit 1) # Feel free to remove the "check-clean" dependency if you know what you're doing. .PHONY: dist dist: check-clean commit.h .git create_dirs ./gen-origtar ### == Cleaning in various flavors == ### .PHONY: clean-here clean-here: rm -rf ${DIR_LIST} "$(PRPL_LIBNAME)" telegram-purple.nsi po/*.mo autom4te.cache AppStream/po/*.mo commit.h -include test/Makefile .PHONY: clean clean: clean-here clean-test tgl/Makefile +${MAKE} -C tgl clean telegram-purple/README.md000066400000000000000000000427141363674160100154610ustar00rootroot00000000000000Telegram-Purple Unofficial (Beta) ================================= Telegram-purple is a Libpurple protocol plugin that adds support for the Telegram messenger. I keep getting many questions about this plugin in my E-mail, so I've created a [telegram group chat](https://bit.ly/2S539ia) for telegram-purple related discussions or questions. Installation ------------ If you are just interested in using the plugin you probably want to use one of the following binary distributions. Please note that I do not control most of those package sources and the version may lag behind. If your platform is not supported or you want to contribute by testing or development, scroll down to "Building form Source". #### macOS (Adium) 1. Download and execute the [Telegram-Adium bundle] (https://github.com/majn/telegram-purple/releases/download/v1.3.0/telegram-adium-1.3.0.AdiumLibpurplePlugin.zip) 2. Restart Adium #### Windows We provide an installer for Windows users: 1. Download and execute the corresponding setup from https://github.com/majn/telegram-purple/releases 2. Restart Pidgin 3. If not detected, restart Pidgin again This installer is built in a different way than previous builds (specifically, by Eion Robb http://eion.robbmob.com/telegram/), and may still have some issues. Specifically, the installer is compressed, so if you have an overzealous anti-virus installed, the installer may get flagged. The build is 32-bit, so connecting with Telegram for the first time may take a few moments. Alternatively, see "Building the Windows Installer" below. #### Fedora (22, 23) The package is available in the Fedora 22 and 23 testing repositories: dnf config-manager --set-enabled updates-testing dnf install purple-telegram #### Arch Linux (AUR) https://aur.archlinux.org/packages/telegram-purple/ #### Debian You can build it from source (see following section) or build a `.deb` file for your package manager. Building From Source -------------------- Below, you will find the instructions for how to build the libpurple protocol plugin from source. #### 1. Clone This repository has submodules, so you need to clone recursively. git clone --recursive https://github.com/majn/telegram-purple cd telegram-purple #### 1b. Cloning if you're a packager If you are unsure about whether you need this, then you are not a packager and don't have any use for this. If you need an "orig-tarball", it can be generated by `make dist`. Note that this automatically generates an appropriate version number like `1.2.4-58-g8e3cebf`. You can truncate the git suffix (`-g8e3cebf`). If the `-58` part exists, it means that you're using a development version, which is probably not what you want. If you still want to package this, please leave the commit number (i.e., `58`) intact, as this indicates that this version is in fact much further than just `1.2.4`. #### 2. Fetch all dependencies ##### Fedora sudo dnf install gcc gettext libgcrypt-devel libwebp-devel libpurple-devel zlib-devel ##### Debian / Ubuntu sudo apt-get install libgcrypt20-dev libpurple-dev libwebp-dev gettext build-essential libpng-dev ##### OpenSUSE sudo zypper install gcc glib glib-devel libpurple libpurple-devel zlib-devel libwebp-devel And the development files for gcrypt, probably `gcrypt-devel` or something. (FIXME) #### 3. Compile and install If libwebp is not available, you can disable sticker support by calling ./configure --disable-libweb instead. Please note that this is usually not necessary. ./configure make sudo make install Pulling Updates --------------- This repository contains submodules, and a simple pull just won't be enough to update all the submodules’ files. Pull new changes with: git pull git submodule sync # just in case the configuration has changed git submodule update --recursive Usage ----- #### First Login The username is your current phone number, including your full country prefix. For Germany, this would be '+49', resulting in a user name like '+49151123456'. Telegram will verify your phone number by sending you a code via SMS. You will be prompted for this code, once that happens. #### Buddy List Like in the official Telegram apps, the displayed buddy list consists of all active conversations. ##### Foreign Users Foreign users, like for example people you only know through a group chat but never had any conversation with, will not be part of your buddy list by default. You can add those users to the buddy list by clicking on "Add contact..." in the users context menu. #### Using secret chats You can use Telegram secret chats with this plugin, they will show up as a new buddy with a '!' in front of the buddy name. One caveat of secret chats in Telegram is that they can only have one endpoint, this is a limitation of the protocol. This means that if you create a secret chat in Pidgin or Adium you will not be able to use that chat on your phone. You will be asked whether to accept each secret chat, so you can always choose to accept the chat on a different device if you want. You can set a default behavior for dealing with secret chats (Accept or Decline) in the account settings, if you don't want that prompt to appear every time. Self destructive messages will be ignored, since I don't know any way to delete them from the conversation and the history. ##### Confirming the key authenticity Click on the buddy in the buddy list and click on "Show Info" to visualize the key fingerprint. ##### Initiate secret chats To initiate a secret chat from Pidgin or Adium, click on a Buddy in the Buddy List and hit "Start Secret Chat" ##### Deleting secret chats If you delete a secret chat from the buddy list, it will be terminated and no longer be usable. #### Unicode Emojis for Pidgin The Telegram phone applications for iOS and Android make use of standardized Unicode smileys (called [Emojis](https://en.wikipedia.org/wiki/Emoji)). Pidgin does not display those smileys natively, but you can install a custom smiley theme like (https://github.com/stv0g/unicode-emoji) or (https://github.com/VxJasonxV/emoji-for-pidgin) and activate it under Settings > Themes > Smiley Theme. #### Code-Tags Since 1.3.0 it is possible to write messages in monospaced fonts using the markdown backtick syntax. ##### Example ``` if (true) { // do smth }``` ##### Result if (true) { // do smth } Compiling on macOS ------------------------- On macOS you probably want to use the [prebuilt Bundle](https://github.com/majn/telegram-purple/releases) for Adium (see above) and not compile it from source. Compiling the bundle for Adium oder Pidgin on macOS is rather complicated and usually not required. # Building the Pidgin Plugin These steps are necessary when you want to build telegram-purple as a libpurple Plugin for macOS. The outputs of this build are also necessary when building the Adium bundle. 1. [Install Homebrew](https://brew.sh/) 2. Clone repository git clone --recursive https://github.com/majn/telegram-purple cd telegram-purple 3. Install dependencies using homebrew brew install glib brew install pkg-config brew install pidgin brew install webp brew install libgcrypt libgpg-error 4. Configure make install ./configure CFLAGS="-I/usr/local/include -ggdb -O0" LDFLAGS="-L/usr/local/lib" --disable-translation # I currently don't know of an easy to support translations for Pidgin under macOS (sorry) make sudo make install # Building the Adium Plugin (This part may be a little outdated.) Compiling with XCode is a little bit problematic, since it requires you to compile Adium first to get the necessary framework files. My advice is to just use the [prebuilt bundle](https://github.com/majn/telegram-purple/releases), but if you really want to do it, follow these steps: 1. Get the Adium source, compile it with XCode and copy the build output into telegram-adium/Frameworks/Adium. It should contain at least Adium.framework, AdiumLibpurple.framework and AIUitilies.framework 2. Open the Adium source code, go to ./Frameworks and copy libglib.framework and libpurple.framework into telegram-adium/Frameworks/Adium 3. Build the tgl submodule and delete libtgl.so from libs/ (it should only contain libtgl.a) 4. Install libpng, libwebp, libgcrypt and gnupg with homebrew: brew install libpng webp brew install libgcrypt libgpg-error 5. If you already downloaded libwebp/libgcrypt in previous builds make sure that the binaries are up-to-date brew update brew upgrade libpng webp libgcrypt 6. Install with homebrew and move it into the appropriate directory so that XCode can find them. Note that the versions might differ, use the one that is mkdir -p ./telegram-adium/Frameworks/Adium cp /usr/local/Cellar/libpng/1.6.37/lib/libpng.a ./telegram-adium/Frameworks cp /usr/local/Cellar/webp/1.0.3/lib/libwebp.a ./telegram-adium/Frameworks cp /usr/local/Cellar/libgcrypt/1.8.4/lib/libgcrypt.20.dylib ./telegram-adium/Frameworks/Adium cp /usr/local/Cellar/libgpg-error/1.36/lib/libgpg-error.0.dylib ./telegram-adium/Frameworks/Adium 7. Update the paths in the dylibs, to assure that the resulting binary will load them form within the bundle. cd ./telegram-adium/Frameworks/Adium install_name_tool -id "@loader_path/../Resources/libgcrypt.20.dylib" ./libgcrypt.20.dylib install_name_tool -id "@loader_path/../Resources/libgpg-error.0.dylib" ./libgpg-error.0.dylib install_name_tool -change "/usr/local/lib/libgpg-error.0.dylib" "@loader_path/../Resources/libgpg-error.0.dylib" ./libgcrypt.20.dylib 7. Build the XCode-Project and execute the created bundle Building the Debian Package --------------------------- If you just need a `.deb`, simply do: sudo apt-get install debhelper fakeroot ./debian/rules binary And you're done! The `telegram-purple_….deb` and `telegram-purple-dbgsym_….deb` files are in the parent directory. To show some info about it, try this: dpkg --info telegram-purple_*.deb Please note that installing the debugging symbols (`dbgsym`) help a lot in troubleshooting, so please do install them, too! #### Debian Maintainers #### If you're a maintainer (if you're not sure, then you aren't a maintainer), you need to produce a lot more files than that. Here's how you can generate a `.orig.tar.gz`: make dist The following command requires the original tar to exist, and will build all further files, specifically `.debian.tar.xz`, `.dsc`, `.deb`, and `.changes`: dpkg-buildpackage If this fails with a cryptic error message, first make sure that the `….orig.tar` really is in place. For the upload, you should use `pbuilder` and similar to build the package in a more minimalistic environment. That covers the official part of the work-flow. Of course, you can call small parts of the build process directly, in order to avoid overhead like rebuilding. For example, if you only need the `.debian.tar.xz` and `.dsc` files, do this: make dist false # Move tar to parent directory, by hand dpkg-source -b . Note that we no longer actively try to get it into the Debian repository. Building the Windows Installer --------------------------- You will need a Debian-ish operating system, and the following packages: ``` apt-get install build-essentials gcc-mingw-w64-i686 libgcrypt-mingw-w64-dev \ libgpg-error-mingw-w64-dev libz-mingw-w64-dev \ gettext libgcrypt20-dev libpurple-dev libwebp-dev \ nsis ``` After that, run the build script: ``` ./mkwindows.sh ``` This generates a file like `telegram-purple-1.3.1+gcb96ff77aa.exe`, which contains everything the Windows users need. Discussion / Help ----------------- #### Custom pubkeys As we want to avoid OpenSSL, it has become necessary to replace the PEM file format. This means that if you use a custom pubkey (which you really REALLY shouldn't be doing), you have to adapt, sorry. We no longer read the public key of the Telegram servers from a file. If you really need a different public key, and know what you're doing (e.g., connecting to some kind of test environment internal to Telegram, which also is a very bad idea), you need to find the call to `tgl_set_rsa_key_direct` in `telegram-purple.c`, and provide the key directly by yourself. FAQ --- - How can I improve the translations? * A: Request access in some form or another, for example through the development chat (see below), a GitHub issue, or request it directly on the [Transifex website](https://www.transifex.com/telegram-purple-developers/telegram-purple/). You will need an account on that website, and need to make all changes there. I will then pull it at my next convenience. If you want it any faster, you can poke me on the dev chat. - How do I set telegram-purple up with Bitlbee? * A (easy): Use bitlbee-telegram instead. It is made for bitlbee. * A (hard): Mainly just followed the wiki steps: - First install bitlbee with purple enabled. In Arch, use the bitlbee-libpurple aur package. - Started the Bitlbee daemon, which runs with the bitlbee user: # systemctl start bitlbee.service - With any IRC client (e.g., irssi), connect to localhost with `/connect localhost`, then create the account with the commands: account add telegram account telegram on This was adapted from https://github.com/majn/telegram-purple/issues/461 . Thanks! - I receive pictures in a chat, but they aren't showing up * A: Make sure that you don't have a plugin like "Conversation Colors" that strips HTML from messages and removes the pictures. - I receive RPC_CALL_FAIL_401: SESSION REVOKED * A: This basically means your session has been terminated but the program doesn't handle terminated sessions properly yet. You have to clean the ~/.purple/telegram-purple/$PHONENUMBER directory to fix this issue. For Arch Linux users that use Bitlbee you can find this directory in `/var/lib/bitlbee/purple/telegram-purple/` - I don't see instructions for building on my Linux Distro, and/or I'm new to Linux as a whole! Help! * A: We don't know what kind of packaging system your distro has, but it has something, we're sure, so look up something like "how to install stuff on the command line in \", and familiarize yourself with the base of that command, because you probably will find yourself using it a lot. Then, use it to install git, and whatever other dependencies you need (they may be named something different, look up something like "what \ packages provide gcc" and so on for each dependency you can't find) then, do ```git clone --recursive https://github.com/majn/telegram-purple``` and ```cd telegram-purple``` then, as with most anything, the ```./configure```, ```make```, and ```sudo make install```. If you're using Linux, especially one with a young/small package repository, or missing a package manager entirely, then you will have to be open to teaching yourself a lot of stuff. Good luck! #### Group chat Telegram group chat for telegram-purple or libtgl related discussions or questions: https://bit.ly/2S539ia Submitting Bug Reports ---------------------- **IMPORTANT**: if you report bugs PLEASE make sure to always **include as much information as possible**. This should always include **at least the telegram-purple version and (if possible) commit**, where you got telegram-purple from (Source build, package repository, etc.), the Pidgin version (if you use a different messenger please state that too!) and your OS Version. If you describe some issue please be as precise as possible. Descriptions like "XY doesn't work" will not help me. Describe what you are doing what kind of issue you are experiencing: "If I click on X, Y happens, but instead I would expect Z to happen". For error reports please include the application logs. To get Pidgin to print a log, [start it from command line, specifying the -d option](https://developer.pidgin.im/wiki/GetABacktrace#TheEasyWay). **ATTENTION**: This log will contain personal information like your phone number, message content or contact or chat names. If you plan on uploading it somewhere public mask those entries in the log. Bug reports regarding crashes should include a backtrace if possible, there is extended documentation available on [how to get a backtrace for crashes](https://developer.pidgin.im/wiki/GetABacktrace) Empathy / libtelepathy ---------------------- Empathy doesn't natively support libpurple plugins since its based on libtelepathy, but there is a compatibillity layer called telepathy-haze that can be used to execute libpurple plugins. This means that you can basically run this plugin thanks to telepathy-haze but you will usually get less features and worse usability compared to real libpurple clients. If you use Empathy (or anything else based on libtelepathy) I recommend [telepathy-morse](https://projects.kde.org/projects/playground/network/telepathy/telepathy-morse/repository) which is a connection manager written specifically for your messenger. Authors ------- Telegram-Purple was written by: - Matthias Jentsch - Vitaly Valtman - Ben Wiederhake - Christopher Althaus Acknowledgements ---------------- This software is based on the library [Libtgl](https://github.com/vysheng/tgl), which was written by Vitaly Valtman and others, see (https://github.com/vysheng/tgl/) telegram-purple/autogen.sh000077500000000000000000000024731363674160100162010ustar00rootroot00000000000000#!/bin/sh set -e autoreconf ( cd po export XGETTEXT="xgettext -kP_:1,2" intltool-update --pot ## Translations are managed at https://www.transifex.com/telegram-purple-developers/telegram-purple/ ## To update the .po files, download it from there, since intltool, msginit, and transifex produce slightly different files, and I'd like to avoid gigantic git diffs that only change indentation or similar things. ## Also, for some reason, the header generated by GNU intltool does not conform to ## What GNU.org says the header should look like. So, let's fix it. ## First, check whether the header is exactly as expected. oldlines=20 tmpfile=$(mktemp) head -n ${oldlines} telegram-purple.pot | grep -v '^"POT-Creation-Date:' > ${tmpfile} if ! diff -u ${tmpfile} pot_header.old then echo "Unexpected header of telegram-purple.pot! Please check by hand." rm ${tmpfile} exit 2 fi rm ${tmpfile} ## Great, now replace the header by what we want it to be. tmpfile=$(mktemp) cat pot_header.new >> ${tmpfile} # Off by one: missing newline at end tail -n +${oldlines} telegram-purple.pot >> ${tmpfile} # Off-by-one: extra newline at beginning # Together, this works out exaclty, and saves me from computing $oldlines+1 cp ${tmpfile} telegram-purple.pot rm ${tmpfile} ) test -r Makefile || ./configure -q make --quiet build-nsi telegram-purple/commit.h.gen000077500000000000000000000025041363674160100164070ustar00rootroot00000000000000#!/bin/sh # This file is part of telegram-purple # # 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 02111-1301 USA # # Copyright Matthias Jentsch, Ben Wiederhake 2016 set -e if ! (command -v git && git status) >/dev/null 2>&1 then if test -r commit.h then echo "No git available. Assuming everything is up-to-date." exit 0 else echo >&2 "No git available. Can't reconstruct commit.h" exit 1 fi fi GIT_COMMIT=`git rev-parse HEAD | cut -c1-10` if grep -scq "${GIT_COMMIT}" commit.h then echo "commit.h is up-to-date" else echo "Refresh commit.h" echo "#ifndef GIT_COMMIT" > commit.h echo "# define GIT_COMMIT \"${GIT_COMMIT}\"" >> commit.h echo "#endif" >> commit.h fi telegram-purple/config.h.in000066400000000000000000000050531363674160100162200ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define the gettext package to be used */ #undef GETTEXT_PACKAGE /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `gcrypt' library (-lgcrypt). */ #undef HAVE_LIBGCRYPT /* Define to 1 if you have the `png' library (-lpng). */ #undef HAVE_LIBPNG /* Define to 1 if you have the `rt' library (-lrt). */ #undef HAVE_LIBRT /* Define to 1 if you have the `webp' library (-lwebp). */ #undef HAVE_LIBWEBP /* Define to 1 if you have `z' library (-lz) */ #undef HAVE_LIBZ /* Define to 1 if you have the `malloc' function. */ #undef HAVE_MALLOC /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to `unsigned int' if does not define. */ #undef size_t telegram-purple/configure000077500000000000000000005313131363674160100161070ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for telegram-purple 1.4.3. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='telegram-purple' PACKAGE_TARNAME='telegram-purple' PACKAGE_VERSION='1.4.3' PACKAGE_STRING='telegram-purple 1.4.3' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="config.h.in" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS GETTEXT_PACKAGE MSGFMT_PATH CHECK_GETTEXT PURPLE_CPPFLAGS PURPLE_LIBS PURPLE_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH EGREP GREP CPP OPENSSL_LDFLAGS OPENSSL_LIBS OPENSSL_INCLUDES PKG_CONFIG CRYPTO_FLAG INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_gcrypt with_openssl with_zlib enable_libwebp enable_libpng enable_icons enable_translation ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR PURPLE_CFLAGS PURPLE_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures telegram-purple 1.4.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/telegram-purple] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of telegram-purple 1.4.3:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-gcrypt Disable gcrypt, use OpenSSL instead. DO NOT DISTRIBUTE BINARIES! --disable-libwebp Disable libwebp, stickers won't be displayed in the chat --disable-libpng Disable libpng, stickers won't be converted --disable-icons Unsupported option. Use 'make noicon_install' instead. --disable-translation Disable gettext translation Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-openssl=DIR root of the OpenSSL directory --with-zlib=DIR root directory path of zlib installation [defaults to /usr/local or /usr if not found in /usr/local] --without-zlib to disable zlib usage completely Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path PURPLE_CFLAGS C compiler flags for PURPLE, overriding pkg-config PURPLE_LIBS linker flags for PURPLE, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF telegram-purple configure 1.4.3 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by telegram-purple $as_me 1.4.3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_openssl.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) # # DESCRIPTION # # Look for OpenSSL in a number of default spots, or in a user-selected # spot (via --with-openssl). Sets # # OPENSSL_INCLUDES to the include directives required # OPENSSL_LIBS to the -l directives required # OPENSSL_LDFLAGS to the -L or -R flags required # # and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately # # This macro sets OPENSSL_INCLUDES such that source files should use the # openssl/ directory in include directives: # # #include # # LICENSE # # Copyright (c) 2009,2010 Zmanda Inc. # Copyright (c) 2009,2010 Dustin J. Mitchell # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 8 # This is what autoupdate's m4 run will expand. It fires # the warning (with _au_warn_XXX), outputs it into the # updated configure.ac (with AC_DIAGNOSE), and then outputs # the replacement expansion. # This is an auxiliary macro that is also run when # autoupdate runs m4. It simply calls m4_warning, but # we need a wrapper so that each warning is emitted only # once. We break the quoting in m4_warning's argument in # order to expand this macro's arguments, not AU_DEFUN's. # Finally, this is the expansion that is picked up by # autoconf. It tells the user to run autoupdate, and # then outputs the replacement expansion. We do not care # about autoupdate's warning because that contains # information on what to do *after* running autoupdate. # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_zlib.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_ZLIB([action-if-found], [action-if-not-found]) # # DESCRIPTION # # This macro searches for an installed zlib library. If nothing was # specified when calling configure, it searches first in /usr/local and # then in /usr, /opt/local and /sw. If the --with-zlib=DIR is specified, # it will try to find it in DIR/include/zlib.h and DIR/lib/libz.a. If # --without-zlib is specified, the library is not searched at all. # # If either the header file (zlib.h) or the library (libz) is not found, # shell commands 'action-if-not-found' is run. If 'action-if-not-found' is # not specified, the configuration exits on error, asking for a valid zlib # installation directory or --without-zlib. # # If both header file and library are found, shell commands # 'action-if-found' is run. If 'action-if-found' is not specified, the # default action appends '-I${ZLIB_HOME}/include' to CPFLAGS, appends # '-L$ZLIB_HOME}/lib' to LDFLAGS, prepends '-lz' to LIBS, and calls # AC_DEFINE(HAVE_LIBZ). You should use autoheader to include a definition # for this symbol in a config.h file. Sample usage in a C/C++ source is as # follows: # # #ifdef HAVE_LIBZ # #include # #endif /* HAVE_LIBZ */ # # LICENSE # # Copyright (c) 2008 Loic Dachary # Copyright (c) 2010 Bastien Chevreux # # 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, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 14 # This is what autoupdate's m4 run will expand. It fires # the warning (with _au_warn_XXX), outputs it into the # updated configure.ac (with AC_DIAGNOSE), and then outputs # the replacement expansion. # This is an auxiliary macro that is also run when # autoupdate runs m4. It simply calls m4_warning, but # we need a wrapper so that each warning is emitted only # once. We break the quoting in m4_warning's argument in # order to expand this macro's arguments, not AU_DEFUN's. # Finally, this is the expansion that is picked up by # autoconf. It tells the user to run autoupdate, and # then outputs the replacement expansion. We do not care # about autoupdate's warning because that contains # information on what to do *after* running autoupdate. # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- # PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- # _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- # _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- # PKG_CHECK_MODULES # PKG_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable pkgconfigdir as the location where a module # should install pkg-config .pc files. By default the directory is # $libdir/pkgconfig, but the default can be changed by passing # DIRECTORY. The user can override through the --with-pkgconfigdir # parameter. # PKG_NOARCH_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable noarch_pkgconfigdir as the location where a # module should install arch-independent pkg-config .pc files. By # default the directory is $datadir/pkgconfig, but the default can be # changed by passing DIRECTORY. The user can override through the # --with-noarch-pkgconfigdir parameter. # PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # ------------------------------------------- # Retrieves the value of the pkg-config variable for the given module. # PKG_CHECK_VAR # Checks for programs. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifdef NDEBUG #error "NDEBUG detected" #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else as_fn_error $? "The macro NDEBUG cannot work. All writes and reads are wrapped in asserts. For more info, see https://github.com/majn/telegram-purple/issues/429" "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 $as_echo_n "checking for clock_gettime in -lrt... " >&6; } if ${ac_cv_lib_rt_clock_gettime+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_rt_clock_gettime=yes else ac_cv_lib_rt_clock_gettime=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 $as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRT 1 _ACEOF LIBS="-lrt $LIBS" fi # Check whether --enable-gcrypt was given. if test "${enable_gcrypt+set}" = set; then : enableval=$enable_gcrypt; fi if test "x$enable_gcrypt" != "xno"; then : # Even though tgl/configure will do this too, still call our own libgcrypt check to assure that -lgcrypt is added to our makefile { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcry_mpi_snatch in -lgcrypt" >&5 $as_echo_n "checking for gcry_mpi_snatch in -lgcrypt... " >&6; } if ${ac_cv_lib_gcrypt_gcry_mpi_snatch+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgcrypt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gcry_mpi_snatch (); int main () { return gcry_mpi_snatch (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_gcrypt_gcry_mpi_snatch=yes else ac_cv_lib_gcrypt_gcry_mpi_snatch=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gcrypt_gcry_mpi_snatch" >&5 $as_echo "$ac_cv_lib_gcrypt_gcry_mpi_snatch" >&6; } if test "x$ac_cv_lib_gcrypt_gcry_mpi_snatch" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBGCRYPT 1 _ACEOF LIBS="-lgcrypt $LIBS" else as_fn_error $? "no libgcrypt >= 1.60 found. If its not available try --disable-gcrypt to link against openssl, but in that case YOU MAY NOT REDISTRIBUTE THE BINARY due to licensing restrictions." "$LINENO" 5 fi CRYPTO_FLAG=--disable-openssl else found=false # Check whether --with-openssl was given. if test "${with_openssl+set}" = set; then : withval=$with_openssl; case "$withval" in "" | y | ye | yes | n | no) as_fn_error $? "Invalid --with-openssl value" "$LINENO" 5 ;; *) ssldirs="$withval" ;; esac else # if pkg-config is installed and openssl has installed a .pc file, # then use that information and don't search ssldirs # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$PKG_CONFIG" != x""; then OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` if test $? = 0; then OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` found=true fi fi # no such luck; use some default ssldirs if ! $found; then ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" fi fi # note that we #include , so the OpenSSL headers have to be in # an 'openssl' subdirectory if ! $found; then OPENSSL_INCLUDES= for ssldir in $ssldirs; do { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $ssldir" >&5 $as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; } if test -f "$ssldir/include/openssl/ssl.h"; then OPENSSL_INCLUDES="-I$ssldir/include" OPENSSL_LDFLAGS="-L$ssldir/lib" OPENSSL_LIBS="-lssl -lcrypto" found=true { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } break else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi done # if the file wasn't found, well, go ahead and try the link anyway -- maybe # it will just work! fi # try the preprocessor and linker with our new flags, # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5 $as_echo_n "checking whether compiling and linking against OpenSSL works... " >&6; } echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&5 save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" LIBS="$OPENSSL_LIBS $LIBS" CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { SSL_new(NULL) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } No openssl found. fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # # Handle user hints # { $as_echo "$as_me:${as_lineno-$LINENO}: checking if zlib is wanted" >&5 $as_echo_n "checking if zlib is wanted... " >&6; } zlib_places="/usr/local /usr /opt/local /sw" # Check whether --with-zlib was given. if test "${with_zlib+set}" = set; then : withval=$with_zlib; if test "$withval" != no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } if test -d "$withval" then zlib_places="$withval $zlib_places" else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sorry, $withval does not exist, checking usual places" >&5 $as_echo "$as_me: WARNING: Sorry, $withval does not exist, checking usual places" >&2;} fi else zlib_places= { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi # # Locate zlib, if wanted # if test -n "${zlib_places}" then # check the user supplied or any other more or less 'standard' place: # Most UNIX systems : /usr/local and /usr # MacPorts / Fink on OSX : /opt/local respectively /sw for ZLIB_HOME in ${zlib_places} ; do if test -f "${ZLIB_HOME}/include/zlib.h"; then break; fi ZLIB_HOME="" done ZLIB_OLD_LDFLAGS=$LDFLAGS ZLIB_OLD_CPPFLAGS=$CPPFLAGS if test -n "${ZLIB_HOME}"; then LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateEnd in -lz" >&5 $as_echo_n "checking for inflateEnd in -lz... " >&6; } if ${ac_cv_lib_z_inflateEnd+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inflateEnd (); int main () { return inflateEnd (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_inflateEnd=yes else ac_cv_lib_z_inflateEnd=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateEnd" >&5 $as_echo "$ac_cv_lib_z_inflateEnd" >&6; } if test "x$ac_cv_lib_z_inflateEnd" = xyes; then : zlib_cv_libz=yes else zlib_cv_libz=no fi ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes; then : zlib_cv_zlib_h=yes else zlib_cv_zlib_h=no fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test "$zlib_cv_libz" = "yes" && test "$zlib_cv_zlib_h" = "yes" then # # If both library and header were found, action-if-found # CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" LIBS="-lz $LIBS" $as_echo "#define HAVE_LIBZ 1" >>confdefs.h else # # If either header or library was not found, action-if-not-found # as_fn_error $? "No zlib found" "$LINENO" 5 fi fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PURPLE" >&5 $as_echo_n "checking for PURPLE... " >&6; } if test -n "$PURPLE_CFLAGS"; then pkg_cv_PURPLE_CFLAGS="$PURPLE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"purple\""; } >&5 ($PKG_CONFIG --exists --print-errors "purple") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PURPLE_CFLAGS=`$PKG_CONFIG --cflags "purple" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$PURPLE_LIBS"; then pkg_cv_PURPLE_LIBS="$PURPLE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"purple\""; } >&5 ($PKG_CONFIG --exists --print-errors "purple") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PURPLE_LIBS=`$PKG_CONFIG --libs "purple" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then PURPLE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "purple" 2>&1` else PURPLE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "purple" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PURPLE_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (purple) were not met: $PURPLE_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables PURPLE_CFLAGS and PURPLE_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables PURPLE_CFLAGS and PURPLE_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else PURPLE_CFLAGS=$pkg_cv_PURPLE_CFLAGS PURPLE_LIBS=$pkg_cv_PURPLE_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libwebp" >&5 $as_echo_n "checking for libwebp... " >&6; } # Check whether --enable-libwebp was given. if test "${enable_libwebp+set}" = set; then : enableval=$enable_libwebp; fi if test "x$enable_libwebp" != "xno"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 $as_echo "enabled" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for WebPDecodeRGBA in -lwebp" >&5 $as_echo_n "checking for WebPDecodeRGBA in -lwebp... " >&6; } if ${ac_cv_lib_webp_WebPDecodeRGBA+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lwebp $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char WebPDecodeRGBA (); int main () { return WebPDecodeRGBA (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_webp_WebPDecodeRGBA=yes else ac_cv_lib_webp_WebPDecodeRGBA=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_webp_WebPDecodeRGBA" >&5 $as_echo "$ac_cv_lib_webp_WebPDecodeRGBA" >&6; } if test "x$ac_cv_lib_webp_WebPDecodeRGBA" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBWEBP 1 _ACEOF LIBS="-lwebp $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing WebPDecodeRGBA" >&5 $as_echo_n "checking for library containing WebPDecodeRGBA... " >&6; } if ${ac_cv_search_WebPDecodeRGBA+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char WebPDecodeRGBA (); int main () { return WebPDecodeRGBA (); ; return 0; } _ACEOF for ac_lib in '' webp-7; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_WebPDecodeRGBA=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_WebPDecodeRGBA+:} false; then : break fi done if ${ac_cv_search_WebPDecodeRGBA+:} false; then : else ac_cv_search_WebPDecodeRGBA=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_WebPDecodeRGBA" >&5 $as_echo "$ac_cv_search_WebPDecodeRGBA" >&6; } ac_res=$ac_cv_search_WebPDecodeRGBA if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else as_fn_error $? "no libwebp found, try --disable-libwebp, but stickers won't be displayed in the chat" "$LINENO" 5 fi # If we get here, then it's one of the special-case scenarios. # So we *do* want to set 'HAVE_LIBWEBP' to 1. But because the primary check # failed, it would now go to "undefined". # Therefore, override it: $as_echo "#define HAVE_LIBWEBP 1" >>confdefs.h fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libpng" >&5 $as_echo_n "checking for libpng... " >&6; } # Check whether --enable-libpng was given. if test "${enable_libpng+set}" = set; then : enableval=$enable_libpng; fi if test "x$enable_libpng" != "xno"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 $as_echo "enabled" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for png_write_png in -lpng" >&5 $as_echo_n "checking for png_write_png in -lpng... " >&6; } if ${ac_cv_lib_png_png_write_png+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpng $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char png_write_png (); int main () { return png_write_png (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_png_png_write_png=yes else ac_cv_lib_png_png_write_png=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_png_png_write_png" >&5 $as_echo "$ac_cv_lib_png_png_write_png" >&6; } if test "x$ac_cv_lib_png_png_write_png" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPNG 1 _ACEOF LIBS="-lpng $LIBS" else as_fn_error $? "no libpng found, try --disable-libpng" "$LINENO" 5 fi fi # Check whether --enable-icons was given. if test "${enable_icons+set}" = set; then : enableval=$enable_icons; fi if test "x$enable_icons" == "xno"; then : as_fn_error $? "--disable-icons is now obsolete. Please use 'make noicon_install' for the same effect." "$LINENO" 5 fi # Checks for header files. for ac_header in arpa/inet.h fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Checks for typedefs, structures, and compiler characteristics. ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi # Checks for library functions. for ac_func in malloc memset strdup do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # Check whether --enable-translation was given. if test "${enable_translation+set}" = set; then : enableval=$enable_translation; fi if test "x$enable_translation" != "xno"; then : # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CHECK_GETTEXT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CHECK_GETTEXT"; then ac_cv_prog_CHECK_GETTEXT="$CHECK_GETTEXT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CHECK_GETTEXT=""yes"" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CHECK_GETTEXT" && ac_cv_prog_CHECK_GETTEXT=""no"" fi fi CHECK_GETTEXT=$ac_cv_prog_CHECK_GETTEXT if test -n "$CHECK_GETTEXT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CHECK_GETTEXT" >&5 $as_echo "$CHECK_GETTEXT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$CHECK_GETTEXT" != x"yes" ; then as_fn_error $? "no gettext found, use --disable-translation if you dont need it." "$LINENO" 5 fi MSGFMT_PATH=$(which msgfmt) fi # Define the domain name for the translated words GETTEXT_PACKAGE=$PACKAGE_NAME cat >>confdefs.h <<_ACEOF #define GETTEXT_PACKAGE "$GETTEXT_PACKAGE" _ACEOF ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by telegram-purple $as_me 1.4.3, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ telegram-purple config.status 1.4.3 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi telegram-purple/configure.ac000066400000000000000000000110021363674160100164520ustar00rootroot00000000000000# This file is part of telegram-purple # # 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 02111-1301 USA # # Copyright Matthias Jentsch, Vitaly Valtman, Christopher Althaus, Markus Endres 2014-2015 # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([telegram-purple], [1.4.3]) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) m4_include([m4_ax_check_openssl.m4]) m4_include([m4_ax_check_zlib.m4]) m4_include([m4_ax_pkg_config.m4]) # Checks for programs. AC_PROG_CC AC_PROG_INSTALL AC_TRY_COMPILE([], [ #ifdef NDEBUG #error "NDEBUG detected" #endif], [], [AC_MSG_ERROR([The macro NDEBUG cannot work. All writes and reads are wrapped in asserts. For more info, see https://github.com/majn/telegram-purple/issues/429])]) AC_CHECK_LIB([rt], [clock_gettime]) AC_ARG_ENABLE([gcrypt], AS_HELP_STRING([--disable-gcrypt], [Disable gcrypt, use OpenSSL instead. DO NOT DISTRIBUTE BINARIES!])) AS_IF([test "x$enable_gcrypt" != "xno"], [ # Even though tgl/configure will do this too, still call our own libgcrypt check to assure that -lgcrypt is added to our makefile AC_CHECK_LIB([gcrypt], [gcry_mpi_snatch], [], [ AC_MSG_ERROR([no libgcrypt >= 1.60 found. If its not available try --disable-gcrypt to link against openssl, but in that case YOU MAY NOT REDISTRIBUTE THE BINARY due to licensing restrictions.]) ]) AC_SUBST([CRYPTO_FLAG], [--disable-openssl]) ], [ AX_CHECK_OPENSSL([], [No openssl found.]) ]) AX_CHECK_ZLIB(, [AC_MSG_ERROR([No zlib found])]) PKG_CHECK_MODULES([PURPLE], [purple]) AC_MSG_CHECKING([for libwebp]) AC_ARG_ENABLE([libwebp], AS_HELP_STRING([--disable-libwebp], [Disable libwebp, stickers won't be displayed in the chat])) AS_IF([test "x$enable_libwebp" != "xno"], [ AC_MSG_RESULT([enabled]) AC_CHECK_LIB([webp], [WebPDecodeRGBA], [], [ AC_SEARCH_LIBS([WebPDecodeRGBA], [webp-7], [], [AC_MSG_ERROR([no libwebp found, try --disable-libwebp, but stickers won't be displayed in the chat])]) # If we get here, then it's one of the special-case scenarios. # So we *do* want to set 'HAVE_LIBWEBP' to 1. But because the primary check # failed, it would now go to "undefined". # Therefore, override it: AC_DEFINE(HAVE_LIBWEBP, 1) ]) ]) AC_MSG_CHECKING([for libpng]) AC_ARG_ENABLE([libpng], AS_HELP_STRING([--disable-libpng], [Disable libpng, stickers won't be converted])) AS_IF([test "x$enable_libpng" != "xno"], [ AC_MSG_RESULT([enabled]) AC_CHECK_LIB([png], [png_write_png], [], [AC_MSG_ERROR([no libpng found, try --disable-libpng])]) ]) AC_ARG_ENABLE([icons], AS_HELP_STRING([--disable-icons], [Unsupported option. Use 'make noicon_install' instead.])) AS_IF([test "x$enable_icons" == "xno"], [ AC_MSG_ERROR([--disable-icons is now obsolete. Please use 'make noicon_install' for the same effect.]) ]) # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T # Checks for library functions. AC_CHECK_FUNCS([malloc memset strdup]) AC_SUBST(PURPLE_CFLAGS) AC_SUBST(PURPLE_CPPFLAGS) AC_SUBST(PURPLE_LIBS) AC_ARG_ENABLE([translation], AS_HELP_STRING([--disable-translation], [Disable gettext translation])) AS_IF([test "x$enable_translation" != "xno"], [ AC_CHECK_PROG(CHECK_GETTEXT, msgfmt, "yes", "no", $PATH) if test x"$CHECK_GETTEXT" != x"yes" ; then AC_MSG_ERROR([no gettext found, use --disable-translation if you dont need it.]) fi AC_SUBST(MSGFMT_PATH, $(which msgfmt)) ]) # Define the domain name for the translated words GETTEXT_PACKAGE=$PACKAGE_NAME AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, ["$GETTEXT_PACKAGE"], [Define the gettext package to be used]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT telegram-purple/debian/000077500000000000000000000000001363674160100154145ustar00rootroot00000000000000telegram-purple/debian/.gitignore000066400000000000000000000001661363674160100174070ustar00rootroot00000000000000/files /telegram-purple/ /telegram-purple.* /.debhelper/ /autoreconf.after /autoreconf.before /debhelper-build-stamp telegram-purple/debian/README.source000066400000000000000000000110241363674160100175710ustar00rootroot00000000000000Packing, unpacking, and modifying (as per §4.14) ================================================ 1. Generate the fully patched source, in a form ready for editing, that would be built to create Debian packages. This step does not need any special attention. The standard invocation of "dpkg-source -x" does exactly what is needed. 2. Modify the source and save those modifications so that they will be applied when building the package. == AND == 3. Remove source modifications that are currently being applied when building the package. There is no standard procedure for this package. Please note that: - quilt seems to be the default tool for this kind of work. - git-buildpackage (gbp) might not work as expected, so I refrained from trying it for this task. See below. So far, issues reported against the project have been resolved quickly enough to avoid scenarios that usually need the d/patches/ directory. 4. Generate a *.orig.tar.gz from the git repository, e.g., upgrade the Debian source package to a new upstream version. Easy way: use the provided orig-tars, e.g., 'telegram-purple_1.2.6.orig.tar.gz' Hard way (the procedure used to create these files): $ git clone --recursive --branch debian-master \ https://github.com/majn/telegram-purple.git $ cd telegram-purple ...$ make dist The output should look like this: Refresh commit.h ./gen-origtar mv -f bin/result.tar.gz telegram-purple_deb-v1.2.4-2-161-gb5272d4.orig.tar.gz The following approaches do NOT work: - Github's "download source tar", as this leaves out submodules. - git-buildpackage (gpb). No support for submodules-within-submodules. The file README.md of the project contains some hints about how to build packages, so here's a cheat sheet: - Just build a *.deb, ideal for local use: fakeroot ./debian/rules binary - Build the package for analysis, e.g. lintian: dpkg-buildpackage - Only produce a *.dsc and *.debian.tar.xz file: ( cd .. && dpkg-source -b telegram-purple ) - Run pbuilder (needs the previous step): ( cd .. && sudo pbuilder --build telegram-purple_*.dsc ) Package name ============ At the time of writing (2016-01-03), the Debian repository contained the following libpurple-backends: - pidgin-encryption - pidgin-latex - pidgin-otr - pidgin-plugin-pack - pidgin-privacy-please So following that tradition, this package would be called "pidgin-telegram". However, this would have a lot of disadvantages: - This is a frontend-agnostic backend that works with Adium, pidgin, and Finch. We hope that it works nicely with all other frontends, too. Calling it "pidgin-something" would be highly misleading. - All error messages and their translations would need to be adapted - paths would need to change that aren't configurable - some users are expecting the name to be "telegram-purple" (at least initially) Overall, we consider this a needlessly confusing convention, and intentionally break with it. Packaging libtgl separately (as per §4.13) ========================================== No. So far, ABI-compatibility was broken between virtually every other commit to libtgl, and the library is still under development. The latest "stable" release is heavily outdated and can no longer be used productively (missing features, known breaking bugs, etc.), so if we were to package tgl we would need to repackage it constantly, with no defined concept of version, soname, or anything reliable. No other program (*including* tg-cli) can be expected to use the same version of libtgl as telegram-purple does. (This might happen every now and then, but that would be random chance. Finally, it's highly unlikely that someone installs and uses both telegram-purple and tg-cli.) Packaging "tl-parser" or the intermediate "generate" program is also a bad idea: One *could* do that, but it's only useful for libtgl. So there is a significant lack of users. Note that tl-parser is a relatively (in comparison to the rest of libtgl) stable, portable application (not library). The output format hasn't changed in a over a year. If you believe that these six files will be used by a lot of people, I'll be happy to package tl-parser for you. However, please note that this would require at least two packages: tl-parser (binary), tl-parser-dev (headers), and possibly libtl-parser (common object files). In short: there's no set of component that could be packaged in a more clever way. About this document =================== This is not written in Markdown. All formatting is in the hope of making it easy to read. telegram-purple/debian/changelog000066400000000000000000000020651363674160100172710ustar00rootroot00000000000000telegram-purple (1.4.0-1) UNRELEASED; urgency=medium * New upstream release * No longer actively try to push it into Debian: too unstable. If you really want a .deb file, see README.md in the toplevel directory. -- Ben Wiederhake Mon, 10 Apr 2017 23:31:32 +0200 telegram-purple (1.3.0-1) unstable; urgency=medium [ Hugues Morisset ] * Initial Release (Closes: #833793) [ Ben Wiederhake ] * Please note that due to the format-switch in 1.2.6, the file /etc/telegram-purple/server.pub is obsolete for all version after it. It is ignored to allow for smooth transition from old, manual installations, and may be removed in future versions. * New upstream release - Add translations and plural support - Fix lots of bugs around secret chats (still not perfect, though) - Fix behavior around hibernation - Fix display errors and false warnings - Fix crash on 'unsupported' media - Support supergroups and channels -- Ben Wiederhake Mon, 22 Aug 2016 20:59:47 +0200 telegram-purple/debian/compat000066400000000000000000000000021363674160100166120ustar00rootroot000000000000009 telegram-purple/debian/control000066400000000000000000000027571363674160100170320ustar00rootroot00000000000000Source: telegram-purple Section: net Priority: optional Maintainer: Ben Wiederhake Uploaders: Hugues Morisset Build-Depends: autotools-dev, debhelper (>= 9), dh-autoreconf, libgcrypt20-dev, libglib2.0-dev, libpurple-dev, libwebp-dev, pkg-config, zlib1g-dev, libpng-dev, git Standards-Version: 3.9.8 Homepage: https://github.com/majn/telegram-purple Vcs-Git: https://github.com/majn/telegram-purple.git Vcs-Browser: https://github.com/majn/telegram-purple Package: telegram-purple Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} Suggests: pidgin | finch Description: Purple plugin to support Telegram Plugin for purple which lets you use and manage your Telegram account like any other account in purple. Some features like self-destruct messages are currently in development. X-Comment: Traditionally, this plugin should be named "telegram-pidgin". However, this plugin is also designed to work with at least Adium, Finch, and hopefully all other libpurple-frontends, so this name would be highly misleading. Furthermore, the plugin refers to itself as "telegram-purple", and changing this (e.g. via a patch) would be highly non-trivial and fragile. Finally, several users know this plugin under the name telegram-purple only, so naming the Debian package differently would be another source of confusion. Thus we intentionally break with this tradition, and re-used the name telegram-purple from the original project. telegram-purple/debian/copyright000066400000000000000000000105771363674160100173610ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: pidgin-telegram Source: https://github.com/majn/telegram-purple Files: * Copyright: 2014-2015 Matthias Jentsch 2014 Vitaly Valtman 2014 Christopher Althaus 2014 Markus Endres License: GPL-2+ Files: AppStream/telegram-purple.metainfo.untranslated.xml Copyright: 2015 Jiri Eischmann License: GFDL-NIV License-Grant: GFDL-1.3 Files: debian/* Copyright: 2015 Hugues Morisset 2015 Ben Wiederhake License: GPL-2+ Files: tgl/* Copyright: 2013-2015 Vitaly Valtman 2015 Matthias Jentsch 2015 Ben Wiederhake License: LGPL-2.1+ Files: tgl/tl-parser/* Copyright: 2015 Matthias Jentsch 2015 Vitaly Valtman 2015 Christopher Althaus 2015 Markus Endres License: GPL-2+ Files: tgl/tl-parser/portable_endian.h Copyright: 2013-2014 Mathias Panzenböck 2015 PkmX License: BSD-3-clause or Expat or Apache-2 License-Grant: I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. In case there are jurisdictions that don't support putting things in the public domain you can also consider it to be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it an example on how to get the endian conversion functions on different platforms. FIXME: This is a tag for the sole purpose and hope that one day, someone searches for "Fixme" (possibly case-sensitive). Thus, the issue in the following "Comment" field can be found in both the Debian archive and the original project. Comment: This is a comment from the person who wrote this debian/copyright file. . The licensing was obviously meant to be "use whatever". However, we have to mirror it precisely, and verbatim. I took the freedom to interprete the terms "the MIT licenses" as "Expat"; "the BSD licenses" as BSD 3-clause; and "the Apache licenses" as Apache 2.0. I do this in order to keep the list reasonably small and close enough. However, someone who understands the legal implications should take a close look at this. License: LGPL-2.1+ On Debian systems, the complete text of the GNU Lesser General Public License can be found in "/usr/share/common-licenses/LGPL-2.1". License: GPL-2+ On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". License: BSD-3-clause On Debian systems, the complete text of the Revised BSD License (3-clause) can be found in "/usr/share/common-licenses/GPL-3". License: Apache-2 On Debian systems, the complete text of version 2.0 of the Apache License can be found in ‘/usr/share/common-licenses/Apache-2.0’. License: GFDL-NIV On Debian systems, the complete text of version 1.3 of the GNU Free Document License ‘/usr/share/common-licenses/GFDL-1.3’. License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. telegram-purple/debian/docs000066400000000000000000000000101363674160100162560ustar00rootroot00000000000000AUTHORS telegram-purple/debian/rules000077500000000000000000000014161363674160100164760ustar00rootroot00000000000000#!/usr/bin/make -f DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/default.mk %: dh $@ --parallel --with autoreconf # dh_auto_clean tries to "make distclean", but we don't have that target. override_dh_auto_clean: test ! -e Makefile || $(MAKE) clean ## http://wiki.debian.org/onlyjob/get-orig-source PKD := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) PKG := $(shell dpkg-parsechangelog -l$(PKD)/changelog --show-field=Source) VER ?= $(shell dpkg-parsechangelog -l$(PKD)/changelog --show-field=Version | cut -d- -f1) .PHONY: get-orig-source get-orig-source: $(info I: $(PKG)_$(VER)) @echo "# Downloading for ${PKD}" uscan --noconf --verbose --rename --destdir=$(CURDIR) \ --check-dirname-level=0 --force-download --download-version "$(VER)" $(PKD) telegram-purple/debian/source/000077500000000000000000000000001363674160100167145ustar00rootroot00000000000000telegram-purple/debian/source/format000066400000000000000000000000141363674160100201220ustar00rootroot000000000000003.0 (quilt) telegram-purple/debian/source/options000066400000000000000000000000771363674160100203360ustar00rootroot00000000000000extend-diff-ignore = "(^|/)(config\.(h|log|status)|Makefile)$" telegram-purple/debian/upstream/000077500000000000000000000000001363674160100172545ustar00rootroot00000000000000telegram-purple/debian/upstream/metadata000066400000000000000000000030361363674160100207610ustar00rootroot00000000000000Bug-Database: https://github.com/majn/telegram-purple/issues/ Bug-Submit: https://github.com/majn/telegram-purple/issues/new #Cite-As: telegram-purple ## Intentionally left out, to make sure that we don't accidentally break someone's ## workflow. We err on the side of not prescribing anyone how to cite this work. #Changelog: https://github.com/majn/telegram-purple/blob/master/CHANGELOG.md ## Intentionally left out as it's already outdated at the time of writing. #Contact: https://bit.ly/2S539ia ## The old goo.gl link is not in use anymore. ## The development chat group. ## Intentionally left out as the link changes constantly. ## https://github.com/majn/telegram-purple#group-chat ## for a recent link. #Donation: See 'Contact' #FAQ: https://github.com/majn/telegram-purple/#faq ## Intentionally left out: no real content yet. Name: telegram-purple ## Might be superfluous, but I want to confirm that the upstream name is ## indeed telegram-purple, hence the package name in Debian. Repository: https://github.com/majn/telegram-purple/ Repository-Browse: https://github.com/majn/telegram-purple/ Security-Contact: Main developer: Matthias Jentch Debian packager: Ben Wiederhake # Development channel (public): https://bit.ly/2S539ia ## The old goo.gl link is not in use anymore. ## Intentionally left out as the link changes constantly. ## https://github.com/majn/telegram-purple#group-chat ## for a recent link. telegram-purple/debian/watch000066400000000000000000000013531363674160100164470ustar00rootroot00000000000000version=4 opts="\ downloadurlmangle=s/tag\/v(.*)$/download\/v$1\/telegram-purple_$1.orig.tar.gz/,\ filenamemangle=s/.*tag\/v(.*)$/telegram-purple_$1.orig.tar.gz/,\ uversionmangle=s/-(beta\d*)$/~$1/,\ " \ https://github.com/majn/telegram-purple/releases \ /tag/v([\d\.]*(?:-beta\d*)?) \ debian \ uupdate # Rationales (from bottom up): # - There will always be tags of the style "v1.2.5", so search for that # - The "beta" group must be non-capturing, otherwise uscan tries to concatenate them (e.g. "1.2.3-beta.-beta") # - Github tars are unusable; use the (hopefully attached) origtar # - Beta-releases should be ordered before the "main" release (was never relevant so far) # - Spacing in order to have exactly one rule per line telegram-purple/gen-origtar000077500000000000000000000045171363674160100163450ustar00rootroot00000000000000#!/bin/sh # This file is part of telegram-purple # # 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 02111-1301 USA # # Copyright Matthias Jentsch, Ben Wiederhake 2016 set -e # -- Cleanup possibly left-over artifacts rm -f bin/tgl.tar bin/commit.h.tar bin/result.tar bin/result.tar.gz # Very old artifact rm -f bin/tgl_tl-parser.tar # Setup mkdir -p bin # -- Create parts # Abuse the "bin" dir for temporary files. ( cd tgl && git archive --prefix=telegram-purple/tgl/ --output=../bin/tgl.tar HEAD ) git archive --prefix=telegram-purple/ --output=bin/result.tar HEAD # This is a lot of options. Here's why. # --sort --mtime --owner --group => be reproducible (same commit produces binarily identical files) # --transform => be in the same "tar-folder" as the rest # (absence of --numeric-ids) => have identical behavior as git-archive # --mode=664 => have identical behavior as git-archive # http://www.gelato.unsw.edu.au/archives/git/0701/36326.html # This is hacky. TODO: Find a better way to unify permissions. tar --sort=name --mtime="1970-01-01 00:00Z" --owner=root --group=root --transform s%^%telegram-purple/% --mode=664 -cf bin/commit.h.tar commit.h # -- Concatenate it all tar --concatenate -f bin/result.tar bin/tgl.tar tar --concatenate -f bin/result.tar bin/commit.h.tar gzip -n bin/result.tar # -- Determine name and move TARNAME="telegram-purple_`git describe --tags | sed s/^v// `.orig.tar.gz" # "mv -f" means "overwrite, if necessary" echo mv -f bin/result.tar.gz $TARNAME mv -f bin/result.tar.gz $TARNAME # -- Cleanup (never fail) rm -f bin/tgl.tar bin/commit.h.tar bin/result.tar bin/result.tar.gz || true telegram-purple/imgs/000077500000000000000000000000001363674160100151315ustar00rootroot00000000000000telegram-purple/imgs/telegram.png000066400000000000000000000034721363674160100174450ustar00rootroot00000000000000PNG  IHDR@@iqIDATx[]lU蓴P$BwgR4Q/> h|P1x0|cвQcP vlwKw_ϝݲ3wInvݙ=*);RS,+vI1${WXR.^HvQ>﷉&^j[ι -PuBûU6IiIďqd2YGJA6.v rXO@̦(g,qv{_&6Hh*͊Q!PQog}60oJMPg֌O>&*)7kc%<ڦLZ@e .W!odbgb66GFasڀW2"(h &(B,b 8Dݻ.*LxyKDJ>{sCO_5~s*)/ƺyV'.-:pH!՞ "V]}C.ycgt:|sIS eӚ²C7CɜfJgv]P*d~o*B ) Sˎ~B'YwKCtzvcYVr2]zgUc=]'a]BT.}y5_Lm=Rk?\ C4d&Rs>s5w^煙kUx6B\@b  U:*Zȟf3m˿mCqH*/hfk"i:|8)F>hM|ӑX$dJ! 4C)Oj)tde/mM=](<*H#^!PhW˛PBZ2  u t q1`AV Y]v7x @a~N9zP >EuSj)1`TN ,R>qmNO0QuPW68RJs> >)PMOwK7@5G@czo$ q-U5){o/ڀѶn!~W;# aMl1? Q3MFc1)}6JT Z!x֥*:i< E9:=-_FګZIkV`h4T$UվIYyYp7CÚetxZ(&6 _+sK[zXXsѮ 3t`eSd*Q@O!R"uwRŒ+д#\'ÑeqH)3`d1oSQ` ^Q<>hّotR4ݢ*4 M+G)Gi:`084ptx\ZLo/“Vǵ cZ'N5} {mΤMCŻs);k@Tr{a~R.3kʎWf[4U:hB!Մ.Ow|3T̂|JcGfh1 +72Cd)ldf(ə.ɧ@R-R:0oO 338)|\QtX3Op'9=;x+J)Msb,:*ڈ쇧#J%9<<=yX|ux,Ne=/ɻxDT֌QpF^w%Y_z ֪%3% hnOIENDB`telegram-purple/imgs/telegram16.png000066400000000000000000000006601363674160100176100ustar00rootroot00000000000000PNG  IHDR(-SPLTE,,,,+,-,-,-,++,+,17//-,q&Rߧb_?߹\(tRNSЏ,ձ/.0IDATUW0 De;"ˢ$v#;yYi`pl(04,E=!lT%;D!"yX%Z([TM=Y>U2]n6Uvq3 +]y +RE0WY5LF,/^WVJP)!S0=R6GoQ)#==FvzЦIENDB`telegram-purple/imgs/telegram22.png000066400000000000000000000016571363674160100176140ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|dbzTXtRaw profile type APP1xUȱ 0 Sxw2BEBA WlzkGUUUϒkif^n (_-LD + HzPsIDAT8MoUs0I\%B(IT*EUb%a: 6/ @B| Y\""S3QLlC9=y \q!eЗPw 1m o~pvg4AfA<+?-}vڎPj1 B4no.MoxkG0AK.>t]v; xv ^0(TAspٵŭ+_rOpmG+7.s_hw~ʋ'Oh@&?3L8󲗶e M4e o>_dO{z!8t@a^}sO ;{Lnb!S*ERj7v|ʓL ۻĎ|ɊMV~8ik?燌ٞ QFn=h1z۟m?xn^`TaĘm$Nh~؍_ֲEm61f \YՈYVjd?}ddž(+.nU؞=͔;icJݪn`<"A) oU~=m~A t͝X/"<ZE)C8!GH*9nm`}?AXL8z7`si& U ^XZht):>5T@) Dꏗ_߀< IENDB`telegram-purple/imgs/telegram48.png000066400000000000000000000037201363674160100176150ustar00rootroot00000000000000PNG  IHDR00WsBIT|dbzTXtRaw profile type APP1xUȱ 0 Sxw2BEBA WlzkGUUUϒkif^n (_-LD + HzPsIDAThݚlTY?73ohKi,j!1fٺǺCQA &DcM0]w ]~&Ud0d)v(Lg޻? dJ; {{=wHh󣟈.ki/n&Ed9NDLqFՑeRU:}ZTl."8.EUg4QU! so;u_Hۯ3&kSIq7-ΌI;|mkQl ~ bAZ5ڿYx؎O6ۙCƘ-Xz`VmD;~z`)SZʟ[JbƓPl1KSǮ # tgdcp lif\o-@wf8c!sa6KTSEI y?Sq=,@N|?߆-pޓļx2YK?@hdi !cA;ST+wHEb-T8>`=Aͤ”U..xkZ*._.OqdY U[A"=n@@ Qîlݐᕱ}cnGUPmx2- \\hC3OOxդo#P٥4'-Yu}ײIst…N9qqvFUqlZ] ϊx)M Gsͤ` >x>WjTQ]Z *5nI:Y Kl6p%[IZ\ @DP c n"\~fGxM.MӤO 3&9>Z#s/_:uq5>>tWfhTy(&ywRǮ5bӈ;@Fx5N'wnۃ߽]EG2qj6L&H%{ x얀O̎"!%_7Ū'15_! *͜ao-}6zV!Ygdq!#Kgi{u;0?׵a&y*[J+pqi7GoW/Ѱ_FkIENDB`telegram-purple/install-sh000077500000000000000000000332551363674160100162060ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: telegram-purple/m4_ax_check_openssl.m4000066400000000000000000000101321363674160100203410ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_openssl.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) # # DESCRIPTION # # Look for OpenSSL in a number of default spots, or in a user-selected # spot (via --with-openssl). Sets # # OPENSSL_INCLUDES to the include directives required # OPENSSL_LIBS to the -l directives required # OPENSSL_LDFLAGS to the -L or -R flags required # # and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately # # This macro sets OPENSSL_INCLUDES such that source files should use the # openssl/ directory in include directives: # # #include # # LICENSE # # Copyright (c) 2009,2010 Zmanda Inc. # Copyright (c) 2009,2010 Dustin J. Mitchell # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 8 AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) AC_DEFUN([AX_CHECK_OPENSSL], [ found=false AC_ARG_WITH([openssl], [AS_HELP_STRING([--with-openssl=DIR], [root of the OpenSSL directory])], [ case "$withval" in "" | y | ye | yes | n | no) AC_MSG_ERROR([Invalid --with-openssl value]) ;; *) ssldirs="$withval" ;; esac ], [ # if pkg-config is installed and openssl has installed a .pc file, # then use that information and don't search ssldirs AC_PATH_PROG([PKG_CONFIG], [pkg-config]) if test x"$PKG_CONFIG" != x""; then OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` if test $? = 0; then OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` found=true fi fi # no such luck; use some default ssldirs if ! $found; then ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" fi ] ) # note that we #include , so the OpenSSL headers have to be in # an 'openssl' subdirectory if ! $found; then OPENSSL_INCLUDES= for ssldir in $ssldirs; do AC_MSG_CHECKING([for openssl/ssl.h in $ssldir]) if test -f "$ssldir/include/openssl/ssl.h"; then OPENSSL_INCLUDES="-I$ssldir/include" OPENSSL_LDFLAGS="-L$ssldir/lib" OPENSSL_LIBS="-lssl -lcrypto" found=true AC_MSG_RESULT([yes]) break else AC_MSG_RESULT([no]) fi done # if the file wasn't found, well, go ahead and try the link anyway -- maybe # it will just work! fi # try the preprocessor and linker with our new flags, # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS AC_MSG_CHECKING([whether compiling and linking against OpenSSL works]) echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" LIBS="$OPENSSL_LIBS $LIBS" CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" AC_LINK_IFELSE( [AC_LANG_PROGRAM([#include ], [SSL_new(NULL)])], [ AC_MSG_RESULT([yes]) $1 ], [ AC_MSG_RESULT([no]) $2 ]) CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" AC_SUBST([OPENSSL_INCLUDES]) AC_SUBST([OPENSSL_LIBS]) AC_SUBST([OPENSSL_LDFLAGS]) ]) telegram-purple/m4_ax_check_zlib.m4000066400000000000000000000124501363674160100176230ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_zlib.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_ZLIB([action-if-found], [action-if-not-found]) # # DESCRIPTION # # This macro searches for an installed zlib library. If nothing was # specified when calling configure, it searches first in /usr/local and # then in /usr, /opt/local and /sw. If the --with-zlib=DIR is specified, # it will try to find it in DIR/include/zlib.h and DIR/lib/libz.a. If # --without-zlib is specified, the library is not searched at all. # # If either the header file (zlib.h) or the library (libz) is not found, # shell commands 'action-if-not-found' is run. If 'action-if-not-found' is # not specified, the configuration exits on error, asking for a valid zlib # installation directory or --without-zlib. # # If both header file and library are found, shell commands # 'action-if-found' is run. If 'action-if-found' is not specified, the # default action appends '-I${ZLIB_HOME}/include' to CPFLAGS, appends # '-L$ZLIB_HOME}/lib' to LDFLAGS, prepends '-lz' to LIBS, and calls # AC_DEFINE(HAVE_LIBZ). You should use autoheader to include a definition # for this symbol in a config.h file. Sample usage in a C/C++ source is as # follows: # # #ifdef HAVE_LIBZ # #include # #endif /* HAVE_LIBZ */ # # LICENSE # # Copyright (c) 2008 Loic Dachary # Copyright (c) 2010 Bastien Chevreux # # 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, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 14 AU_ALIAS([CHECK_ZLIB], [AX_CHECK_ZLIB]) AC_DEFUN([AX_CHECK_ZLIB], # # Handle user hints # [AC_MSG_CHECKING(if zlib is wanted) zlib_places="/usr/local /usr /opt/local /sw" AC_ARG_WITH([zlib], [ --with-zlib=DIR root directory path of zlib installation @<:@defaults to /usr/local or /usr if not found in /usr/local@:>@ --without-zlib to disable zlib usage completely], [if test "$withval" != no ; then AC_MSG_RESULT(yes) if test -d "$withval" then zlib_places="$withval $zlib_places" else AC_MSG_WARN([Sorry, $withval does not exist, checking usual places]) fi else zlib_places= AC_MSG_RESULT(no) fi], [AC_MSG_RESULT(yes)]) # # Locate zlib, if wanted # if test -n "${zlib_places}" then # check the user supplied or any other more or less 'standard' place: # Most UNIX systems : /usr/local and /usr # MacPorts / Fink on OSX : /opt/local respectively /sw for ZLIB_HOME in ${zlib_places} ; do if test -f "${ZLIB_HOME}/include/zlib.h"; then break; fi ZLIB_HOME="" done ZLIB_OLD_LDFLAGS=$LDFLAGS ZLIB_OLD_CPPFLAGS=$CPPFLAGS if test -n "${ZLIB_HOME}"; then LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" fi AC_LANG_SAVE AC_LANG_C AC_CHECK_LIB([z], [inflateEnd], [zlib_cv_libz=yes], [zlib_cv_libz=no]) AC_CHECK_HEADER([zlib.h], [zlib_cv_zlib_h=yes], [zlib_cv_zlib_h=no]) AC_LANG_RESTORE if test "$zlib_cv_libz" = "yes" && test "$zlib_cv_zlib_h" = "yes" then # # If both library and header were found, action-if-found # m4_ifblank([$1],[ CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" LIBS="-lz $LIBS" AC_DEFINE([HAVE_LIBZ], [1], [Define to 1 if you have `z' library (-lz)]) ],[ # Restore variables LDFLAGS="$ZLIB_OLD_LDFLAGS" CPPFLAGS="$ZLIB_OLD_CPPFLAGS" $1 ]) else # # If either header or library was not found, action-if-not-found # m4_default([$2],[ AC_MSG_ERROR([either specify a valid zlib installation with --with-zlib=DIR or disable zlib usage with --without-zlib]) ]) fi fi ]) telegram-purple/m4_ax_pkg_config.m4000066400000000000000000000171671363674160100176460ustar00rootroot00000000000000# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES # PKG_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable pkgconfigdir as the location where a module # should install pkg-config .pc files. By default the directory is # $libdir/pkgconfig, but the default can be changed by passing # DIRECTORY. The user can override through the --with-pkgconfigdir # parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_INSTALLDIR # PKG_NOARCH_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable noarch_pkgconfigdir as the location where a # module should install arch-independent pkg-config .pc files. By # default the directory is $datadir/pkgconfig, but the default can be # changed by passing DIRECTORY. The user can override through the # --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_NOARCH_INSTALLDIR # PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # ------------------------------------------- # Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])# PKG_CHECK_VAR telegram-purple/mkwindows.sh000077500000000000000000000321431363674160100165560ustar00rootroot00000000000000#!/bin/sh # This file is part of telegram-purple # # 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 02111-1301 USA # # Copyright Ben Wiederhake 2017-2018 set -e # === What flavor? === if [ -z "${USE_WEBP}" ] then USE_WEBP=y # Otherwise: # USE_WEBP=n else echo "Note: webp disabled" fi if [ -z "${USE_PNG}" ] then USE_PNG=y # Otherwise: # USE_PNG=n else echo "Note: png disabled" fi if [ -z "${USE_VERSIONINFO}" ] then USE_VERSIONINFO=y # Otherwise: # USE_VERSIONINFO=n fi if [ -z "${USE_REPRODUCIBLE}" ] then USE_REPRODUCIBLE=y # Otherwise: # USE_REPRODUCIBLE=n FAKETIME="with_faketime" SOURCE_DATE_EPOCH="$(git log -1 --date='format:%s' --format=%cd)" FAKETIME_DATETIME="$(git log -1 --date=iso --format=%cd)" with_faketime () { showargs faketime -f "${FAKETIME_DATETIME}" "$@" faketime -f "${FAKETIME_DATETIME}" "$@" } else FAKETIME="" SOURCE_DATE_EPOCH="" fi # Other flags go here, i.e., libpng # === Set up environment. === # If you want to run parts by hand, these might be helpful. # These are *all* variables used anywhere in the script. # Sigh. HOST_MACHINE="$(uname -m)" HOST="${HOST_MACHINE}-linux-gnu" # MinGW MINGW_MACHINE="i686" MINGW_TARGET="${MINGW_MACHINE}-w64-mingw32" MINGW_BASE=/usr/${MINGW_TARGET} # WebP compilation WEBP_INSTALL_DIR="objs/webp/install/" mkdir -p ${WEBP_INSTALL_DIR} # Needed for realpath WEBP_INSTALL_DIR_FULL="$(realpath ${WEBP_INSTALL_DIR})" WEBP_BUILD_DIR="objs/webp/build/" # Win32 references # Sadly, the library paths must be resolved *now* already. # AND, they must be absolute. Sigh. mkdir -p win32 WIN32_GTK_DEV_DIR=$(realpath win32/gtk+-bundle_2.24.10-20120208_win32) WIN32_PIDGIN_DIR=$(realpath win32/pidgin-2.13.0) WIN32_WEBP_PRISTINE="win32/libwebp-1.0.2/" # Versioning information ./configure -q make commit.h VERSION=$(grep -E 'PACKAGE_VERSION' config.h | sed -re 's/^.*"(.*)".*$/\1/') COMMIT=$(grep -E 'define' commit.h | sed -re 's/^.*"(.*)".*$/\1/') # === Ensure that all tools are available. === # Commands for cmd in faketime file make makensis "${MINGW_TARGET}-gcc" realpath sed tar unzip ; do if ! command -v "$cmd" >/dev/null 2>&1 ; then echo "No '$cmd' available. Are you sure you know what you're doing?" exit 1 fi done # Fail-early for some obvious dependencies: if [ ! -r "${MINGW_BASE}/bin/libgcrypt-20.dll" ] ; then echo "You're probably missing libgcrypt-mingw-w64-dev or so." echo "Expected file: ${MINGW_BASE}/bin/libgcrypt-20.dll" echo "For non-Debian systems, this could be a false positive, though." exit 1 fi if [ ! -r "${MINGW_BASE}/include/gpg-error.h" ] ; then echo "You're probably missing libgpg-error-mingw-w64-dev or so." echo "Expected file: ${MINGW_BASE}/include/gpg-error.h" echo "For non-Debian systems, this could be a false positive, though." exit 1 fi if [ ! -r "${MINGW_BASE}/lib/zlib1.dll" ] ; then echo "You're probably missing libz-mingw-w64 or so." echo "Expected file: ${MINGW_BASE}/lib/zlib1.dll" echo "For non-Debian systems, this could be a false positive, though." exit 1 fi if [ ! -r "${MINGW_BASE}/include/zlib.h" ] ; then echo "You're probably missing libz-mingw-w64-dev or so." echo "Expected file: ${MINGW_BASE}/include/zlib.h" echo "For non-Debian systems, this could be a false positive, though." exit 1 fi # === Download all sources === echo "===== 01: Prepare sources" make clean download_win32_sources # === Build libpng and libwebp === # Sadly, we cannot use the pre-built binaries from Google, # as they are built with MVSC and that seems to be incompatible with MinGW. # Specifically, reading their libwebp.lib (requires special linker flags to # find that file) fails with the error "corrupt .drectve at end of def file". # GCC version 6.3.0 20170516 (GCC) echo "===== 02: Cross-compile libpng, libwebp" if [ "n" = "${USE_WEBP}" ] then echo " Skipping webp" else mkdir -p "${WEBP_INSTALL_DIR}" # -a to (hopefully) preserve some timestamps cp -ar "${WIN32_WEBP_PRISTINE}" "${WEBP_BUILD_DIR}" ( cd "${WEBP_BUILD_DIR}" # ./autogen.sh && ./configure && make ./autogen.sh WEBP_LDFLAGS="" WEBP_CFLAGS="-g -O2 -pthread" # Default CFLAGS. Why can't I just add some? if [ "y" = "${USE_REPRODUCIBLE}" ] then # Check if -fstack-protector-strong is supported before enabling it WEBP_CC=i686-w64-mingw32-gcc if ${WEBP_CC} -fstack-protector-strong 2>&1 | grep -q 'stack-protector-strong' then true # Don't add flag: not supported. else WEBP_CFLAGS="${WEBP_CFLAGS} -fstack-protector-strong" fi # Check if -frandom-seed is supported before enabling it if ${WEBP_CC} -frandom-seed=77e0418a98676b76729b50fe91cc1f250c14fd8f664f8430649487a6f918926d 2>&1 | grep -q 'random-seed' then true # Don't add flag: not supported. else WEBP_CFLAGS="${WEBP_CFLAGS} "'-frandom-seed=0x$$(sha256sum $< | cut -f1 -d" ")' fi # Check if -ffile-prefix-map is supported before enabling it if ${WEBP_CC} -ffile-prefix-map=/foo/bar/baz=/quux 2>&1 | grep -q 'file-prefix-map' then true # Don't add flag: not supported. else WEBP_CFLAGS="${WEBP_CFLAGS} -ffile-prefix-map=$(realpath .)=webp" fi fi # Disable linking against PNG, JPEG, TIFF, GIF, WIC, # as those would either need cross-compilation, too, or some other magic. # libtoolize (called by autoreconf, called by autogen.sh) must not see # `install-sh` because it would become confused by it. # That's why the hierarchy is so deep. ./configure -q --build ${HOST} --host ${MINGW_TARGET} --target ${MINGW_TARGET} \ --disable-dependency-tracking --prefix="${WEBP_INSTALL_DIR_FULL}/" \ --disable-static --enable-shared \ --enable-swap-16bit-csp \ --disable-libwebpmux --disable-libwebpdemux \ --disable-libwebpdecoder --disable-libwebpextras \ --disable-png --disable-jpeg --disable-tiff --disable-gif --disable-wic # The warning # "configure: WARNING: using cross tools not prefixed with host triplet" # stems from the fact that 'mt' (magnetic tape control) is not available # for i686-w64-mingw32, so the x86_64 version is used. We can ignore that. # For some reason, "--no-insert-timestamp" doesn't seem to work. # To make the timestamp in the final DLL reproducible, use the time of # the last commit instead. ${FAKETIME} make --quiet -j4 CFLAGS="${WEBP_CFLAGS}" LDFLAGS="${WEBP_LDFLAGS}" install ) if [ ! -r ${WEBP_INSTALL_DIR}/include/webp/decode.h ] || [ ! -r ${WEBP_INSTALL_DIR}/bin/libwebp-7.dll ] ; then # I expect that cross-compiling webp is going to be very fragile, # so print a nice error in case this happens. echo "Cross-compilation apparently failed:" echo "Some files in ${WEBP_INSTALL_DIR} are missing." echo "Please submit a bugreport." exit 1 fi mkdir -p contrib cp ${WEBP_INSTALL_DIR}/bin/libwebp-7.dll contrib fi # === Build auto-gen files === # Create and backup all auto/ files echo "===== 03: Create those precious executables" make tgl/Makefile cd tgl && git checkout tl-parser/tl-parser.c tl-parser/tlc.c && cd .. make -C tgl -j4 bin/generate bin/tl-parser make bin tar cf bin/tgl-bin.tar tgl/bin/ # === Cross-compilation itself === # Clean tgl only (do not touch bin/ with the auto-gen files!) echo "===== 04: Cleanup tgl" make -C tgl clean # Reconfigure echo "===== 05: Configure for cross-compilation" # Must first configure telegram-purple, otherwise it thinks tgl/Makefile is outdated. if [ "y" = "${USE_WEBP}" ] then LDFLAGS_WEBP="-L${WEBP_INSTALL_DIR_FULL}/bin" CONFFLAGS_WEBP="--enable-libwebp" fi if [ "y" = "${USE_PNG}" ] then # Library should already be present in win32/gtk+-bundle_2.24.10-20120208_win32/lib CONFFLAGS_PNG="--enable-libpng" fi # pkg-config is used to find the right directories for icons, library, etc on linux. # For Windows, this is already hardcoded in telegram-purple.nsi, so pkg-config isn't needed. PKG_CONFIG=/bin/false ./configure -q --build ${HOST} --host ${MINGW_TARGET} --target ${MINGW_TARGET} \ --disable-libpng --disable-libwebp \ --with-zlib="${MINGW_BASE}" \ PURPLE_CFLAGS="\${WIN32_INC}" \ PURPLE_LIBS="-lpurple -lglib-2.0" \ LDFLAGS="-L${WIN32_GTK_DEV_DIR}/lib -L${WIN32_PIDGIN_DIR}-win32bin ${LDFLAGS_WEBP}" \ LIBS="-lssp -lintl -lws2_32" \ ${CONFFLAGS_WEBP} ${CONFFLAGS_PNG} ( cd tgl ./configure -q --build ${HOST} --host ${MINGW_TARGET} --target ${MINGW_TARGET} \ --disable-openssl --disable-extf \ --with-zlib="${MINGW_BASE}" \ LIBS="-lssp" ) # Pretend we're building up the preliminaries for auto/ echo "===== 06: Compile tgl, pre-'generate' files" # Need to override LOCAL_LDFLAGS to remove '-rdynamic'. echo " In case this fails mysteriously with some 'file stubs-32.h not found':" echo " You're probably missing libc6-dev-i386 or some other dev files." # Don't care about unportability of tl-parser echo 'int main(){return 1;}' > tgl/tl-parser/tl-parser.c echo ' ' > tgl/tl-parser/tlc.c make -C tgl -j4 LOCAL_LDFLAGS="-lz -lgcrypt -lssp -ggdb" bin/generate bin/tl-parser # Surprise! Don't use the host bin/generate and bin/tl-parser to create the autogen files, # but instead use the *build* versions. The advantage: we can actually run them! echo "===== 07: Inject binaries" tar xf bin/tgl-bin.tar --touch # Just DO IT! echo "===== 08: Compile tgl, post-'generate' files" make -C tgl -j4 LOCAL_LDFLAGS="-lz -lgcrypt -lssp -ggdb" libs/libtgl.a # Don't let your DREAMS stay DREAMS! echo "===== 09: Compile telegram-purple" # Optionally, prepare and add the "resources" file. VERSIONINFO_OBJECTS="" if [ "y" = "${USE_VERSIONINFO}" ] then make objs commit.h cat < objs/info.rc #include "../commit.h" 1 VERSIONINFO FILEVERSION MAGIC_SED_VERSION BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "0409" BEGIN VALUE "FileDescription", "Telegram protocol plug-in for libpurple" VALUE "FileVersion", GIT_COMMIT END END END EOFRC COMMA_VERSION=$(grep -E 'PACKAGE_VERSION' config.h | sed -re 's/^.*"(.*)".*$/\1/' -e 's/\./,/g') sed -i -re "s/MAGIC_SED_VERSION/${COMMA_VERSION}/" objs/info.rc ${MINGW_TARGET}-windres objs/info.rc -O coff -o objs/info.res VERSIONINFO_OBJECTS="objs/info.res" fi # CFLAGS: Remove LOCALEDIR definition. # PRPL_NAME: Assign Windows-specific name. # (Baked into the file, so we can't just rename it.) # LDFLAGS: Remove -rdynamic flag. ${FAKETIME} make -j4 bin/libtelegram.dll \ CFLAGS_INTL="-DENABLE_NLS -DSOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}" \ PRPL_NAME=libtelegram.dll \ EXTRA_OBJECTS="${VERSIONINFO_OBJECTS}" \ LDFLAGS_EXTRA=-ggdb # Package it up echo "===== 10: Create installer" make PRPL_NAME=libtelegram.dll win-installer-deps VARIANT_SUFFIX="" if [ "y" != "${USE_PNG}" ] then VARIANT_SUFFIX="${VARIANT_SUFFIX}_nopng" fi if [ "y" != "${USE_WEBP}" ] then VARIANT_SUFFIX="${VARIANT_SUFFIX}_nowebp" fi if [ "y" != "${USE_REPRODUCIBLE}" ] then VARIANT_SUFFIX="${VARIANT_SUFFIX}_norepro" # makensis packages the file mtimes. I don't think this can be changed, # and the project seems too slow to ever introduce a feature like that. # Therefore, we need to "fix" the mtimes. # The following files cannot be modified: # ${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico # ${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico # But thankfully, Debian's package system includes mtime, # so the time stamps are set by the pyckage version of nsis. touch --no-create --date FAKETIME_DATETIME \ bin/libtelegram.dll contrib/libgcc_s_sjlj-1.dll contrib/libgpg-error-0.dll \ contrib/libgcrypt-20.dll contrib/libwebp-7.dll po/*.mo COPYING imgs/* fi if [ "i686" != "${MINGW_MACHINE}" ] then VARIANT_SUFFIX="${VARIANT_SUFFIX}_${MINGW_MACHINE}" fi ${FAKETIME} makensis -DPLUGIN_VERSION="${VERSION}+g${COMMIT}${VARIANT_SUFFIX}" -DPRPL_NAME=libtelegram.dll \ -DWIN32_DEV_TOP=contrib telegram-purple.nsi # There's no monster under your bed, I swear. echo "===== 11: Unspoof files" # Stealth cleanup ( cd tgl && git checkout tl-parser/tl-parser.c tl-parser/tlc.c ) echo "===== COMPLETE: All done. Installer executable is in top directory." telegram-purple/msglog.c000066400000000000000000000075241363674160100156360ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #include #include #include "telegram-purple.h" /* msglog.c: Convenience methods for logging to libpurple log */ void log_level_printf (const char* format, va_list ap, int level) { char buffer[256]; vsnprintf (buffer, sizeof(buffer), format, ap); int last = (int)strlen (buffer) - 1; if (last >= 2 && buffer[last] == '\n') { buffer[last] = '\0'; } purple_debug (level, PLUGIN_ID, "%s\n", buffer); } void debug(const char* format, ...) { va_list ap; va_start (ap, format); log_level_printf (format, ap, PURPLE_DEBUG_MISC); va_end (ap); } void info(const char* format, ...) { va_list ap; va_start (ap, format); log_level_printf (format, ap, PURPLE_DEBUG_INFO); va_end (ap); } void warning(const char* format, ...) { va_list ap; va_start (ap, format); log_level_printf (format, ap, PURPLE_DEBUG_WARNING); va_end (ap); } void failure(const char* format, ...) { va_list ap; va_start (ap, format); log_level_printf (format, ap, PURPLE_DEBUG_ERROR); va_end (ap); } void fatal(const char* format, ...) { va_list ap; va_start (ap, format); log_level_printf (format, ap, PURPLE_DEBUG_FATAL); va_end (ap); info ("\n"); } const char *print_flags (const char **names, int len, unsigned flags) { static char *text = NULL; if (text) { g_free (text); text = NULL; } int i; for (i = 0; i < len; i ++) { if (flags & 1) { char *new; if (text) { new = g_strconcat (text, " ", names[i], NULL); g_free (text); } else { new = g_strdup (names[i]); } text = new; } flags >>= 1; } return (const char*)text; } const char *print_flags_peer (unsigned flags) { const char *names[] = { "CREATED", "HAS_PHOTO", "DELETED", "OFFICIAL", "KICKED", "ADMIN", "CREATOR", "LEFT", "DEACTIVATED" }; return print_flags (names, 9, flags); } const char *print_flags_channel (unsigned flags) { static char *text; if (text) { g_free (text); text = NULL; } const char *names[] = { "BROADCAST", "EDITOR", "MODERATOR", "MEGAGROUP" }; text = g_strdup (print_flags_peer (flags)); char *old = text; text = g_strconcat (text, " ", print_flags (names, 4, flags >> 16), NULL); g_free (old); return text; } const char *print_flags_user (unsigned flags) { static char *text; if (text) { g_free (text); text = NULL; } const char *names[] = { "CONTACT", "MUTUAL_CONTACT", "BLOCKED", "SELF", "BOT" }; text = g_strdup (print_flags_peer (flags)); char *old = text; text = g_strconcat (text, " ", print_flags (names, 5, flags >> 16), NULL); g_free (old); return text; } const char *print_flags_update (unsigned flags) { const char *names[] = { "CREATED", "DELETED", "PHONE", "CONTACT", "PHOTO", "BLOCKED", "REAL_NAME", "NAME", "REQUESTED", "WORKING", "FLAGS", "TITLE", "ADMIN", "MEMBERS", "ACCESS_HASH", "USERNAME" }; return print_flags (names, 16, flags); } telegram-purple/msglog.h000066400000000000000000000023021363674160100156300ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #include void debug(const char* format, ...); void info(const char* format, ...); void warning(const char* format, ...); void failure(const char* format, ...); void fatal(const char* format, ...); const char *print_flags_update (unsigned update); const char *print_flags_channel (unsigned flags); const char *print_flags_peer (unsigned flags); const char *print_flags_user (unsigned flags); telegram-purple/po/000077500000000000000000000000001363674160100146105ustar00rootroot00000000000000telegram-purple/po/.gitignore000066400000000000000000000001201363674160100165710ustar00rootroot00000000000000/*.mo # See Makefile, section "Translation fixes": /de.po /it.po /pl.po /ru.po telegram-purple/po/LINGUAS000066400000000000000000000000631363674160100156340ustar00rootroot00000000000000bg cs_CZ de es es_AR fr it nl nn pl pt_BR ru sq uk telegram-purple/po/LINGUAS.BAD000066400000000000000000000005651363674160100162300ustar00rootroot00000000000000# This file lists translations that are too bad or incomplete for installation. # If you would like to improve the state of this, please see the translation page: # https://www.transifex.com/telegram-purple-developers/telegram-purple/ da # < 47% complete # These languages have dangerously low translation ratios: # - Dutch # - French # - Ukranian # (All at around 80%.) telegram-purple/po/POTFILES.in000066400000000000000000000002411363674160100163620ustar00rootroot00000000000000# List of source files containing translatable strings. telegram-base.c telegram-purple.c tgp-2prpl.c tgp-msg.c tgp-net.c tgp-request.c tgp-utils.c tgp-chat.c telegram-purple/po/README000066400000000000000000000006121363674160100154670ustar00rootroot00000000000000Do not edit these files! The translations are maintained in Transifex: https://www.transifex.com/telegram-purple-developers/telegram-purple/ Contributors therefore should have no need to meddle with these files directly. The main developers are supposed to fetch the translations from there, unzip the result into this folder, and NOT TOUCH the files. (See CONTRIBUTING.md for details.) telegram-purple/po/bg.po000066400000000000000000000510321363674160100155410ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Bulgarian (https://www.transifex.com/telegram-purple-developers/teams/53149/bg/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: bg\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Неуспешно създаване на група" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Моля, изберете поне един друг потребител:" #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Заявката беше неуспешна" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Тайният разговор е готов." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Тайният разговор беше приключен." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Съобщението е отбелязано като прочетено." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Връзка за покана: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Създаването на връзка беше неуспешно" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Само администраторите на групата могат да правят това." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Присъединихте се към разговора" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Разговорът беше добавен към списъка от стаи за разговори." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Започване на таен разговор…" #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Покана на потребители чрез връзка…" #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Изтриване и изход…" #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Неуспешно вписване като %s: има проблем с вътрешната библиотека „tgl“. Моля," " изпратете доклад за грешката, заедно с журнала." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Проблем в „tgl“" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Неуспешно вписване като %s: телефонният код не съдържа код на страната. " "Номерата трябва да започват с пълния международен телефонен код на страната," " например +359 за България." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Непълен телефонен номер" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Тайният разговор вече е изтрит" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Тайният разговор не е готов" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Само създателят на канала може да публикува съобщения." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Неуспешно канене на приятел в разговора" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Посоченият потребител не съществува." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "тел. номер (+ код на страната)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "kick <потребител>: Изритване на потребител от стаята." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Парола (двустепенно удостоверяване)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Резервно удостоверяване чрез КС\n" "(Помага, когато не използвате „Pidgin“ и от Вас не се изисква кода)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Винаги" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Никога" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Питане всеки път" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Приемане на тайни разговори" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Показване на приятелите извън линия след (брой дни)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Да не се изтегля историята, по-стара от (брой дни)\n" "(0 = неограничено)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Отхвърляне" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Автоматично зареждане" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Авт. зареждане на файлови прехвърляния до (КБ)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Прехвърляния на по-големи файлове" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Добавяне на всички групови разговори в списъка с приятели" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Показване на уведомления за получаване" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Изпращане на уведомления за получаване при присъствие" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Да се използва IPv6 за свързавне (нужно е рестартиране)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Добавка за протокола „Telegram“." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s създаде разговор %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s промени заглавието на „%1$s“." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s промени снимката си." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s изтри снимка." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s добави потребителя %2$s чрез връзка." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s добави потребителя %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s изтри потребителя %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s настрои брояч за самоунищожение на %1$d секунда." msgstr[1] "%2$s настрои брояч за самоунищожение на %1$d секунди." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s отбеляза %1$d съобщение като прочетено." msgstr[1] "%2$s отбеляза %1$d съобщения като прочетени." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s изтри %1$d съобщение." msgstr[1] "%2$s изтри %1$d съобщения." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s направи снимка на %1$d съобщение." msgstr[1] "%2$s направи снимка на %1$d съобщения." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Каналът „%1$s“ беше създаден" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Канали в Telegram" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Неуспешно изпращане на съобщението." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Неуспешно изпращане на изображениео." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s изпрати стикер." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[снимка]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[звук]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[видео]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[документ]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[местоположение]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[контакт]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[уеб-страница]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[неподдържан формат]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> %s написа:
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Неизвестен потребител написа:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "неуспешно зареждане на съобщение" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "документ" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "звук" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "анимация" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "видео" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "неуспешно зареждане на документ или изображение" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Неуспешно свързване с главния сървър" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Неуспешно свързване със сървъра. Изтече времето за изчакване." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Връзката със сървъра беше прекъсната…" #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram иска да потвърди самоличността Ви. Моля, въведете кода за влизане, " "който трябва да сте получили чрез КС." #: ../tgp-request.c:54 msgid "Login code" msgstr "Код за влизане" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Въведете кода за влизане" #: ../tgp-request.c:54 msgid "the code" msgstr "кодът" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "Добре" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Отказ" #: ../tgp-request.c:94 msgid "Registration" msgstr "Регистрация" #: ../tgp-request.c:95 msgid "First name" msgstr "Собствено име" #: ../tgp-request.c:98 msgid "Last name" msgstr "Фамилия" #: ../tgp-request.c:102 msgid "Register" msgstr "Регистриране" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Моля, регистрирайте телефонния си номер" #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Телефонният номер не е регистриран. Моля, регистрирайте телефона си чрез " "друг клиент." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Нерегистриран" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Нужна е парола" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Въведете парола за двустепенно удостоверяване" #: ../tgp-request.c:122 msgid "Ok" msgstr "Добре" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Няма зададена парола за двустепенно удостоверяване. Моля, въведете я в " "разширените настройки." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Паролата е грешна" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Приемане на тайния разговор „%s“ на това устройство?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Таен разговор" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Тайните разговори могат да се провеждат само на едно устройство. Ако " "приемете таен разговор на това устройство, той няма да бъде достъпен никъде " "другаде. Ако откажете, ще можете да го приемете на друго устройство." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Поканете поне още един потребител, като посочите\n" " пълното му име (разполагате с авт. допълване).\n" "Можете да добавите повече потребители и след началото на разговора." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Потребителско име" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Създаване на групов разговор" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Канене на потребители" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Промяна на паролата" #: ../tgp-request.c:218 msgid "Current" msgstr "Текуща" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Парола" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Потвърждаване" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Нова парола" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Грешен телефонен номер" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Моля, въвеждайте само цифри във формата за международен телефонен номер: знака +, следван от кода на страната и телефонния номер.\n" "Не използвайте други специални знаци." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Напускане на разговора" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Наистина ли искате да напуснете този разговор завинаги?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Край на тайния разговор" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Наистина ли искате да прекратите този таен разговор завинаги?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Изтриване на контакта" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "" "Наистина ли искате да премахнете този потребител от общия си списък с " "контакти?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Напускане на канала" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Наистина ли искате да напуснете този канал?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "наскоро" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "последната седмица" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "последния месец" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "неизвестно" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Разговори в Telegram" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Вече сте напуснали този разговор" #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Тема:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Връзка за покана:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Ид. на разговора:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Надгрупа" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Канал" #: ../tgp-chat.c:421 msgid "Group" msgstr "Група" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Потребители в разговора" #: ../tgp-chat.c:440 msgid "Type" msgstr "Вид" telegram-purple/po/cs_CZ.po000066400000000000000000000424301363674160100161540ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Czech (Czech Republic) (https://www.transifex.com/telegram-purple-developers/teams/53149/cs_CZ/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: cs_CZ\n" "Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Nelze vytvořit skupinu" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Prosím vyberte alespoň jednoho dalšího uživatele." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Dotaz selhal" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Tajný chat připraven." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Tajný chat ukončen." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Zpráva označena jako přečtená." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Odkaz pozvánky: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Vytváření odkazu pro chat selhalo" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "K tomuto úkonu potřebujete být administrátorem skupiny." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Připojeno k chatu" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Chat přidán do seznamu chatovacích místností" #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Začít tajný chat..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Pozvat uživatele odkazem..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Smazat a ukončit..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Nelze se přihlásit jako %s: problém v použité knihovně \"tgl\". Prosím " "nahlaste chybu včetně chybového protokolu." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problém v tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Nelze se přihlásit jako %s: telefonnímu číslu chybí předčíslí země. Čísla " "musí začínat s plným mezinárodním předčíslím, např. +420 pro Českou " "republiku." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Nekompletní telefonní číslo" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Tajný chat byl již smazán" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Tajný chat není připraven" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Pouze tvůrce kanálu může zasílat zprávy." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Nelze pozvat kamaráda do chatu" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Zadaný uživatel neexistuje." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "telefonní číslo (+ předčíslí země)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "vykopnout : Vykopnout uživatele z místnosti." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Heslo (dvoufaktorová autentizace)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Záložní ověřovací SMS\n" "(Pomáhá, když nepoužíváte Pidgin a nejste vyzváni k zadání kódu)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Vždy" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Nikdy" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Zeptat se" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Přijímat tajné chaty" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Zobrazit odpojené kamarády po (dny)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Nestahovat historii starší než (dny)\n" "(0 pro neomezeně)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Vyřadit" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Automatické načtení" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Automatické přenášení souborů do (kb)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Přenosy větších souborů" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Přidat všechny chatovací skupiny do seznamu kamarádů" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Zobrazit oznámení o doručení" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "V přítomnosti zasílat oznámení o doručení" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Pro připojení použít IPv6 (vyžaduje restart)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Zásuvný modul protokolu Telegram." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s vytvořil(a) chat %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s změnil(a) titulek na %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s změnil(a) fotografii." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s smazal(a) fotografii." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s přidal(a) uživatele %2$s odkazem." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s přidal(a) uživatele %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s smazal(a) uživatele %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s nastavil(a) sebedestrukční časovač na %1$d sekundu." msgstr[1] "%2$s nastavil(a) sebedestrukční časovač na %1$d sekundy." msgstr[2] "%2$s nastavil(a) sebedestrukční časovač na %1$d sekund." msgstr[3] "%2$s nastavil(a) sebedestrukční časovač na %1$d sekund." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s označil(a) %1$d zprávu jako přečtenou." msgstr[1] "%2$s označil(a) %1$d zprávy jako přečtené." msgstr[2] "%2$s označil(a) %1$d zpráv jako přečtené." msgstr[3] "%2$s označil(a) %1$d zpráv jako přečtené." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s smazal(a) %1$d zprávu." msgstr[1] "%2$s smazal(a) %1$d zprávy." msgstr[2] "%2$s smazal(a) %1$d zpráv." msgstr[3] "%2$s smazal(a) %1$d zpráv." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s vytvořil(a) screenshot %1$d zprávy." msgstr[1] "%2$s vytvořil(a) screenshot %1$d zpráv." msgstr[2] "%2$s vytvořil(a) screenshot %1$d zpráv." msgstr[3] "%2$s vytvořil(a) screenshot %1$d zpráv." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Kanál %1$s vytvořen" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Kanály Telegramu" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Odeslání zprávy selhalo." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Odeslání obrázku selhalo." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s odeslal nálepku." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[fotka]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[audio]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[video]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[dokument]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[pozice]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[kontakt]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[webová stránka]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> %s napsal(a):
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Neznámý uživatel napsal:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "selhalo načítání zprávy" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "dokument" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "audio" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "animace" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "video" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "nahrávání dokumentu nebo obrázku sehlalo" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Nelze se připojit k hlavnímu serveru" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Nelze se připojit k serveru: Vypršel časový limit pingu" #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Ztraceno spojení se serverem..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram potřebuje ověřit identitu. Prosím zadejte přihlašovací kód, který " "jste obdrželi v SMS." #: ../tgp-request.c:54 msgid "Login code" msgstr "Přihlašovací kód" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Zadejte přihlašovací kód" #: ../tgp-request.c:54 msgid "the code" msgstr "kód" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "OK" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Zrušit" #: ../tgp-request.c:94 msgid "Registration" msgstr "Registrace" #: ../tgp-request.c:95 msgid "First name" msgstr "Jméno" #: ../tgp-request.c:98 msgid "Last name" msgstr "Příjmení" #: ../tgp-request.c:102 msgid "Register" msgstr "Registrovat" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Prosím zaregistrujte své telefonní číslo." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Telefonní číslo není zaregistrované. Prosím zaregistrujte své telefonní " "číslo v jiné aplikaci." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Neregistrován" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Vyžadováno heslo" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Zadejte heslo pro dvoufaktorovou autentizaci" #: ../tgp-request.c:122 msgid "Ok" msgstr "Ok" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Není zadáno heslo pro dvoufaktorovou autentizaci. Prosím zadejte jej v " "pokročilém nastavení." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Neplatné heslo" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Přijmout tajný chat '%s' na tomto zařízení?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Tajný chat" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Tajný chat může mít pouze jeden koncový bod. Pokud přijmete tajný chat na " "tomto zařízení, zprávy nebudou dostupné nikde jinde. Pokud odmítnete, můžete" " stále přijmout chat na jiném zařízení." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Pozvěte minimálně jednoho dalšího uživatele tím,\n" "že zadáte jeho celé jméno (automatické doplňování dostupné).\n" "Můžete přidat více uživatelů po té, co je chat vytvořen." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Uživatelské jméno" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Vytvořit skupinový chat" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Pozvat uživatele" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Změnit heslo" #: ../tgp-request.c:218 msgid "Current" msgstr "Aktuální" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Heslo" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Potvrdit" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Nové heslo" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Neplatné telefonní číslo" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Prosím zadejte pouze čísla v mezinárodním telefonním formátu, počáteční + následované mezinárodním předčíslím a telefonním číslem.\n" "Nepoužívejte žádné jiné speciální znaky." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Opustit chat" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Chcete tento chat opustit trvale?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Ukončit tajný chat" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Chcete ukončit tento tajný chat trvale?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Smazat kontant" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "Chcete tohoto uživatele odstranit ze seznamu kontaktů?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Opustit kanál" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Chcete opustit tento kanál?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "nedávno" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "poslední týden" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "poslední měsíc" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "neznámé" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Chaty Telegramu" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Již jste tento chat opistili." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Předmět:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Odkaz pozvánky:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "ID Chatu:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Superskupina" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Kanál" #: ../tgp-chat.c:421 msgid "Group" msgstr "Skupina" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Uživatelé v chatu" #: ../tgp-chat.c:440 msgid "Type" msgstr "Typ" telegram-purple/po/da.po000066400000000000000000000334131363674160100155400ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Ben Wiederhake , 2019 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2019\n" "Language-Team: Danish (https://www.transifex.com/telegram-purple-developers/teams/53149/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: da\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Kunne ikke lave gruppe" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Vælg mindst én anden bruger." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Forespørgsel fejlede" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Hemmelig chat klar." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Hemmelig chat afsluttet." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Besked markeret som læst." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Invitationslink: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Oprettelse af chatlink fejlede" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Du skal være admin af gruppen for at kunne gøre det." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Chat tilsluttet" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Chat tilføjet listen af chatrum." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Start hemmelig chat..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Invitér brugere med link..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Slet og afslut..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problem i tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Ugyldigt telefonnummer" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Hemmelig chat er allerede slettet" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Hemmelig chat er ikke klar" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Kun den der opretter en kanal kan skrive beskeder." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Kan ikke invitere ven til chat" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Angivet bruger eksisterer ikke." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "Telefon nr. (+ landekode)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "" #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Kodeord (to-vejs godkendelse)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Acceptér hemmelige chats" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Vis venner som offline efter (dage)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Hent ikke historie ældre end (dage)\n" "(0 for ubegrænset)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Vis modtagelseskvittering" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "" #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s oprettede chat %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s ændrede titel til %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s ændrede foto." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s slettede foto." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s tilføjede bruger %2$s med link." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s tilføjede bruger %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s slettede bruger %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "" msgstr[1] "" #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "" msgstr[1] "" #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "" msgstr[1] "" #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "" msgstr[1] "" #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "" #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Afsendelse af billede fejlede." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "" #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "" #: ../tgp-msg.c:535 msgid "[video]" msgstr "" #: ../tgp-msg.c:540 msgid "[document]" msgstr "" #: ../tgp-msg.c:545 msgid "[position]" msgstr "" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "" #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "" #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" #: ../tgp-request.c:54 msgid "Login code" msgstr "Log ind kode" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Indtast log ind kode" #: ../tgp-request.c:54 msgid "the code" msgstr "koden" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "OK" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Afbryd" #: ../tgp-request.c:94 msgid "Registration" msgstr "Registrering" #: ../tgp-request.c:95 msgid "First name" msgstr "Fornavn" #: ../tgp-request.c:98 msgid "Last name" msgstr "Efternavn" #: ../tgp-request.c:102 msgid "Register" msgstr "Registrér" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Registrér venligst dit telefonnummer" #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" #: ../tgp-request.c:109 msgid "Not registered" msgstr "" #: ../tgp-request.c:121 msgid "Password needed" msgstr "" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Indtast kodeord til to-vejs godkendelse" #: ../tgp-request.c:122 msgid "Ok" msgstr "" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Intet kodeord sat til to-vejs godkendelse. Indtast det venligst i de " "udvidede indstillinger." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Ugyldigt kodeord" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Brugernavn" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Lav gruppechat" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Invitér brugere" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "" #: ../tgp-request.c:218 msgid "Current" msgstr "" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Kodeord" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Ugyldigt telefonnummer" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "for nyligt" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "sidste uge" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "sidste mÃ¥ned" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "ukendt" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Du har allerede forladt denne chat." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Emne:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Invitationslink:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Chat ID:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "" #: ../tgp-chat.c:418 msgid "Channel" msgstr "" #: ../tgp-chat.c:421 msgid "Group" msgstr "" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "" #: ../tgp-chat.c:440 msgid "Type" msgstr "" telegram-purple/po/de_DE.po000066400000000000000000000420101363674160100161050ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: German (Germany) (https://www.transifex.com/telegram-purple-developers/teams/53149/de_DE/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: de_DE\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Konnte Gruppe nicht erstellen." #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Wählen Sie mindestens einen weiteren Benutzer." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Anfrage fehlgeschlagen" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Geheimer Chat ist bereit." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Geheimer Chat wurde beendet." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Nachricht als gelesen markiert." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Einladungslink: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Konnte keinen Link zum Chat erstellen" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Sie müssen Gruppenadmin sein, um das zu tun." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Chat beigetreten" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Chat der Liste von Chat-Räumen hinzugefügt." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Beginne geheimen Chat ..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Nutzer per Link einladen ..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Löschen und verlassen ..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Konnte nicht als %s einloggen: Problem in der Bibliothek 'tgl'. Bitte " "erstelle einen Bigreport mit Debug-Log." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problem in tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Konnte nicht als %s einloggen: Telefonnummer hat kein Präfix. Telefonnummern" " müssen mit dem vollen internationalen Präfix-Code starten, z.B. +49 für " "Deutschland." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Unvollständige Telefonnummer" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Geheimer Chat wurde bereits gelöscht." #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Geheimer Chat ist noch nicht bereit." #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Nur der Ersteller eines Kanals kann Nachrichten senden." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Kann den Freund nicht zum Chat einladen" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Angegebener Benutzer existiert nicht." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "Telefonnummer (+ Länder-Präfix)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "kick : Entferne aus dem Raum." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Passwort (Zwei-Faktor-Authentifizierung)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Ausweich SMS-Verifizierung\n" "(Hilfreich wenn Sie nicht Pidgin verwenden, und die Frage\n" "nach dem SMS-Code aus bleibt)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Immer" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Nie" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Nachfragen" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Geheime Chats akzeptieren" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Freunde als offline anzeigen nach (Tage)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Abrufen des Verlaufs begrenzen auf (Tage)\n" "(0 für unbegrenzt)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Verwerfen" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Immer laden" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Lade Dateien automatisch bis zu (kb)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Größere Dateitransfers" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Alle Gruppenchats in die Freundesliste einfügen" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Empfangsbestätigungen anzeigen" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Empfangsbestätigungen senden wenn anwesend" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Benutze IPv6 (Neustart notwendig)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Plugin für das Telegram Protokoll." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s hat den Chat %1$s erstellt." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s hat den Titel zu %1$s geändert." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s hat das Photo geändert." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s hat das Photo gelöscht." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s fügte Benutzer %2$s per Link hinzu." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s hat den Nutzer %1$s hinzufügt." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s entfernte Benutzer %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s setzte Selbstzerstörungs-Timer auf %1$d Sekunde." msgstr[1] "%2$s setzte Selbstzerstörungs-Timer auf %1$d Sekunden." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s markierte %1$d Nachricht als gelesen." msgstr[1] "%2$s markierte %1$d Nachrichten als gelesen." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s entfernte %1$d Nachricht." msgstr[1] "%2$s entfernte %1$d Nachrichten." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s machte einen Screenshot von %1$d Nachricht." msgstr[1] "%2$s machte einen Screenshot von %1$d Nachrichten." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Kanal %1$s erstellt" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Telegram Kanäle" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Absenden der Nachricht fehlgeschlagen." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Absenden des Bilds fehlgeschlagen." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s hat einen Sticker gesendet." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "[Nachricht nicht verfügbar]" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[Foto]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[Audio]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[Video]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[Dokumenŧ]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[Position]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[Kontakt]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[Webseite]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[nicht unterstütztes Format]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> %s schrieb:
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Unbekannter Benutzer schrieb:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "konnte Nachricht nicht laden." #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "Dokument" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "Audio" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "Animation" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "Video" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "> Weitergeleitet von %s:
> %s" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "> Weitergeleitet:
> %s" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "konnte Dokument oder Datei nicht laden" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Keine Verbindung zum Haupt-Server" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Keine Verbindung zum Server: Zeitüberschreitung" #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Verbindung zum Server verloren ..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram möchte Ihre Identität prüfen. Bitte geben Sie den Login-Code ein, " "den Sie per SMS erhalten haben." #: ../tgp-request.c:54 msgid "Login code" msgstr "Login-Code" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Login-Code eingeben" #: ../tgp-request.c:54 msgid "the code" msgstr "der Login-Code" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "Ok" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Abbrechen" #: ../tgp-request.c:94 msgid "Registration" msgstr "Anmeldung" #: ../tgp-request.c:95 msgid "First name" msgstr "Vorname" #: ../tgp-request.c:98 msgid "Last name" msgstr "Nachname" #: ../tgp-request.c:102 msgid "Register" msgstr "Anmelden" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Bitte registriere deine Telefonnummer." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Telefonnummer wurde noch nicht bei Telegram registriert. Bitte registrieren " "Sie Ihre Telefonnummer mit einem anderen Client." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Nicht registriert" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Passwort benötigt" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Passwort für die Zwei-Faktor-Authentifizierung angeben" #: ../tgp-request.c:122 msgid "Ok" msgstr "Ok" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Kein Passwort für die Zwei-Faktor-Authentifizierung gesetzt, bitte\n" "spezifizieren Sie dies in den erweiterten Einstellungen." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Passwort ungültig" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Geheimen Chat '%s' auf diesem Gerät akzeptieren?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Geheimer Chat" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Geheime Chats können nur einen Endpunkt haben. Wenn du den geheimen Chat auf" " diesem Geräte akzeptierst werden die Nachrichten nirgendwo anders verfügbar" " sein. Wenn du ablehnst kannst du den Chat immernoch auf anderen Geräten " "akzeptieren." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Lade noch mindestens einen zusätzlichen Benutzer\n" "durch Eingabe des vollständigen Namens ein\n" "(Autovervollständigung verfügbar).\n" "Sie können später weitere Nutzer einladen, sobald\n" "der Chat erstellt wurde." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Benutzername" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Gruppenchat erstellen" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Benutzer einladen" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Passwort ändern" #: ../tgp-request.c:218 msgid "Current" msgstr "Momentan" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Passwort" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Bestätigen" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Neues Passwort" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Ungültige Telefonnummer" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Bitte geben Sie Telefonnummern im internationalen Format ein, bestehend aus einem führenden + gefolgt vom Länderpräfix\n" "und der Rufnummer. Verwenden Sie keine anderen Sonderzeichen." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Chat verlassen" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Möchten Sie diesen Chat dauerhaft verlassen?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Geheimen Chat abbrechen" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Möchten Sie diesen geheimen Chat dauerhaft verlassen?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Kontakt löschen" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "Möchten Sie diesen Kontakt global löschen?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Kanal verlassen" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Möchten Sie diesen Kanal dauerhaft verlassen?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "Kürzlich" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "Letzte Woche" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "Letzten Monat" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "Unbekannt" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Telegram Unterhaltugen" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Du hast diesen Chat bereits verlassen." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Thema:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Einladungslink:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Chat ID:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Über-Gruppe" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Kanal" #: ../tgp-chat.c:421 msgid "Group" msgstr "Gruppe" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Benutzer im Chat" #: ../tgp-chat.c:440 msgid "Type" msgstr "Typ" telegram-purple/po/es.po000066400000000000000000000425661363674160100155740ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # aguador , 2019 # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Spanish (https://www.transifex.com/telegram-purple-developers/teams/53149/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "No se pudo crear el grupo" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Por favor, seleccioná al menos otro usuario." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Falló la consulta" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Conversación secreta lista." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Finalizó la conversación secreta." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Mensaje marcado como leído." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Enlace de invitación: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Falló la creación del enlace de converesación" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Necesite ser administrador del grupo para hacer eso." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Unido a la conversación" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Conversación agregada a la lista de salas de conversaciones." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Iniciar conversación secreta..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Invitar a usuarios por enlace..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Eliminar y salir..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "No se pudo iniciar sesión como %s: problema con la biblioteca 'tgl'. Por " "favor, envíe un informe de error con el registro de depuración." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problema en tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "No se pudo iniciar sesión como %s: al número de teléfono le falta el prefijo" " del país. Los números deben comenzar con el código de prefijo " "internacional, por ejemplo: +34 para España." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Número de teléfono incompleto" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Ya se eliminó la conversación secreta" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "La conversación secreta no está lista" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Sólo el creador de un canal puede publicar mensajes." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "No se pudo invitar al contacto a la conversación" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "El usuario especificado no existe." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "Núm. tlf. (+ prefijo país)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "Echar : Echar al usuario de la sala." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Contraseña (autenticación de dos pasos)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Verificación por mensaje de texto\n" "(Sirve para cuando no está usando Pidgin y no se le pido el código)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Siempre" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Nunca" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Preguntar" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Aceptar conversaciones secretas" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Mostrar contactos desconectados después de (días)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "No recuperar el historial anterior a (días)\n" "(introducir '0' para no aplicar límites)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Deshacer" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Cargar automáticamente" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Cargar automático archivos hasta (kb)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Transferencias más grandes" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Agregar todas las conversaciones grupales a la lista del contacto" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Mostrar acuses de recibo" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Enviar acuses de recibo al estar presente" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Usar IPV6 para conectarse (reinicio es requerido)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Plugin de protocolo de Telegram." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s creó la conversación %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s cambió el título a %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s cambió la foto." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s eliminó la foto." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s agregó al usuario %2$s mediante un enlace." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s agregó al usuario %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s eliminó al usuario %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s estableció un temporizador autodestructivo a %1$d segundo." msgstr[1] "%2$s estableció un temporizador autodestructivo a %1$d segundos." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s marcó %1$d mensaje como leído." msgstr[1] "%2$s marcó %1$d mensajes como leídos." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s eliminó %1$d mensaje." msgstr[1] "%2$s eliminó %1$d mensajes." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s tomó una captura de pantalla de %1$d mensaje." msgstr[1] "%2$s tomó una captura de pantalla de %1$d mensajes." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Canal %1$s creado" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Canales de Telegram" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Falló el envío de mensajes." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Falló el envío de imágenes." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s envió un sticker." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "[mensaje no disponible]" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[foto]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[audio]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[video]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[documento]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[posición]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[contacto]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[página web]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[medio no soportado]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> %s escribió:
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Usuario desconocido escribió:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "falló la carga del mensaje" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "documento" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "audio" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "animación" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "vídeo" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "> Reenviado desde %s\\:
> %s " #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "> Reenviado\\:
> %s " #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "falló la carga del documento o imagen" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "No se puede conectar al servidor principal" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "No se puede conectar al servidor: tiempo de espera agotado." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Se perdió la conexión con el servidor..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram quiere verificar su identidad. Por favor, introduce el código que " "recibió en un mensaje de texto." #: ../tgp-request.c:54 msgid "Login code" msgstr "Código de inicio de sesión" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Intoducir código de inicio de sesión" #: ../tgp-request.c:54 msgid "the code" msgstr "el código" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "Aceptar" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Cancelar" #: ../tgp-request.c:94 msgid "Registration" msgstr "Registro" #: ../tgp-request.c:95 msgid "First name" msgstr "Nombre" #: ../tgp-request.c:98 msgid "Last name" msgstr "Apellido" #: ../tgp-request.c:102 msgid "Register" msgstr "Registrar" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Por favor, registre su número de teléfono." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "No se registró el número de teléfono. Por favor, registre su teléfono en un " "cliente diferente." #: ../tgp-request.c:109 msgid "Not registered" msgstr "No registrado" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Se necesita la contraseña" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Introducir contraseña para la autenticación de dos pasos" #: ../tgp-request.c:122 msgid "Ok" msgstr "Aceptar" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "No se estableció contraseña para la autenticación de dos pasos. Por favor, " "introdúcela en la configuración extendida." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Contraseña no válida" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "¿Acepte la conversación secreta '%s' en este dispositivo?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Conversación secreta" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Las conversaciones secretas son uno a uno. Si acepte una conversación " "secreta en este dispositivo, la misma no estará disponible en ningún otro " "lado. Si decline, pueda aceptar la conversación en otro dispositivo." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Invite al menos a un usuario más especificando\n" "su nombre completo (disponible autocompletado).\n" "Pueda agregar más usuarios una vez que se cree la conversación." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Nombre de usuario" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Crear conversación grupal" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Invitar a los usuarios" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Cambiar contraseña" #: ../tgp-request.c:218 msgid "Current" msgstr "Actual" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Contraseña" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Confirmar" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Nueva contraseña" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Número de teléfono no válido" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Por favor, introduce sólo números en el formato de números de teléfono internacional, con el signo '+' seguido del código de país [más prefijo para el acceso a la red celular, si corresponde] y el número de teléfono.\n" "No use ningún otro carácter." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Abandonar conversación" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "¿Querés abandonar esta conversación permanentemente?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Cancelar conversación secreta" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "" "¿Esté seguro que quiere eliminar esta conversación secreta permanentemente?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Eliminar contacto" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "¿Quiere quitar este usuario de su lista global de contactos?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Abandonar canal" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "¿Quiere abandonar este canal?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y - %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "recientemente" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "la semana pasada" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "el mes pasado" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "desconocido" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Conversaciones de Telegram" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Ya ha abandonado esta conversación." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Asunto:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Enlace de invitación:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Identificación de conversación:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Súpergrupo" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Canal" #: ../tgp-chat.c:421 msgid "Group" msgstr "Grupo" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Usuarios en la conversación" #: ../tgp-chat.c:440 msgid "Type" msgstr "Tipo" telegram-purple/po/es_AR.po000066400000000000000000000426701363674160100161520ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # ᏦᏁᎢᎵᏫ , 2019 # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Spanish (Argentina) (https://www.transifex.com/telegram-purple-developers/teams/53149/es_AR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: es_AR\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "No se pudo crear el grupo" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Por favor, seleccioná al menos otro usuario." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Falló la consulta" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Conversación secreta lista." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Finalizó la conversación secreta." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Mensaje marcado como leído." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Enlace de invitación: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Falló la creación del enlace de conversación" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Necesitás ser administrador del grupo para hacer eso." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Unido a la conversación" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Conversación agregada a la lista de salas de conversaciones." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Iniciar conversación secreta..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Invitar a usuarios por enlace..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Eliminar y salir..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "No se pudo iniciar sesión como %s: hay un problema con la biblioteca " "\"tgl\". Por favor, enviá un informe de errores con el registro de " "depuración." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problema en tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "No se pudo iniciar sesión como %s: al número de teléfono le falta el prefijo" " del país. Los números deben comenzar con el código de prefijo " "internacional, por ejemplo: +54 para Argentina." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Número de teléfono incompleto" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Ya se eliminó la conversación secreta" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "La conversación secreta no está lista" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Sólo el creador de un canal puede publicar mensajes." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "No se pudo invitar al contacto a la conversación" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "El usuario especificado no existe." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "Número de teléfono (+ prefijo de país)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "Kick : expulsa a un usuario de una sala." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Contraseña (autenticación de 2 pasos)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Verificación por mensaje de texto\n" "(Sirve para cuando no estás usando Pidgin y no se te pide el código)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Siempre" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Nunca" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Preguntar" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Aceptar conversaciones secretas" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Mostrar contactos desconectados después de (días)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "No recuperar el historial anterior a (días)\n" "(ingresá \"0\" para no aplicar límites)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Descartar" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Descarga automática" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Descarga automática de archivos de hasta (KB)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Transferencias de archivos más grande" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Agregar todas las conversaciones grupales a la lista del contacto" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Mostrar acuses de recibo" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Enviar acuses de recibo al estar presente" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Usar IPv6 para conectarse (requiere reinicio)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Plugin de protocolo de Telegram." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s creó la conversación %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s cambió el título a %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s cambió la imagen." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s eliminó la imagen." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s agregó al usuario %2$s mediante un enlace." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s agregó al usuario %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s eliminó al usuario %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s estableció un contador autodestructivo a %1$d segundo." msgstr[1] "%2$s estableció un contador autodestructivo a %1$d segundos." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s marcó %1$d mensaje como leído." msgstr[1] "%2$s marcó %1$d mensajes como leídos." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s eliminó %1$d mensaje." msgstr[1] "%2$s eliminó %1$d mensajes." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s tomó una captura de pantalla de %1$d mensaje." msgstr[1] "%2$s tomó una captura de pantalla de %1$d mensajes." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Se creó el canal %1$s" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Canales de Telegram" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Falló el envío de mensajes." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Falló el envío de imágenes." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s envió un sticker." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "[mensaje no disponible]" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[imagen]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[audio]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[video]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[documento]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[ubicación]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[contacto]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[página web]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[medio no compatible]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s>%sescribió:
>%s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Un usuario desconocido escribió:
>%s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "falló la carga del mensaje" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "documento" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "audio" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "animación" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "video" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "> Reenviado desde %s:
>%s" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "> Reenviado:
>%s" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "falló la carga del documento o imagen" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "No se puede conectar al servidor principal" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "No se puede conectar al servidor: tiempo de respuesta agotado." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Se perdió la conexión con el servidor..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram quiere verificar tu identidad. Por favor, ingresá el código que " "recibiste en un mensaje de texto." #: ../tgp-request.c:54 msgid "Login code" msgstr "Código de inicio de sesión" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Ingresar código de inicio de sesión" #: ../tgp-request.c:54 msgid "the code" msgstr "el código" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "Aceptar" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Cancelar" #: ../tgp-request.c:94 msgid "Registration" msgstr "Registro" #: ../tgp-request.c:95 msgid "First name" msgstr "Nombre" #: ../tgp-request.c:98 msgid "Last name" msgstr "Apellido" #: ../tgp-request.c:102 msgid "Register" msgstr "Registrarse" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Por favor, registrá tu número de teléfono." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "No se registró el número de teléfono. Por favor, registrá tu teléfono en un " "cliente diferente." #: ../tgp-request.c:109 msgid "Not registered" msgstr "No registrado" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Se necesita la contraseña" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Ingresar contraseña para la autenticación de 2 pasos" #: ../tgp-request.c:122 msgid "Ok" msgstr "Aceptar" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "No se estableció contraseña para la autenticación de 2 pasos. Por favor, " "ingresala en la configuración extendida." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Contraseña no válida" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "¿Aceptás la conversación secreta \"%s\" en este dispositivo?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Conversación secreta" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Las conversaciones secretas son uno a uno. Si aceptás una conversación " "secreta en este dispositivo, la misma no estará disponible en ningún otro " "lado. Si declinás, podés aceptar la conversación en otro dispositivo." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Invitá al menos a un usuario más especificando\n" "su nombre completo (disponible autocompletado).\n" "Podés agregar más usuarios una vez que se cree la conversación." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Nombre de usuario" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Crear conversación grupal" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Invitar a usuarios" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Cambiar contraseña" #: ../tgp-request.c:218 msgid "Current" msgstr "Actual" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Contraseña" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Confirmar" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Nueva contraseña" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Número de teléfono no válido" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Por favor, ingresá sólo números en el formato de números de teléfono internacional, con el signo \"+\" seguido del código de país [más prefijo para el acceso a la red celular, si corresponde] y el número de teléfono.\n" "No usés ningún otro caracter." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Abandonar conversación" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "¿Querés abandonar esta conversación permanentemente?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Cancelar conversación secreta" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "" "¿Estás seguro que querés eliminar esta conversación secreta permanentemente?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Eliminar contacto" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "¿Querés quitar este usuario de tu lista global de contactos?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Abandonar canal" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "¿Querés abandonar este canal?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%Y.%m.%d - %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "recientemente" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "la semana pasada" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "el mes pasado" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "[desconocido]" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Conversaciones de Telegram" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Ya abandonaste esta conversación." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Asunto:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Enlace de invitación:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Identificación de conversación:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Súpergrupo" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Canal" #: ../tgp-chat.c:421 msgid "Group" msgstr "Grupo" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Usuarios en la conversación" #: ../tgp-chat.c:440 msgid "Type" msgstr "Tipo" telegram-purple/po/fr.po000066400000000000000000000415231363674160100155640ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: French (https://www.transifex.com/telegram-purple-developers/teams/53149/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "N'a pas pu créer le groupe" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Veuillez sélectionner au moins un autre utilisateur." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Requête échouée" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Conversation secrète prête." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Conversation secrète terminée." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Message marqué comme lu." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Lien d'invitation : %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Création du lien d'invitation échouée" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Vous devez être administrateur du groupe pour faire cela." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Conversation atteinte." #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Conversation ajoutée dans la liste des conversations." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Commencer une conversation secrète..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Inviter des utilisateurs avec un lien..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Supprimer et quitter..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Impossible de s'identifier comme %s : Problème avec la librairie sous-" "jacente 'tgl'. Veuillez svp soumettre un rapport de bug incluant des " "informations de débug." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problème relatif à Tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Impossible de se connecter avec %s : le préfixe de pays est manquant. Le " "numéro de téléphone doit commencer avec le numéro de préfixe international, " "ex: +33 pour la France." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Numéro de téléphone incomplet" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Conversation secrète déjà supprimée." #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Conversation secrète non prête" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Seul le créateur du canal peut publier des messages" #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Impossible d'ajouter le contact à la conversation" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "L'utilisateur spécifié n'existe pas." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "n° téléphone (+ préfixe pays)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "" #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Mot de passe (authentification à deux facteurs)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Vérification par SMS\n" "(Cela aide si vous n’utilisez pas Pidgin et que vous n'êtes pas notifié pour le code)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Accepter la conversation secrète" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Afficher les contacts déconnectés après (jours)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Ne pas récupérer l'historique plus vieux que (jours)\n" "(0 pour infinie)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Ajouter tous les membres de la conversation dans la liste de contact" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Afficher les notifications de réception" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Envoyer des notifications de réception quand vous êtes présent." #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Extension Protocole Telegram" #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s a créé la conversation %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s a changé le titre pour %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s a changé sa photo." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s a supprimé la photo." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s a ajouté l'utilisateur %2$s avec un lien." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s a ajouté l'utilisateur %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s a supprimé l'utilisateur %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s a mis le compte a rebours d'auto destruction à %1$d secondes." msgstr[1] "%2$s a mis le compte à rebours d'auto destruction à %1$d secondes." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s a marqué les messages de %1$d lu." msgstr[1] "%2$s a marqué les messages de %1$d lus." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s a supprimé les messages de %1$d." msgstr[1] "%2$s a supprimé les messages de %1$d." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s a pris un copie d'écran des messages de %1$d." msgstr[1] "%2$s a pris une copie d'écran des messages de %1$d." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Canal %1$s créé" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Canaux Telegram" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "L'envoi du message a échoué." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "L'envoi de l'image a échoué." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s a envoyé un sticker." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "" #: ../tgp-msg.c:535 msgid "[video]" msgstr "" #: ../tgp-msg.c:540 msgid "[document]" msgstr "" #: ../tgp-msg.c:545 msgid "[position]" msgstr "" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "échec au chargement du message" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "échec au chargement du document ou de l'image" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Impossible de se connecter au serveur principal" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Impossible de se connecter avec le serveur : Délai d'attente dépassé." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Connexion au serveur perdue..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram veut vérifier votre identité, Entrez le code que vous avez reçu par" " SMS." #: ../tgp-request.c:54 msgid "Login code" msgstr "Code de connexion" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Entrez le code de connexion" #: ../tgp-request.c:54 msgid "the code" msgstr "le code" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "OK" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Annuler" #: ../tgp-request.c:94 msgid "Registration" msgstr "Enregistrement" #: ../tgp-request.c:95 msgid "First name" msgstr "Prénom" #: ../tgp-request.c:98 msgid "Last name" msgstr "Nom de famille" #: ../tgp-request.c:102 msgid "Register" msgstr "Enregistrer" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Enregistrez votre numéro de téléphone." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Numéro de téléphone non enregistré. Enregistrez un numéro de téléphone sur " "un appareil différent." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Non enregistré" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Besoin du mot de passe" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Entrez le mot de passe pour l'authentification à deux facteurs" #: ../tgp-request.c:122 msgid "Ok" msgstr "Ok" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Pas de mot de passe à deux facteurs spécifié. Entrez-en un dans la " "configuration étendue." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Mot de passe invalide" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Accepter la conversation secrète %s sur cet appareil ?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Conversation secrète" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Les conversations secrètes ne peuvent être vues que sur un seul appareil. Si" " vous acceptez la conversation secrète sur cet appareil, elle ne sera pas " "disponible ailleurs. Si vous refusez, vous pourrez toujours accepter cette " "conversation sur un autre appareil." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Invitez au moins un autre utilisateur (auto-complétion disponible).\n" "Vous pouvez ajouter plus d'utilisateurs une fois la conversation créée." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Nom d'utilisateur" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Créer une conversation de groupe" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Inviter des utilisateurs" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Changer le mot de passe" #: ../tgp-request.c:218 msgid "Current" msgstr "Courrant" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Mot de passe" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Confirmer" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Nouveau mot de passe" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Numéro de téléphone invalide" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Entrez seulement des numéros dans le champs pour le numéro international, un + suivi du préfixe de pays et du numéro de téléphone.\n" "N'utilisez aucun autre caractère spécial." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Quitter la conversation" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Voulez-vous quitter cette discussion définitivement ?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Abandonner la conversation secrète" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Voulez-vous clore cette conversation définitivement ?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Supprimer ce contact" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "" "Voulez-vous supprimer cet utilisateur de votre liste de contacts globale ?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Quitter le canal" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Voulez-vous quitter ce canal ?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "récemment" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "semaine précédente" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "mois précédent" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "inconnue" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Conversations de Telegram" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Vous avez déjà quitté cette conversation." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Sujet :" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Lien d'invitation :" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Chat ID :" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Supergroup" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Canal" #: ../tgp-chat.c:421 msgid "Group" msgstr "Groupe" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Utilisateurs dans la conversation" #: ../tgp-chat.c:440 msgid "Type" msgstr "Type" telegram-purple/po/it_IT.po000066400000000000000000000417111363674160100161640ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Roberto Bellingeri , 2020 # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Italian (Italy) (https://www.transifex.com/telegram-purple-developers/teams/53149/it_IT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: it_IT\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Impossibile creare un gruppo" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Seleziona almeno un altro utente" #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Richiesta fallita" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Chat segreta pronta." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Chat segreta terminata." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Messaggio contrassegnato come letto." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Link d'invito: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Creazione del link della chat fallito" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Devi essere admin del gruppo per eseguire questa operazione." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Entrato nella chat" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Chat aggiunta alla lista delle chat rooms" #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Inizia chat segreta..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Invita utenti tramite link..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Elimina ed esci..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Impossibile accedere come %s: problema con la libreria 'tgl'. Invia un bug " "report con il log di debug." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problema in tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Impossibile accedere come %s: il numero telefonico manca del prefisso " "internazionale.I numeri devono iniziare con il prefisso internazionale " "completo, p.e. +39 per Italia." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Numero di telefono incompleto" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "La chat segreta è già stata eliminata" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "La chat segreta non è pronta" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Solo il creatore di un canale può postare messaggi." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Impossibile invitare il contatto alla chat." #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "L'utente specificato non esiste." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "num. telefono ( + prefisso internazionale)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "espelli : espelli un utente dalla stanza." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Password (autenticazione a due fattori)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Verifica via SMS di scorta.\n" "(Aiuta quando non si usa Pidgin e non viene richiesto il codice)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Sempre" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Mai" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Chiedi" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Accetta chat segrete" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Mostra utenti offline dopo (giorni)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Non recuperare la cronologia meno recente di (giorni)\n" "(0 per illimitato)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Annulla" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Caricamento automatico" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Carica automaticamente i trasferimenti di file fino a (kb)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Trasferimenti di file più grandi" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Aggiungi tutte le chat di gruppo alla lista contatti" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Mostra notifiche di ricezione" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Invia notifiche di ricezione quando presente" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Utilizza IPv6 per la connessione (riavvio richiesto)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Plugin di protocollo Telegram" #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s ha creato la chat %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s ha cambiato titolo a %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s ha cambiato la foto." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s ha cancellato la foto." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s ha aggiunto l'utente %2$s tramite link." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s ha aggiunto l'utente %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s ha eliminato l'utente %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s ha impostato il timer di autodistruzione a %1$d secondi." msgstr[1] "%2$s ha impostato il timer di autodistruzione a %1$d secondi." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s ha contrassegnato come letti i messaggi %1$d " msgstr[1] "%2$s ha contrassegnato come letti i messaggi %1$d " #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s ha cancellato %1$d messaggi." msgstr[1] "%2$s ha cancellato %1$d messaggi." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s ha creato una immagine dello schermo dei messaggi %1$d." msgstr[1] "%2$s ha creato una immagine dello schermo dei messaggi %1$d." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Canale %1$s creato" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Canali Telegram" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Invio immagine fallito." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Invio immagine fallito." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s ha inviato uno sticker." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "[messaggio non disponibile]" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[foto]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[audio]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[video]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[documento]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[posizione]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[contatto]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[pagina web]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[media non supportato]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> %s ha scritto:
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Utente sconosciuto ha scritto:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "caricamento del messaggio fallito" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "documento" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "audio" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "animazione" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "video" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "> Inoltrato da %s:
> %s" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "> Inoltrato:
> %s" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "caricamento del documento o della foto fallito" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Impossibile connettersi col server" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Impossibile connettersi al server: Ping timeout." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Connessione al server fallita..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram vuole verificare la tua identità, Prego inserisci il codice " "ricevuto via SMS." #: ../tgp-request.c:54 msgid "Login code" msgstr "Codice di accesso (login)" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Inserire codice d'accesso (login)" #: ../tgp-request.c:54 msgid "the code" msgstr "il codice" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "OK" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Annulla" #: ../tgp-request.c:94 msgid "Registration" msgstr "Registrazione" #: ../tgp-request.c:95 msgid "First name" msgstr "Nome" #: ../tgp-request.c:98 msgid "Last name" msgstr "Cognome" #: ../tgp-request.c:102 msgid "Register" msgstr "Registrati" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Per favore registra il tuo numero di telefono." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Numero telefonico non registrato. Per favore registra il tuo numero " "telefonico con un client differente." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Non registrato" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Password necessaria" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Inserire password per autenticazione a due fattori" #: ../tgp-request.c:122 msgid "Ok" msgstr "Ok" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Nessuna password impostata per l'autenticazione a due fattori.Prego " "impostarla nelle impostazioni estese" #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Password non valida" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Accetti la Chat Segreta '%s'?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Chat Segreta" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Le Chat Segrete possono avere un solo punto terminale. Se accetti la chat " "segreta su questo dispositivo, i messaggi dentro di essa non saranno " "disponibili da nessun altra parte. Se declini, potrai accettare la chat su " "altri dispositivi." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Invita almeno un altro utente specificando\n" " il suo nome completo (autocompletamento disponibile).\n" "Puoi aggiungere più utenti una volta che la chat è stata creata." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Nome utente" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Crea chat di gruppo" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Invita utenti" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Cambia password" #: ../tgp-request.c:218 msgid "Current" msgstr "Corrente" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Password" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Conferma" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Nuova password" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Numero di telefono non valido" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Inserire solo numeri nel formato telefonico internazionale, un + iniziale, seguito dal prefisso internazionale e al numero telefonico completo. \n" "Non usare altri caratteri speciali." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Lascia la Chat" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Vuoi lasciare questa chat in modo permanente?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Annulla Chat Segreta" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Vuoi terminare questa chat segreta in modo permanente?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Elimina Contatto" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "Vuoi rimuovere questo utente dal tuo elenco dei contatti globale?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Lascia il Canale" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Vuoi lasciare questo canale?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "recentemente" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "ultima settimana" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "ultimo mese" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "sconosciuto" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Chat di Telegram" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Hai già lasciato questa chat." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Oggetto:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Link d'invito:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "ID chat:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Supergruppo" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Canale" #: ../tgp-chat.c:421 msgid "Group" msgstr "Gruppo" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Utenti in chat." #: ../tgp-chat.c:440 msgid "Type" msgstr "Tipo" telegram-purple/po/nl.po000066400000000000000000000406041363674160100155650ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Dutch (https://www.transifex.com/telegram-purple-developers/teams/53149/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Kon groep niet aanmaken" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Selecteer minimaal één andere gebruiker." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Zoekopdracht mislukt" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Geheime chat gereed." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Geheime chat beëindigd." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Bericht gemarkeerd als gelezen." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Uitnodigingkoppeling: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Chatkoppeling aanmaken mislukt" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "U moet administrator van de groep zijn om dat te kunnen doen." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Bij chat binnengekomen" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Chat toegevoegd aan de chatruimtelijst." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Geheime chat starten..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Gebruikers met koppeling uitnodigen..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Verwijderen en afsluiten..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Kon niet aanmelden als %s: probleem in de onderliggende bibliotheek ‘tgl’. " "Verstuur alstublieft een foutenrapport met het debuglogboek." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Probleem in tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Kon niet aanmelden als %s: landnummer ontbreekt in telefoonnummer. Nummers " "moeten starten met het volledige internationale landnummer, bijvoorbeeld +31" " voor Nederland." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Onvolledig telefoonnummer" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Geheime chat was al verwijderd" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Geheime chat is niet gereed" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Alleen de maker van een kanaal kan berichten plaatsen." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Kan vriend niet uitnodigen om te chatten" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Opgegeven gebruiker bestaat niet." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "telefoonnummer (+ landnummer)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "" #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Wachtwoord (authentificatie in twee stappen)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "SMS-verificatie om op terug te vallen\n" "(Helpt wanneer u Pidgin niet gebruikt en niet wordt gevraagd om de code)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Geheime chats accepteren" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Vrienden offline weergeven na (dagen)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Geschiedenis niet ophalen voor ouder\n" "dan (dagen) (0 voor oneindig)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Alle groepschats aan de vriendenlijst toevoegen" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Ontvangstmeldingen tonen" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Ontvangstmeldingen versturen indien aanwezig" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Telegram-protocol-plug-in." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s heeft geheime chat %1$s aangemaakt." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s heeft titel naar %1$s gewijzigd." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s heeft foto gewijzigd." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s heeft foto verwijderd." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s heeft gebruiker %2$s toegevoegd met koppeling." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s heeft gebruiker %1$s toegevoegd." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s heeft gebruiker %1$s verwijderd." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s heeft zelfvernietigingstimer ingesteld op %1$d seconde." msgstr[1] "%2$s heeft zelfvernietigingstimer ingesteld op %1$d seconden." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s heeft %1$d bericht als gelezen gemarkeerd." msgstr[1] "%2$s heeft %1$d berichten als gelezen gemarkeerd." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s heeft %1$d bericht verwijderd." msgstr[1] "%2$s heeft %1$d berichten verwijderd." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s heeft een schermafdruk gemaakt van %1$d bericht." msgstr[1] "%2$s heeft een schermafdruk gemaakt van %1$d berichten." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Kanaal %1$s aangemaakt" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Telegram-kanalen" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Bericht versturen mislukt." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Afbeelding versturen mislukt." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s heeft een sticker verzonden." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "" #: ../tgp-msg.c:535 msgid "[video]" msgstr "" #: ../tgp-msg.c:540 msgid "[document]" msgstr "" #: ../tgp-msg.c:545 msgid "[position]" msgstr "" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "bericht laden mislukt" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "document of foto laden mislukt" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Kan niet verbinden met hoofdserver" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Kan niet verbinden met server: ping-timeout" #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Verbinding met de server verloren..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram wil uw identiteit graag controleren. Voer de inlogcode in die u per" " SMS heeft ontvangen." #: ../tgp-request.c:54 msgid "Login code" msgstr "Inlogcode" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Inlogcode invoeren" #: ../tgp-request.c:54 msgid "the code" msgstr "de code" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "Ok" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Annuleren" #: ../tgp-request.c:94 msgid "Registration" msgstr "Registratie" #: ../tgp-request.c:95 msgid "First name" msgstr "Voornaam" #: ../tgp-request.c:98 msgid "Last name" msgstr "Achternaam" #: ../tgp-request.c:102 msgid "Register" msgstr "Registreren" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Registreer uw telefoonnummer." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Uw telefoonnummer is niet geregistreerd. Registreer uw telefoon op een ander" " apparaat." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Niet geregistreerd" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Wachtwoord benodigd" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Wachtwoord invoeren voor authentificatie in twee stappen" #: ../tgp-request.c:122 msgid "Ok" msgstr "Ok" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Geen wachtwoord ingesteld voor authentificatie in twee stappen. Voer deze in" " bij de uitgebreide instellingen." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Wachtwoord ongeldig" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Geheime chat ‘%s’ op dit apparaat accepteren?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Geheime chat" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Geheime chat kunnen slechts één afleverpunt bevatten. Als u een geheime chat" " op dit apparaat accepteert kunt u deze berichten nergens anders bekijken. " "Als u weigert kunt u de chat nog steeds op andere apparaten accepteren." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Nodig minimaal één andere gebruiker uit door\n" " volledige namen op te geven (automatisch \n" "aanvullen is beschikbaar). U kunt meer gebruikers\n" "toevoegen als de chat aangemaakt is." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Gebruikersnaam" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Groepschat aanmaken" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Gebruikers uitnodigen" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Wachtwoord wijzigen" #: ../tgp-request.c:218 msgid "Current" msgstr "Huidig" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Wachtwoord" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Bevestigen" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Nieuw wachtwoord" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Onvolledig telefoonnummer" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Voer alleen cijfers in in het internationale telefoonnummerformaat, dus om te beginnen een + gevolgd door het landnummer en het telefoonnummer.\n" "Gebruik geen andere speciale tekens." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Chat verlaten" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Wilt u deze chat permanent verlaten?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Geheime chat beëindigen" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Wilt u deze geheime chat permanent beëindigen?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Contact verwijderen" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "Wil u deze gebruiker uit uw algemene contactenlijst verwijderen?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Kanaal verlaten" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Wilt u dit kanaal verlaten?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d-%m-%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "recent" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "afgelopen week" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "afgelopen maand" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "onbekend" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Telegram-chats" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "U heeft dit kanaal al verlaten." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Onderwerp:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Uitnodigingskoppeling:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Chat-ID:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Supergroep" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Kanaal" #: ../tgp-chat.c:421 msgid "Group" msgstr "Groep" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Gebruikers in chat" #: ../tgp-chat.c:440 msgid "Type" msgstr "Soort" telegram-purple/po/nn.po000066400000000000000000000411131363674160100155630ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Yngve Spjeld-Landro , 2020 # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Norwegian Nynorsk (https://www.transifex.com/telegram-purple-developers/teams/53149/nn/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: nn\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Klarte ikkje å laga gruppa" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Vel minst éin annan brukar." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Spørjinga feila" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Den private praten er klar." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Den private praten vart avslutta." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Meldinga er merkt som lesen." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Invitasjonslenkje: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Klarte ikkje å laga pratelenkja" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Du må vera gruppeadministrator for å gjera det." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Vart med i praten" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Praten vart lagt til prateromslista." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Start privat prat …" #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Inviter brukarar med lenkje …" #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Slett og avslutt …" #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Klarer ikkje å logga på som %s: problem i det underliggjande biblioteket " "'tgl'. Send gjerne ei feilmelding saman med feilmeldingsloggen. " #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problem i tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Klarte ikkje å logga på som %s: telefonnummeret manglar landskoden. Nummeret" " må byrja med den fulle internasjonale landskoden, t.d. +47 for Noreg." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Ufullstendig telefonnummer" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Den private praten var allereie sletta" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Den private praten er ikkje klar" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Berre den som laga kanalen kan leggja til meldingar." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Klarer ikkje å invitera kontakten til praten" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Den oppgjevne brukaren finst ikkje." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "telefonnr. (+ landskode)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "kick : spark ein brukar frå rommet." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Passord (to-stegs-autentisering)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Tekstmeldingsverifisering ved feil\n" "(nyttig om Pidgin ikkje vert nytta og du ikkje vert spurt etter kode)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Alltid" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Aldri" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Spør" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Godta hemmelege pratar" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Syn kontaktar som fråkopla etter (dagar)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Hent ikkje eldre historikk enn (dagar)\n" "(0 er uendeleg)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Forkast" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Auto-lasting" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Auto-last filoverføringar inntil (kb)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Større filoverføringar" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Legg alle gruppepratane til kontaktlista" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Syn mottaksmeldingar" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Send mottaksmeldingar når til stades" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Bruk IPv6 for tilkopling (krev omstart)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Telegram-protokolltillegg." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s laga praten %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s endra tittelen til %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s endra bildet." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s sletta bildet." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s la til brukaren %2$s over ei lenkje." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s la til brukaren %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s sletta brukaren %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s sette den sjølvøydeleggjande nedteljinga til %1$d sekund." msgstr[1] "%2$s sette den sjølvøydeleggjande nedteljinga til %1$d sekund." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s markerte %1$d melding som lesen." msgstr[1] "%2$s markerte %1$d meldingar som lesne." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s sletta %1$d melding." msgstr[1] "%2$s sletta %1$d meldingar." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s laga eit skjembilde av %1$d melding." msgstr[1] "%2$s laga eit skjembilde av %1$d meldingar." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Kanalen %1$s vart oppretta" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Telegram-kanalar" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Klarte ikkje å senda meldinga." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Klarte ikkje å senda bildet." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s sende eit klistremerke." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "[melding ikkje tilgjengeleg]" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[bilde]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[lyd]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[video]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[dokument]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[posisjon]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[kontakt]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[nettside]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[kan ikkje bruka mediet]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> %s skreiv:
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Ukjed brukar skreiv:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "klarte ikkje å lasta meldinga" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "dokument" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "lyd" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "animasjon" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "video" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "> Vidaresendt frå %s:
> %s" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "> Vidaresendt:
> %s" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "klarte ikkje å lasta dokument eller bilde" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Klarer ikkje å kopla opp mot hovudtenaren" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Klarer ikkje å kopla opp mot tenaren: ping-tidsavbrot." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Mista sambandet til tenaren …" #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram må verifisera identiteten din. Skriv koden du fekk som " "tekstmelding." #: ../tgp-request.c:54 msgid "Login code" msgstr "Påloggingskode" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Skriv påloggingskoden" #: ../tgp-request.c:54 msgid "the code" msgstr "koden" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "OK" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Avbryt" #: ../tgp-request.c:94 msgid "Registration" msgstr "Registrering" #: ../tgp-request.c:95 msgid "First name" msgstr "Fornamn" #: ../tgp-request.c:98 msgid "Last name" msgstr "Etternamn" #: ../tgp-request.c:102 msgid "Register" msgstr "Registrer" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Registrer telefonnummeret ditt." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Telefonnummeret er ikkje registrert. Registrer telefonnummeret ditt frå ein " "annan klient." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Ikkje registrert" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Må ha passordet" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Skriv passordet for to-stegs-autentisering" #: ../tgp-request.c:122 msgid "Ok" msgstr "OK" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Passordet til to-stegs-autentiseringa er enno ikkje laga. Skriv det i dei " "utvida innstillingane." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Passordet er ugyldig" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Vil du godta den private praten '%s' på denne eininga?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Privat prat" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Private pratar kan berre ha eitt endepunkt. Godtek du ein privat prat på " "denne eininga vil ikkje meldingane i han vera tilgjengelege nokon annan " "stad. Om du avslår, kan du godta praten på andre einingar." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Inviter minst éin annan brukar ved å skriva det fulle\n" "namnet (auto-fullføring er mogleg).\n" "Du kan leggja til fleire brukarar straks praten er oppretta." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Brukarnamn" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Lag gruppeprat" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Inviter brukarar" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Endra passordet" #: ../tgp-request.c:218 msgid "Current" msgstr "Gjeldande" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Passord" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Stadfest" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Nytt passord" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Ugyldig telefonnummer" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Bruk berre tal i det internasjonale telefonnummerformatet: eit plussteikn saman med landskoden og sjølve telefonnummeret.\n" "Du kan ikkje nytta andre teikn." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Forlat praten" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Vil du forlata denne praten for alltid?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Avbryt privat prat" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Vil du avslutta denne løynde praten for alltid?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Slett kontakt" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "Vil du fjerna denne brukaren frå den globale kontaktlista di?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Forlat kanalen" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Vil du forlata denne kanalen?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "nyleg" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "sist veke" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "sist månad" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "ukjend" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Telegram-pratar" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Du har allereie forlate denne praten." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Emne:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Invitasjonslenkje:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Prat-ID:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Supergruppe" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Kanal" #: ../tgp-chat.c:421 msgid "Group" msgstr "Gruppe" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Brukarar i praten" #: ../tgp-chat.c:440 msgid "Type" msgstr "Type" telegram-purple/po/pl_PL.po000066400000000000000000000441301363674160100161600ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Piotr Drąg , 2019 # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Polish (Poland) (https://www.transifex.com/telegram-purple-developers/teams/53149/pl_PL/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pl_PL\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Nie można utworzyć grupy" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Należy wybrać co najmniej jednego użytkownika." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Zapytanie się nie powiodło" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Tajna rozmowa jest gotowa." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Zakończono tajną rozmowę." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Oznaczono wiadomość jako przeczytaną." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Odnośnik do zaproszenia: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Utworzenie odnośnika do rozmowy się nie powiodło" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Należy być administratorem grupy, aby to zrobić." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Dołączono do rozmowy" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Dodano rozmowę do listy pokojów rozmów." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Rozpocznij tajną rozmowę…" #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Zaproś użytkowników przez odnośnik…" #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Usuń i wyjdź…" #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Nie można zalogować jako %s: problem w bibliotece „tgl”. Proszę zgłosić błąd" " z dziennikiem debugowania." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problem w bibliotece tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Nie można zalogować jako %s: numer telefonu nie ma przedrostka kraju. Numery" " muszą zaczynać się od pełnego międzynarodowego przedrostka, np. +48 dla " "Polski." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Niepełny numer telefonu" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Już usunięto tajną rozmowę" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Tajna rozmowa nie jest gotowa" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Tylko twórca kanału może wysyłać wiadomości." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Nie można zaprosić znajomego do rozmowy" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Podany użytkownik nie istnieje." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "numer telefonu (+ przedrostek kraju)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "kick : wyrzuca użytkownika z pokoju." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Hasło (uwierzytelnianie dwuetapowe)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Zapasowa weryfikacja przez SMS\n" "(Pomaga w przypadkach, kiedy nie jest używany program Pidgin i użytkownik nie jest pytany o kod)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Zawsze" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Nigdy" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Pytanie" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Odbieranie tajnych rozmów" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Wyświetlanie znajomych jako w trybie offline po (w dniach)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Bez pobierania historii starszej niż (w dniach)\n" "(0 oznacza brak ograniczenia)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Odrzucanie" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Wczytywanie automatycznie" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Automatyczne wczytywanie przesyłania plików do (KB)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Przesyłanie większych plików" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Dodawanie wszystkich rozmów grupowych do listy znajomych" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Wyświetlanie powiadomień o odebraniu" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Wysyłanie powiadomień o odebraniu podczas obecności" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Używanie IPv6 do łączenia (wymaga ponownego uruchomienia)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Wtyczka protokołu Telegram." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "Użytkownik %2$s utworzył rozmowę %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "Użytkownik %2$s zmienił tytuł na %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "Użytkownik %s zmienił zdjęcie." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "Użytkownik %s usunął zdjęcie." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "Użytkownik %1$s dodał użytkownika %2$s przez odnośnik." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "Użytkownik %2$s dodał użytkownika %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "Użytkownik %2$s usunął użytkownika %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "Użytkownik %2$s ustawił czas samozniszczenia na %1$d sekundę." msgstr[1] "Użytkownik %2$s ustawił czas samozniszczenia na %1$d sekundy." msgstr[2] "Użytkownik %2$s ustawił czas samozniszczenia na %1$d sekund." msgstr[3] "Użytkownik %2$s ustawił czas samozniszczenia na %1$d sekund." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "Użytkownik %2$s oznaczył %1$d wiadomość jako przeczytaną." msgstr[1] "Użytkownik %2$s oznaczył %1$d wiadomości jako przeczytane." msgstr[2] "Użytkownik %2$s oznaczył %1$d wiadomości jako przeczytane." msgstr[3] "Użytkownik %2$s oznaczył %1$d wiadomości jako przeczytane." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "Użytkownik %2$s usunął %1$d wiadomość." msgstr[1] "Użytkownik %2$s usunął %1$d wiadomości." msgstr[2] "Użytkownik %2$s usunął %1$d wiadomości." msgstr[3] "Użytkownik %2$s usunął %1$d wiadomości." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "Użytkownik %2$s utworzył zrzut ekranu %1$d wiadomości." msgstr[1] "Użytkownik %2$s utworzył zrzut ekranu %1$d wiadomości." msgstr[2] "Użytkownik %2$s utworzył zrzut ekranu %1$d wiadomości." msgstr[3] "Użytkownik %2$s utworzył zrzut ekranu %1$d wiadomości." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Utworzono kanał %1$s" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Kanały Telegram" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Wysłanie wiadomości się nie powiodło." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Wysłanie obrazu się nie powiodło." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "Użytkownik %s wysłał naklejkę." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "[wiadomość jest niedostępna]" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[zdjęcie]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[dźwięk]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[film]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[dokument]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[pozycja]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[kontakt]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[strona WWW]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[nieobsługiwane multimedia]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> Użytkownik %s napisał:
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Nieznany użytkownik napisał:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "wczytanie wiadomości się nie powiodło" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "dokument" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "dźwięk" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "animacja" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "film" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "> Przekazano od %s:
> %s" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "> Przekazano:
> %s" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "wczytywanie dokumentu lub obrazu się nie powiodło" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Nie można połączyć z głównym serwerem" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "" "Nie można połączyć z serwerem: przekroczono czas oczekiwania na odpowiedź." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Utracono połączenie z serwerem…" #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Usługa Telegram musi zweryfikować tożsamość użytkownika. Proszę podać kod " "logowania otrzymany w wiadomości SMS." #: ../tgp-request.c:54 msgid "Login code" msgstr "Kod logowania" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Proszę podać kod logowania" #: ../tgp-request.c:54 msgid "the code" msgstr "kod" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "OK" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Anuluj" #: ../tgp-request.c:94 msgid "Registration" msgstr "Rejestracja" #: ../tgp-request.c:95 msgid "First name" msgstr "Imię" #: ../tgp-request.c:98 msgid "Last name" msgstr "Nazwisko" #: ../tgp-request.c:102 msgid "Register" msgstr "Zarejestruj" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Proszę zarejestrować numer telefonu." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Numer telefonu nie jest zarejestrowany. Proszę go zarejestrować w innym " "kliencie." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Niezarejestrowany" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Wymagane jest hasło" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Proszę podać hasło dla uwierzytelniania dwuetapowego" #: ../tgp-request.c:122 msgid "Ok" msgstr "OK" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Nie ustawiono hasła dla uwierzytelniania dwuetapowego. Proszę podać je w " "rozszerzonych ustawieniach." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Nieprawidłowe hasło" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Odebrać tajną rozmowę „%s” na tym urządzeniu?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Tajna rozmowa" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Tajne rozmowy mogą mieć tylko jeden punkt wyjściowy. Jeśli tajna rozmowa " "zostanie odebrana na tym urządzeniu, to jej wiadomości nie będą dostępne " "nigdzie indziej. Jeśli zostanie odrzucona, to nadal można ją odebrać na " "innych urządzeniach." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Należy zaprosić co najmniej jednego użytkownika podając\n" "jego imię i nazwisko (automatyczne uzupełnianie jest dostępne).\n" "Można dodać więcej użytkowników po utworzeniu rozmowy." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Nazwa użytkownika" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Utwórz rozmowę grupową" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Zaproś użytkowników" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Zmień hasło" #: ../tgp-request.c:218 msgid "Current" msgstr "Obecne" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Hasło" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Potwierdzenie" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Nowe hasło" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Nieprawidłowy numer telefonu" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Proszę podać tylko numery w międzynarodowym formacie numerów telefonu, czyli + z przedrostkiem kraju i numer telefonu.\n" "Nie należy używać innych znaków specjalnych." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Opuść rozmowę" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Trwale opuścić tę rozmowę?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Przerwij tajną rozmowę" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Trwale zakończyć tę tajną rozmowę?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Usuń kontakt" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "Usunąć tego użytkownika z globalnej listy kontaktów?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Opuść kanał" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Opuścić ten kanał?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H∶%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "niedawno" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "ostatni tydzień" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "ostatni miesiąc" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "nieznane" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Rozmowy Telegram" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Już opuszczono tę rozmowę." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Temat:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Odnośnik do zaproszenia:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Identyfikator rozmowy:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Supergrupa" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Kanał" #: ../tgp-chat.c:421 msgid "Group" msgstr "Grupa" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Użytkownicy w rozmowie" #: ../tgp-chat.c:440 msgid "Type" msgstr "Typ" telegram-purple/po/pot_header.new000066400000000000000000000012561363674160100174410ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Ben Wiederhake \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" telegram-purple/po/pot_header.old000066400000000000000000000011211363674160100174150ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" telegram-purple/po/pt_BR.po000066400000000000000000000416241363674160100161650ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Portuguese (Brazil) (https://www.transifex.com/telegram-purple-developers/teams/53149/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Não foi possível criar o grupo" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Por favor, selecione pelo menos 1 usuário." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Falha na fila" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Conversa secreta pronta" #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Conversa secreta terminada." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Mensagem marcada como \"lida\"." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Link de convite: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Falha na criação do link para a conversa" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Você precisa ser Administrador do grupo para fazer isso" #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Entrou na conversa" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Conversa adicionada a listas de salas de conversa" #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Começar conversa secreta..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Convidar usuários pelo link..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Deletar e sair..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Impossível entrar em 1%s: problema na importante biblioteca 'tgl'. Por favor" " envie um relatório de bug com o registro de debug" #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problema na tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Impossível entrar em %s: número de telefone sem o prefixo do país. Números " "de telefone precisam iniciar com o código do prefixo internacional, por " "exemplo +1 para Estados Unidos" #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Número de telefone inválido" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Bate papo secreto já foi excluído" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Bate papo secreto não está pronto" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Somente o criador do canal consegue enviar mensagens." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Não foi possível convidar o amigo para a conversa" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "O usuário especificado não existe." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "número do telefone(+ prefixo do país)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "Chutar : Chutar um usuário da sala." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Senha (dois processos de autenticação)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Retorno de verificaçao via SMS\n" "(Ajuda quando não estiver usando o Pidgin e não é apresentado a janela com o código)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Sempre" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Nunca" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Perguntar" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Aceitar conversa secrete" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Mostrar período que os amigos estão offline (dias)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Não trazer históricos mais velhos que (dias)\n" "(0 para não limitar)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Descartar" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Carregar automaticamente" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Carregar automaticamente arquivos transferidos até (kb)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Transferência de grandes arquivos" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Adicinar todos os grupos de conversa a lista de amigos" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Mostrar avisos de recebimento" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Mandar avisos de recebimento quando estiver online" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Use IPv6 para conexão (necessário reiniciar)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Plugin do protocolo do Telegram" #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s criouo a conversa %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s mudou o assunto para %1$s," #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s mudou a foto." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s deletou a foto." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s adicionou o usuário %2$s por link." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s adicionou o usuário %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s reoveu o usuário %1$s" #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s tempo para auto destruição configurado para %1$d segundos." msgstr[1] "%2$s tempo para auto destruição configurado para %1$d segundos." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s marcou %1$d mensagens como lidas." msgstr[1] "%2$s marcou %1$d mensagens como lidas." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s deletou %1$d mensagens." msgstr[1] "%2$s deletou %1$d mensagens." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s capturou a tela de %1$d mensagens." msgstr[1] "%2$s capturou a tela de %1$d mensagens." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Canal %1$s criado" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Canais do Telegram" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Envio de imagem falhou." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Envio de imagem falhou." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s enviou um adesivo." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[imagem]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[audio]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[video]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[documento]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[posição]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[contato]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[site]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[mídias não suportadas]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> %s escreveu:
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Usuário desconhecido escreveu:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "Carregamento da mensagem falhou" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "documento" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "áudio" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "animação" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "vídeo" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "carregamento de documento ou imagem falhou" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Não pode se conectar no servidor principal" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Não pode se conectar no servidor: Ping timeout." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Conexão com o servidor foi perdida..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram quer confirmar sua identidade. Por favor insira o código recebido " "por SMS." #: ../tgp-request.c:54 msgid "Login code" msgstr "Código de login" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Insira o código de login" #: ../tgp-request.c:54 msgid "the code" msgstr "o código" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "OK" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Cancelar" #: ../tgp-request.c:94 msgid "Registration" msgstr "Registrar" #: ../tgp-request.c:95 msgid "First name" msgstr "Primeiro nome" #: ../tgp-request.c:98 msgid "Last name" msgstr "Último nome" #: ../tgp-request.c:102 msgid "Register" msgstr "Registrar" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Por favor registre seu número de telefone." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Número de telefone não registrado. Por favor registre seu número de telefone" " com um cliente diferente." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Não Registrado" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Senha necessária" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Insira a senha para o processo de autenticação dupla" #: ../tgp-request.c:122 msgid "Ok" msgstr "OK" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Não há senha configurado para o processo de autenticação dupla. Por favor " "insira nas configurações expandidas." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Senha inválida." #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Aceitar conversa Secreta '%s'?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Conversa Secreta" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Conversas secretas podem ocorrer em apenas um local. Se você aceitar uma " "conversa secreta nesse dispositivo, essas mensagens não estarão disponíveis " "em nenhum outro local. Se você rejeitar, pode aceitar a conversa em outros " "dispositivos." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Convidar ao menos mais um usuário\n" "pelo nome completo (autocompletar disponível).\n" "Você pode adicionar mais usuários depois que a conversa for criada." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Nome de usuário" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Criar conversa em grupo" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Convidar usuários" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Mudar senha" #: ../tgp-request.c:218 msgid "Current" msgstr "Atual" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Senha" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Confirma" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Nova senha" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Número de telefone inválido" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Por favor insira apenas número no formato de número telefônico internacional, começando com + seguido pelo código do país e o número do telefone.\n" "Não use caractéres especiais." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Deixar bate papo" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Você deseja deixar este bate papo permanentemente?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Suspender bate papo secreto" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Você deseja encerrar este bate papo secreto permanentemente?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Contato excluído" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "Você deseja remover este usuário da sua lista de contatos global?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Sair do canal" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Você deseja sair deste canal?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "recentemente" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "semana passada" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "mês passado" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "desconhecido" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Bate papos Telegram" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Você já saiu dessa conversa." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Assunto:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Link do convite:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "Identificação da conversa:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Supergrupo" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Canal" #: ../tgp-chat.c:421 msgid "Group" msgstr "Grupo" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Usuários no chat." #: ../tgp-chat.c:440 msgid "Type" msgstr "Tipo" telegram-purple/po/ru_RU.po000066400000000000000000000523211363674160100162070ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Olesya Gerasimenko , 2019 # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Russian (Russia) (https://www.transifex.com/telegram-purple-developers/teams/53149/ru_RU/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru_RU\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Не удалось создать группу" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Пожалуйста, выберите хотя бы одного другого пользователя." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Ошибка запроса" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Секретный чат готов." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Секретный чат завершён." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Сообщение помечено как прочитанное." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Пригласительная ссылка: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Не удалось создать ссылку чата" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Вы должны быть администратором группы, чтобы сделать это." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Чат подключён." #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Чат добавлен в список чатов." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Начать секретный чат…" #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Пригласить пользователей по ссылке..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Удалить и выйти..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Не удалось войти как %s: проблема с базовой библиотекой «tgl». Пожалуйста, " "отправьте сообщение об ошибке, приложив соответствующие сообщения журнала " "отладки." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Проблема с библиотекой «tgl»" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Не удалось войти как %s: номер телефона не содержит кода страны. Номера " "должны начинаться с международного кода, +7 для России." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Неполный номер телефона" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Секретный чат уже был удалён" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Секретный чат не готов" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Только создатель канала может отправлять сообщения." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Не удалось пригласить пользователя в чат" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Указанный пользователь не существует." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "номер телефона (+ префикс страны)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "удалить : удалить пользователя из чата." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Пароль (двухфакторная аутентификация) " #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Альтернативная СМС-верификация\n" "(Помогает, если вы не используете Pidgin и вам не было предложено ввести код)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Всегда" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Никогда" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Спрашивать" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Присоединяться к секретным чатам" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Показывать друзей как оффлайн через (в днях)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Не загружать историю старше чем (в днях)\n" "(«0» — загрузка без ограничений)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Не принимать" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Загружать автоматически" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Автоматически загружать файлы размером не более (КБ)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Передача больших файлов" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Добавлять все групповые чаты в контакт-лист" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Показывать уведомления о получении" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Отправлять уведомления о получении, если имеются" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Использовать IPv6 для подключения (требуется перезапуск)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Подключаемый модуль протокола Telegram." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s создал чат %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s сменил название на %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s сменил фото." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s удалил фото." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s добавил пользователя %2$s по ссылке." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s добавил пользователя %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s удалил пользователя %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s установил таймер самоуничтожения на %1$d секунду." msgstr[1] "%2$s установил таймер самоуничтожения на %1$d секунды." msgstr[2] "%2$s установил таймер самоуничтожения на %1$d секунд." msgstr[3] "%2$s установил таймер самоуничтожения на %1$d секунд." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s пометил %1$d сообщение прочитанными." msgstr[1] "%2$s пометил %1$d сообщения прочитанными." msgstr[2] "%2$s пометил %1$d сообщений прочитанными." msgstr[3] "%2$s пометил %1$d сообщений прочитанными." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s удалил %1$d сообщение." msgstr[1] "%2$s удалил %1$d сообщения." msgstr[2] "%2$s удалил %1$d сообщений." msgstr[3] "%2$s удалил %1$d сообщений." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s сделал снимок экрана %1$d сообщения." msgstr[1] "%2$s сделал снимок экрана %1$d сообщений." msgstr[2] "%2$s сделал снимок экрана %1$d сообщений." msgstr[3] "%2$s сделал снимок экрана %1$d сообщений." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Канал %1$s создан" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Telegram-каналы" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Не удалось отправить сообщение." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Не удалось отправить изображение." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s отправил стикер." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "[сообщение недоступно]" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[фото]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[аудио]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[видео]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[документ]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[местоположение]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[контакт]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[веб-страница]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[неподдерживаемый формат]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> %s написал:
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Неизвестный пользователь написал:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "не удалось загрузить сообщения" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "документ" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "аудио" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "анимация" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "видео" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "> Переслано от %s:
> %s" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "> Переслано:
> %s" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "не удалось загрузить документ или изображение" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Не удалось подключиться к главному серверу" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Не удалось подключиться к серверу: истекло время проверки связи." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Потеряно соединение с сервером..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram необходимо подтвердить вашу личность. Пожалуйста, введите код, " "полученный вами через СМС." #: ../tgp-request.c:54 msgid "Login code" msgstr "Код входа" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Введите код входа" #: ../tgp-request.c:54 msgid "the code" msgstr "код" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "Подтвердить" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Отмена" #: ../tgp-request.c:94 msgid "Registration" msgstr "Регистрация" #: ../tgp-request.c:95 msgid "First name" msgstr "Имя" #: ../tgp-request.c:98 msgid "Last name" msgstr "Фамилия" #: ../tgp-request.c:102 msgid "Register" msgstr "Зарегистрироваться" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Пожалуйста, зарегистрируйте свой номер телефона." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Номер телефона не зарегистрирован. Пожалуйста, зарегистрируйте ваш телефон в" " другом клиенте." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Не зарегистрирован" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Необходим пароль" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Введите пароль для двухфакторной аутентификации" #: ../tgp-request.c:122 msgid "Ok" msgstr "ОК" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Не указан пароль для двухфакторной аутентификации. Пожалуйста, введите его в" " расширенных настройках." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Неверный пароль" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Присоединиться к секретному чату «%s» на этом устройстве?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Секретный чат" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Секретные чаты могут иметь только одну конечную точку. Если вы подтвердите " "секретный чат на этом устройстве, то его сообщения не будут доступны на " "других устройствах. Если вы отклоните секретный чат, то сможете подтвердить " "его на других устройствах." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Пригласите хотя бы одного дополнительного пользователя,\n" "указав его полное имя (доступно автодополнение).\n" "Вы сможете добавить больше пользователей после создания чата." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Пользователь" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Создать групповой чат" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Пригласить пользователей" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Сменить пароль" #: ../tgp-request.c:218 msgid "Current" msgstr "Текущий" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Пароль" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Подтвердить" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Новый пароль" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Неправильный номер телефона" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Пожалуйста, введите только цифры в международном формате телефонного номера: сначала знак +, затем префикс страны и далее сам телефонный номер.\n" "Не используйте никакие другие специальные символы." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Покинуть чат" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Покинуть этот чат навсегда?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Отменить секретный чат" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Отменить этот чат навсегда?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Удалить контакт" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "" "Удалить этого пользователя из вашего глобального списка контактов навсегда?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Покинуть канал" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Покинуть этот канал?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "недавно" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "прошлая неделя" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "прошлый месяц" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "неизвестно" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Telegram-чаты" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Вы уже покинули этот чат." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Заголовок:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Пригласительная ссылка:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "ID чата:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Супергруппа" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Канал" #: ../tgp-chat.c:421 msgid "Group" msgstr "Группа" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Пользователи в чате" #: ../tgp-chat.c:440 msgid "Type" msgstr "Тип" telegram-purple/po/sq.po000066400000000000000000000421761363674160100156050ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Besnik , 2019 # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Albanian (https://www.transifex.com/telegram-purple-developers/teams/53149/sq/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: sq\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "S’u krijua dot grup" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Ju lutemi, përzgjidhni të paktën një përdorues tjetër." #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Kërkesa Dështoi" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Fjalosje e fshehtë gati." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Fjalosja e fshehtë përfundoi." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Mesazh i shënuar si i lexuar." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Lidhje ftese: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Krijimi i lidhjes së fjalosjes dështoi" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Lypset të jeni përgjegjës grupi që të bëni këtë." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "U hy në fjalosje" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Fjalosja u shtua te listë dhomash fjalosjeje." #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Filloni fjalosje të fshehtë..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Ftoni përdorues përmes lidhjesh..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Fshije dhe dil..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "S’arrihet të hyhet si %s: problem në librarinë përkatëse 'tgl'. Ju lutemi, " "parashtroni një njoftim të metash të shoqëruar nga regjistrimi i " "diagnostikimit." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Problem në tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "I pazoti të hyjë si %s: numrit të telefonit i mungon prefiksi i vendit. " "Numrat duhet të fillojnë me kodin e plotë prefiksi ndërkombëtar, p.sh. +355 " "për Shqipërinë." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Numër telefoni jo i plotë" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Fjalosja e fshehtë qe fshirë tashmë" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Fjalosja e fshehtë s’është gati" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Mesazhe mund të postojë vetëm krijuesi i një kanali." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "S’ftohet dot shok në fjalosje" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Përdoruesi i treguar nuk ekziston." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "nr. telefoni (+ prefiks vendi)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "kick : Përzini një përdorues nga dhoma." #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Fjalëkalim (mirëfilltësim dyfaktorësh)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Kalim vetvetiu për verfikime SMS\n" "(I dobishëm kur s’përdoret Pidgin-i dhe nuk ju kërkohet kod)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "Përherë" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "Kurrë" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "Pyet" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Prano fjalosje të fshehta" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Shfaqi shokët si jo të lidhur pas (ditësh)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Mos sill historik më të vjetë se (ditë)\n" "(0 për pa kufizim)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "Hidhe tej" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "Vetëngarkoje" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "Vetëngarko shpërngulje kartelash deri në (kb)" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "Shpërngulje më të mëdha kartelash" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Shtoji krejt fjalosjet e grupit te lista e shokëve" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Shfaq njoftime dëftese" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Dërgo njoftime dëftese kur ka" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "Për lidhje përdor IPv6 (lyp rinisje)" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Shtojcë Protokolli Telegram." #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s krijoi fjalosjen %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s ndryshoi titullin te %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s ndryshoi foton." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s fshiu foton." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s shtoi përdoruesin %2$s përmes lidhjeje." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s shtoi përdoruesin %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s fshiu përdoruesin %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s e vendosi kohëmatësin e vetëshkatërrimit në %1$d sekondë." msgstr[1] "%2$s e vendosi kohëmatësin e vetëshkatërrimit në %1$d sekonda." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s shënoi %1$d mesazh si të lexuar." msgstr[1] "%2$s shënoi %1$d mesazhe si të lexuar." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s fshiu %1$d mesazh." msgstr[1] "%2$s fshiu %1$d mesazhe." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s bëri një foto ekrani të %1$d mesazhi." msgstr[1] "%2$s bëri një foto ekrani të %1$d mesazheve." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Kanali %1$s u krijua" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Kanale Telegram-i" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Dërgimi i mesazhit dështoi." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Dërgimi i figurës dështoi." #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s dërgoi një ngjitëse." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "[mesazh jo i passhëm]" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "[foto]" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "[audio]" #: ../tgp-msg.c:535 msgid "[video]" msgstr "[video]" #: ../tgp-msg.c:540 msgid "[document]" msgstr "[dokument]" #: ../tgp-msg.c:545 msgid "[position]" msgstr "[pozicion]" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "[kontakt]" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "[faqe web]" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "[media që nuk mbulohet]" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "%s> %s shkroi:
> %s
%s" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "%s> Një përdorues i panjohur shkroi:
> %s
%s" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "dështoi në ngarkim mesazhi" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "dokument" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "audio" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "animacion" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "video" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "> Përcjellë nga %s:
> %s" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "> Përcjellë:
> %s" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "Ngarkimi i dokumentit ose fotos dështoi" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "S’lidhet dot te shërbyesi kryesor" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "S’lidhet dot te shërbyesi: Ping-ut i mbaroi koha." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Humbi lidhja me shërbyesin..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram-i dëshiron të verifikojë identitetin tuaj. Ju lutemi, jepni kodin e" " hyrjes që keni marrë përmes SMS-je." #: ../tgp-request.c:54 msgid "Login code" msgstr "Kod hyrjeje" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Jepni kodin e hyrjes postar" #: ../tgp-request.c:54 msgid "the code" msgstr "kodi" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "OK" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Anuloje" #: ../tgp-request.c:94 msgid "Registration" msgstr "Regjistrim" #: ../tgp-request.c:95 msgid "First name" msgstr "Emër" #: ../tgp-request.c:98 msgid "Last name" msgstr "Mbiemër" #: ../tgp-request.c:102 msgid "Register" msgstr "Regjistrohuni" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Ju lutemi, regjistroni numrin tuaj të telefonit." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Numri i telefonit s’është i regjistruar. Ju lutemi, regjistroni telefonin " "tuaj me një klient tjetër." #: ../tgp-request.c:109 msgid "Not registered" msgstr "I paregjistruar" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Lypset fjalëkalim" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Jepni fjalëkalim për mirëfilltësim dyfaktorësh" #: ../tgp-request.c:122 msgid "Ok" msgstr "Ok" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Pa fjalëkalim të caktuar, për mirëfilltësim dyfaktorësh. Ju lutemi, jepeni " "te rregullimet e thelluara." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Fjalëkalim i pavlefshëm" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Të pranohet fjalosja e fshehtë '%s' në këtë pajisje?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Fjalosje e fshehtë" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "Fjalosjet e fshehta mund të kenë vetëm një pikë marrjeje. Nëse pranoni një " "fjalosje të fshehtë në këtë pajisje, mesazhet e saj nuk do të jenë të " "dukshme gjetiu. Nëse nuk e pranoni, mund ta pranoni fjalosjen në pajisje të " "tjera." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Ftoni të paktën një përdorues shtesë duke dhënë\n" " emrat e tyre të plotë (mund të përdoret vetëplotësimi).\n" "Pasi fjalosja të jetë krijuar, mund të shtoni më tepër përdorues." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Emër përdoruesi" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Krijoni fjalosje grupi" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Ftoni përdorues" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Ndryshoni fjalëkalimin" #: ../tgp-request.c:218 msgid "Current" msgstr "I tanishmi" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Fjalëkalim" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Ripohojeni" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Fjalëkalimi i ri" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Numër telefoni i pavlefshëm" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Ju lutemi, jepni vetëm numra në formatin për numra telefonash ndërkombëtarë, një + paraprijës të ndjekur nga prefiksi i vendit dhe numri i telefonit.\n" "Mos përdorni shenja të tjera speciale." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Braktise Fjalosjen" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Doni të dilni përgjithmonë nga kjo fjalosje?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Ndërprite Fjalosjen e Fshehtë" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Doni ta përfundoni përgjithmonë këtë fjalosje të fshehtë?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Fshije Kontaktin" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "Doni të hiqet ky përdorues prej listës suaj globale të kontakteve?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Braktise Kanalin" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Doni ta braktisni këtë kanal?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "së fundi" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "javën e fundit" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "muajin e fundit" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "e panjohur" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Fjalosje Telegram-i" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "E keni lëndë tashmë këtë fjalosje." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Subjekt:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Lidhje ftese:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "ID Fjalosjeje:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Supergrup" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Kanal" #: ../tgp-chat.c:421 msgid "Group" msgstr "Grup" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Përdorues në fjalosje" #: ../tgp-chat.c:440 msgid "Type" msgstr "Lloj" telegram-purple/po/telegram-purple.pot000066400000000000000000000302771363674160100204520ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Ben Wiederhake \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "" #: ../telegram-base.c:497 msgid "Query Failed" msgstr "" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "" #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "" #: ../telegram-purple.c:179 msgid "Telegram" msgstr "" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "" #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "" #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "" #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "" #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "" #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "" #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "" #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "" #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "" #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "" #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "" #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "" #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "" #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "" #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "" #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "" #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "" #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "" #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "" #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "" msgstr[1] "" #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "" msgstr[1] "" #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "" msgstr[1] "" #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "" msgstr[1] "" #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "" #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "" #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "" #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "" #: ../tgp-msg.c:535 msgid "[video]" msgstr "" #: ../tgp-msg.c:540 msgid "[document]" msgstr "" #: ../tgp-msg.c:545 msgid "[position]" msgstr "" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "" #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "" #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you " "have received via SMS." msgstr "" #: ../tgp-request.c:54 msgid "Login code" msgstr "" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "" #: ../tgp-request.c:54 msgid "the code" msgstr "" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "" #: ../tgp-request.c:94 msgid "Registration" msgstr "" #: ../tgp-request.c:95 msgid "First name" msgstr "" #: ../tgp-request.c:98 msgid "Last name" msgstr "" #: ../tgp-request.c:102 msgid "Register" msgstr "" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "" #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" #: ../tgp-request.c:109 msgid "Not registered" msgstr "" #: ../tgp-request.c:121 msgid "Password needed" msgstr "" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "" #: ../tgp-request.c:122 msgid "Ok" msgstr "" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" #: ../tgp-request.c:126 msgid "Password invalid" msgstr "" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "" #: ../tgp-request.c:197 msgid "Invite users" msgstr "" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "" #: ../tgp-request.c:218 msgid "Current" msgstr "" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "" #. if we arrive here for the second time the specified phone number is not valid. We do not #. ask for the phone number directly, cause in that case the account would still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a " "leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "" #. This should be the language's timestamp format. This is preceded by a colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "" #: ../tgp-chat.c:300 msgid "Subject:" msgstr "" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "" #: ../tgp-chat.c:418 msgid "Channel" msgstr "" #: ../tgp-chat.c:421 msgid "Group" msgstr "" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "" #: ../tgp-chat.c:440 msgid "Type" msgstr "" telegram-purple/po/uk.po000066400000000000000000000476751363674160100156120ustar00rootroot00000000000000# Translation (template) of telegram-purple # Copyright (C) 2014-2018 Matthias Jentsch, Ben Wiederhake, Christopher Althaus, Markus Endres # This file is distributed under the same license as the telegram-purple plugin. # FIRST AUTHOR , YEAR. # # Translators: # Ben Wiederhake , 2020 # msgid "" msgstr "" "Project-Id-Version: telegram-purple\n" "POT-Creation-Date: 2018-08-01 23:11+0200\n" "PO-Revision-Date: 2019-08-31 08:10+0000\n" "Last-Translator: Ben Wiederhake , 2020\n" "Language-Team: Ukrainian (https://www.transifex.com/telegram-purple-developers/teams/53149/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" #: ../telegram-base.c:442 msgid "Couldn't create group" msgstr "Не вдається створити групу" #: ../telegram-base.c:443 msgid "Please select at least one other user." msgstr "Будь ласка, виберіть ще хоча б одного іншого користувача" #: ../telegram-base.c:497 msgid "Query Failed" msgstr "Запит не вдався" #: ../telegram-purple.c:159 msgid "Secret chat ready." msgstr "Таємний чат готовий." #: ../telegram-purple.c:167 msgid "Secret chat terminated." msgstr "Таємний чат перерваний." #: ../telegram-purple.c:179 msgid "Telegram" msgstr "Telegram" #: ../telegram-purple.c:226 msgid "Message marked as read." msgstr "Повідомлення помічено як прочитане." #: ../telegram-purple.c:343 #, c-format msgid "Invite link: %s" msgstr "Адреса для запрошення: %s" #. FIXME: Can TGLCHF_MODERATOR export links? #: ../telegram-purple.c:354 msgid "Creating chat link failed" msgstr "Створення посилання на чат не вдалося" #: ../telegram-purple.c:355 msgid "You need to be admin of the group to do that." msgstr "Для цього ви маєте бути адміном групи." #: ../telegram-purple.c:440 msgid "Chat joined" msgstr "Чат підключений" #: ../telegram-purple.c:441 msgid "Chat added to list of chat rooms." msgstr "Чат доданий до списку чат-кімнат" #: ../telegram-purple.c:466 msgid "Start secret chat..." msgstr "Запустити таємний чат..." #. Generate Public Link #: ../telegram-purple.c:473 msgid "Invite users by link..." msgstr "Запросити користувачів посиланням..." #. Delete self from chat #: ../telegram-purple.c:481 msgid "Delete and exit..." msgstr "Видалити та вийти..." #: ../telegram-purple.c:560 #, c-format msgid "" "Unable to sign on as %s: problem in the underlying library 'tgl'. Please " "submit a bug report with the debug log." msgstr "" "Не вдається увійти як %s: проблема в існуючій бібліотеці 'tgl'. Будь ласка, " "відправте звіт про помилку в журнал помилок." #: ../telegram-purple.c:564 msgid "Problem in tgl" msgstr "Проблема в tgl" #. TRANSLATORS: Please fill in your own prefix! #: ../telegram-purple.c:576 #, c-format msgid "" "Unable to sign on as %s: phone number lacks country prefix. Numbers must " "start with the full international prefix code, e.g. +1 for USA." msgstr "" "Не вдалось зайти як %s: в номері телефону не вистачає префікса країни. " "Номери повинні починатись з повного міжнародного префіксу-коду, напр., +38 " "для України." #: ../telegram-purple.c:581 msgid "Incomplete phone number" msgstr "Неповноцінний номер телефону" #: ../telegram-purple.c:639 msgid "Secret chat was already deleted" msgstr "Таємний чат вже видалений." #: ../telegram-purple.c:641 msgid "Secret chat is not ready" msgstr "Таємний чат не готовий." #: ../telegram-purple.c:649 msgid "Only the creator of a channel can post messages." msgstr "Писати повідомлення може тільки автор каналу." #: ../telegram-purple.c:692 msgid "Cannot invite buddy to chat" msgstr "Не вдається запросити друга в чат" #: ../telegram-purple.c:693 msgid "Specified user does not exist." msgstr "Такого користувача немає." #: ../telegram-purple.c:706 msgid "phone no. (+ country prefix)" msgstr "№ телефону (+ код країни)" #: ../telegram-purple.c:801 msgid "kick : Kick a user from the room." msgstr "" #. Login #: ../telegram-purple.c:823 msgid "Password (two factor authentication)" msgstr "Пароль (двух-факторна аутентифікація)" #: ../telegram-purple.c:828 msgid "" "Fallback SMS verification\n" "(Helps when not using Pidgin and you aren't being prompted for the code)" msgstr "" "Резервна SMS-перевірка\n" "(Допомагає, коли ви не використовуєте Піджин, і вас не запрошено до кодування)" #. Whether to do fallback SMS verification #: ../telegram-purple.c:835 msgid "Always" msgstr "" #. Whether to do fallback SMS verification #: ../telegram-purple.c:837 msgid "Never" msgstr "" #. Whether to do fallback SMS verification #. How to handle "large" files #: ../telegram-purple.c:839 ../telegram-purple.c:860 msgid "Ask" msgstr "" #: ../telegram-purple.c:841 msgid "Accept secret chats" msgstr "Приймати таємні чати" #: ../telegram-purple.c:845 msgid "Display buddies offline after (days)" msgstr "Відображати друзів, що оффлайн (днів)" #: ../telegram-purple.c:849 msgid "" "Don't fetch history older than (days)\n" "(0 for unlimited)" msgstr "" "Не піднімати історію, старшу за (днів)\n" "(піднімати усю - 0)" #. How to handle "large" files #: ../telegram-purple.c:856 msgid "Discard" msgstr "" #. How to handle "large" files #: ../telegram-purple.c:858 msgid "Auto load" msgstr "" #: ../telegram-purple.c:862 msgid "Auto load file transfers up to (kb)" msgstr "" #: ../telegram-purple.c:866 msgid "Bigger file transfers" msgstr "" #. Chats #: ../telegram-purple.c:870 msgid "Add all group chats to buddy list" msgstr "Додати усі групові чати в список контактів" #. Receipts #: ../telegram-purple.c:875 msgid "Display notices of receipt" msgstr "Показувати повідомлення про отримання" #: ../telegram-purple.c:879 msgid "Send notices of receipt when present" msgstr "Відправляти повідомлення про отримання, якщо воно є" #. IPv6 #: ../telegram-purple.c:884 msgid "Use IPv6 for connecting (restart required)" msgstr "" #: ../telegram-purple.c:909 msgid "Telegram Protocol Plugin." msgstr "Плагін Протоколу Telegram" #: ../tgp-msg.c:58 #, c-format msgid "%2$s created chat %1$s." msgstr "%2$s створив чат %1$s." #: ../tgp-msg.c:61 #, c-format msgid "%2$s changed title to %1$s." msgstr "%2$s змінив назву на %1$s." #: ../tgp-msg.c:64 #, c-format msgid "%s changed photo." msgstr "%s змінив фото." #: ../tgp-msg.c:67 #, c-format msgid "%s deleted photo." msgstr "%s видалив фото." #: ../tgp-msg.c:75 #, c-format msgid "%1$s added user %2$s by link." msgstr "%1$s додав %2$s за посиланням." #: ../tgp-msg.c:90 #, c-format msgid "%2$s added user %1$s." msgstr "%2$s додав користувача %1$s." #: ../tgp-msg.c:114 ../tgp-msg.c:131 #, c-format msgid "%2$s deleted user %1$s." msgstr "%2$s видалив користувача %1$s." #: ../tgp-msg.c:138 #, c-format msgid "%2$s set self destruction timer to %1$d second." msgid_plural "%2$s set self destruction timer to %1$d seconds." msgstr[0] "%2$s встановив таймер самознищення на %1$d секунду." msgstr[1] "%2$s встановив таймер самознищення на %1$d секунди." msgstr[2] "%2$s встановив таймер самознищення на %1$d секунд." msgstr[3] "%2$s встановив таймер самознищення на %1$d секунд." #: ../tgp-msg.c:144 #, c-format msgid "%2$s marked %1$d message read." msgid_plural "%2$s marked %1$d messages read." msgstr[0] "%2$s помітив %1$d повідомлення як прочитане." msgstr[1] "%2$s помітив %1$d повідомлення як прочитані." msgstr[2] "%2$s помітив %1$d повідомленнь як прочитані." msgstr[3] "%2$s помітив %1$d повідомленнь як прочитані." #: ../tgp-msg.c:150 #, c-format msgid "%2$s deleted %1$d message." msgid_plural "%2$s deleted %1$d messages." msgstr[0] "%2$s видалив %1$d повідомлення." msgstr[1] "%2$s видалив %1$d повідомлення." msgstr[2] "%2$s видалив %1$d повідомленнь." msgstr[3] "%2$s видалив %1$d повідомленнь." #: ../tgp-msg.c:156 #, c-format msgid "%2$s made a screenshot of %1$d message." msgid_plural "%2$s made a screenshot of %1$d messages." msgstr[0] "%2$s зробив скріншот %1$d повідомлення." msgstr[1] "%2$s зробив скріншот %1$d повідомлень." msgstr[2] "%2$s зробив скріншот %1$d повідомленнь." msgstr[3] "%2$s зробив скріншот %1$d повідомленнь." #: ../tgp-msg.c:162 #, c-format msgid "Channel %1$s created" msgstr "Канал %1$s створений" #. FIXME: check if this makes sense #: ../tgp-msg.c:165 ../tgp-chat.c:124 ../tgp-chat.c:667 msgid "Telegram Channels" msgstr "Канали Telegram" #: ../tgp-msg.c:222 msgid "Sending message failed." msgstr "Відправка повідомлення не вдалась." #: ../tgp-msg.c:293 msgid "Sending image failed." msgstr "Відправка зображення не вдалася" #: ../tgp-msg.c:497 #, c-format msgid "%s sent a sticker." msgstr "%s відправив липучку." #: ../tgp-msg.c:513 msgid "[message unavailable]" msgstr "" #: ../tgp-msg.c:527 msgid "[photo]" msgstr "" #: ../tgp-msg.c:531 msgid "[audio]" msgstr "" #: ../tgp-msg.c:535 msgid "[video]" msgstr "" #: ../tgp-msg.c:540 msgid "[document]" msgstr "" #: ../tgp-msg.c:545 msgid "[position]" msgstr "" #: ../tgp-msg.c:549 msgid "[contact]" msgstr "" #: ../tgp-msg.c:553 msgid "[webpage]" msgstr "" #: ../tgp-msg.c:557 msgid "[unsupported media]" msgstr "" #: ../tgp-msg.c:582 #, c-format msgid "%s> %s wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:584 #, c-format msgid "%s> Unknown user wrote:
> %s
%s" msgstr "" #: ../tgp-msg.c:640 msgid "failed loading message" msgstr "не вдалось завантажити повідомлення" #. Content of a file transfer #: ../tgp-msg.c:682 ../tgp-msg.c:732 msgid "document" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:685 msgid "audio" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:688 msgid "animation" msgstr "" #. Content of a file transfer #: ../tgp-msg.c:691 msgid "video" msgstr "" #: ../tgp-msg.c:810 #, c-format msgid "> Forwarded from %s:
> %s" msgstr "" #: ../tgp-msg.c:812 #, c-format msgid "> Forwarded:
> %s" msgstr "" #: ../tgp-msg.c:921 msgid "loading document or picture failed" msgstr "завантаження документу чи картинки не вдалось" #: ../tgp-net.c:281 msgid "Cannot connect to main server" msgstr "Не вдається підключитись до головного сервера" #: ../tgp-net.c:322 msgid "Cannot connect to server: Ping timeout." msgstr "Не вдається підключитись до сервера: сервер не відповідає." #: ../tgp-net.c:365 msgid "Lost connection to the server..." msgstr "Зв'язок із сервером втрачений..." #: ../tgp-request.c:51 msgid "" "Telegram wants to verify your identity. Please enter the login code that you" " have received via SMS." msgstr "" "Telegram хоче перевірити вашу особистість. Будь ласка, введіть логін, що " "отримали по SMS." #: ../tgp-request.c:54 msgid "Login code" msgstr "Код входу" #: ../tgp-request.c:54 msgid "Enter login code" msgstr "Введіть код входу" #: ../tgp-request.c:54 msgid "the code" msgstr "код" #: ../tgp-request.c:54 ../tgp-request.c:103 ../tgp-request.c:197 #: ../tgp-request.c:232 ../tgp-request.c:262 msgid "OK" msgstr "ОК" #: ../tgp-request.c:55 ../tgp-request.c:103 ../tgp-request.c:122 #: ../tgp-request.c:198 ../tgp-request.c:233 ../tgp-request.c:263 msgid "Cancel" msgstr "Відміна" #: ../tgp-request.c:94 msgid "Registration" msgstr "Регістрація" #: ../tgp-request.c:95 msgid "First name" msgstr "Ім'я" #: ../tgp-request.c:98 msgid "Last name" msgstr "Прізвище" #: ../tgp-request.c:102 msgid "Register" msgstr "Зарегіструватись" #: ../tgp-request.c:102 msgid "Please register your phone number." msgstr "Будь ласка, зареєструйте ваш номер телефону." #. purple_request API not available #: ../tgp-request.c:107 msgid "" "Phone number is not registered. Please register your phone on a different " "client." msgstr "" "Номер телефону не зареєстрований. Будь ласка, зареєструйте ваш телефон на " "іншого кліента." #: ../tgp-request.c:109 msgid "Not registered" msgstr "Не зареєстрований" #: ../tgp-request.c:121 msgid "Password needed" msgstr "Потрібен пароль" #: ../tgp-request.c:121 msgid "Enter password for two factor authentication" msgstr "Введіть пароль для двофакторної авторизації" #: ../tgp-request.c:122 msgid "Ok" msgstr "Гаразд" #: ../tgp-request.c:124 msgid "" "No password set for two factor authentication. Please enter it in the " "extended settings." msgstr "" "Для двофакторної авторизації не встановлений пароль. Будь ласка, введіть " "його в розширених настройках." #: ../tgp-request.c:126 msgid "Password invalid" msgstr "Пароль невірний" #: ../tgp-request.c:149 #, c-format msgid "Accept secret chat '%s' on this device?" msgstr "Прийняти таємний чат '%s' на цьому пристрої?" #: ../tgp-request.c:150 msgid "Secret chat" msgstr "Таємний чат" #: ../tgp-request.c:150 msgid "" "Secret chats can only have one end point. If you accept a secret chat on " "this device, its messages will not be available anywhere else. If you " "decline, you can still accept the chat on other devices." msgstr "" "У таємного чата може бути тільки одна кінцева точка. Якщо ви приймаєте на " "цьому пристрої таємний чат, його повідомлення будуть не будуть доступні з " "інших місць. Якщо відмовитесь, то можете прийняти чат з інших пристроїв." #: ../tgp-request.c:181 msgid "" "Invite at least one additional user by specifying\n" " their full name (autocompletion available).\n" "You can add more users once the chat was created." msgstr "" "Запросіть щонайменше одного додаткового користувача вказанням його повного імені (автозавершення доступне).\n" "Ви можете додати більше користувачів одразу після створення чата." #: ../tgp-request.c:184 ../tgp-request.c:188 ../tgp-request.c:192 msgid "Username" msgstr "Ім'я користувача" #: ../tgp-request.c:197 msgid "Create group chat" msgstr "Створити груповий чат" #: ../tgp-request.c:197 msgid "Invite users" msgstr "Запросити користувачів" #: ../tgp-request.c:216 ../tgp-request.c:231 msgid "Change password" msgstr "Змінити пароль" #: ../tgp-request.c:218 msgid "Current" msgstr "Поточний" #: ../tgp-request.c:222 ../tgp-request.c:252 msgid "Password" msgstr "Пароль" #: ../tgp-request.c:226 ../tgp-request.c:256 msgid "Confirm" msgstr "Підтвердити" #: ../tgp-request.c:250 ../tgp-request.c:261 msgid "New password" msgstr "Новий пароль" #. if we arrive here for the second time the specified phone number is not #. valid. We do not #. ask for the phone number directly, cause in that case the account would #. still be created #. named with the invalid phone number, even though the login will work #: ../tgp-request.c:299 msgid "Invalid phone number" msgstr "Невірний номер телефону" #: ../tgp-request.c:300 msgid "" "Please enter only numbers in the international phone number format, a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars." msgstr "" "Будь ласка, введіть номер тільки цифри в міжнародному телефонному форматі. Значок +, потім код країни і номер абонента.\n" "Не використовуйте інших символів." #: ../tgp-request.c:369 msgid "Leave Chat" msgstr "Покинути чат" #: ../tgp-request.c:371 msgid "Do you want to leave this chat permanently?" msgstr "Бажаєте надовго покинути цей таємний чат?" #: ../tgp-request.c:376 msgid "Abort Secret Chat" msgstr "Про таємний чат" #: ../tgp-request.c:378 msgid "Do you want to terminate this secret chat permanently?" msgstr "Бажаєте надовго перервати цей таємний чат?" #: ../tgp-request.c:383 msgid "Delete Contact" msgstr "Видалити контакт" #: ../tgp-request.c:385 msgid "Do you want to remove this user from your global contact list?" msgstr "" "Бажаєте видалити цього користувача з вашого глобального списку контактів?" #: ../tgp-request.c:400 msgid "Leave Channel" msgstr "Покинути канал" #: ../tgp-request.c:402 msgid "Do you want to leave this channel?" msgstr "Бажаєте покинути цей канал?" #. This should be the language's timestamp format. This is preceded by a #. colon. #: ../tgp-utils.c:27 msgid "%d.%m.%Y %H:%M" msgstr "%d.%m.%Y %H:%M" #. This is preceded by a colon. #: ../tgp-utils.c:48 msgid "recently" msgstr "нещодавно" #. This is preceded by a colon. #: ../tgp-utils.c:52 msgid "last week" msgstr "на тому тижні" #. This is preceded by a colon. #: ../tgp-utils.c:56 msgid "last month" msgstr "минулого місяця" #. This is preceded by a colon. It refers to a point on time. #: ../tgp-utils.c:60 msgid "unknown" msgstr "невідомо" #: ../tgp-chat.c:108 ../tgp-chat.c:673 msgid "Telegram Chats" msgstr "Чати Telegram" #: ../tgp-chat.c:113 msgid "You have already left this chat." msgstr "Ви вже покинули цей чат." #: ../tgp-chat.c:300 msgid "Subject:" msgstr "Тема:" #: ../tgp-chat.c:306 msgid "Invite link:" msgstr "Посилання для запрошення:" #: ../tgp-chat.c:312 msgid "Chat ID:" msgstr "ID чата:" #: ../tgp-chat.c:418 msgid "Supergroup" msgstr "Супергрупа" #: ../tgp-chat.c:418 msgid "Channel" msgstr "Канал" #: ../tgp-chat.c:421 msgid "Group" msgstr "Група" #: ../tgp-chat.c:437 msgid "Users in chat" msgstr "Користувачі у чаті" #: ../tgp-chat.c:440 msgid "Type" msgstr "Тип" telegram-purple/rpm/000077500000000000000000000000001363674160100147705ustar00rootroot00000000000000telegram-purple/rpm/purple-telegram.spec000066400000000000000000000037641363674160100207630ustar00rootroot00000000000000Name: purple-telegram Version: 1.4.3 Release: 1%{?dist} Summary: Adds support for Libpurple based messengers Group: Applications/Internet License: GPLv2+ URL: https://github.com/majn/telegram-purple Source0: https://codeload.github.com/majn/telegram-purple/tar.gz/v%{version}.tar.gz BuildRequires: gettext, libgcrypt-devel >= 1.6, pkgconfig(zlib), pkgconfig(purple), pkgconfig(libwebp) BuildRequires: pkgconfig(appstream-glib) %description Adds support for Telegram to Pidgin, Adium, Finch and other Libpurple based messengers. %prep %autosetup %build %configure make %{?_smp_mflags} %install %make_install chmod 755 %{buildroot}/%{_libdir}/purple-2/telegram-purple.so %find_lang telegram-purple %check appstream-util validate-relax --nonet %{buildroot}/%{_datadir}/appdata/telegram-purple.metainfo.xml %files -f telegram-purple.lang %doc README* CHANGELOG* %{_libdir}/purple-2/telegram-purple.so %config %{_sysconfdir}/telegram-purple/* %{_datadir}/appdata/telegram-purple.metainfo.xml %{_datadir}/pixmaps/pidgin/protocols/16/telegram.png %{_datadir}/pixmaps/pidgin/protocols/22/telegram.png %{_datadir}/pixmaps/pidgin/protocols/48/telegram.png %{_datadir}/appdata/telegram-purple.metainfo.xml %changelog * Wed Mar 25 2020 BenWiederhake 1.4.3-1 - Build for 1.4.3 * Sat Aug 31 2019 BenWiederhake 1.4.2-1 - Build for 1.4.2 * Sat Mar 2 2019 BenWiederhake 1.4.1-1 - Build for 1.4.1 * Sun Apr 9 2017 mjentsch 1.3.1-1 - Build for 1.3.1 * Thu Dec 10 2015 tuxmaster 1.3.0-1 - Build for 1.3.0 * Sat Jan 23 mjentsch 1.2.5-1 - build for 1.2.5 * Thu Dec 10 2015 tuxmaster 1.2.4-2 - Fix build for appdata. * Thu Dec 10 2015 mjentsch 1.2.4-1 - build for 1.2.4 * Thu Dec 10 2015 tuxmaster 1.2.4-2 - Fix build for appdata. * Wed Nov 18 2015 tuxmaster 1.2.2-3 - Add required version for libgcrypt. * Wed Oct 14 2015 tuxmaster 1.2.2-2 - Use the better pkconfig for build requires. - Add translations. - Switch to libgcrypt from openssl. * Wed Oct 07 2015 mjentsch 1.2.2-1 - update version to 1.2.2 telegram-purple/telegram-adium/000077500000000000000000000000001363674160100170675ustar00rootroot00000000000000telegram-purple/telegram-adium/.gitignore000066400000000000000000000001401363674160100210520ustar00rootroot00000000000000/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/ /telegram-adium.xcodeproj/xcuserdata/ telegram-purple/telegram-adium/PurpleDefaultsTelegram.plist000066400000000000000000000007441363674160100245710ustar00rootroot00000000000000 Telegram:accept-secret-chats ask Telegram:inactive-days-offline 7 Telegram:display-read-notifications Telegram:history-retrieve-days 14 Telegram:history-sync-all telegram-purple/telegram-adium/TelegramAccount.h000066400000000000000000000016451363674160100223230ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import #import #import @interface TelegramAccount : CBPurpleAccount @end telegram-purple/telegram-adium/TelegramAccount.m000066400000000000000000000157501363674160100223320ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import "TelegramAccount.h" #import "tgp-ft.h" #import #import #import #import #import #include "telegram-purple.h" @implementation TelegramAccount - (const char*)protocolPlugin { return "prpl-telegram"; } - (NSString *)host { return @"149.154.167.50"; } - (BOOL)shouldDisplayOutgoingMUCMessages { return NO; } - (int)port { return 443; } - (void)didConnect { [super didConnect]; [self purpleAccount]; // FIXME: Crashed after going online // Storing chats in the blist breaks Adium bookmarks. Adium doesn't // show those chats anyway, so we can just safely delete those. PurpleBlistNode *node = purple_blist_get_root(); while (node) { if (PURPLE_BLIST_NODE_IS_CHAT(node)) { PurpleChat *ch = PURPLE_CHAT(node); if (purple_chat_get_account(ch) == account) { NSLog (@"Removing chat from blist: %s", ch->alias); purple_blist_remove_chat (ch); } } node = purple_blist_node_next (node, 0); } } - (void)configurePurpleAccount { [super configurePurpleAccount]; purple_account_set_string (account, TGP_KEY_PASSWORD_TWO_FACTOR, [[self preferenceForKey:@"Telegram:"TGP_KEY_PASSWORD_TWO_FACTOR group:GROUP_ACCOUNT_STATUS] UTF8String]); purple_account_set_string (account, TGP_KEY_ACCEPT_SECRET_CHATS, [[self preferenceForKey:@"Telegram:"TGP_KEY_ACCEPT_SECRET_CHATS group:GROUP_ACCOUNT_STATUS] UTF8String]); purple_account_set_bool (account, TGP_KEY_DISPLAY_READ_NOTIFICATIONS, [[self preferenceForKey:@"Telegram:"TGP_KEY_DISPLAY_READ_NOTIFICATIONS group:GROUP_ACCOUNT_STATUS] boolValue]); purple_account_set_bool (account, TGP_KEY_SEND_READ_NOTIFICATIONS, [[self preferenceForKey:@"Telegram:"TGP_KEY_SEND_READ_NOTIFICATIONS group:GROUP_ACCOUNT_STATUS] boolValue]); purple_account_set_int (account, TGP_KEY_HISTORY_RETRIEVAL_THRESHOLD, [[self preferenceForKey:@"Telegram:"TGP_KEY_HISTORY_RETRIEVAL_THRESHOLD group:GROUP_ACCOUNT_STATUS] intValue]); purple_account_set_int (account, TGP_KEY_INACTIVE_DAYS_OFFLINE, [[self preferenceForKey:@"Telegram:"TGP_KEY_INACTIVE_DAYS_OFFLINE group:GROUP_ACCOUNT_STATUS] intValue]); } #pragma mark Action Menu -(NSMenu*)actionMenuForChat:(AIChat*)chat { NSArray *listObjects = nil; AIListObject *listObject = nil; if (listObjects.count) { listObject = [listObjects objectAtIndex:0]; } NSMenu *menu = [adium.menuController contextualMenuWithLocations: [NSArray arrayWithObjects: [NSNumber numberWithInteger: Context_GroupChat_Manage], [NSNumber numberWithInteger: Context_Group_Manage], [NSNumber numberWithInteger: Context_GroupChat_Action], nil] forChat: chat]; [menu addItem:[NSMenuItem separatorItem]]; [menu addItemWithTitle:@"Invite users by link..." target:self action:@selector(addUserByLink) keyEquivalent:@"" tag:0]; [menu addItemWithTitle:@"Delete and exit..." target:self action:@selector(deleteAndExit) keyEquivalent:@"" tag:0]; return menu; } - (void)addUserByLink { connection_data *conn = purple_connection_get_protocol_data (purple_account_get_connection(account)); AIChat *chat = adium.interfaceController.activeChat; if (chat) { export_chat_link_by_name (conn->TLS, [chat.name UTF8String]); } } - (void)deleteAndExit { connection_data *conn = purple_connection_get_protocol_data (purple_account_get_connection(account)); AIChat *chat = adium.interfaceController.activeChat; if (chat) { leave_and_delete_chat_by_name (conn->TLS, [chat.name UTF8String]); } } #pragma mark File transfer - (BOOL)canSendOfflineMessageToContact:(AIListContact *)inContact { return YES; } - (void)beginSendOfFileTransfer:(ESFileTransfer *)fileTransfer { [super _beginSendOfFileTransfer:fileTransfer]; } - (void)acceptFileTransferRequest:(ESFileTransfer *)fileTransfer { [super acceptFileTransferRequest:fileTransfer]; } - (void)rejectFileReceiveRequest:(ESFileTransfer *)fileTransfer { [super rejectFileReceiveRequest:fileTransfer]; } - (void)cancelFileTransfer:(ESFileTransfer *)fileTransfer { [super cancelFileTransfer:fileTransfer]; } - (NSString *)encodedAttributedString:(NSAttributedString *)inAttributedString forListObject:(AIListObject *)inListObject { static AIHTMLDecoder *htmlEncoder = nil; if (!htmlEncoder) { htmlEncoder = [[AIHTMLDecoder alloc] init]; [htmlEncoder setIncludesHeaders:NO]; [htmlEncoder setIncludesFontTags:NO]; [htmlEncoder setClosesFontTags:YES]; [htmlEncoder setIncludesStyleTags:NO]; [htmlEncoder setIncludesColorTags:NO]; [htmlEncoder setEncodesNonASCII:NO]; [htmlEncoder setPreservesAllSpaces:NO]; [htmlEncoder setUsesAttachmentTextEquivalents:YES]; } return [htmlEncoder encodeHTML:inAttributedString imagesPath:nil]; } #pragma mark Group Chats /*! * @brief Re-create the chat's join options. */ - (NSDictionary *)extractChatCreationDictionaryFromConversation:(PurpleConversation *)conv { connection_data *conn = purple_connection_get_protocol_data (purple_conversation_get_gc (conv)); const char *name = purple_conversation_get_name (conv); tgl_peer_t *P = tgp_blist_lookup_peer_get (conn->TLS, purple_conversation_get_title (conv)); if (P) { return [NSMutableDictionary dictionaryWithObjectsAndKeys: [NSString stringWithFormat:@"%d", tgl_get_peer_id(P->id)], @"id", [NSString stringWithUTF8String: name], @"subject", nil]; } return nil; } @end telegram-purple/telegram-adium/TelegramAccountView.xib000066400000000000000000000442551363674160100235150ustar00rootroot00000000000000 NSAllRomanInputSourcesLocaleIdentifier telegram-purple/telegram-adium/TelegramAccountViewController.h000066400000000000000000000025321363674160100252160ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import #import @interface TelegramAccountViewController : PurpleAccountViewController { IBOutlet NSButton *checkbox_historySyncAll; IBOutlet NSButton *checkbox_displayReadNotifications; IBOutlet NSButton *checkbox_sendReadNotifications; IBOutlet NSTextField *textField_maxMsgSplitCount; IBOutlet NSTextField *textField_inactiveDaysOffline; IBOutlet NSTextField *textField_historyRetrieveDays; IBOutlet NSSecureTextField *textField_passwordTwoFactor; IBOutlet NSMatrix *radio_Encryption; } @end telegram-purple/telegram-adium/TelegramAccountViewController.m000066400000000000000000000076061363674160100252320ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import "TelegramAccountViewController.h" #import "TelegramAccount.h" #include "telegram-purple.h" @implementation TelegramAccountViewController - (NSString *)nibName{ return @"TelegramAccountView"; } - (void)configureForAccount:(AIAccount *)inAccount { [super configureForAccount:inAccount]; NSString *acceptSecretChats = [account preferenceForKey:@"Telegram:"TGP_KEY_ACCEPT_SECRET_CHATS group:GROUP_ACCOUNT_STATUS] ?: @TGP_DEFAULT_ACCEPT_SECRET_CHATS; NSInteger row = 0; if ([acceptSecretChats isEqual:@"always"]) { row = 1; } else if ([acceptSecretChats isEqual:@"never"]) { row = 2; } [radio_Encryption selectCellAtRow:row column:0]; NSString *passwordTwoFactor = [account preferenceForKey:@"Telegram:"TGP_KEY_PASSWORD_TWO_FACTOR group:GROUP_ACCOUNT_STATUS] ?: @""; [textField_password setStringValue:passwordTwoFactor]; id read = [account preferenceForKey:@"Telegram:"TGP_KEY_DISPLAY_READ_NOTIFICATIONS group:GROUP_ACCOUNT_STATUS]; [checkbox_displayReadNotifications setState:[read boolValue]]; id send = [account preferenceForKey:@"Telegram:"TGP_KEY_SEND_READ_NOTIFICATIONS group:GROUP_ACCOUNT_STATUS]; [checkbox_sendReadNotifications setState:[send boolValue]]; NSString *inactiveDaysOffline = [account preferenceForKey:@"Telegram:"TGP_KEY_INACTIVE_DAYS_OFFLINE group:GROUP_ACCOUNT_STATUS] ?: @""; [textField_inactiveDaysOffline setStringValue:inactiveDaysOffline]; NSString *historyRetrievalThreshold = [account preferenceForKey:@"Telegram:"TGP_KEY_HISTORY_RETRIEVAL_THRESHOLD group:GROUP_ACCOUNT_STATUS] ?: @""; [textField_historyRetrieveDays setStringValue:historyRetrievalThreshold]; } - (void)saveConfiguration { [super saveConfiguration]; NSArray *selections = @[@"ask", @"always", @"never"]; [account setPreference:[textField_password stringValue] forKey:@"Telegram:"TGP_KEY_PASSWORD_TWO_FACTOR group:GROUP_ACCOUNT_STATUS]; [account setPreference:selections[[radio_Encryption selectedRow]] forKey:@"Telegram:"TGP_KEY_ACCEPT_SECRET_CHATS group:GROUP_ACCOUNT_STATUS]; [account setPreference:[NSNumber numberWithBool:[checkbox_displayReadNotifications state]] forKey:@"Telegram:"TGP_KEY_DISPLAY_READ_NOTIFICATIONS group:GROUP_ACCOUNT_STATUS]; [account setPreference:[NSNumber numberWithBool: [checkbox_sendReadNotifications state]] forKey:@"Telegram:"TGP_KEY_SEND_READ_NOTIFICATIONS group:GROUP_ACCOUNT_STATUS]; [account setPreference:[textField_historyRetrieveDays stringValue] forKey:@"Telegram:"TGP_KEY_HISTORY_RETRIEVAL_THRESHOLD group:GROUP_ACCOUNT_STATUS]; [account setPreference:[textField_inactiveDaysOffline stringValue] forKey:@"Telegram:"TGP_KEY_INACTIVE_DAYS_OFFLINE group:GROUP_ACCOUNT_STATUS]; } @end telegram-purple/telegram-adium/TelegramAutocompletionDelegate.h000066400000000000000000000017301363674160100253570ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import #include @interface TelegramAutocompletionDelegate : NSObject { @private struct tgl_state *TLS; } - (void)setTLS:(struct tgl_state *)TLS; @endtelegram-purple/telegram-adium/TelegramAutocompletionDelegate.m000066400000000000000000000033531363674160100253670ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import "TelegramAutocompletionDelegate.h" @implementation TelegramAutocompletionDelegate - (NSArray *)tokenField:(NSTokenField *)tokenField completionsForSubstring:(NSString *)substring indexOfToken:(NSInteger)tokenIndex indexOfSelectedItem:(NSInteger *)selectedIndex { NSMutableArray *matchingUsers = [NSMutableArray new]; const char *startsWith = [substring UTF8String]; if (TLS) { int i = 0; while (i != -1) { char *R = NULL; i = tgl_complete_user_list (TLS, i, startsWith, (int) strlen(startsWith), &R); if (R) { [matchingUsers addObject: [[NSString alloc] initWithUTF8String:R]]; } } } return matchingUsers; } - (id)tokenField:(NSTokenField *)tokenField representedObjectForEditingString:(NSString *)editingString { return nil; } - (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject { return nil; } - (void)setTLS:(struct tgl_state *)_TLS { TLS = _TLS; } @endtelegram-purple/telegram-adium/TelegramJoinChatView.xib000066400000000000000000000246701363674160100236170ustar00rootroot00000000000000
telegram-purple/telegram-adium/TelegramJoinChatViewController.h000066400000000000000000000022061363674160100253170ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import @class AIAccount, AICompletingTextField; @interface TelegramJoinChatViewController : DCJoinChatViewController { IBOutlet NSPopUpButton *popupButton_existingChat; IBOutlet NSTextField *textField_joinByLink; IBOutlet NSTextField *textField_createChatName; IBOutlet NSTokenField *tokenField_createChatUsers; } @endtelegram-purple/telegram-adium/TelegramJoinChatViewController.m000066400000000000000000000106371363674160100253330ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #include "telegram-purple.h" #include "TelegramJoinChatViewController.h" #include "TelegramAutocompletionDelegate.h" #import #import #import @interface NSObject (JointChatViewDelegate) - (void)setJoinChatEnabled:(BOOL)enabled; @end @implementation TelegramJoinChatViewController static void tgl_chat_iterator_cb (tgl_peer_t *peer, void *extra) { NSMutableArray *A = (__bridge NSMutableArray *)(extra); if (tgl_get_peer_type (peer->id) == TGL_PEER_CHAT && !(peer->chat.flags & TGLCF_LEFT)) { [A addObject: [NSString stringWithUTF8String: peer->print_name]]; } } static void tgl_channel_iterator_cb (tgl_peer_t *peer, void *extra) { NSMutableArray *A = (__bridge NSMutableArray *)(extra); if (tgl_get_peer_type (peer->id) == TGL_PEER_CHANNEL && !(peer->channel.flags & TGLCHF_LEFT)) { [A addObject: [NSString stringWithUTF8String: peer->print_name]]; } } - (void)configureForAccount:(AIAccount *)inAccount { [super configureForAccount:inAccount]; PurpleAccount *pa = [(CBPurpleAccount *)inAccount purpleAccount]; PurpleConnection *gc = purple_account_get_connection(pa); if (gc && PURPLE_CONNECTION_IS_CONNECTED(gc)) { connection_data *conn = purple_connection_get_protocol_data (gc); // fetch all active chats and put them into the select box [popupButton_existingChat removeAllItems]; NSMutableArray *chats = [NSMutableArray new]; tgl_peer_iterator_ex (conn->TLS, tgl_chat_iterator_cb, (__bridge void *)(chats)); tgl_peer_iterator_ex (conn->TLS, tgl_channel_iterator_cb, (__bridge void *)(chats)); [popupButton_existingChat addItemsWithTitles: [chats sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]]; // provide the current TLS instance for access by the autocompletion TelegramAutocompletionDelegate *D = [tokenField_createChatUsers delegate]; if (D != nil) { [D setTLS:conn->TLS]; } } } - (void)joinChatWithAccount:(AIAccount *)inAccount { PurpleAccount *pa = [(CBPurpleAccount *)inAccount purpleAccount]; PurpleConnection *gc = purple_account_get_connection(pa); if (gc && PURPLE_CONNECTION_IS_CONNECTED(gc)) { connection_data *conn = purple_connection_get_protocol_data (gc); // Join by link NSString *link = [textField_joinByLink stringValue]; if ([link length]) { import_chat_link (conn->TLS, [link UTF8String]); return; } // Create a new chat with provided participants NSString *createChatName = [textField_createChatName stringValue]; NSArray *tokens = [tokenField_createChatUsers objectValue]; if ([createChatName length] && [tokens count]) { int i, cnt = (int)[tokens count]; const char **users = g_malloc(cnt * sizeof(char*)); for (i = 0; i < cnt; i++) { users[i] = [tokens[i] UTF8String]; } tgp_create_group_chat_by_usernames (conn->TLS, [createChatName UTF8String], users, i, TRUE); g_free (users); return; } // Pass the joining to the prpl const char *name = [[[popupButton_existingChat selectedItem] title] UTF8String]; PurpleChat *purpleChat = purple_blist_find_chat (conn->pa, name); if (purpleChat) { serv_join_chat (conn->gc, purple_chat_get_components (purpleChat)); } else { GHashTable *chatCreationInfo = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); g_hash_table_insert (chatCreationInfo, "subject", g_strdup (name)); serv_join_chat (conn->gc, chatCreationInfo); g_hash_table_destroy (chatCreationInfo); } } } - (NSString *)nibName { return @"TelegramJoinChatView"; } @end telegram-purple/telegram-adium/TelegramPlugin.h000066400000000000000000000016221363674160100221600ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import #import @interface TelegramPlugin : AIPlugin { } @end telegram-purple/telegram-adium/TelegramPlugin.m000066400000000000000000000033271363674160100221710ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "../commit.h" #import "TelegramPlugin.h" #import "TelegramService.h" #import "telegram-purple.h" extern void purple_init_telegram_plugin(); @implementation TelegramPlugin - (void) installPlugin { purple_init_telegram_plugin(); [TelegramService registerService]; } - (void) installLibpurplePlugin { } - (void) loadLibpurplePlugin { } - (void) uninstallPlugin { } - (NSString *)pluginAuthor { return @PLUGIN_AUTHOR; } -(NSString *)pluginVersion { return @PACKAGE_VERSION "\n\t\t\tcommit: " GIT_COMMIT "\n\t\t\tlibtgl: " TGL_VERSION; } -(NSString *)pluginDescription { return @"Telegram Protocol Plugin"; } -(char*)getPkName { const char* utf8String = (char *)[[[NSBundle bundleForClass: [self class]] pathForResource: @"tg-server" ofType: @"tglpub"] UTF8String]; size_t len = strlen(utf8String) + 1; char *buf = malloc(len); memcpy(buf, utf8String, len); return buf; } @end telegram-purple/telegram-adium/TelegramService.h000066400000000000000000000016101363674160100223170ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import #import @interface TelegramService : PurpleService { } @end telegram-purple/telegram-adium/TelegramService.m000066400000000000000000000075161363674160100223370ustar00rootroot00000000000000/** * 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 02111-1301 USA * * Copyright Matthias Jentsch 2014-2015 */ #import "TelegramService.h" #import "TelegramAccount.h" #import "TelegramAccountViewController.h" #import "TelegramJoinChatViewController.h" #import #import @implementation TelegramService - (Class)accountClass{ return [TelegramAccount class]; } - (AIAccountViewController *)accountViewController{ return [TelegramAccountViewController accountViewController]; } - (DCJoinChatViewController *)joinChatView{ return [TelegramJoinChatViewController joinChatView]; } //Service Description - (NSString *)serviceCodeUniqueID{ return @"prpl-telegram"; } - (NSString *)serviceID{ return @"Telegram"; } - (NSString *)serviceClass{ return @"Telegram"; } - (NSString *)shortDescription{ return @"Telegram"; } - (NSString *)longDescription{ return @"Telegram"; } - (NSString *)userNameLabel { return @"Phone number\n(with country prefix)"; } - (BOOL)supportsProxySettings{ return YES; } - (BOOL)supportsPassword { return NO; } - (BOOL)requiresPassword { return NO; } - (BOOL)canCreateGroupChats { return YES; } - (NSString *)UIDPlaceholder { return @"e.g. +49157123456"; } - (BOOL)isSocialNetworkingService { return NO; } - (AIServiceImportance)serviceImportance { return AIServiceSecondary; } - (NSCharacterSet *)allowedCharacters{ return [[NSCharacterSet illegalCharacterSet] invertedSet]; } - (NSCharacterSet *)allowedCharactersForAccountName { return ([NSCharacterSet characterSetWithCharactersInString: @"+1234567890"]); } - (NSUInteger)allowedLengthForAccountName { return 16; } - (BOOL)caseSensitive { return YES; } - (NSImage *)defaultServiceIconOfType:(AIServiceIconType)iconType { if ((iconType == AIServiceIconSmall) || (iconType == AIServiceIconList)) { return [NSImage imageNamed:@"telegram16" forClass:[self class] loadLazily:YES]; } else { return [NSImage imageNamed:@"telegram" forClass:[self class] loadLazily:YES]; } } - (NSString *)pathForDefaultServiceIconOfType:(AIServiceIconType)iconType { if ((iconType == AIServiceIconSmall) || (iconType == AIServiceIconList)) { return [[NSBundle bundleForClass:[self class]] pathForImageResource:@"telegram16"]; } return [[NSBundle bundleForClass:[self class]] pathForImageResource:@"telegram"]; } - (void)registerStatuses { #define ADDSTATUS(name, type) \ [adium.statusController registerStatus:name \ withDescription:[adium.statusController localizedDescriptionForCoreStatusName:name] \ ofType:type forService:self] [adium.statusController registerStatus:STATUS_NAME_AVAILABLE withDescription:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_AVAILABLE] ofType:AIAvailableStatusType forService:self]; ADDSTATUS(STATUS_NAME_AVAILABLE, AIAvailableStatusType); ADDSTATUS(STATUS_NAME_NOT_AVAILABLE, AIAvailableStatusType); ADDSTATUS(STATUS_NAME_OFFLINE, AIOfflineStatusType); } - (NSString *)normalizeChatName:(NSString *)inChatName { // prevent Adium from normalizing chat names, which would break searching chats by user names return inChatName; } @end telegram-purple/telegram-adium/telegram-adium.xcodeproj/000077500000000000000000000000001363674160100237605ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium.xcodeproj/project.pbxproj000066400000000000000000001150401363674160100270350ustar00rootroot00000000000000// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 33070C10341336CD4EC97534 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 33070D636377BD8BA47CBF63 /* InfoPlist.strings */; }; 3765D8B222F0964A008BA793 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3765D8B122F0964A008BA793 /* libpng.a */; }; C40564871A7937C600A293B9 /* AdiumLibpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C40564861A7937C600A293B9 /* AdiumLibpurple.framework */; }; C410948A19BB2D7D0083BF3F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C410948919BB2D7D0083BF3F /* CoreFoundation.framework */; }; C410949B19BB337A0083BF3F /* TelegramPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = C410949A19BB337A0083BF3F /* TelegramPlugin.m */; }; C41D58411A16D88E00B22448 /* tgp-2prpl.c in Sources */ = {isa = PBXBuildFile; fileRef = C41D58401A16D88E00B22448 /* tgp-2prpl.c */; }; C425F9181A7069C300361AFC /* tgp-utils.c in Sources */ = {isa = PBXBuildFile; fileRef = C425F9161A7069C300361AFC /* tgp-utils.c */; }; C431EB7D1A76C737006521CB /* tgp-chat.c in Sources */ = {isa = PBXBuildFile; fileRef = C431EB7B1A76C737006521CB /* tgp-chat.c */; }; C438CE271A12BEAF00E1DA0F /* telegram.png in Resources */ = {isa = PBXBuildFile; fileRef = C438CE231A12BEAF00E1DA0F /* telegram.png */; }; C438CE281A12BEAF00E1DA0F /* telegram16.png in Resources */ = {isa = PBXBuildFile; fileRef = C438CE241A12BEAF00E1DA0F /* telegram16.png */; }; C438CE291A12BEAF00E1DA0F /* telegram22.png in Resources */ = {isa = PBXBuildFile; fileRef = C438CE251A12BEAF00E1DA0F /* telegram22.png */; }; C438CE2A1A12BEAF00E1DA0F /* telegram48.png in Resources */ = {isa = PBXBuildFile; fileRef = C438CE261A12BEAF00E1DA0F /* telegram48.png */; }; C438CE321A12C07800E1DA0F /* msglog.c in Sources */ = {isa = PBXBuildFile; fileRef = C438CE2D1A12C07800E1DA0F /* msglog.c */; }; C438CE331A12C07800E1DA0F /* telegram-base.c in Sources */ = {isa = PBXBuildFile; fileRef = C438CE2E1A12C07800E1DA0F /* telegram-base.c */; }; C438CE341A12C07800E1DA0F /* telegram-purple.c in Sources */ = {isa = PBXBuildFile; fileRef = C438CE2F1A12C07800E1DA0F /* telegram-purple.c */; }; C438CE351A12C07800E1DA0F /* tgp-net.c in Sources */ = {isa = PBXBuildFile; fileRef = C438CE301A12C07800E1DA0F /* tgp-net.c */; }; C438CE361A12C07800E1DA0F /* tgp-timers.c in Sources */ = {isa = PBXBuildFile; fileRef = C438CE311A12C07800E1DA0F /* tgp-timers.c */; }; C448ADA71AB0789A001B7ECD /* tgp-msg.c in Sources */ = {isa = PBXBuildFile; fileRef = C448ADA61AB0789A001B7ECD /* tgp-msg.c */; }; C465FC211C0D0191001CCEE8 /* libgcrypt.20.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C465FC1B1C0CF43A001CCEE8 /* libgcrypt.20.dylib */; }; C465FC231C0D01B5001CCEE8 /* libgcrypt.20.dylib in Resources */ = {isa = PBXBuildFile; fileRef = C465FC221C0D01B5001CCEE8 /* libgcrypt.20.dylib */; }; C466937819E703370036A108 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C466937719E703370036A108 /* AppKit.framework */; }; C479A8021BB69C2100C153DF /* tgp-request.c in Sources */ = {isa = PBXBuildFile; fileRef = C479A8001BB69C2100C153DF /* tgp-request.c */; }; C4877C1819BB37EA006FA91F /* TelegramService.m in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1719BB37EA006FA91F /* TelegramService.m */; }; C4877C1E19BB676B006FA91F /* TelegramAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1D19BB676B006FA91F /* TelegramAccount.m */; }; C487A18C1A792E9B0044F135 /* Adium.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C487A1891A792E9B0044F135 /* Adium.framework */; }; C487A18E1A792E9B0044F135 /* AIUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C487A18B1A792E9B0044F135 /* AIUtilities.framework */; }; C487A1911A792EA50044F135 /* libglib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C487A18F1A792EA50044F135 /* libglib.framework */; }; C487A1921A792EA50044F135 /* libpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C487A1901A792EA50044F135 /* libpurple.framework */; }; C49A915819BBC5C5001B3DC0 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C49A915719BBC5C5001B3DC0 /* libz.dylib */; }; C4B4BE2E1AB392F80064AC17 /* TelegramAccountView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C4B4BE2D1AB392F80064AC17 /* TelegramAccountView.xib */; }; C4B4BE311AB393800064AC17 /* TelegramAccountViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C4B4BE2F1AB393800064AC17 /* TelegramAccountViewController.m */; }; C4B4BE331AB4536F0064AC17 /* PurpleDefaultsTelegram.plist in Resources */ = {isa = PBXBuildFile; fileRef = C4B4BE321AB4536F0064AC17 /* PurpleDefaultsTelegram.plist */; }; C4B4BE371AB5FB5C0064AC17 /* TelegramJoinChatViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C4B4BE351AB5FB5C0064AC17 /* TelegramJoinChatViewController.m */; }; C4B4BE391AB613950064AC17 /* TelegramJoinChatView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C4B4BE381AB613950064AC17 /* TelegramJoinChatView.xib */; }; C4B57BF01B1598D4006997F4 /* libtgl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B57BEF1B1598D4006997F4 /* libtgl.a */; }; C4D12DF01BC534CF00C0F6E1 /* tgp-blist.c in Sources */ = {isa = PBXBuildFile; fileRef = C4D12DEF1BC534CF00C0F6E1 /* tgp-blist.c */; }; C4D3EB5A1C3824C5003C895B /* tgp-info.c in Sources */ = {isa = PBXBuildFile; fileRef = C4D3EB581C3824C5003C895B /* tgp-info.c */; }; C4D819061A5C862E0044CBA9 /* tgp-structs.c in Sources */ = {isa = PBXBuildFile; fileRef = C4D819041A5C862E0044CBA9 /* tgp-structs.c */; }; C4D9185B1C1C6B3900AECCA2 /* libgpg-error.0.dylib in Resources */ = {isa = PBXBuildFile; fileRef = C4D9185A1C1C6B3900AECCA2 /* libgpg-error.0.dylib */; }; C4D9185C1C1C6B9C00AECCA2 /* libgpg-error.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C4D9185A1C1C6B3900AECCA2 /* libgpg-error.0.dylib */; }; C4E528111A8A907200C4B915 /* tgp-ft.c in Sources */ = {isa = PBXBuildFile; fileRef = C4E5280F1A8A907200C4B915 /* tgp-ft.c */; }; C4EA965A1B204C67006CBAD0 /* libwebp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C4EA96591B204C67006CBAD0 /* libwebp.a */; }; C4FFD0DC1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h in Sources */ = {isa = PBXBuildFile; fileRef = C4FFD0DB1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h */; }; C4FFD0DE1B5FC68400939D8A /* TelegramAutocompletionDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FFD0DD1B5FC68400939D8A /* TelegramAutocompletionDelegate.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 33070918C1B3F67A227F6286 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 33070A9DBCF625AD9E07CE94 /* telegram-adium-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.info; path = "telegram-adium-Info.plist"; sourceTree = ""; }; 33070CD59974365A33795EAF /* telegram-adium-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "telegram-adium-Prefix.pch"; sourceTree = ""; }; 3765D8B122F0964A008BA793 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = Frameworks/libpng.a; sourceTree = ""; }; C40564861A7937C600A293B9 /* AdiumLibpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdiumLibpurple.framework; path = Frameworks/Adium/AdiumLibpurple.framework; sourceTree = ""; }; C410948619BB2D7D0083BF3F /* telegram-adium.AdiumLibpurplePlugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "telegram-adium.AdiumLibpurplePlugin"; sourceTree = BUILT_PRODUCTS_DIR; }; C410948919BB2D7D0083BF3F /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; C410949919BB337A0083BF3F /* TelegramPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramPlugin.h; sourceTree = ""; }; C410949A19BB337A0083BF3F /* TelegramPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramPlugin.m; sourceTree = ""; }; C41D583F1A16D86A00B22448 /* tgp-2prpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-2prpl.h"; path = "../tgp-2prpl.h"; sourceTree = ""; }; C41D58401A16D88E00B22448 /* tgp-2prpl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-2prpl.c"; path = "../tgp-2prpl.c"; sourceTree = ""; }; C425F9161A7069C300361AFC /* tgp-utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-utils.c"; path = "../tgp-utils.c"; sourceTree = ""; }; C425F9171A7069C300361AFC /* tgp-utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-utils.h"; path = "../tgp-utils.h"; sourceTree = ""; }; C431EB7B1A76C737006521CB /* tgp-chat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-chat.c"; path = "../tgp-chat.c"; sourceTree = ""; }; C431EB7C1A76C737006521CB /* tgp-chat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-chat.h"; path = "../tgp-chat.h"; sourceTree = ""; }; C438CE231A12BEAF00E1DA0F /* telegram.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram.png; path = ../imgs/telegram.png; sourceTree = ""; }; C438CE241A12BEAF00E1DA0F /* telegram16.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram16.png; path = ../imgs/telegram16.png; sourceTree = ""; }; C438CE251A12BEAF00E1DA0F /* telegram22.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram22.png; path = ../imgs/telegram22.png; sourceTree = ""; }; C438CE261A12BEAF00E1DA0F /* telegram48.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram48.png; path = ../imgs/telegram48.png; sourceTree = ""; }; C438CE2B1A12BF3400E1DA0F /* libtgl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtgl.a; path = ../../tg/libs/libtgl.a; sourceTree = ""; }; C438CE2D1A12C07800E1DA0F /* msglog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = msglog.c; path = ../msglog.c; sourceTree = ""; }; C438CE2E1A12C07800E1DA0F /* telegram-base.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "telegram-base.c"; path = "../telegram-base.c"; sourceTree = ""; }; C438CE2F1A12C07800E1DA0F /* telegram-purple.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "telegram-purple.c"; path = "../telegram-purple.c"; sourceTree = ""; }; C438CE301A12C07800E1DA0F /* tgp-net.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-net.c"; path = "../tgp-net.c"; sourceTree = ""; }; C438CE311A12C07800E1DA0F /* tgp-timers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-timers.c"; path = "../tgp-timers.c"; sourceTree = ""; }; C438CE371A12C0C900E1DA0F /* msglog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = msglog.h; path = ../msglog.h; sourceTree = ""; }; C438CE381A12C0C900E1DA0F /* telegram-base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "telegram-base.h"; path = "../telegram-base.h"; sourceTree = ""; }; C438CE391A12C0C900E1DA0F /* telegram-purple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "telegram-purple.h"; path = "../telegram-purple.h"; sourceTree = ""; }; C438CE3A1A12C0C900E1DA0F /* tgp-net.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-net.h"; path = "../tgp-net.h"; sourceTree = ""; }; C438CE3B1A12C0C900E1DA0F /* tgp-timers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-timers.h"; path = "../tgp-timers.h"; sourceTree = ""; }; C438CE3C1A12C15100E1DA0F /* tg-server.pub */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "tg-server.pub"; path = "../tg-server.pub"; sourceTree = ""; }; C448ADA61AB0789A001B7ECD /* tgp-msg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-msg.c"; path = "../tgp-msg.c"; sourceTree = ""; }; C448ADA81AB078BB001B7ECD /* tgp-msg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "tgp-msg.h"; path = "../tgp-msg.h"; sourceTree = ""; }; C465FC1B1C0CF43A001CCEE8 /* libgcrypt.20.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libgcrypt.20.dylib; path = Frameworks/Adium/libgcrypt.20.dylib; sourceTree = ""; }; C465FC221C0D01B5001CCEE8 /* libgcrypt.20.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libgcrypt.20.dylib; path = Frameworks/Adium/libgcrypt.20.dylib; sourceTree = ""; }; C466937719E703370036A108 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; C479A7FE1BB1C95300C153DF /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = Frameworks/libcrypto.a; sourceTree = ""; }; C479A8001BB69C2100C153DF /* tgp-request.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-request.c"; path = "../tgp-request.c"; sourceTree = ""; }; C479A8011BB69C2100C153DF /* tgp-request.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-request.h"; path = "../tgp-request.h"; sourceTree = ""; }; C4877C1619BB37EA006FA91F /* TelegramService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramService.h; sourceTree = ""; }; C4877C1719BB37EA006FA91F /* TelegramService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramService.m; sourceTree = ""; }; C4877C1C19BB676B006FA91F /* TelegramAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramAccount.h; sourceTree = ""; }; C4877C1D19BB676B006FA91F /* TelegramAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramAccount.m; sourceTree = ""; }; C487A1781A792CD80044F135 /* libssl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.dylib; path = usr/lib/libssl.dylib; sourceTree = SDKROOT; }; C487A1891A792E9B0044F135 /* Adium.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Adium.framework; path = Frameworks/Adium/Adium.framework; sourceTree = ""; }; C487A18B1A792E9B0044F135 /* AIUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AIUtilities.framework; path = Frameworks/Adium/AIUtilities.framework; sourceTree = ""; }; C487A18F1A792EA50044F135 /* libglib.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libglib.framework; path = Frameworks/Adium/libglib.framework; sourceTree = ""; }; C487A1901A792EA50044F135 /* libpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libpurple.framework; path = Frameworks/Adium/libpurple.framework; sourceTree = ""; }; C49A915719BBC5C5001B3DC0 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; C4B4BE2D1AB392F80064AC17 /* TelegramAccountView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TelegramAccountView.xib; sourceTree = ""; }; C4B4BE2F1AB393800064AC17 /* TelegramAccountViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramAccountViewController.m; sourceTree = ""; }; C4B4BE301AB393800064AC17 /* TelegramAccountViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramAccountViewController.h; sourceTree = ""; }; C4B4BE321AB4536F0064AC17 /* PurpleDefaultsTelegram.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = PurpleDefaultsTelegram.plist; sourceTree = ""; }; C4B4BE351AB5FB5C0064AC17 /* TelegramJoinChatViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramJoinChatViewController.m; sourceTree = ""; }; C4B4BE361AB5FB5C0064AC17 /* TelegramJoinChatViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramJoinChatViewController.h; sourceTree = ""; }; C4B4BE381AB613950064AC17 /* TelegramJoinChatView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TelegramJoinChatView.xib; sourceTree = ""; }; C4B57BE51B109E6D006997F4 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; C4B57BE81B10D814006997F4 /* configure.ac */ = {isa = PBXFileReference; lastKnownFileType = text; name = configure.ac; path = ../configure.ac; sourceTree = ""; }; C4B57BE91B10D822006997F4 /* Makefile.in */ = {isa = PBXFileReference; lastKnownFileType = text; name = Makefile.in; path = ../Makefile.in; sourceTree = ""; }; C4B57BED1B1598BE006997F4 /* telegram-purple */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "telegram-purple"; path = ..; sourceTree = ""; }; C4B57BEF1B1598D4006997F4 /* libtgl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtgl.a; path = ../libs/libtgl.a; sourceTree = ""; }; C4D12DEE1BC534CF00C0F6E1 /* tgp-blist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-blist.h"; path = "../tgp-blist.h"; sourceTree = ""; }; C4D12DEF1BC534CF00C0F6E1 /* tgp-blist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-blist.c"; path = "../tgp-blist.c"; sourceTree = ""; }; C4D3EB581C3824C5003C895B /* tgp-info.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-info.c"; path = "../tgp-info.c"; sourceTree = ""; }; C4D3EB591C3824C5003C895B /* tgp-info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-info.h"; path = "../tgp-info.h"; sourceTree = ""; }; C4D432D71BC2783C00561667 /* tg-server.tglpub */ = {isa = PBXFileReference; lastKnownFileType = file; name = "tg-server.tglpub"; path = "../tg-server.tglpub"; sourceTree = ""; }; C4D819041A5C862E0044CBA9 /* tgp-structs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-structs.c"; path = "../tgp-structs.c"; sourceTree = ""; }; C4D819051A5C862E0044CBA9 /* tgp-structs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-structs.h"; path = "../tgp-structs.h"; sourceTree = ""; }; C4D9185A1C1C6B3900AECCA2 /* libgpg-error.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libgpg-error.0.dylib"; path = "Frameworks/Adium/libgpg-error.0.dylib"; sourceTree = ""; }; C4E5280F1A8A907200C4B915 /* tgp-ft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-ft.c"; path = "../tgp-ft.c"; sourceTree = ""; }; C4E528101A8A907200C4B915 /* tgp-ft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-ft.h"; path = "../tgp-ft.h"; sourceTree = ""; }; C4EA96591B204C67006CBAD0 /* libwebp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwebp.a; path = Frameworks/libwebp.a; sourceTree = ""; }; C4FFD0DB1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramAutocompletionDelegate.h; sourceTree = ""; }; C4FFD0DD1B5FC68400939D8A /* TelegramAutocompletionDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramAutocompletionDelegate.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ C410948319BB2D7D0083BF3F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( C4D9185C1C1C6B9C00AECCA2 /* libgpg-error.0.dylib in Frameworks */, C465FC211C0D0191001CCEE8 /* libgcrypt.20.dylib in Frameworks */, C49A915819BBC5C5001B3DC0 /* libz.dylib in Frameworks */, C466937819E703370036A108 /* AppKit.framework in Frameworks */, C4B57BF01B1598D4006997F4 /* libtgl.a in Frameworks */, C4EA965A1B204C67006CBAD0 /* libwebp.a in Frameworks */, 3765D8B222F0964A008BA793 /* libpng.a in Frameworks */, C40564871A7937C600A293B9 /* AdiumLibpurple.framework in Frameworks */, C487A18C1A792E9B0044F135 /* Adium.framework in Frameworks */, C487A18E1A792E9B0044F135 /* AIUtilities.framework in Frameworks */, C487A1911A792EA50044F135 /* libglib.framework in Frameworks */, C487A1921A792EA50044F135 /* libpurple.framework in Frameworks */, C410948A19BB2D7D0083BF3F /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 330704C72BA03B848124B6F7 /* telegram-adium */ = { isa = PBXGroup; children = ( 3307063DD9566C77D08006F9 /* Supporting Files */, ); path = "telegram-adium"; sourceTree = ""; }; 3307063DD9566C77D08006F9 /* Supporting Files */ = { isa = PBXGroup; children = ( 33070A9DBCF625AD9E07CE94 /* telegram-adium-Info.plist */, 33070D636377BD8BA47CBF63 /* InfoPlist.strings */, 33070CD59974365A33795EAF /* telegram-adium-Prefix.pch */, ); name = "Supporting Files"; sourceTree = ""; }; C410947D19BB2D7D0083BF3F = { isa = PBXGroup; children = ( C4FFD0DB1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h */, C4FFD0DD1B5FC68400939D8A /* TelegramAutocompletionDelegate.m */, C4B4BE321AB4536F0064AC17 /* PurpleDefaultsTelegram.plist */, C438CE251A12BEAF00E1DA0F /* telegram22.png */, C438CE231A12BEAF00E1DA0F /* telegram.png */, C438CE241A12BEAF00E1DA0F /* telegram16.png */, C438CE261A12BEAF00E1DA0F /* telegram48.png */, C410949919BB337A0083BF3F /* TelegramPlugin.h */, C410949A19BB337A0083BF3F /* TelegramPlugin.m */, C4877C1619BB37EA006FA91F /* TelegramService.h */, C4877C1719BB37EA006FA91F /* TelegramService.m */, C4877C1C19BB676B006FA91F /* TelegramAccount.h */, C4877C1D19BB676B006FA91F /* TelegramAccount.m */, C4B4BE361AB5FB5C0064AC17 /* TelegramJoinChatViewController.h */, C4B4BE351AB5FB5C0064AC17 /* TelegramJoinChatViewController.m */, C4B4BE2F1AB393800064AC17 /* TelegramAccountViewController.m */, C4B4BE381AB613950064AC17 /* TelegramJoinChatView.xib */, C4B4BE301AB393800064AC17 /* TelegramAccountViewController.h */, C4B4BE2D1AB392F80064AC17 /* TelegramAccountView.xib */, C465FC221C0D01B5001CCEE8 /* libgcrypt.20.dylib */, C4D9185A1C1C6B3900AECCA2 /* libgpg-error.0.dylib */, C4BF990319BB8B200038D507 /* telegram-purple */, C410948819BB2D7D0083BF3F /* Frameworks */, C410948719BB2D7D0083BF3F /* Products */, C4877C2919BB6D22006FA91F /* Resources */, ); sourceTree = ""; }; C410948719BB2D7D0083BF3F /* Products */ = { isa = PBXGroup; children = ( C410948619BB2D7D0083BF3F /* telegram-adium.AdiumLibpurplePlugin */, ); name = Products; sourceTree = ""; }; C410948819BB2D7D0083BF3F /* Frameworks */ = { isa = PBXGroup; children = ( C465FC1B1C0CF43A001CCEE8 /* libgcrypt.20.dylib */, C479A7FE1BB1C95300C153DF /* libcrypto.a */, C4B57BEF1B1598D4006997F4 /* libtgl.a */, C4EA96591B204C67006CBAD0 /* libwebp.a */, 3765D8B122F0964A008BA793 /* libpng.a */, C4B57BED1B1598BE006997F4 /* telegram-purple */, C40564861A7937C600A293B9 /* AdiumLibpurple.framework */, C487A18F1A792EA50044F135 /* libglib.framework */, C487A1901A792EA50044F135 /* libpurple.framework */, C487A1891A792E9B0044F135 /* Adium.framework */, C487A18B1A792E9B0044F135 /* AIUtilities.framework */, C49A915719BBC5C5001B3DC0 /* libz.dylib */, C487A1781A792CD80044F135 /* libssl.dylib */, C438CE2B1A12BF3400E1DA0F /* libtgl.a */, C466937719E703370036A108 /* AppKit.framework */, C410948919BB2D7D0083BF3F /* CoreFoundation.framework */, ); name = Frameworks; sourceTree = ""; }; C4877C2919BB6D22006FA91F /* Resources */ = { isa = PBXGroup; children = ( C438CE3C1A12C15100E1DA0F /* tg-server.pub */, ); name = Resources; sourceTree = ""; }; C4BF990319BB8B200038D507 /* telegram-purple */ = { isa = PBXGroup; children = ( C4D432D71BC2783C00561667 /* tg-server.tglpub */, C4B57BE81B10D814006997F4 /* configure.ac */, C4B57BE91B10D822006997F4 /* Makefile.in */, C4B57BE51B109E6D006997F4 /* README.md */, C425F9161A7069C300361AFC /* tgp-utils.c */, C425F9171A7069C300361AFC /* tgp-utils.h */, C4D819041A5C862E0044CBA9 /* tgp-structs.c */, C4D819051A5C862E0044CBA9 /* tgp-structs.h */, C438CE371A12C0C900E1DA0F /* msglog.h */, C438CE381A12C0C900E1DA0F /* telegram-base.h */, C438CE391A12C0C900E1DA0F /* telegram-purple.h */, C438CE3A1A12C0C900E1DA0F /* tgp-net.h */, C438CE3B1A12C0C900E1DA0F /* tgp-timers.h */, C438CE2D1A12C07800E1DA0F /* msglog.c */, C438CE2E1A12C07800E1DA0F /* telegram-base.c */, C438CE2F1A12C07800E1DA0F /* telegram-purple.c */, C448ADA61AB0789A001B7ECD /* tgp-msg.c */, C448ADA81AB078BB001B7ECD /* tgp-msg.h */, C438CE301A12C07800E1DA0F /* tgp-net.c */, C438CE311A12C07800E1DA0F /* tgp-timers.c */, C41D583F1A16D86A00B22448 /* tgp-2prpl.h */, C41D58401A16D88E00B22448 /* tgp-2prpl.c */, C431EB7B1A76C737006521CB /* tgp-chat.c */, C431EB7C1A76C737006521CB /* tgp-chat.h */, C4E5280F1A8A907200C4B915 /* tgp-ft.c */, C4E528101A8A907200C4B915 /* tgp-ft.h */, C479A8001BB69C2100C153DF /* tgp-request.c */, C479A8011BB69C2100C153DF /* tgp-request.h */, C4D12DEE1BC534CF00C0F6E1 /* tgp-blist.h */, C4D12DEF1BC534CF00C0F6E1 /* tgp-blist.c */, C4D3EB591C3824C5003C895B /* tgp-info.h */, C4D3EB581C3824C5003C895B /* tgp-info.c */, 330704C72BA03B848124B6F7 /* telegram-adium */, ); name = "telegram-purple"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ C410948519BB2D7D0083BF3F /* telegram-adium */ = { isa = PBXNativeTarget; buildConfigurationList = C410949419BB2D7D0083BF3F /* Build configuration list for PBXNativeTarget "telegram-adium" */; buildPhases = ( C410948219BB2D7D0083BF3F /* Sources */, C410948319BB2D7D0083BF3F /* Frameworks */, C410948419BB2D7D0083BF3F /* Resources */, C4C325A11C91BD230020D32E /* ShellScript */, ); buildRules = ( ); dependencies = ( ); name = "telegram-adium"; productName = "telegram-adium"; productReference = C410948619BB2D7D0083BF3F /* telegram-adium.AdiumLibpurplePlugin */; productType = "com.apple.product-type.bundle"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ C410947E19BB2D7D0083BF3F /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0510; ORGANIZATIONNAME = "Matthias Jentsch"; }; buildConfigurationList = C410948119BB2D7D0083BF3F /* Build configuration list for PBXProject "telegram-adium" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = C410947D19BB2D7D0083BF3F; productRefGroup = C410948719BB2D7D0083BF3F /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( C410948519BB2D7D0083BF3F /* telegram-adium */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ C410948419BB2D7D0083BF3F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( C4D9185B1C1C6B3900AECCA2 /* libgpg-error.0.dylib in Resources */, C465FC231C0D01B5001CCEE8 /* libgcrypt.20.dylib in Resources */, C438CE271A12BEAF00E1DA0F /* telegram.png in Resources */, C4B4BE391AB613950064AC17 /* TelegramJoinChatView.xib in Resources */, C4B4BE2E1AB392F80064AC17 /* TelegramAccountView.xib in Resources */, C438CE281A12BEAF00E1DA0F /* telegram16.png in Resources */, C438CE291A12BEAF00E1DA0F /* telegram22.png in Resources */, C438CE2A1A12BEAF00E1DA0F /* telegram48.png in Resources */, C4B4BE331AB4536F0064AC17 /* PurpleDefaultsTelegram.plist in Resources */, 33070C10341336CD4EC97534 /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ C4C325A11C91BD230020D32E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "install_name_tool -change \"@executable_path/../Frameworks/libglib.framework/Versions/2.38.1/libglib\" \"@executable_path/../Frameworks/libglib.framework/libglib\" \"$TARGET_BUILD_DIR/$PRODUCT_NAME.$WRAPPER_EXTENSION/Contents/MacOS/$PRODUCT_NAME\"\ninstall_name_tool -change \"@executable_path/../Frameworks/libpurple.framework/Versions/2.10.7rd8d96a636413/libpurple\" \"@executable_path/../Frameworks/libpurple.framework/libpurple\" \"$TARGET_BUILD_DIR/$PRODUCT_NAME.$WRAPPER_EXTENSION/Contents/MacOS/$PRODUCT_NAME\"\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ C410948219BB2D7D0083BF3F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( C4FFD0DC1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h in Sources */, C438CE321A12C07800E1DA0F /* msglog.c in Sources */, C438CE351A12C07800E1DA0F /* tgp-net.c in Sources */, C438CE331A12C07800E1DA0F /* telegram-base.c in Sources */, C4B4BE371AB5FB5C0064AC17 /* TelegramJoinChatViewController.m in Sources */, C438CE341A12C07800E1DA0F /* telegram-purple.c in Sources */, C4877C1819BB37EA006FA91F /* TelegramService.m in Sources */, C4D12DF01BC534CF00C0F6E1 /* tgp-blist.c in Sources */, C448ADA71AB0789A001B7ECD /* tgp-msg.c in Sources */, C4FFD0DE1B5FC68400939D8A /* TelegramAutocompletionDelegate.m in Sources */, C4E528111A8A907200C4B915 /* tgp-ft.c in Sources */, C438CE361A12C07800E1DA0F /* tgp-timers.c in Sources */, C410949B19BB337A0083BF3F /* TelegramPlugin.m in Sources */, C4B4BE311AB393800064AC17 /* TelegramAccountViewController.m in Sources */, C4877C1E19BB676B006FA91F /* TelegramAccount.m in Sources */, C41D58411A16D88E00B22448 /* tgp-2prpl.c in Sources */, C479A8021BB69C2100C153DF /* tgp-request.c in Sources */, C425F9181A7069C300361AFC /* tgp-utils.c in Sources */, C4D819061A5C862E0044CBA9 /* tgp-structs.c in Sources */, C431EB7D1A76C737006521CB /* tgp-chat.c in Sources */, C4D3EB5A1C3824C5003C895B /* tgp-info.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 33070D636377BD8BA47CBF63 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 33070918C1B3F67A227F6286 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ C410949219BB2D7D0083BF3F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( HAVE_CONFIG_H, HAVE_LIBWEBP, DEBUG, ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; name = Debug; }; C410949319BB2D7D0083BF3F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = ( HAVE_CONFIG_H, HAVE_LIBWEBP, ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; SDKROOT = macosx; }; name = Release; }; C410949519BB2D7D0083BF3F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; DEPLOYMENT_LOCATION = YES; DEPLOYMENT_POSTPROCESSING = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Frameworks/Adium", "$(LOCAL_LIBRARY_DIR)/Frameworks", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "telegram-adium/telegram-adium-Prefix.pch"; HEADER_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/../auto", "$(PROJECT_DIR)/../tgl", "$(PROJECT_DIR)/Frameworks/Adium/libpurple.framework/Headers", "$(PROJECT_DIR)/Frameworks/Adium/libglib.framework/Headers", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, /usr/local/include, ); INFOPLIST_FILE = "telegram-adium/telegram-adium-Info.plist"; INSTALL_PATH = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/../tgl/libs", "$(PROJECT_DIR)", "$(PROJECT_DIR)/Frameworks", "$(PROJECT_DIR)/Frameworks/Adium", ); OTHER_CFLAGS = "-DPURPLE_STATIC_PRPL"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = AdiumLibpurplePlugin; }; name = Debug; }; C410949619BB2D7D0083BF3F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; DEPLOYMENT_LOCATION = YES; DEPLOYMENT_POSTPROCESSING = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Frameworks/Adium", "$(LOCAL_LIBRARY_DIR)/Frameworks", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "telegram-adium/telegram-adium-Prefix.pch"; HEADER_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/../auto", "$(PROJECT_DIR)/../tgl", "$(PROJECT_DIR)/Frameworks/Adium/libpurple.framework/Headers", "$(PROJECT_DIR)/Frameworks/Adium/libglib.framework/Headers", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, /usr/local/include, ); INFOPLIST_FILE = "telegram-adium/telegram-adium-Info.plist"; INSTALL_PATH = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)", "$(PROJECT_DIR)/../tgl/libs", "$(PROJECT_DIR)/Frameworks", "$(PROJECT_DIR)/Frameworks/Adium", ); OTHER_CFLAGS = "-DPURPLE_STATIC_PRPL"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = AdiumLibpurplePlugin; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ C410948119BB2D7D0083BF3F /* Build configuration list for PBXProject "telegram-adium" */ = { isa = XCConfigurationList; buildConfigurations = ( C410949219BB2D7D0083BF3F /* Debug */, C410949319BB2D7D0083BF3F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; C410949419BB2D7D0083BF3F /* Build configuration list for PBXNativeTarget "telegram-adium" */ = { isa = XCConfigurationList; buildConfigurations = ( C410949519BB2D7D0083BF3F /* Debug */, C410949619BB2D7D0083BF3F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ }; rootObject = C410947E19BB2D7D0083BF3F /* Project object */; } telegram-purple/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/000077500000000000000000000000001363674160100277565ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/contents.xcworkspacedata000066400000000000000000000002371363674160100347220ustar00rootroot00000000000000 telegram-purple/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata/000077500000000000000000000000001363674160100324115ustar00rootroot00000000000000telegram-adium.xccheckout000066400000000000000000000027641363674160100373220ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata IDESourceControlProjectFavoriteDictionaryKey IDESourceControlProjectIdentifier 1C5A3335-4726-410A-8E70-801C8879E269 IDESourceControlProjectName telegram-adium IDESourceControlProjectOriginsDictionary 2BAF9F6AF710B4D765F611851696219A50533669 https://github.com/majn/telegram-purple.git IDESourceControlProjectPath telegram-adium/telegram-adium.xcodeproj IDESourceControlProjectRelativeInstallPathDictionary 2BAF9F6AF710B4D765F611851696219A50533669 ../../.. IDESourceControlProjectURL https://github.com/majn/telegram-purple.git IDESourceControlProjectVersion 111 IDESourceControlProjectWCCIdentifier 2BAF9F6AF710B4D765F611851696219A50533669 IDESourceControlProjectWCConfigurations IDESourceControlRepositoryExtensionIdentifierKey public.vcs.git IDESourceControlWCCIdentifierKey 2BAF9F6AF710B4D765F611851696219A50533669 IDESourceControlWCCName telegram-purple telegram-adium.xcscmblueprint000066400000000000000000000050641363674160100402200ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata{ "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "41D8FEA2FB3AAB94D0D4027A64957635038B427E", "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { }, "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { "32693D74F7AAA18802B0105461C73E1FD01CF3A3" : 0, "2BAF9F6AF710B4D765F611851696219A50533669" : 0, "41D8FEA2FB3AAB94D0D4027A64957635038B427E" : 0, "78234520DB6A5DE1B463A6198C9122A9D1A44221" : 0 }, "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "1C5A3335-4726-410A-8E70-801C8879E269", "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { "32693D74F7AAA18802B0105461C73E1FD01CF3A3" : "telegram-purple\/tgl\/", "2BAF9F6AF710B4D765F611851696219A50533669" : "tg\/", "41D8FEA2FB3AAB94D0D4027A64957635038B427E" : "telegram-purple\/", "78234520DB6A5DE1B463A6198C9122A9D1A44221" : "telegram-purple\/tgl\/tl-parser\/" }, "DVTSourceControlWorkspaceBlueprintNameKey" : "telegram-adium", "DVTSourceControlWorkspaceBlueprintVersion" : 204, "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "telegram-adium\/telegram-adium.xcodeproj", "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ { "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/vysheng\/tg", "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "2BAF9F6AF710B4D765F611851696219A50533669" }, { "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/vysheng\/tgl", "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "32693D74F7AAA18802B0105461C73E1FD01CF3A3" }, { "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/majn\/telegram-purple.git", "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "41D8FEA2FB3AAB94D0D4027A64957635038B427E" }, { "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/vysheng\/tl-parser", "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "78234520DB6A5DE1B463A6198C9122A9D1A44221" } ] }telegram-purple/telegram-adium/telegram-adium.xcodeproj/xcshareddata/000077500000000000000000000000001363674160100264135ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium.xcodeproj/xcshareddata/xcschemes/000077500000000000000000000000001363674160100303755ustar00rootroot00000000000000telegram-adium Release.xcscheme000066400000000000000000000051731363674160100363030ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium.xcodeproj/xcshareddata/xcschemes telegram-adium.xcscheme000066400000000000000000000052451363674160100347420ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium.xcodeproj/xcshareddata/xcschemes telegram-purple.xcscheme000066400000000000000000000055111363674160100351460ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium.xcodeproj/xcshareddata/xcschemes telegram-purple/telegram-adium/telegram-adium/000077500000000000000000000000001363674160100217645ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium/en.lproj/000077500000000000000000000000001363674160100235135ustar00rootroot00000000000000telegram-purple/telegram-adium/telegram-adium/en.lproj/InfoPlist.strings000066400000000000000000000000551363674160100270350ustar00rootroot00000000000000/* Localized versions of Info.plist keys */ telegram-purple/telegram-adium/telegram-adium/telegram-adium-Info.plist000066400000000000000000000027701363674160100266350ustar00rootroot00000000000000 AIMinimumAdiumVersionRequirement 1.5.10 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier org.telegram-purple.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 1.4.3 CFBundleSignature AdIM CFBundleVersion 1.4.3 CFPlugInDynamicRegisterFunction CFPlugInDynamicRegistration NO CFPlugInFactories 00000000-0000-0000-0000-000000000000 MyFactoryFunction CFPlugInTypes 00000000-0000-0000-0000-000000000000 00000000-0000-0000-0000-000000000000 CFPlugInUnloadFunction NSHumanReadableCopyright Copyright © 2014-2017 Matthias Jentsch. NSPrincipalClass TelegramPlugin telegram-purple/telegram-adium/telegram-adium/telegram-adium-Prefix.pch000066400000000000000000000003751363674160100266150ustar00rootroot00000000000000// // Prefix header // // The contents of this file are implicitly included at the beginning of every source file. // #ifdef __OBJC__ #import #import #endif #ifndef __ADIUM_ #define __ADIUM_ #endiftelegram-purple/telegram-base.c000066400000000000000000000410551363674160100170530ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch, Vitaly Valtman, Ben Wiederhake, Christopher Althaus 2014-2015 */ #define _GNU_SOURCE #include #include #include #include #include "telegram-base.h" // O_BINARY exists on windows and must be defined, but doesn't exist on unix-based systems #ifndef O_BINARY #define O_BINARY 0 #endif #define DC_SERIALIZED_MAGIC 0x868aa81d #define STATE_FILE_MAGIC 0x28949a93 #define SECRET_CHAT_FILE_MAGIC 0x37a1988a void read_state_file (struct tgl_state *TLS) { char *name = 0; name = g_strdup_printf("%s/%s", TLS->base_path, "state"); int state_file_fd = open (name, O_CREAT | O_RDWR | O_BINARY, 0600); free (name); if (state_file_fd < 0) { return; } int version, magic; if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return; } if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return; } if (read (state_file_fd, &version, 4) < 4 || version < 0) { close (state_file_fd); return; } int x[4]; if (read (state_file_fd, x, 16) < 16) { close (state_file_fd); return; } int pts = x[0]; int qts = x[1]; int seq = x[2]; int date = x[3]; close (state_file_fd); bl_do_set_seq (TLS, seq); bl_do_set_pts (TLS, pts); bl_do_set_qts (TLS, qts); bl_do_set_date (TLS, date); info ("read state file: seq=%d pts=%d qts=%d date=%d", seq, pts, qts, date); } void write_state_file (struct tgl_state *TLS) { int wseq; int wpts; int wqts; int wdate; wseq = TLS->seq; wpts = TLS->pts; wqts = TLS->qts; wdate = TLS->date; char *name = 0; name = g_strdup_printf("%s/%s", TLS->base_path, "state"); int state_file_fd = open (name, O_CREAT | O_RDWR | O_BINARY, 0600); free (name); if (state_file_fd < 0) { return; } int x[6]; x[0] = STATE_FILE_MAGIC; x[1] = 0; x[2] = wpts; x[3] = wqts; x[4] = wseq; x[5] = wdate; assert (write (state_file_fd, x, 24) == 24); close (state_file_fd); info ("wrote state file: wpts=%d wqts=%d wseq=%d wdate=%d", wpts, wqts, wseq, wdate); } static gboolean write_files_gw (gpointer data) { struct tgl_state *TLS = data; ((connection_data *)TLS->ev_base)->write_timer = 0; write_state_file (TLS); write_secret_chat_file (TLS); return FALSE; } void write_files_schedule (struct tgl_state *TLS) { connection_data *conn = TLS->ev_base; if (! conn->write_timer) { conn->write_timer = purple_timeout_add (0, write_files_gw, TLS); } } struct write_dc_extra { int auth_file; int flags; }; void write_dc (struct tgl_dc *DC, void *extra) { struct write_dc_extra *ex = extra; int auth_file_fd = ex->auth_file; if (!DC) { int x = 0; assert (write (auth_file_fd, &x, 4) == 4); return; } else { int x = 1; assert (write (auth_file_fd, &x, 4) == 4); } assert (DC->flags & TGLDCF_LOGGED_IN); assert (write (auth_file_fd, &DC->options[ex->flags]->port, 4) == 4); int l = strlen (DC->options[ex->flags]->ip); assert (write (auth_file_fd, &l, 4) == 4); assert (write (auth_file_fd, DC->options[ex->flags]->ip, l) == l); assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8); assert (write (auth_file_fd, DC->auth_key, 256) == 256); } void write_auth_file (struct tgl_state *TLS) { struct write_dc_extra extra; char *name = 0; name = g_strdup_printf("%s/%s", TLS->base_path, "auth"); int auth_file_fd = open (name, O_CREAT | O_RDWR | O_BINARY, 0600); free (name); if (auth_file_fd < 0) { return; } int x = DC_SERIALIZED_MAGIC; assert (write (auth_file_fd, &x, 4) == 4); assert (write (auth_file_fd, &TLS->max_dc_num, 4) == 4); assert (write (auth_file_fd, &TLS->dc_working_num, 4) == 4); extra.auth_file = auth_file_fd; extra.flags = TLS->ipv6_enabled ? 1 : 0; tgl_dc_iterator_ex (TLS, write_dc, &extra); assert (write (auth_file_fd, &TLS->our_id, 4) == 4); close (auth_file_fd); info ("wrote auth file: magic=%d max_dc_num=%d dc_working_num=%d", x, TLS->max_dc_num, TLS->dc_working_num); } void read_dc (struct tgl_state *TLS, int auth_file_fd, int id, unsigned ver) { int port = 0; assert (read (auth_file_fd, &port, 4) == 4); int l = 0; assert (read (auth_file_fd, &l, 4) == 4); assert (l >= 0 && l < 100); char ip[100]; assert (read (auth_file_fd, ip, l) == l); ip[l] = 0; long long auth_key_id; static unsigned char auth_key[256]; assert (read (auth_file_fd, &auth_key_id, 8) == 8); assert (read (auth_file_fd, auth_key, 256) == 256); bl_do_dc_option (TLS, TLS->ipv6_enabled ? 1: 0, id, "DC", 2, ip, l, port); bl_do_set_auth_key (TLS, id, auth_key); bl_do_dc_signed (TLS, id); debug ("read dc: id=%d", id); } int tgp_error_if_false (struct tgl_state *TLS, int val, const char *cause, const char *msg) { if (! val) { connection_data *conn = TLS->ev_base; purple_connection_error_reason (conn->gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, msg); purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, cause, msg, NULL, NULL, NULL); return TRUE; } return 0; } void empty_auth_file (struct tgl_state *TLS) { info ("initializing empty auth file"); if (TLS->test_mode) { bl_do_dc_option (TLS, 0, 1, "", 0, TG_SERVER_TEST_1, strlen (TG_SERVER_TEST_1), 443); bl_do_dc_option (TLS, 0, 2, "", 0, TG_SERVER_TEST_2, strlen (TG_SERVER_TEST_2), 443); bl_do_dc_option (TLS, 0, 3, "", 0, TG_SERVER_TEST_3, strlen (TG_SERVER_TEST_3), 443); bl_do_set_working_dc (TLS, TG_SERVER_TEST_DEFAULT); } else { if (TLS->ipv6_enabled) { bl_do_dc_option (TLS, 1, 1, "", 0, TG_SERVER_IPV6_1, strlen (TG_SERVER_IPV6_1), 443); bl_do_dc_option (TLS, 1, 2, "", 0, TG_SERVER_IPV6_2, strlen (TG_SERVER_IPV6_2), 443); bl_do_dc_option (TLS, 1, 3, "", 0, TG_SERVER_IPV6_3, strlen (TG_SERVER_IPV6_3), 443); bl_do_dc_option (TLS, 1, 4, "", 0, TG_SERVER_IPV6_4, strlen (TG_SERVER_IPV6_4), 443); bl_do_dc_option (TLS, 1, 5, "", 0, TG_SERVER_IPV6_5, strlen (TG_SERVER_IPV6_5), 443); } else { bl_do_dc_option (TLS, 0, 1, "", 0, TG_SERVER_1, strlen (TG_SERVER_1), 443); bl_do_dc_option (TLS, 0, 2, "", 0, TG_SERVER_2, strlen (TG_SERVER_2), 443); bl_do_dc_option (TLS, 0, 3, "", 0, TG_SERVER_3, strlen (TG_SERVER_3), 443); bl_do_dc_option (TLS, 0, 4, "", 0, TG_SERVER_4, strlen (TG_SERVER_4), 443); bl_do_dc_option (TLS, 0, 5, "", 0, TG_SERVER_5, strlen (TG_SERVER_5), 443); } bl_do_set_working_dc (TLS, TG_SERVER_DEFAULT); } } void read_auth_file (struct tgl_state *TLS) { char *name = 0; name = g_strdup_printf("%s/%s", TLS->base_path, "auth"); int auth_file_fd = open (name, O_CREAT | O_RDWR | O_BINARY, 0600); free (name); if (auth_file_fd < 0) { empty_auth_file (TLS); return; } assert (auth_file_fd >= 0); unsigned x; unsigned m; if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC)) { close (auth_file_fd); empty_auth_file (TLS); return; } assert (read (auth_file_fd, &x, 4) == 4); assert (x > 0); int dc_working_num; assert (read (auth_file_fd, &dc_working_num, 4) == 4); int i; for (i = 0; i <= (int)x; i++) { int y; assert (read (auth_file_fd, &y, 4) == 4); if (y) { read_dc (TLS, auth_file_fd, i, m); } } bl_do_set_working_dc (TLS, dc_working_num); int our_id; int l = read (auth_file_fd, &our_id, 4); if (l < 4) { assert (!l); } if (our_id) { bl_do_set_our_id (TLS, TGL_MK_USER (our_id)); } close (auth_file_fd); info ("read auth file: dcs=%d dc_working_num=%d our_id=%d", x, dc_working_num, our_id); } void write_secret_chat (tgl_peer_t *_P, void *extra) { struct tgl_secret_chat *P = (void *)_P; if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) { return; } if (P->state != sc_ok) { return; } int *a = extra; int fd = a[0]; a[1] ++; int id = tgl_get_peer_id (P->id); assert (write (fd, &id, 4) == 4); int l = strlen (P->print_name); assert (write (fd, &l, 4) == 4); assert (write (fd, P->print_name, l) == l); assert (write (fd, &P->user_id, 4) == 4); assert (write (fd, &P->admin_id, 4) == 4); assert (write (fd, &P->date, 4) == 4); assert (write (fd, &P->ttl, 4) == 4); assert (write (fd, &P->layer, 4) == 4); assert (write (fd, &P->access_hash, 8) == 8); assert (write (fd, &P->state, 4) == 4); assert (write (fd, &P->key_fingerprint, 8) == 8); assert (write (fd, &P->key, 256) == 256); assert (write (fd, &P->first_key_sha, 20) == 20); assert (write (fd, &P->in_seq_no, 4) == 4); assert (write (fd, &P->last_in_seq_no, 4) == 4); assert (write (fd, &P->out_seq_no, 4) == 4); debug ("wrote secret chat: %s, state=%d, in_seq_no=%d, out_seq_no=%d", P->print_name, P->state, P->in_seq_no, P->out_seq_no); } void write_secret_chat_file (struct tgl_state *TLS) { char *name = 0; name = g_strdup_printf("%s/%s", TLS->base_path, "secret"); int secret_chat_fd = open (name, O_CREAT | O_RDWR | O_BINARY, 0600); free (name); assert (secret_chat_fd >= 0); int x = SECRET_CHAT_FILE_MAGIC; assert (write (secret_chat_fd, &x, 4) == 4); x = 2; assert (write (secret_chat_fd, &x, 4) == 4); // version assert (write (secret_chat_fd, &x, 4) == 4); // num int y[2]; y[0] = secret_chat_fd; y[1] = 0; tgl_peer_iterator_ex (TLS, write_secret_chat, y); lseek (secret_chat_fd, 8, SEEK_SET); assert (write (secret_chat_fd, &y[1], 4) == 4); close (secret_chat_fd); info ("wrote secret chat file: %d chats written.", y[1]); } void read_secret_chat (struct tgl_state *TLS, int fd, int v) { int id, l, user_id, admin_id, date, ttl, layer, state; long long access_hash, key_fingerprint; static char s[1000]; static unsigned char key[256]; static unsigned char sha[20]; assert (read (fd, &id, 4) == 4); assert (read (fd, &l, 4) == 4); assert (l > 0 && l < 999); assert (read (fd, s, l) == l); assert (read (fd, &user_id, 4) == 4); assert (read (fd, &admin_id, 4) == 4); assert (read (fd, &date, 4) == 4); assert (read (fd, &ttl, 4) == 4); assert (read (fd, &layer, 4) == 4); assert (read (fd, &access_hash, 8) == 8); assert (read (fd, &state, 4) == 4); assert (read (fd, &key_fingerprint, 8) == 8); assert (read (fd, &key, 256) == 256); if (v >= 2) { assert (read (fd, sha, 20) == 20); } else { PurpleCipher *sha1_cipher = purple_ciphers_find_cipher("sha1"); PurpleCipherContext *sha1_ctx = purple_cipher_context_new(sha1_cipher, NULL); purple_cipher_context_append(sha1_ctx, key, 256); purple_cipher_context_digest(sha1_ctx, 20, sha, NULL); purple_cipher_context_destroy(sha1_ctx); } int in_seq_no = 0, out_seq_no = 0, last_in_seq_no = 0; if (v >= 1) { assert (read (fd, &in_seq_no, 4) == 4); assert (read (fd, &last_in_seq_no, 4) == 4); assert (read (fd, &out_seq_no, 4) == 4); } s[l] = '\0'; debug ("read secret chat: %s, state=%d, in_seq_no=%d, last_in_seq_no=%d, out_seq_no=%d", s, state, in_seq_no, last_in_seq_no, out_seq_no); bl_do_encr_chat (TLS, id, &access_hash, &date, &admin_id, &user_id, key, NULL, sha, &state, &ttl, &layer, &in_seq_no, &last_in_seq_no, &out_seq_no, &key_fingerprint, TGLECF_CREATE | TGLECF_CREATED, s, l); } void read_secret_chat_file (struct tgl_state *TLS) { char *name = 0; name = g_strdup_printf("%s/%s", TLS->base_path, "secret"); int secret_chat_fd = open (name, O_RDWR | O_BINARY, 0600); free (name); if (secret_chat_fd < 0) { return; } int x; if (read (secret_chat_fd, &x, 4) < 4) { close (secret_chat_fd); return; } if (x != SECRET_CHAT_FILE_MAGIC) { close (secret_chat_fd); return; } int v = 0; assert (read (secret_chat_fd, &v, 4) == 4); assert (v == 0 || v == 1 || v == 2); // version assert (read (secret_chat_fd, &x, 4) == 4); assert (x >= 0); int cnt = x; while (x -- > 0) { read_secret_chat (TLS, secret_chat_fd, v); } close (secret_chat_fd); info ("read secret chat file: %d chats read", cnt); } gchar *get_config_dir (char const *username) { gchar *dir = g_strconcat (purple_user_dir(), G_DIR_SEPARATOR_S, config_dir, G_DIR_SEPARATOR_S, username, NULL); if (g_str_has_prefix (dir, g_get_tmp_dir())) { // telepathy-haze will set purple user dir to a tmp path, // but we need the files to be persistent g_free (dir); dir = g_strconcat (g_get_home_dir(), G_DIR_SEPARATOR_S, ".telegram-purple", G_DIR_SEPARATOR_S, username, NULL); } g_mkdir_with_parents (dir, 0700); return dir; } gchar *get_download_dir (struct tgl_state *TLS) { assert (TLS->base_path); static gchar *dir; if (dir) { g_free (dir); } if (g_strcmp0(purple_core_get_ui(), "BitlBee") == 0) { dir = g_strconcat ("/tmp", G_DIR_SEPARATOR_S, "downloads", NULL); } else { dir = g_strconcat (TLS->base_path, G_DIR_SEPARATOR_S, "downloads", NULL); g_mkdir_with_parents (dir, 0700); } return dir; } void write_secret_chat_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *_) { if (!success) { tgp_notify_on_error_gw (TLS, NULL, success); return; } write_secret_chat_file (TLS); } void tgp_create_group_chat_by_usernames (struct tgl_state *TLS, const char *title, const char **users, int num_users, int use_print_names) { tgl_peer_id_t ids[num_users + 1]; int i, j = 0; ids[j++] = TLS->our_id; for (i = 0; i < num_users; i++) if (str_not_empty (users[i])) { tgl_peer_t *P = NULL; if (use_print_names) { // used by Adium autocompletion that is based on print_names P = tgl_peer_get_by_name (TLS, users[i]); } else { P = tgp_blist_lookup_peer_get (TLS, users[i]); } if (P && tgl_get_peer_id (P->id) != tgl_get_peer_id (TLS->our_id)) { debug ("Adding %s: %d", P->print_name, tgl_get_peer_id (P->id)); ids[j++] = P->id; } else { debug ("User %s not found in peer list", users[j]); } } if (j > 1) { tgl_do_create_group_chat (TLS, j, ids, title, (int) strlen(title), tgp_notify_on_error_gw, g_strdup (title)); } else { purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, _("Couldn't create group"), _("Please select at least one other user."), NULL, NULL, NULL); } } /** * This function generates a png image to visualize the sha1 key from an encrypted chat. */ int tgp_visualize_key (struct tgl_state *TLS, unsigned char* sha1_key) { int colors[4] = { 0xffffff, 0xd5e6f3, 0x2d5775, 0x2f99c9 }; unsigned img_size = 160; unsigned char* image = (unsigned char*)malloc (img_size * img_size * 4); assert (image); unsigned x, y, i, j, idx = 0; int bitpointer = 0; for (y = 0; y < 8; y++) { unsigned offset_y = y * img_size * 4 * (img_size / 8); for (x = 0; x < 8; x++) { int offset = bitpointer / 8; int shiftOffset = bitpointer % 8; int val = sha1_key[offset + 3] << 24 | sha1_key[offset + 2] << 16 | sha1_key[offset + 1] << 8 | sha1_key[offset]; idx = abs ((val >> shiftOffset) & 3) % 4; bitpointer += 2; unsigned offset_x = x * 4 * (img_size / 8); for (i = 0; i < img_size / 8; i++) { unsigned off_y = offset_y + i * img_size * 4; for (j = 0; j < img_size / 8; j++) { unsigned off_x = offset_x + j * 4; image[off_y + off_x + 0] = colors[idx] & 0xFF; image[off_y + off_x + 1] = (colors[idx] >> 8) & 0xFF; image[off_y + off_x + 2] = (colors[idx] >> 16) & 0xFF; image[off_y + off_x + 3] = 0xFF; } } } } int imgStoreId = p2tgl_imgstore_add_with_id_raw(image, img_size, img_size); used_images_add ((connection_data*)TLS->ev_base, imgStoreId); g_free (image); return imgStoreId; } void tgp_notify_on_error_gw (struct tgl_state *TLS, void *extra, int success) { if (!success) { char *errormsg = g_strdup_printf ("%d: %s", TLS->error_code, TLS->error); failure (errormsg); purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, _("Query Failed"), errormsg, NULL, NULL, NULL); g_free (errormsg); return; } } telegram-purple/telegram-base.h000066400000000000000000000036061363674160100170600ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch, Vitaly Valtman, Christopher Althaus, Ben Wiederhake 2014-2015 */ #ifndef __TELEGRAM_BASE_H__ #define __TELEGRAM_BASE_H__ #include "telegram-purple.h" void read_state_file (struct tgl_state *TLS); void read_auth_file (struct tgl_state *TLS); void write_auth_file (struct tgl_state *TLS); void write_state_file (struct tgl_state *TLS); void write_files_schedule (struct tgl_state *TLS); void read_secret_chat_file (struct tgl_state *TLS); void write_secret_chat_file (struct tgl_state *TLS); void write_secret_chat_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E); gchar *get_config_dir (char const *username); gchar *get_download_dir (struct tgl_state *TLS); int tgp_visualize_key (struct tgl_state *TLS, unsigned char* sha1_key); void tgp_create_group_chat_by_usernames (struct tgl_state *TLS, const char *title, const char *users[], int num_users, int print_names); void tgp_notify_on_error_gw (struct tgl_state *TLS, void *extra, int success); int tgp_error_if_false (struct tgl_state *TLS, int val, const char *cause, const char *msg); #endif telegram-purple/telegram-purple.c000066400000000000000000001045101363674160100174440ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch, Vitaly Valtman, Ben Wiederhake, Christopher Althaus 2014-2015 */ #include #include "telegram-purple.h" #include "commit.h" #ifdef WIN32 #include "win32/win32dep.h" #endif static void update_message_handler (struct tgl_state *TLS, struct tgl_message *M); static void update_marked_read (struct tgl_state *TLS, int num, struct tgl_message *list[]); static void update_on_logged_in (struct tgl_state *TLS); static void update_on_ready (struct tgl_state *TLS); static void update_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum tgl_typing_status status); static void update_secret_chat_typing (struct tgl_state *TLS, struct tgl_secret_chat *E); static void update_user_status_handler (struct tgl_state *TLS, struct tgl_user *U); static void update_user_handler (struct tgl_state *TLS, struct tgl_user *U, unsigned flags); static void update_secret_chat_handler (struct tgl_state *TLS, struct tgl_secret_chat *C, unsigned flags); static void update_on_failed_login (struct tgl_state *TLS); const char *config_dir = "telegram-purple"; struct tgl_update_callback tgp_callback = { .new_msg = update_message_handler, .marked_read = update_marked_read, .logprintf = debug, .get_values = request_value, .logged_in = update_on_logged_in, .started = update_on_ready, .type_notification = update_user_typing, // FIXME: what about user_registred, user_activated, new_authorization, our_id ? .type_in_secret_chat_notification = update_secret_chat_typing, .type_in_chat_notification = update_chat_typing, .chat_update = update_chat_handler, .channel_update = update_channel_handler, .user_update = update_user_handler, .secret_chat_update = update_secret_chat_handler, .msg_receive = update_message_handler, .user_status_update = update_user_status_handler, .create_print_name = tgp_blist_create_print_name, .on_failed_login = update_on_failed_login }; static void _update_buddy (struct tgl_state *TLS, tgl_peer_t *user, unsigned flags) { PurpleBuddy *buddy = tgp_blist_buddy_find (TLS, user->id); if (buddy) { if (flags & TGL_UPDATE_DELETED) { debug ("update deleted"); purple_blist_remove_buddy (buddy); } else { if (flags & TGL_UPDATE_CONTACT) { debug ("update contact"); purple_blist_alias_buddy (buddy, user->print_name); } if (flags & TGL_UPDATE_PHOTO) { debug ("update photo"); tgp_info_update_photo (&buddy->node, user); } } } } static void update_user_handler (struct tgl_state *TLS, struct tgl_user *user, unsigned flags) { debug ("update_user_handler() (%s)", print_flags_update (flags)); if (tgl_get_peer_id (TLS->our_id) == tgl_get_peer_id (user->id) && (flags & (TGL_UPDATE_NAME | TGL_UPDATE_CONTACT))) { // own user object, do not add that user to the buddy list but make the ID known to the name lookup and // set the print name as the name to be displayed in IM chats instead of the login name (the phone number) purple_connection_set_display_name (tls_get_conn (TLS), user->print_name); tgp_blist_lookup_add (TLS, user->id, user->print_name); return; } if (flags & TGL_UPDATE_CREATED) { // user was allocated, fetch the corresponding buddy from the buddy list PurpleBuddy *buddy = tgp_blist_buddy_find (TLS, user->id); debug ("new user %s allocated (%s)", user->print_name, print_flags_user (user->flags)); if (user->flags & TGLUF_DELETED) { if (buddy) { info ("user %d was deleted, removing from buddy list ...", tgl_get_peer_id (user->id)); purple_blist_remove_buddy (buddy); } } else { g_return_if_fail(user->print_name); if (! buddy) { // if the buddy is still stored in the legacy naming format find and migrate it. This // should only happen when making the switch from a version < 1.2.2 to a version >= 1.2.2 char *id = g_strdup_printf ("%d", tgl_get_peer_id (user->id)); buddy = purple_find_buddy (tls_get_pa (TLS), id); g_free (id); if (buddy) { info ("migrating buddy from old name %s to %s", purple_buddy_get_name (buddy), user->print_name); buddy = tgp_blist_buddy_migrate (TLS, buddy, user); } // the id isn't known to the lookup yet since the user is not in the buddy list. Add the id to the // lookup to allow sending messages to this user based on the purple name. tgp_blist_lookup_add (TLS, user->id, user->print_name); } else { // Keep the users name up-to-date. Changing the actual user name would imply making the history // inacessible, therefore name changes should only affect the alias. if (strcmp (purple_buddy_get_alias (buddy), user->print_name)) { serv_got_alias (tls_get_conn (TLS), purple_buddy_get_name (buddy), user->print_name); } } if (user->flags & TGLUF_CONTACT) { if (! buddy) { tgp_blist_contact_add (TLS, user); } } if (buddy) { p2tgl_prpl_got_user_status (TLS, user->id, &user->status); tgp_info_update_photo (&buddy->node, tgl_peer_get (TLS, user->id)); } } } else { // peer was not created, but altered in some way _update_buddy (TLS, (tgl_peer_t *)user, flags); } } static void update_secret_chat_handler (struct tgl_state *TLS, struct tgl_secret_chat *U, unsigned flags) { debug ("update_secret_chat_handler() (%s)", print_flags_update (flags)); PurpleBuddy *buddy = tgp_blist_buddy_find (TLS, U->id); if (flags & TGL_UPDATE_CREATED) { tgp_blist_lookup_add (TLS, U->id, U->print_name); } else { if (flags & TGL_UPDATE_WORKING) { write_secret_chat_file (TLS); if (U->state == sc_ok) { tgp_msg_special_out (TLS , _("Secret chat ready.") , U->id, PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_SYSTEM); } } if (buddy) { if (flags & TGL_UPDATE_DELETED) { U->state = sc_deleted; write_secret_chat_file (TLS); tgp_msg_special_out (TLS , _("Secret chat terminated.") , U->id, PURPLE_MESSAGE_SYSTEM); purple_prpl_got_user_status (tls_get_pa (TLS), tgp_blist_lookup_purple_name (TLS, U->id), "offline", NULL); purple_blist_remove_buddy (buddy); } else { _update_buddy (TLS, (tgl_peer_t *)U, flags); } } } if (!(flags & TGL_UPDATE_DELETED)) { if (! buddy) { buddy = tgp_blist_buddy_new (TLS, (tgl_peer_t *)U); purple_blist_add_buddy (buddy, NULL, tgp_blist_group_init (_("Telegram")), NULL); purple_blist_alias_buddy (buddy, U->print_name); } purple_prpl_got_user_status (tls_get_pa (TLS), tgp_blist_lookup_purple_name (TLS, U->id), "mobile", NULL); } if (flags & TGL_UPDATE_REQUESTED) { const char* choice = purple_account_get_string (tls_get_pa (TLS), TGP_KEY_ACCEPT_SECRET_CHATS, "ask"); if (! strcmp (choice, "always")) { tgl_do_accept_encr_chat_request (TLS, U, write_secret_chat_gw, 0); } else if (! strcmp (choice, "ask")) { request_accept_secret_chat (TLS, U); } } } static void update_user_status_handler (struct tgl_state *TLS, struct tgl_user *U) { p2tgl_prpl_got_user_status (TLS, U->id, &U->status); } static void update_message_handler (struct tgl_state *TLS, struct tgl_message *M) { write_files_schedule (TLS); tgp_msg_recv (TLS, M, NULL); } static void update_secret_chat_typing (struct tgl_state *TLS, struct tgl_secret_chat *E) { g_return_if_fail (tgp_blist_lookup_purple_name (TLS, E->id)); serv_got_typing (tls_get_conn (TLS), tgp_blist_lookup_purple_name (TLS, E->id), 2, PURPLE_TYPING); } static void update_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum tgl_typing_status status) { g_return_if_fail (tgp_blist_lookup_purple_name (TLS, U->id)); if (status == tgl_typing_typing) { serv_got_typing (tls_get_conn (TLS), tgp_blist_lookup_purple_name (TLS, U->id), 2, PURPLE_TYPING); } } static void update_marked_read (struct tgl_state *TLS, int num, struct tgl_message *list[]) { if (! purple_account_get_bool (tls_get_pa (TLS), TGP_KEY_DISPLAY_READ_NOTIFICATIONS, FALSE)) { return; } int i; for (i = 0; i < num; i++) { if (list[i]) { // only display the read recipes for messages that we sent ourselves if (tgl_get_peer_id (list[i]->from_id) == tgl_get_peer_id (TLS->our_id)) { debug ("update_mark_read to=%d", tgl_get_peer_id (list[i]->to_id)); tgp_msg_special_out (TLS , _("Message marked as read."), list[i]->to_id, PURPLE_MESSAGE_SYSTEM); } } } } static void on_get_dialog_list_done (struct tgl_state *TLS, void *extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]) { info ("Fetched dialogue list of size: %d", size); connection_data *conn = tls_get_data(TLS); if (tgp_error_if_false (TLS, success, "Fetching dialogue list failed", TLS->error)) { return; } // add all peers in the dialogue list to the buddy list int i; for (i = size - 1; i >= 0; i--) { tgl_peer_t *UC = tgl_peer_get (TLS, peers[i]); if (! UC) { g_warn_if_reached (); continue; } // our own contact shouldn't show up in our buddy list if (tgl_get_peer_id (UC->id) == tgl_get_peer_id (TLS->our_id)) { continue; } if (tgl_get_peer_type (UC->id) == TGL_PEER_USER) { if (! (UC->user.flags & TGLUF_DELETED)) { tgp_blist_contact_add (TLS, &UC->user); } } } // handle pending roomlist request if (conn->roomlist != NULL && purple_roomlist_get_in_progress (conn->roomlist)) { tgp_chat_roomlist_populate (TLS); } // handle all pending chat joins tls_get_data (TLS)->dialogues_ready = TRUE; tgp_chat_join_all_pending (TLS); } static void on_get_channel_list_done (struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]) { int i; for (i = 0; i < size; i ++) { if (! tgp_channel_loaded (TLS, peers[i])) { tgp_channel_load (TLS, tgl_peer_get (TLS, peers[i]), NULL, NULL); } } } static const char *tgprpl_list_icon (PurpleAccount *acct, PurpleBuddy *buddy) { return "telegram"; } static void tgprpl_tooltip_text (PurpleBuddy *buddy, PurpleNotifyUserInfo *info, gboolean full) { // buddy in old format that didn't migrate if (! tgp_blist_buddy_has_id (buddy)) { return; } tgl_peer_t *P = tgl_peer_get (pbn_get_data (&buddy->node)->TLS, tgp_blist_buddy_get_id (buddy)); g_return_if_fail (P); gchar *status = tgp_format_user_status (&P->user.status); purple_notify_user_info_add_pair (info, "last online: ", status); g_free (status); } static GList *tgprpl_status_types (PurpleAccount *acct) { debug ("tgprpl_status_types()"); GList *types = NULL; PurpleStatusType *type; type = purple_status_type_new_full (PURPLE_STATUS_AVAILABLE, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_prepend (types, type); type = purple_status_type_new_full (PURPLE_STATUS_MOBILE, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_prepend (types, type); type = purple_status_type_new_full (PURPLE_STATUS_OFFLINE, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_prepend (types, type); /* The states below are only registered internally so that we get notified about state changes to away and unavailable. This is useful for deciding when to send No other peer should ever have those states. */ type = purple_status_type_new_full (PURPLE_STATUS_AWAY, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_prepend (types, type); type = purple_status_type_new_full (PURPLE_STATUS_UNAVAILABLE, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_prepend (types, type); return g_list_reverse (types); } static void create_secret_chat_done (struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E) { if (! success) { tgp_notify_on_error_gw (TLS, NULL, success); return; } write_secret_chat_file (TLS); } static void start_secret_chat (PurpleBlistNode *node, gpointer data) { tgl_do_create_secret_chat (pbn_get_data (node)->TLS, tgp_blist_buddy_get_id ((PurpleBuddy *)node), create_secret_chat_done, NULL); } static void create_chat_link_done (struct tgl_state *TLS, void *extra, int success, const char *url) { tgl_peer_t *P = extra; if (success) { char *msg = g_strdup_printf (_("Invite link: %s"), url); tgp_chat_got_in (TLS, P, P->id, msg, PURPLE_MESSAGE_SYSTEM, time(NULL)); g_free (msg); } else { tgp_notify_on_error_gw (TLS, NULL, success); } } void export_chat_link (struct tgl_state *TLS, tgl_peer_t *P) { if (! (P->flags & (TGLPF_ADMIN | TGLPF_CREATOR))) { // FIXME: Can TGLCHF_MODERATOR export links? purple_notify_error (_telegram_protocol, _("Creating chat link failed"), _("Creating chat link failed"), _("You need to be admin of the group to do that.")); return; } if (tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { tgl_do_export_chat_link (TLS, P->id, create_chat_link_done, P); } else if (tgl_get_peer_type(P->id) == TGL_PEER_CHANNEL) { tgl_do_export_channel_link (TLS, P->id, create_chat_link_done, P); } else { g_warn_if_reached(); } } static void export_chat_link_checked_gw (PurpleBlistNode *node, gpointer data) { PurpleChat *chat = (PurpleChat*)node; export_chat_link_by_name (pbn_get_data (node)->TLS, purple_chat_get_name (chat)); } void export_chat_link_by_name (struct tgl_state *TLS, const char *name) { g_return_if_fail(name); tgl_peer_t *C = tgp_blist_lookup_peer_get (TLS, name); g_warn_if_fail(C != NULL); export_chat_link (TLS, C); } static void leave_and_delete_chat_gw (PurpleBlistNode *node, gpointer data) { PurpleChat *C = (PurpleChat *)node; g_return_if_fail(tgp_chat_has_id (C)); leave_and_delete_chat (pbn_get_data (node)->TLS, tgl_peer_get (pbn_get_data (node)->TLS, tgp_chat_get_id (C))); } void leave_and_delete_chat (struct tgl_state *TLS, tgl_peer_t *P) { g_return_if_fail (P); if (tgl_get_peer_type(P->id) == TGL_PEER_CHAT) { if (!(P->chat.flags & TGLCHF_LEFT)) { tgl_do_del_user_from_chat (TLS, P->id, TLS->our_id, tgp_notify_on_error_gw, NULL); } } else if (tgl_get_peer_type(P->id) == TGL_PEER_CHANNEL) { tgl_do_leave_channel (TLS, P->id, tgp_notify_on_error_gw, NULL); } else { g_return_if_reached(); } serv_got_chat_left (tls_get_conn (TLS), tgl_get_peer_id (P->id)); PurpleChat *PC = tgp_blist_chat_find (TLS, P->id); if (PC) { purple_blist_remove_chat (PC); } } void leave_and_delete_chat_by_name (struct tgl_state *TLS, const char *name) { g_return_if_fail(name); tgl_peer_t *P = tgp_blist_lookup_peer_get (TLS, name); g_return_if_fail(P); leave_and_delete_chat (TLS, P); } static PurpleCmdRet tgprpl_cmd_kick(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar **error, void *data) { PurpleConnection *pc = NULL; int id = -1; gchar *who; pc = conv->account->gc; id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)); if (pc == NULL || id == -1) { return PURPLE_CMD_RET_FAILED; } who = g_strjoinv(" ", args); tgprpl_kick_from_chat(pc, id, who); g_free(who); return PURPLE_CMD_RET_OK; } static void import_chat_link_done (struct tgl_state *TLS, void *extra, int success) { if (! success) { tgp_notify_on_error_gw (TLS, NULL, success); return; } purple_notify_info (_telegram_protocol, _("Chat joined"), _("Chat joined"), _("Chat added to list of chat rooms.")); } void import_chat_link (struct tgl_state *TLS, const char *link) { tgl_do_import_chat_link (TLS, link, (int) strlen(link), import_chat_link_done, NULL); } static GList* tgprpl_blist_node_menu (PurpleBlistNode *node) { debug ("tgprpl_blist_node_menu()"); // skip orphaned buddies in "old" format that didn't migrate and don't have an ID if (PURPLE_BLIST_NODE_IS_BUDDY(node) && ! tgp_blist_buddy_has_id ((PurpleBuddy *)node)) { return NULL; } // chats that don't have a proper ID aren't usable if (PURPLE_BLIST_NODE_IS_CHAT(node) && ! tgp_chat_has_id ((PurpleChat *)node)) { return NULL; } GList* menu = NULL; if (PURPLE_BLIST_NODE_IS_BUDDY(node) && tgl_get_peer_type (tgp_blist_buddy_get_id ((PurpleBuddy *)node)) == TGL_PEER_USER) { // Add encrypted chat option to the right click menu of all buddies PurpleBuddy* buddy = (PurpleBuddy *)node; PurpleMenuAction* action = purple_menu_action_new (_("Start secret chat..."), PURPLE_CALLBACK(start_secret_chat), buddy, NULL); menu = g_list_append (menu, (gpointer)action); } if (PURPLE_BLIST_NODE_IS_CHAT(node)) { // Generate Public Link PurpleMenuAction* action = purple_menu_action_new (_("Invite users by link..."), PURPLE_CALLBACK(export_chat_link_checked_gw), NULL, NULL); menu = g_list_append (menu, (gpointer)action); } if (PURPLE_BLIST_NODE_IS_CHAT(node)) { // Delete self from chat PurpleMenuAction* action = purple_menu_action_new (_("Delete and exit..."), PURPLE_CALLBACK(leave_and_delete_chat_gw), NULL, NULL); menu = g_list_append (menu, (gpointer)action); } return menu; } static void update_on_logged_in (struct tgl_state *TLS) { info ("update_on_logged_in(): The account is signed in"); write_auth_file (TLS); debug ("state: seq = %d, pts = %d, date = %d", TLS->seq, TLS->pts, TLS->date); purple_connection_set_state (tls_get_conn (TLS), PURPLE_CONNECTED); purple_blist_add_account (tls_get_pa (TLS)); tgp_blist_lookup_init (TLS); // It is important to load secret chats exactly at this point during login, cause if it was done earlier, // the update function wouldn't find existing chats and create duplicate entries. If it was done later, eventual // updates for those secret chats wouldn't be able to be decrypted due to missing secret keys. read_secret_chat_file (TLS); } static void update_on_ready (struct tgl_state *TLS) { info ("update_on_ready(): The account is done fetching new history"); tgl_peer_t *P = tgl_peer_get (TLS, TLS->our_id); g_warn_if_fail(P); if (P) { purple_connection_set_display_name (tls_get_conn (TLS), P->print_name); } tgl_do_get_dialog_list (TLS, 200, 0, on_get_dialog_list_done, NULL); tgl_do_get_channels_dialog_list (TLS, 50, 0, on_get_channel_list_done, NULL); tgl_do_update_contact_list (TLS, 0, 0); } static void update_on_failed_login (struct tgl_state *TLS) { info ("update_on_failed_login(): Login to telegram failed."); // 401: SESSION_REVOKED is called when the session is cancelled during runtime // 401: AUTH_KEY_UNREGISTERED is called when logging into a revoked session if (strstr (TLS->error, "SESSION_REVOKED") || strstr (TLS->error, "AUTH_KEY_UNREGISTERED")) { purple_account_set_bool (tls_get_pa (TLS), TGP_KEY_RESET_AUTH, TRUE); } purple_connection_error (tls_get_conn (TLS), TLS->error); } static gulong chat_conversation_typing_signal = 0; static void tgprpl_login (PurpleAccount * acct) { info ("tgprpl_login(): Purple is telling the prpl to connect the account"); PurpleConnection *gc = purple_account_get_connection (acct); gc->flags |= PURPLE_CONNECTION_NO_BGCOLOR; struct tgl_state *TLS = tgl_state_alloc (); connection_data *conn = connection_data_init (TLS, gc, acct); purple_connection_set_protocol_data (gc, conn); TLS->base_path = get_config_dir (purple_account_get_username (acct)); tgl_set_download_directory (TLS, get_download_dir(TLS)); debug ("base configuration path: '%s'", TLS->base_path); tgl_set_rsa_key_direct (TLS, tglmp_get_default_e(), tglmp_get_default_key_len(), tglmp_get_default_key()); tgl_set_ev_base (TLS, conn); tgl_set_net_methods (TLS, &tgp_conn_methods); tgl_set_timer_methods (TLS, &tgp_timers); tgl_set_callback (TLS, &tgp_callback); tgl_register_app_id (TLS, TGP_APP_ID, TGP_APP_HASH); tgl_set_app_version (TLS, PACKAGE_VERSION); if (tgl_init (TLS) != 0) { debug ("Call to tgl_init failed.\n"); char *cause = g_strdup_printf (_("Unable to sign on as %s: problem in the underlying library" " 'tgl'. Please submit a bug report with the debug log."), purple_account_get_username (acct)); purple_connection_error_reason (gc, PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, cause); purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, _("Problem in tgl"), cause, NULL, NULL, NULL); g_free (cause); return; } if (purple_account_get_bool (acct, TGP_KEY_USE_IPV6, FALSE)) { tgl_enable_ipv6(TLS); } if (! tgp_startswith (purple_account_get_username (acct), "+")) { // TRANSLATORS: Please fill in your own prefix! char *cause = g_strdup_printf (_("Unable to sign on as %s: phone number lacks country prefix." " Numbers must start with the full international" " prefix code, e.g. +1 for USA."), purple_account_get_username (acct)); purple_connection_error_reason (gc, PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, cause); purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, _("Incomplete phone number"), cause, NULL, NULL, NULL); g_free (cause); return; } read_auth_file (TLS); read_state_file (TLS); if (purple_account_get_bool (acct, TGP_KEY_RESET_AUTH, FALSE)) { info ("last login attempt failed, resetting authorization ..."); purple_account_set_bool (tls_get_pa (TLS), TGP_KEY_RESET_AUTH, FALSE); bl_do_reset_authorization (TLS); } purple_connection_set_state (conn->gc, PURPLE_CONNECTING); tgl_login (TLS); if (!chat_conversation_typing_signal) { chat_conversation_typing_signal = purple_signal_connect(purple_conversations_get_handle(), "chat-conversation-typing", purple_connection_get_prpl (gc), PURPLE_CALLBACK(tgprpl_send_chat_typing), NULL); } } static void tgprpl_close (PurpleConnection *gc) { debug ("tgprpl_close()"); connection_data_free (purple_connection_get_protocol_data (gc)); } static int tgprpl_send_im (PurpleConnection *gc, const char *who, const char *message, PurpleMessageFlags flags) { debug ("tgprpl_send_im()"); // workaround to support clients without the request API (request.h), see tgp-request.c:request_code() if (gc_get_data (gc)->request_code_data) { // OTR plugins may try to insert messages that don't contain the code if (tgp_startswith (message, "?OTR")) { info ("Fallback SMS auth, skipping OTR message: '%s'", message); return -1; } struct request_values_data *data = gc_get_data (gc)->request_code_data; data->callback (gc_get_tls (gc), &message, data->arg); free (data); gc_get_data (gc)->request_code_data = NULL; return 1; } // check receiver to give immediate feedback in case sending a message is not possible tgl_peer_t *peer = tgp_blist_lookup_peer_get (gc_get_tls (gc), who); if (! peer) { warning ("peer not found"); return -1; } // secret chat not yet usable if (tgl_get_peer_type (peer->id) == TGL_PEER_ENCR_CHAT && peer->encr_chat.state != sc_ok) { const char *msg; if (peer->encr_chat.state == sc_deleted) { msg = _("Secret chat was already deleted"); } else { msg = _("Secret chat is not ready"); } tgp_msg_special_out (gc_get_tls (gc), msg, peer->id, PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_ERROR); return -1; } // channel owned by someone else (TEST: why does it work with supergroups?) if (tgl_get_peer_type (peer->id) == TGL_PEER_CHANNEL && ! (peer->flags & TGLCHF_CREATOR)) { tgp_msg_special_out (gc_get_tls (gc), _("Only the creator of a channel can post messages."), peer->id, PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_ERROR); return -1; } // when the other peer receives a message it is obvious that the previous messages were read pending_reads_send_user (gc_get_tls (gc), peer->id); return tgp_msg_send (gc_get_tls (gc), message, peer->id); } static unsigned int tgprpl_send_typing (PurpleConnection *gc, const char *who, PurpleTypingState typing) { debug ("tgprpl_send_typing()"); tgl_peer_t *peer = tgp_blist_lookup_peer_get (gc_get_tls (gc), who); if (peer) { tgl_do_send_typing (gc_get_tls (gc), peer->id, typing == PURPLE_TYPING ? tgl_typing_typing : tgl_typing_cancel, 0, 0); // when the other peer sees that the current user is typing it is obvious that the previous messages were read pending_reads_send_user (gc_get_tls (gc), peer->id); } return 0; } static void tgprpl_set_status (PurpleAccount *acct, PurpleStatus *status) { debug ("tgprpl_set_status(%s)", purple_status_get_name (status)); pending_reads_send_all (pa_get_data (acct)->TLS); } static void tgprpl_add_buddy (PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { tgl_peer_t *P = tgl_peer_get_by_name (gc_get_tls (gc), buddy->name); if (P) { tgp_blist_contact_add (gc_get_tls (gc), &P->user); } } static void tgprpl_chat_invite (PurpleConnection *gc, int id, const char *message, const char *who) { debug ("tgprpl_chat_invite()"); tgl_peer_t *chat = tgl_peer_get (gc_get_tls (gc), TGL_MK_CHAT (id)); tgl_peer_t *user = tgp_blist_lookup_peer_get (gc_get_tls (gc), who); if (! chat || ! user) { purple_notify_error (_telegram_protocol, _("Cannot invite buddy to chat"), _("Cannot invite buddy to chat"), _("Specified user does not exist.")); return; } tgl_do_add_user_to_chat (gc_get_tls (gc), chat->id, user->id, 0, tgp_notify_on_error_gw, chat); } static gboolean tgprpl_can_receive_file (PurpleConnection *gc, const char *who) { return TRUE; } static GHashTable *tgprpl_get_account_text_table (PurpleAccount *pa) { GHashTable *HT; HT = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert(HT, "login_label", (gpointer) _("phone no. (+ country prefix)")); return HT; } PurplePlugin *_telegram_protocol = NULL; static PurplePluginProtocolInfo prpl_info = { OPT_PROTO_NO_PASSWORD | OPT_PROTO_IM_IMAGE, NULL, // user_¡splits, initialized in tgprpl_init() NULL, // protocol_options, initialized in tgprpl_init() { "png", 1, // min_width 1, // min_height 512, // max_width 512, // max_height 64000, // max_filesize PURPLE_ICON_SCALE_SEND, }, tgprpl_list_icon, NULL, NULL, tgprpl_tooltip_text, tgprpl_status_types, tgprpl_blist_node_menu, tgprpl_chat_join_info, tgprpl_chat_info_defaults, tgprpl_login, tgprpl_close, tgprpl_send_im, NULL, // set_info tgprpl_send_typing, tgprpl_info_show, tgprpl_set_status, NULL, // set_idle NULL, // change_passwd tgprpl_add_buddy, NULL, // add_buddies tgprpl_request_delete_contact, NULL, // remove_buddies NULL, // add_permit NULL, // add_deny NULL, // rem_permit NULL, // rem_deny NULL, // set_permit_deny tgprpl_chat_join, NULL, // reject_chat tgprpl_get_chat_name, tgprpl_chat_invite, NULL, // chat_leave NULL, // chat_whisper tgprpl_send_chat, NULL, // keepalive NULL, // register_user NULL, // get_cb_info NULL, // get_cb_away NULL, // alias_buddy NULL, // group_buddy NULL, // rename_group NULL, // buddy_free NULL, // convo_closed NULL, // normalize NULL, // tgprpl_set_buddy_icon NULL, // remove_group NULL, NULL, // set_chat_topic NULL, // find_blist_chat tgprpl_roomlist_get_list, tgprpl_roomlist_cancel, NULL, // roomlist_expand_category tgprpl_can_receive_file, tgprpl_send_file, tgprpl_new_xfer, NULL, // offline_message NULL, // whiteboard_prpl_ops NULL, // send_raw NULL, // roomlist_room_serialize NULL, // unregister_user NULL, // send_attention NULL, // get_attention_types sizeof(PurplePluginProtocolInfo), tgprpl_get_account_text_table, // get_account_text_table NULL, // initiate_media NULL, // get_media_caps NULL, // get_moods NULL, // set_public_alias NULL, // get_public_alias NULL, // add_buddy_with_invite NULL // add_buddies_with_invite }; static gboolean tgprpl_load (PurplePlugin *plugin) { purple_cmd_register("kick", "s", PURPLE_CMD_P_PLUGIN, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, PLUGIN_ID, tgprpl_cmd_kick, _("kick : Kick a user from the room."), NULL); return TRUE; } static void tgprpl_init (PurplePlugin *plugin) { PurpleAccountOption *opt; // set domain name that is used for translation #if ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); #endif #define ADD_VALUE(list, desc, v) { \ PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \ kvp->key = g_strdup((desc)); \ kvp->value = g_strdup((v)); \ list = g_list_prepend(list, kvp); \ } // Login opt = purple_account_option_string_new (_("Password (two factor authentication)"), TGP_KEY_PASSWORD_TWO_FACTOR, NULL); purple_account_option_set_masked (opt, TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, opt); opt = purple_account_option_bool_new ( _("Fallback SMS verification\n(Helps when not using Pidgin and you aren't being prompted for the code)"), "compat-verification", 0); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, opt); // Messaging GList *choices = NULL; // Whether to do fallback SMS verification ADD_VALUE(choices, _("Always"), "always"); // Whether to do fallback SMS verification ADD_VALUE(choices, _("Never"), "never"); // Whether to do fallback SMS verification ADD_VALUE(choices, _("Ask"), "ask"); opt = purple_account_option_list_new (_("Accept secret chats"), TGP_KEY_ACCEPT_SECRET_CHATS, choices); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, opt); opt = purple_account_option_int_new (_("Display buddies offline after (days)"), TGP_KEY_INACTIVE_DAYS_OFFLINE, TGP_DEFAULT_INACTIVE_DAYS_OFFLINE); prpl_info.protocol_options = g_list_append (prpl_info.protocol_options, opt); opt = purple_account_option_int_new (_("Don't fetch history older than (days)\n(0 for unlimited)"), TGP_KEY_HISTORY_RETRIEVAL_THRESHOLD, TGP_DEFAULT_HISTORY_RETRIEVAL_THRESHOLD); prpl_info.protocol_options = g_list_append (prpl_info.protocol_options, opt); // Media and documents choices = NULL; // How to handle "large" files ADD_VALUE(choices, _("Discard"), "discard"); // How to handle "large" files ADD_VALUE(choices, _("Auto load"), "autoload"); // How to handle "large" files ADD_VALUE(choices, _("Ask"), "ask"); opt = purple_account_option_int_new (_("Auto load file transfers up to (kb)"), TGP_KEY_MEDIA_SIZE, TGP_DEFAULT_MEDIA_SIZE); prpl_info.protocol_options = g_list_append (prpl_info.protocol_options, opt); opt = purple_account_option_list_new (_("Bigger file transfers"), TGP_KEY_FT_HANDLING, choices); prpl_info.protocol_options = g_list_append (prpl_info.protocol_options, opt); // Chats opt = purple_account_option_bool_new (_("Add all group chats to buddy list"), TGP_KEY_JOIN_GROUP_CHATS, TGP_DEFAULT_JOIN_GROUP_CHATS); prpl_info.protocol_options = g_list_append (prpl_info.protocol_options, opt); // Receipts opt = purple_account_option_bool_new (_("Display notices of receipt"), TGP_KEY_DISPLAY_READ_NOTIFICATIONS, TGP_DEFAULT_DISPLAY_READ_NOTIFICATIONS); prpl_info.protocol_options = g_list_append (prpl_info.protocol_options, opt); opt = purple_account_option_bool_new (_("Send notices of receipt when present"), TGP_KEY_SEND_READ_NOTIFICATIONS, TGP_DEFAULT_SEND_READ_NOTIFICATIONS); prpl_info.protocol_options = g_list_append (prpl_info.protocol_options, opt); // IPv6 opt = purple_account_option_bool_new (_("Use IPv6 for connecting (restart required)"), TGP_KEY_USE_IPV6, TGP_DEFAULT_USE_IPV6); prpl_info.protocol_options = g_list_append (prpl_info.protocol_options, opt); _telegram_protocol = plugin; debug ("tgprpl_init finished: This is " PACKAGE_VERSION "+g" GIT_COMMIT " on libtgl " TGL_VERSION); } static GList *tgprpl_actions (PurplePlugin *plugin, gpointer context) { return (GList *)NULL; } static PurplePluginInfo plugin_info = { PURPLE_PLUGIN_MAGIC, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_PLUGIN_PROTOCOL, NULL, 0, NULL, PURPLE_PRIORITY_DEFAULT, PLUGIN_ID, "Telegram", PACKAGE_VERSION "\n\t\t\tcommit: " GIT_COMMIT "\n\t\t\tlibtgl: " TGL_VERSION, "Telegram", N_("Telegram Protocol Plugin."), PLUGIN_AUTHOR, "https://github.com/majn/telegram-purple", tgprpl_load, // on load NULL, // on unload NULL, // on destroy NULL, // ui specific struct &prpl_info, NULL, // prefs info tgprpl_actions, NULL, // reserved NULL, // reserved NULL, // reserved NULL // reserved }; PURPLE_INIT_PLUGIN (telegram, tgprpl_init, plugin_info) telegram-purple/telegram-purple.h000066400000000000000000000075271363674160100174630ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch, Vitaly Valtman, Christopher Althaus, Ben Wiederhake 2014-2015 */ #ifndef __TG_PURPLE_H__ #define __TG_PURPLE_H__ #ifdef HAVE_CONFIG_H # include "config.h" #endif // Define macros for gettext translation, ENABLE_NLS should be set if configure has detected // libintl.h. If this is not the case a dummy macro is defined to bypass the translation functions #ifdef ENABLE_NLS # include # define P_(Singular,Plural,N) ((char *) g_dngettext (GETTEXT_PACKAGE, Singular, Plural, N)) #else # define _(String) String # define P_(Singular,Plural,N) Plural # define N_(String) String # define gettext(String) String #endif #include #include #include #include #include #include #include "telegram-base.h" #include "tgp-blist.h" #include "tgp-structs.h" #include "tgp-2prpl.h" #include "tgp-net.h" #include "tgp-timers.h" #include "tgp-utils.h" #include "tgp-chat.h" #include "tgp-ft.h" #include "tgp-msg.h" #include "tgp-request.h" #include "tgp-info.h" #include "msglog.h" #define PLUGIN_ID "prpl-telegram" #define PLUGIN_AUTHOR "Matthias Jentsch \n\t\t\tVitaly Valtman\n\t\t\tBen Wiederhake\n\t\t\tChristopher Althaus " #define TGP_APP_HASH "99428c722d0ed59b9cd844e4577cb4bb" #define TGP_APP_ID 16154 #define TGP_MAX_MSG_SIZE 4096 #define TGP_DEFAULT_MAX_MSG_SPLIT_COUNT 4 #define TGP_DEFAULT_FT_HANDLING "ask" #define TGP_KEY_FT_HANDLING "media-handling-behavior" #define TGP_DEFAULT_MEDIA_SIZE 32768 #define TGP_KEY_MEDIA_SIZE "media-size-threshold" #define TGP_KEY_PASSWORD_TWO_FACTOR "password-two-factor" #define TGP_DEFAULT_ACCEPT_SECRET_CHATS "ask" #define TGP_KEY_ACCEPT_SECRET_CHATS "accept-secret-chats" #define TGP_DEFAULT_INACTIVE_DAYS_OFFLINE 7 #define TGP_KEY_INACTIVE_DAYS_OFFLINE "inactive-days-offline" #define TGP_DEFAULT_HISTORY_RETRIEVAL_THRESHOLD 14 #define TGP_KEY_HISTORY_RETRIEVAL_THRESHOLD "history-retrieve-days" #define TGP_DEFAULT_JOIN_GROUP_CHATS TRUE #define TGP_KEY_JOIN_GROUP_CHATS "auto-join-group-chats" #define TGP_DEFAULT_DISPLAY_READ_NOTIFICATIONS FALSE #define TGP_KEY_DISPLAY_READ_NOTIFICATIONS "display-read-notifications" #define TGP_DEFAULT_SEND_READ_NOTIFICATIONS TRUE #define TGP_KEY_SEND_READ_NOTIFICATIONS "send-read-notifications" #define TGP_DEFAULT_CHANNEL_MEMBERS 200 #define TGP_KEY_CHANNEL_MEMBERS "channel-member-count" #define TGP_DEFAULT_USE_IPV6 FALSE #define TGP_KEY_USE_IPV6 "ipv6" #define TGP_KEY_RESET_AUTH "reset-authorization" #define TGP_CHANNEL_HISTORY_LIMIT 100 extern const char *pk_path; extern const char *user_pk_filename; extern const char *config_dir; extern PurplePlugin *_telegram_protocol; void import_chat_link (struct tgl_state *TLS, const char *link); void export_chat_link_by_name (struct tgl_state *TLS, const char *name); void leave_and_delete_chat (struct tgl_state *TLS, tgl_peer_t *P); void leave_and_delete_chat_by_name (struct tgl_state *TLS, const char *name); void channel_load_photo (struct tgl_state *TLS, void *extra, int success, struct tgl_channel *C); #endif telegram-purple/telegram-purple.nsi.awk000066400000000000000000000006301363674160100205720ustar00rootroot00000000000000{ if (match($0,"變")) { do { prev=lang; getline lang<"po/LINGUAS"; l=$0; gsub("變",lang,l); if (prev!=lang) {print l} } while (prev!=lang); } else if (match($0,"或")) { while ((getline def_line<"config.h") > 0) { if (def_line == "#define HAVE_LIBWEBP 1") { gsub("或","",$0); print break } } } else { print } } telegram-purple/telegram-purple.nsi.awk-in000066400000000000000000000072741363674160100212110ustar00rootroot00000000000000; This file is part of telegram-purple ; ; 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 02111-1301 USA ; ; Copyright Matthias Jentsch, Eion Robb 2014-2015 ; Script based on the Skype4Pidgin and Off-the-Record Messaging NSI files SetCompressor /SOLID /FINAL lzma ; todo: SetBrandingImage ; HM NIS Edit Wizard helper defines !define PRODUCT_NAME "telegram-purple" !define PRODUCT_VERSION "${PLUGIN_VERSION}" !define PRODUCT_PUBLISHER "The telegram-purple team" !define PRODUCT_WEB_SITE "https://github.com/majn/telegram-purple" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" ; MUI 1.67 compatible ------ !include "MUI.nsh" ; MUI Settings !define MUI_ABORTWARNING !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico" !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" ; Welcome page !insertmacro MUI_PAGE_WELCOME ; License page !insertmacro MUI_PAGE_LICENSE "COPYING" ; Instfiles page !insertmacro MUI_PAGE_INSTFILES !define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN_TEXT "Run Pidgin" !define MUI_FINISHPAGE_RUN_FUNCTION "RunPidgin" !insertmacro MUI_PAGE_FINISH ; Uninstaller pages ;!insertmacro MUI_UNPAGE_INSTFILES ; Language files !insertmacro MUI_LANGUAGE "English" ; MUI end ------ Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" OutFile "${PRODUCT_NAME}-${PRODUCT_VERSION}.exe" Var "PidginDir" ShowInstDetails show ShowUnInstDetails show Section "MainSection" SEC01 ;Check for pidgin installation Call GetPidginInstPath SetOverwrite try SetOutPath "$PidginDir\pixmaps\pidgin" File "/oname=protocols\16\telegram.png" "imgs\telegram16.png" File "/oname=protocols\22\telegram.png" "imgs\telegram22.png" File "/oname=protocols\48\telegram.png" "imgs\telegram48.png" SetOverwrite try copy: ClearErrors Delete "$PidginDir\plugins\${PRPL_NAME}" IfErrors dllbusy SetOutPath "$PidginDir\plugins" File "bin\${PRPL_NAME}" Goto after_copy dllbusy: MessageBox MB_RETRYCANCEL "${PRPL_NAME} is busy. Please close Pidgin (including tray icon) and try again" IDCANCEL cancel Goto copy cancel: Abort "Installation of telegram-purple aborted" after_copy: SetOutPath "$PidginDir\locale" File /nonfatal "/oname=變\LC_MESSAGES\telegram-purple.mo" "po\變.mo" SetOutPath "$PidginDir" File "${WIN32_DEV_TOP}\libgpg-error-0.dll" File "${WIN32_DEV_TOP}\libgcrypt-20.dll" 或File "${WIN32_DEV_TOP}\libwebp-7.dll" File "${WIN32_DEV_TOP}\libgcc_s_sjlj-1.dll" SectionEnd Function GetPidginInstPath Push $0 ReadRegStr $0 HKLM "Software\pidgin" "" IfFileExists "$0\pidgin.exe" cont ReadRegStr $0 HKCU "Software\pidgin" "" IfFileExists "$0\pidgin.exe" cont MessageBox MB_OK|MB_ICONINFORMATION "Failed to find Pidgin installation." Abort "Failed to find Pidgin installation. Please install Pidgin first." cont: StrCpy $PidginDir $0 FunctionEnd Function RunPidgin ExecShell "" "$PidginDir\pidgin.exe" FunctionEnd telegram-purple/test/000077500000000000000000000000001363674160100151515ustar00rootroot00000000000000telegram-purple/test/.gitignore000066400000000000000000000000121363674160100171320ustar00rootroot00000000000000/bin /tmp telegram-purple/test/Makefile000066400000000000000000000010341363674160100166070ustar00rootroot00000000000000PLUGIN_TESTS:=probetest loadtest PLUGIN_TEST_BINS:=$(addprefix test/bin/,${PLUGIN_TESTS}) test/bin: mkdir -p $@ test/tmp/%: mkdir -p $@ test/bin/%: test/%.c test/bin bin/telegram-purple.so ${CC} ${CFLAGS} ${CPPFLAGS} -I ${srcdir}/tgl -o $@ $< ${LDFLAGS} .PHONY: ${PLUGIN_TESTS} ${PLUGIN_TESTS}: %: test/bin/% test/tmp/user $< bin/telegram-purple.so .PHONY: check check: ${PLUGIN_TESTS} test/tmp/user @echo "'make check' passed." .PHONY: recheck recheck: clean-test check .PHONY: clean-test clean-test: rm -rf test/bin test/tmp telegram-purple/test/loadtest.c000066400000000000000000000220131363674160100171320ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Ben Wiederhake 2016, Purple developers 2007-2015 Derived from the nullclient.c example at https://github.com/Tasssadar/libpurple/blob/master/example/nullclient.c */ #include #include #include #include #include #include #include #include "../commit.h" #include "../telegram-purple.h" // The following eventloop functions are used in both pidgin and purple-text. If your application uses glib mainloop, you can safely use this verbatim. #define PURPLE_GLIB_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) #define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) typedef struct TdfGLibIOClosure { PurpleInputFunction function; guint result; gpointer data; } TdfGLibIOClosure; typedef struct TdfAccountRequestInfo { PurpleAccountRequestType type; PurpleAccount *account; void *ui_handle; char *user; gpointer userdata; PurpleAccountRequestAuthorizationCb auth_cb; PurpleAccountRequestAuthorizationCb deny_cb; guint ref; } TdfAccountRequestInfo; static void tdf_glib_io_destroy (gpointer data) { g_free (data); } static gboolean tdf_glib_io_invoke (GIOChannel *source, GIOCondition condition, gpointer data) { TdfGLibIOClosure *closure = data; PurpleInputCondition purple_cond = 0; if (condition & PURPLE_GLIB_READ_COND) purple_cond |= PURPLE_INPUT_READ; if (condition & PURPLE_GLIB_WRITE_COND) purple_cond |= PURPLE_INPUT_WRITE; closure->function (closure->data, g_io_channel_unix_get_fd (source), purple_cond); return TRUE; } static guint tdf_glib_input_add (gint fd, PurpleInputCondition condition, PurpleInputFunction function, gpointer data) { TdfGLibIOClosure *closure = g_new0(TdfGLibIOClosure, 1); GIOChannel *channel; GIOCondition cond = 0; closure->function = function; closure->data = data; if (condition & PURPLE_INPUT_READ) cond |= PURPLE_GLIB_READ_COND; if (condition & PURPLE_INPUT_WRITE) cond |= PURPLE_GLIB_WRITE_COND; channel = g_io_channel_unix_new (fd); closure->result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond, tdf_glib_io_invoke, closure, tdf_glib_io_destroy); g_io_channel_unref (channel); return closure->result; } static PurpleEventLoopUiOps tdf_glib_eventloop_ops = { g_timeout_add, g_source_remove, tdf_glib_input_add, g_source_remove, NULL, #if GLIB_CHECK_VERSION(2,14,0) g_timeout_add_seconds, #else NULL, #endif // padding NULL, NULL, NULL }; // End of the eventloop functions. static PurpleConnectionUiOps connection_uiops = { NULL, // connect_progress NULL, // connected NULL, // disconnected NULL, // notice NULL, // report_disconnect NULL, // network_connected NULL, // network_disconnected NULL, // report_disconnect_reason // padding NULL, NULL, NULL }; static void tdf_init (void) { // This should initialize the UI components for all the modules. purple_connections_set_ui_ops (&connection_uiops); } static PurpleCoreUiOps tdf_core_uiops = { NULL, NULL, tdf_init, NULL, // padding NULL, NULL, NULL, NULL }; PurplePlugin *tgp = NULL; static void display_search_paths (GList *elem) { printf ("Search paths:"); for (; elem; elem = elem->next) { printf (" %s", (char *)elem->data); } printf ("\n"); } static void tdf_inject_plugin (void) { printf ("Injecting our module into purple_plugins_* ...\n"); purple_plugins_init (); GList *search_paths = purple_plugins_get_search_paths (); assert (!search_paths->prev && !search_paths->next && search_paths->data); GList *new_paths = g_list_append (search_paths, g_strdup ("bin/")); assert (new_paths == search_paths); // Load "my" path before the default. assert (search_paths->next && search_paths->next->data); { // swap(search_paths->data, search_paths->next->data); gchar* tmp = search_paths->data; search_paths->data = search_paths->next->data; search_paths->next->data = tmp; } } gboolean tdf_is_in_ci (void) { gchar* envvar = getenv ("CONTINUOUS_INTEGRATION"); return envvar && g_str_equal ("true", envvar); } static void init_libpurple (void) { // Set a custom user directory (optional) purple_util_set_user_dir ("test/tmp/user"); // We *do* want debugging. However, this is just too much noise. // Then again, this doesn't hurt if Travis does it. Query the environment to check whether we're in CI or not. purple_debug_set_enabled (tdf_is_in_ci ()); /* Set the core-uiops, which is used to * - initialize the ui specific preferences. * - initialize the debug ui. * - initialize the ui components for all the modules. * - uninitialize the ui components for all the modules when the core terminates. */ purple_core_set_ui_ops (&tdf_core_uiops); // Set the uiops for the eventloop. Since our client is glib-based, you can safely copy this verbatim. */ purple_eventloop_set_ui_ops (&tdf_glib_eventloop_ops); tdf_inject_plugin (); display_search_paths (purple_plugins_get_search_paths ()); // Now that all the essential stuff has been set, let's try to init the core. printf ("Enter purple_core_init ...\n"); if (!purple_core_init ("tgp-dummy")) { // Initializing the core failed. Terminate. fprintf (stderr, "libpurple initialization failed. Abort.\n"); abort (); } printf ("Core initialized.\n"); // Create and load the buddylist. purple_set_blist (purple_blist_new ()); // Find our plugin printf ("Checking version:\n"); tgp = purple_plugins_find_with_id (PLUGIN_ID); if (!tgp) { printf ("Huh! Can't find plugin! Expected ID \"" PLUGIN_ID "\"\n"); abort (); } // Make sure we loaded the correct plugin printf ("This is what we loaded:\n\t\t\tversion: %s\n", tgp->info->version); gchar *pos = g_strrstr (tgp->info->version, "commit: " GIT_COMMIT); if (pos == NULL) { printf ("This is the wrong version, we built for commit %s. Abort!\n", GIT_COMMIT); abort (); } else { printf ("Looks like the right version, because we also expected commit %s.\n", GIT_COMMIT); } } //static void signed_on (PurpleConnection *gc) { // PurpleAccount *account = purple_connection_get_account (gc); // printf("Account connected: \"%s\" (%s)\n", purple_account_get_username(account), purple_account_get_protocol_id(account)); //} // //static void received_im_msg (PurpleAccount *account, char *sender, char *message, PurpleConversation *conv, PurpleMessageFlags flags) { // if (conv==NULL) { // conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, sender); // } // // printf("(%s) %s (%s): %s\n", purple_utf8_strftime("%H:%M:%S", NULL), sender, purple_conversation_get_name(conv), message); //} // //static void connect_to_signals(void) //{ // // static int handle; // // purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle, // PURPLE_CALLBACK(signed_on), NULL); // // purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", &handle, // PURPLE_CALLBACK(received_im_msg), NULL); // //} int main(int argc, char *argv[]) { printf ("Running loadtest on %s.\n", argv[1]); GMainLoop *loop = g_main_loop_new(NULL, FALSE); /* libpurple's built-in DNS resolution forks processes to perform * blocking lookups without blocking the main process. It does not * handle SIGCHLD itself, so if the UI does not you quickly get an army * of zombie subprocesses marching around. */ signal(SIGCHLD, SIG_IGN); printf ("Enter init_libpurple\n"); init_libpurple (); printf ("libpurple %s initialized.\n", purple_core_get_version()); // Since we do not yet do anything useful, simply terminate after a few seconds. purple_timeout_add (2000, purple_core_quit_cb, NULL); g_timeout_add (4000, (GSourceFunc)g_main_loop_quit, loop); // connect_to_signals(); // PurpleAccount *account = purple_account_new("YOUR_IM_ACCOUNTS_USERNAME_HERE", "prpl-IM_NETWORK_HERE"); //this could be prpl-aim, prpl-yahoo, prpl-msn, prpl-icq, etc. // purple_account_set_password(account, "YOUR_IM_ACCOUNTS_PASSWORD_HERE"); // purple_accounts_add(account); // purple_account_set_enabled(account, UI_ID, TRUE); g_main_loop_run (loop); return 0; } telegram-purple/test/probetest.c000066400000000000000000000026611363674160100173310ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Ben Wiederhake 2016 */ #include #include #include // Just try to probe (pre-load) the plugin. If that's successful, then probably a lot of stuff works. int main (int argc, char **argv) { assert(argc == 2); printf ("Running probetest on %s.\n", argv[1]); PurplePlugin *tgp = purple_plugin_probe (argv[1]); if (!tgp) { printf ("Looks like there was a problem! Aborting.\n"); return 1; } printf ("Looks good. Here's what I can read:\n"); PurplePluginInfo *info = tgp->info; #define BLURB(x) printf (#x " = %s\n", info->x); BLURB(id) BLURB(name) BLURB(version) BLURB(summary) BLURB(description) BLURB(author) BLURB(homepage) return 0; } telegram-purple/tgl/000077500000000000000000000000001363674160100147605ustar00rootroot00000000000000telegram-purple/tgp-2prpl.c000066400000000000000000000273531363674160100161770ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch, Ben Wiederhake 2014-2015 */ #include "telegram-purple.h" #ifdef HAVE_LIBWEBP #include #endif #ifdef HAVE_LIBPNG #include #endif PurpleAccount *tls_get_pa (struct tgl_state *TLS) { return tls_get_data (TLS)->pa; } PurpleConnection *tls_get_conn (struct tgl_state *TLS) { return tls_get_data (TLS)->gc; } connection_data *tls_get_data (struct tgl_state *TLS) { return TLS->ev_base; } int tls_get_ft_threshold (struct tgl_state *TLS) { return purple_account_get_int (tls_get_pa (TLS), TGP_KEY_MEDIA_SIZE, TGP_DEFAULT_MEDIA_SIZE) << 10; } int tls_get_ft_autoload (struct tgl_state *TLS) { return ! strcmp (purple_account_get_string (tls_get_pa (TLS), TGP_KEY_FT_HANDLING, TGP_DEFAULT_FT_HANDLING), "autoload"); } int tls_get_ft_discard (struct tgl_state *TLS) { return ! strcmp (purple_account_get_string (tls_get_pa (TLS), TGP_KEY_FT_HANDLING, TGP_DEFAULT_FT_HANDLING), "discard"); } connection_data *gc_get_data (PurpleConnection *gc) { return purple_connection_get_protocol_data (gc); } struct tgl_state *gc_get_tls (PurpleConnection *gc) { return ((connection_data *)purple_connection_get_protocol_data (gc))->TLS; } connection_data *pa_get_data (PurpleAccount *pa) { return purple_connection_get_protocol_data (purple_account_get_connection (pa)); } connection_data *pbn_get_data (PurpleBlistNode *node) { if (PURPLE_BLIST_NODE_IS_CHAT (node)) { return pa_get_data (purple_chat_get_account ((PurpleChat *) node)); } if (PURPLE_BLIST_NODE_IS_BUDDY (node)) { return pa_get_data (purple_buddy_get_account ((PurpleBuddy *) node)); } return NULL; } int p2tgl_status_is_present (PurpleStatus *status) { const char *name = purple_status_get_id (status); return !(strcmp (name, "unavailable") == 0 || strcmp (name, "away") == 0); } void tgp_chat_got_in (struct tgl_state *TLS, tgl_peer_t *chat, tgl_peer_id_t from, const char *message, int flags, time_t when) { g_return_if_fail(chat); if (tgp_chat_show (TLS, chat)) { // channel messages in non-megagroups are always sent by the channel itself if (tgl_get_peer_type (chat->id) == TGL_PEER_CHANNEL && !(chat->channel.flags & TGLCHF_MEGAGROUP)) { from = chat->id; } serv_got_chat_in (tls_get_conn (TLS), tgl_get_peer_id (chat->id), tgp_blist_lookup_purple_name (TLS, from), flags, message, when); } else { g_warn_if_reached(); } } void p2tgl_got_im_combo (struct tgl_state *TLS, tgl_peer_id_t who, const char *msg, int flags, time_t when) { connection_data *conn = TLS->ev_base; if (flags & PURPLE_MESSAGE_SYSTEM) { tgp_msg_special_out (TLS, msg, who, flags & PURPLE_MESSAGE_NO_LOG); return; } /* Outgoing messages are not well supported in different libpurple clients, purple_conv_im_write should have the best among different versions. Unfortunately this causes buggy formatting in Adium, so we don't use this workaround in that case. NOTE: Outgoing messages will not work in Adium <= 1.6.0, there is no way to print outgoing messages in those versions at all. */ #ifndef __ADIUM_ if (flags & PURPLE_MESSAGE_SEND) { PurpleConversation *conv = p2tgl_find_conversation_with_account (TLS, who); if (!conv) { conv = purple_conversation_new (PURPLE_CONV_TYPE_IM, tls_get_pa (TLS), tgp_blist_lookup_purple_name (TLS, who)); } purple_conv_im_write (purple_conversation_get_im_data (conv), tgp_blist_lookup_purple_name (TLS, who), msg, flags, when); return; } #endif serv_got_im (conn->gc, tgp_blist_lookup_purple_name (TLS, who), msg, flags, when); } PurpleConversation *p2tgl_find_conversation_with_account (struct tgl_state *TLS, tgl_peer_id_t peer) { int type = PURPLE_CONV_TYPE_IM; if (tgl_get_peer_type (peer) == TGL_PEER_CHAT || tgl_get_peer_type (peer) == TGL_PEER_CHANNEL) { type = PURPLE_CONV_TYPE_CHAT; } PurpleConversation *conv = purple_find_conversation_with_account (type, tgp_blist_lookup_purple_name (TLS, peer), tls_get_pa (TLS)); return conv; } void p2tgl_prpl_got_user_status (struct tgl_state *TLS, tgl_peer_id_t user, struct tgl_user_status *status) { connection_data *data = TLS->ev_base; if (status->online == 1) { purple_prpl_got_user_status (tls_get_pa (TLS), tgp_blist_lookup_purple_name (TLS, user), "available", NULL); } else { debug ("%d: when=%d", tgl_get_peer_id (user), status->when); if (tgp_time_n_days_ago ( purple_account_get_int (data->pa, TGP_KEY_INACTIVE_DAYS_OFFLINE, TGP_DEFAULT_INACTIVE_DAYS_OFFLINE)) > status->when && status->when) { debug ("offline"); purple_prpl_got_user_status (tls_get_pa (TLS), tgp_blist_lookup_purple_name (TLS, user), "offline", NULL); } else { debug ("mobile"); purple_prpl_got_user_status (tls_get_pa (TLS), tgp_blist_lookup_purple_name (TLS, user), "mobile", NULL); } } } void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv, int user, char *message, int flags, int new_arrival) { const char *name = tgp_blist_lookup_purple_name (TLS, TGL_MK_USER (user)); g_return_if_fail (name); purple_conv_chat_add_user (purple_conversation_get_chat_data (conv), name, message, flags, new_arrival); } int p2tgl_imgstore_add_with_id (const char* filename) { gchar *data = NULL; size_t len; GError *err = NULL; g_file_get_contents (filename, &data, &len, &err); int id = purple_imgstore_add_with_id (data, len, NULL); return id; } int p2tgl_imgstore_add_with_id_raw (const unsigned char *raw_bgra, unsigned width, unsigned height) { // Heavily inspired by: https://github.com/EionRobb/pidgin-opensteamworks/blob/master/libsteamworks.cpp#L113 const unsigned char tga_header[] = { // No ID; no color map; uncompressed true color 0,0,2, // No color map metadata 0,0,0,0,0, // No offsets 0,0,0,0, // Dimensions width&0xFF,(width/256)&0xFF,height&0xFF,(height/256)&0xFF, // 32 bits per pixel 32, // "Origin in upper left-hand corner" 32}; // Will be owned by libpurple imgstore, which uses glib functions for managing memory const unsigned tga_len = sizeof(tga_header) + width * height * 4; unsigned char *tga = g_malloc(tga_len); memcpy(tga, tga_header, sizeof(tga_header)); // From the documentation: "The 4 byte entry contains 1 byte each of blue, green, red, and attribute." memcpy(tga + sizeof(tga_header), raw_bgra, width * height * 4); return purple_imgstore_add_with_id (tga, tga_len, NULL); } #ifdef HAVE_LIBPNG static void p2tgl_png_mem_write (png_structp png_ptr, png_bytep data, png_size_t length) { GByteArray *png_mem = (GByteArray *) png_get_io_ptr(png_ptr); g_byte_array_append (png_mem, data, length); } int p2tgl_imgstore_add_with_id_png (const unsigned char *raw_bitmap, unsigned width, unsigned height) { GByteArray *png_mem = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytepp rows = NULL; // init png write struct png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { warning ("error encoding png (create_write_struct failed)"); return 0; } // init png info struct info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); warning ("error encoding png (create_info_struct failed)"); return 0; } // Set up error handling. if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); warning ("error while writing png"); return 0; } // set img attributes png_set_IHDR (png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // alloc row pointers rows = g_new0 (png_bytep, height); if (rows == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); warning ("error converting to png: malloc failed"); return 0; } unsigned i; for (i = 0; i < height; i++) rows[i] = (png_bytep)(raw_bitmap + i * width * 4); // create array and set own png write function png_mem = g_byte_array_new(); png_set_write_fn (png_ptr, png_mem, p2tgl_png_mem_write, NULL); // write png png_set_rows (png_ptr, info_ptr, rows); png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); // cleanup g_free(rows); png_destroy_write_struct (&png_ptr, &info_ptr); unsigned png_size = png_mem->len; gpointer png_data = g_byte_array_free (png_mem, FALSE); return purple_imgstore_add_with_id (png_data, png_size, NULL); } #endif /* HAVE_LIBPNG */ #ifdef HAVE_LIBWEBP static const int MAX_W = 256; static const int MAX_H = 256; int p2tgl_imgstore_add_with_id_webp (const char *filename) { const uint8_t *data = NULL; size_t len; GError *err = NULL; g_file_get_contents (filename, (gchar **) &data, &len, &err); if (err) { warning ("cannot open file %s: %s.", filename, err->message); return 0; } // downscale oversized sticker images displayed in chat, otherwise it would harm readabillity WebPDecoderConfig config; WebPInitDecoderConfig (&config); if (WebPGetFeatures(data, len, &config.input) != VP8_STATUS_OK) { warning ("error reading webp bitstream: %s", filename); g_free ((gchar *)data); return 0; } config.options.use_scaling = 0; config.options.scaled_width = config.input.width; config.options.scaled_height = config.input.height; if (config.options.scaled_width > MAX_W || config.options.scaled_height > MAX_H) { const float max_scale_width = MAX_W * 1.0f / config.options.scaled_width; const float max_scale_height = MAX_H * 1.0f / config.options.scaled_height; if (max_scale_width < max_scale_height) { // => the width is most limiting config.options.scaled_width = MAX_W; // Can't use ' *= ', because we need to do the multiplication in float // (or double), and only THEN cast back to int. config.options.scaled_height = (int) (config.options.scaled_height * max_scale_width); } else { // => the height is most limiting config.options.scaled_height = MAX_H; // Can't use ' *= ', because we need to do the multiplication in float // (or double), and only THEN cast back to int. config.options.scaled_width = (int) (config.options.scaled_width * max_scale_height); } config.options.use_scaling = 1; } #ifdef HAVE_LIBPNG config.output.colorspace = MODE_RGBA; #else config.output.colorspace = MODE_BGRA; #endif if (WebPDecode(data, len, &config) != VP8_STATUS_OK) { warning ("error decoding webp: %s", filename); g_free ((gchar *)data); return 0; } g_free ((gchar *)data); const uint8_t *decoded = config.output.u.RGBA.rgba; // convert and add #ifdef HAVE_LIBPNG int imgStoreId = p2tgl_imgstore_add_with_id_png(decoded, config.options.scaled_width, config.options.scaled_height); #else int imgStoreId = p2tgl_imgstore_add_with_id_raw(decoded, config.options.scaled_width, config.options.scaled_height); #endif WebPFreeDecBuffer (&config.output); return imgStoreId; } #endif telegram-purple/tgp-2prpl.h000066400000000000000000000044531363674160100162000ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #ifndef __telegram_adium__purple2tgl__ #define __telegram_adium__purple2tgl__ #include #include "telegram-purple.h" PurpleAccount *tls_get_pa (struct tgl_state *TLS); PurpleConnection *tls_get_conn (struct tgl_state *TLS); connection_data *tls_get_data (struct tgl_state *TLS); int tls_get_ft_threshold (struct tgl_state *TLS); int tls_get_ft_discard (struct tgl_state *TLS); int tls_get_ft_autoload (struct tgl_state *TLS); connection_data *gc_get_data (PurpleConnection *gc); connection_data *pa_get_data (PurpleAccount *pa); connection_data *pbn_get_data (PurpleBlistNode *node); struct tgl_state *gc_get_tls (PurpleConnection *gc); int p2tgl_status_is_present (PurpleStatus *status); void tgp_chat_got_in (struct tgl_state *TLS, tgl_peer_t *chat, tgl_peer_id_t who, const char *message, int flags, time_t when); void p2tgl_got_im_combo (struct tgl_state *TLS, tgl_peer_id_t who, const char *msg, int flags, time_t when); void p2tgl_prpl_got_user_status (struct tgl_state *TLS, tgl_peer_id_t user, struct tgl_user_status *status); void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv, int user, char *message, int flags, int new_arrival); PurpleConversation *p2tgl_find_conversation_with_account (struct tgl_state *TLS, tgl_peer_id_t peer); int p2tgl_imgstore_add_with_id (const char* filename); int p2tgl_imgstore_add_with_id_raw (const unsigned char *raw_rgba, unsigned width, unsigned height); #ifdef HAVE_LIBWEBP int p2tgl_imgstore_add_with_id_webp (const char *filename); #endif #endif telegram-purple/tgp-blist.c000066400000000000000000000221321363674160100162430ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2015 */ #include "telegram-purple.h" // utilities PurpleBlistNode *tgp_blist_iterate (struct tgl_state *TLS, int (* callback) (PurpleBlistNode *node, void *extra), void *extra) { PurpleBlistNode *node = purple_blist_get_root (); while (node) { if ((PURPLE_BLIST_NODE_IS_BUDDY(node) && purple_buddy_get_account ((PurpleBuddy *)node) == tls_get_pa (TLS)) || (PURPLE_BLIST_NODE_IS_CHAT(node) && purple_chat_get_account ((PurpleChat *)node) == tls_get_pa (TLS))) { if (callback (node, extra)) { return node; } } node = purple_blist_node_next (node, FALSE); } return NULL; } // lookup const char *tgp_blist_lookup_purple_name (struct tgl_state *TLS, tgl_peer_id_t id) { const char *name = g_hash_table_lookup (tls_get_data (TLS)->id_to_purple_name, GINT_TO_POINTER(tgl_get_peer_id (id))); g_warn_if_fail(name); return name; } void tgp_blist_lookup_add (struct tgl_state *TLS, tgl_peer_id_t id, const char *purple_name) { // to avoid issues with differences in string normalization, always store in composed form this helps to avoid // issues with clients like Adium, that will store strings in decomposed format by default const char *name = g_utf8_normalize (purple_name, -1, G_NORMALIZE_DEFAULT_COMPOSE); g_hash_table_replace (tls_get_data (TLS)->id_to_purple_name, GINT_TO_POINTER(tgl_get_peer_id (id)), g_strdup (name)); g_hash_table_replace (tls_get_data (TLS)->purple_name_to_id, g_strdup (name), g_memdup (&id, sizeof(tgl_peer_id_t))); } static tgl_peer_id_t *tgp_blist_lookup_get_id (struct tgl_state *TLS, const char *purple_name) { return g_hash_table_lookup (tls_get_data (TLS)->purple_name_to_id, g_utf8_normalize (purple_name, -1, G_NORMALIZE_DEFAULT_COMPOSE)); } tgl_peer_t *tgp_blist_lookup_peer_get (struct tgl_state *TLS, const char *purple_name) { tgl_peer_id_t *id = tgp_blist_lookup_get_id (TLS, purple_name); g_return_val_if_fail(id, NULL); return tgl_peer_get (TLS, *id); } static int tgp_blist_lookup_init_cb (PurpleBlistNode *node, void *extra) { if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { PurpleBuddy *buddy = (PurpleBuddy *) node; if (tgl_get_peer_type (tgp_blist_buddy_get_id (buddy)) != TGL_PEER_UNKNOWN) { tgp_blist_lookup_add (pbn_get_data (node)->TLS, tgp_blist_buddy_get_id (buddy), purple_buddy_get_name (buddy)); } } if (PURPLE_BLIST_NODE_IS_CHAT(node)) { PurpleChat *chat = (PurpleChat *) node; if (tgp_chat_has_id (chat)) { tgp_blist_lookup_add (pbn_get_data (node)->TLS, tgp_chat_get_id (chat), purple_chat_get_name (chat)); } } return FALSE; } void tgp_blist_lookup_init (struct tgl_state *TLS) { info ("loading known ids from buddy list ..."); tgp_blist_iterate (TLS, tgp_blist_lookup_init_cb, 0); } // buddies PurpleBuddy *tgp_blist_buddy_new (struct tgl_state *TLS, tgl_peer_t *user) { PurpleBuddy *buddy = purple_buddy_new (tls_get_pa (TLS), tgp_blist_lookup_purple_name (TLS, user->id), NULL); tgp_blist_buddy_set_id (buddy, user->id); return buddy; } PurpleBuddy *tgp_blist_buddy_migrate (struct tgl_state *TLS, PurpleBuddy *buddy, struct tgl_user *user) { purple_blist_remove_buddy (buddy); buddy = purple_buddy_new (tls_get_pa (TLS), user->print_name, NULL); tgp_blist_buddy_set_id (buddy, user->id); purple_blist_add_buddy (buddy, NULL, tgp_blist_group_init (_("Telegram")), NULL); return buddy; } void tgp_blist_buddy_set_id (PurpleBuddy *buddy, tgl_peer_id_t id) { int uid = tgl_get_peer_id (id), type = tgl_get_peer_type (id); assert (type == TGL_PEER_ENCR_CHAT || type == TGL_PEER_USER || type == TGL_PEER_CHANNEL); purple_blist_node_set_int (&buddy->node, TGP_BUDDY_KEY_PEER_ID, uid); purple_blist_node_set_int (&buddy->node, TGP_BUDDY_KEY_PEER_TYPE, type); } int tgp_blist_buddy_has_id (PurpleBuddy *buddy) { return purple_blist_node_get_int (&buddy->node, TGP_BUDDY_KEY_PEER_ID) != 0; } tgl_peer_id_t tgp_blist_buddy_get_id (PurpleBuddy *buddy) { int id = purple_blist_node_get_int (&buddy->node, TGP_BUDDY_KEY_PEER_ID), type = purple_blist_node_get_int (&buddy->node, TGP_BUDDY_KEY_PEER_TYPE); if (type == TGL_PEER_USER) { return TGL_MK_USER (id); } else if (type == TGL_PEER_ENCR_CHAT) { return TGL_MK_ENCR_CHAT (id); } else if (type == TGL_PEER_CHANNEL) { return TGL_MK_CHANNEL (id); } else { return tgl_set_peer_id (TGL_PEER_UNKNOWN, 0); } } tgl_peer_t *tgp_blist_buddy_get_peer (PurpleBuddy *buddy) { if (! tgp_blist_buddy_has_id (buddy)) { g_warn_if_reached(); return NULL; } return tgl_peer_get (pbn_get_data (&buddy->node)->TLS, tgp_blist_buddy_get_id (buddy)); } static int tgp_blist_buddy_find_cb (PurpleBlistNode *node, void *extra) { return PURPLE_BLIST_NODE_IS_BUDDY(node) && purple_blist_node_get_int (node, TGP_BUDDY_KEY_PEER_ID) == GPOINTER_TO_INT(extra); } PurpleBuddy *tgp_blist_buddy_find (struct tgl_state *TLS, tgl_peer_id_t user) { return (PurpleBuddy *) tgp_blist_iterate (TLS, tgp_blist_buddy_find_cb, GINT_TO_POINTER(tgl_get_peer_id (user))); } // contacts void tgp_blist_contact_add (struct tgl_state *TLS, struct tgl_user *U) { PurpleBuddy *buddy = tgp_blist_buddy_find (TLS, U->id); if (! buddy) { tgl_peer_t *P = tgl_peer_get (TLS, U->id); info ("Adding contact '%s' to buddy list", tgp_blist_lookup_purple_name (TLS, U->id)); buddy = tgp_blist_buddy_new (TLS, P); purple_blist_add_buddy (buddy, NULL, tgp_blist_group_init (_("Telegram")), NULL); tgp_info_update_photo (&buddy->node, P); } p2tgl_prpl_got_user_status (TLS, U->id, &U->status); } // chats static int tgp_blist_chat_find_cb (PurpleBlistNode *node, void *extra) { if (PURPLE_BLIST_NODE_IS_CHAT(node)) { PurpleChat *chat = PURPLE_CHAT(node); const char *id = g_hash_table_lookup (purple_chat_get_components (chat), "id"); if (id && *id && atoi (id) == GPOINTER_TO_INT(extra)) { return TRUE; } } return FALSE; } PurpleChat *tgp_blist_chat_find (struct tgl_state *TLS, tgl_peer_id_t user) { return (PurpleChat *) tgp_blist_iterate (TLS, tgp_blist_chat_find_cb, GINT_TO_POINTER(tgl_get_peer_id (user))); } // groups PurpleGroup *tgp_blist_group_init (const char *name) { PurpleGroup *grp = purple_find_group (name); if (! grp) { grp = purple_group_new (name); purple_blist_add_group (grp, NULL); } return grp; } // names char *tgp_blist_create_print_name (struct tgl_state *TLS, tgl_peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4) { // libtgl passes 0 for all unused strings, therefore the last passed string will always be followed // by a NULL-termination as expected gchar *name = g_strjoin (" ", a1, a2, a3, a4, NULL); // When the user doesn't provide some input (like last name) ugly trailing or leading // whitespaces may occur due to empty strings in the g_strjoin arguments name = g_strstrip(name); /* Assure that all print_names are unique by checking the following conditions: 1. No other peer with that print_name should exists. If those names are not unique it will not be possible to uniquely refer to users by their print_name and assertions in libtgl will fail. 2. No BlistNode with that name should exists unless it is already corresponding to this peer ID. The rationale is that this prpl uses the first print_name as permanent name for each user. Therefore it must be assured that no foreign user will ever take this exact name again, otherwise the current users actions might be associated with the old BlistNode. 3. Assure that the print name isn't already stored in the peer_by_name_tree. */ int i = 0; gchar *n = NULL; tgl_peer_id_t *id2 = tgp_blist_lookup_get_id (TLS, name); if ( !id2) { tgl_peer_t *tmpP = tgl_peer_get_by_name (TLS, name); if (tmpP) { id2 = &tmpP->id; } } while (id2 && tgl_get_peer_id (*id2) != tgl_get_peer_id (id)) { if (n) { g_free (n); } n = g_strdup_printf ("%s #%d", name, ++ i); debug ("resolving duplicate for %s, assigning: %s", name, n); id2 = tgp_blist_lookup_get_id (TLS, n); if ( !id2) { tgl_peer_t *tmpP = tgl_peer_get_by_name(TLS, n); if (tmpP) { id2 = &tmpP->id; } } } if (n) { g_free (name); name = n; } // the result is owned and freed by libtgl and must not be allocated by glib functions char *S = tstrdup (name); g_free (name); return S; } telegram-purple/tgp-blist.h000066400000000000000000000055451363674160100162610ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2015 */ #ifndef tgp_blist_h #define tgp_blist_h #include #include #define TGP_BUDDY_KEY_PEER_ID "user_id" #define TGP_BUDDY_KEY_PEER_TYPE "peer_type" /* Functions for managing telegram contacts in the buddy list and performing id to purple-username and purple-username to id look-ups. Purple prefers human-readable names for buddy user names, while Telegram uses numerical user ids. In older versions of this plugin, the user id was used as username and the print name as the users alias. This means that getting a useful username in the interface relied on the alias resolution, which unfortunately doesn't work when a user isn't in the buddy list, or in Adium group chats. Because of that, this plugin now uses the unique print names provided by libtgl as username instead. */ const char *tgp_blist_lookup_purple_name (struct tgl_state *TLS, tgl_peer_id_t id); void tgp_blist_lookup_add (struct tgl_state *TLS, tgl_peer_id_t id, const char *purple_name); tgl_peer_t *tgp_blist_lookup_peer_get (struct tgl_state *TLS, const char *purple_name); void tgp_blist_lookup_init (struct tgl_state *TLS); /* To make this new approach robust to names changes, it is necessary to store the user ID in each blist node to allow reliable buddy list look-ups by user ids. */ void tgp_blist_buddy_set_id (PurpleBuddy *buddy, tgl_peer_id_t id); int tgp_blist_buddy_has_id (PurpleBuddy *buddy); tgl_peer_id_t tgp_blist_buddy_get_id (PurpleBuddy *buddy); tgl_peer_t *tgp_blist_buddy_get_peer (PurpleBuddy *peer); PurpleBuddy *tgp_blist_buddy_new (struct tgl_state *TLS, tgl_peer_t *user); PurpleBuddy *tgp_blist_buddy_migrate (struct tgl_state *TLS, PurpleBuddy *buddy, struct tgl_user *user); PurpleBuddy *tgp_blist_buddy_find (struct tgl_state *TLS, tgl_peer_id_t user); void tgp_blist_contact_add (struct tgl_state *TLS, struct tgl_user *U); PurpleChat *tgp_blist_chat_find (struct tgl_state *TLS, tgl_peer_id_t user); PurpleGroup *tgp_blist_group_init (const char *name); char *tgp_blist_create_print_name (struct tgl_state *TLS, tgl_peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); #endif telegram-purple/tgp-chat.c000066400000000000000000000565341363674160100160620ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch, Ben Wiederhake 2014-2016 */ #include "tgp-chat.h" GHashTable *tgp_chat_info_new (struct tgl_state *TLS, tgl_peer_t *P) { // libpurple chat components own the keys and the values when created from blist be consistent GHashTable *ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (ht, g_strdup ("subject"), g_strdup (P->print_name)); g_hash_table_insert (ht, g_strdup ("id"), g_strdup_printf ("%d", tgl_get_peer_id (P->id))); g_hash_table_insert (ht, g_strdup ("type"), g_strdup_printf ("%d", tgl_get_peer_type (P->id))); if (tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL) { g_hash_table_insert (ht, g_strdup ("last_server_id"), g_strdup_printf ("%d", 0)); } return ht; } int tgp_chat_has_id (PurpleChat *C) { const char *id = g_hash_table_lookup (purple_chat_get_components (C), "id"); return id && *id; } tgl_peer_id_t tgp_chat_get_id (PurpleChat *C) { const char *I = g_hash_table_lookup (purple_chat_get_components (C), "id"); const char *T = g_hash_table_lookup (purple_chat_get_components (C), "type"); int type = TGL_PEER_CHAT; if (T && *T) { type = atoi (T); } return tgl_set_peer_id (type, (I && *I) ? atoi (I) : 0); } void tgp_chat_set_last_server_id (struct tgl_state *TLS, tgl_peer_id_t chat, int id) { info ("setting channel message server_id=%d", id); char *key = g_strdup_printf ("last-server-id/%d", tgl_get_peer_id (chat)); purple_account_set_int (tls_get_pa (TLS), key, id); g_free (key); } int tgp_chat_get_last_server_id (struct tgl_state *TLS, tgl_peer_id_t chat) { char *key = g_strdup_printf ("last-server-id/%d", tgl_get_peer_id (chat)); int last = purple_account_get_int (tls_get_pa (TLS), key, 0); g_free (key); return (unsigned int) last; } PurpleChat *tgp_chat_blist_store (struct tgl_state *TLS, tgl_peer_t *P, const char *group) { g_return_val_if_fail(tgl_get_peer_type (P->id) == TGL_PEER_CHAT || tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL, NULL); PurpleChat *PC = tgp_blist_chat_find (TLS, P->id); if (! (P->flags & TGLCF_LEFT)) { if (! PC) { PC = purple_chat_new (tls_get_pa (TLS), P->chat.print_title, tgp_chat_info_new (TLS, P)); // adding chats to the blist in Adium would cause the bookmarks and auto-joins to fail, // as Adium assumes that a chat existing in blist means the user already joined #ifndef __ADIUM_ if (purple_account_get_bool (tls_get_pa (TLS), TGP_KEY_JOIN_GROUP_CHATS, TGP_DEFAULT_JOIN_GROUP_CHATS)) { purple_blist_add_chat (PC, tgp_blist_group_init (group), NULL); } #endif } tgp_info_update_photo (&PC->node, tgl_peer_get (TLS, P->id)); } else { if (PC) { purple_blist_remove_chat (PC); PC = NULL; } } if (PC) { g_hash_table_replace (purple_chat_get_components (PC), g_strdup ("id"), g_strdup_printf ("%d", tgl_get_peer_id (P->id))); g_hash_table_replace (purple_chat_get_components (PC), g_strdup ("type"), g_strdup_printf ("%d", tgl_get_peer_type (P->id))); g_hash_table_replace (purple_chat_get_components (PC), g_strdup ("subject"), g_strdup (tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL ? P->channel.title : P->chat.title)); } return PC; } static void tgp_chat_on_loaded_chat_full_joining (struct tgl_state *TLS, void *_, int success, struct tgl_chat *C) { debug ("tgp_chat_on_loaded_chat_full_joining()"); if (! success) { tgp_notify_on_error_gw (TLS, NULL, success); return; } tgp_chat_blist_store (TLS, tgl_peer_get (TLS, C->id), _("Telegram Chats")); tgp_chat_show (TLS, tgl_peer_get (TLS, C->id)); // Check if the users attempts to join an empty chat if (C->flags & TGLCF_LEFT) { tgp_chat_got_in (TLS, tgl_peer_get (TLS, C->id), C->id, _("You have already left this chat."), PURPLE_MESSAGE_SYSTEM, time (NULL)); } } static void tgp_chat_on_loaded_channel_full_joining (struct tgl_state *TLS, void *extra, int success, tgl_peer_t *P) { debug ("tgp_chat_on_loaded_channel_full_joining()"); if (! success) { tgp_notify_on_error_gw (TLS, NULL, success); return; } tgp_chat_blist_store (TLS, P, _("Telegram Channels")); tgp_chat_show (TLS, P); } static void tgp_chat_add_all_users (struct tgl_state *TLS, PurpleConversation *conv, tgl_peer_t *P) { debug ("tgp_chat_add_all_users()"); GList *users = NULL, *flags = NULL; switch (tgl_get_peer_type (P->id)) { case TGL_PEER_CHAT: { struct tgl_chat *C = &P->chat; int i; for (i = 0; i < C->user_list_size; i ++) { struct tgl_chat_user *uid = (C->user_list + i); const char *name = tgp_blist_lookup_purple_name (TLS, TGL_MK_USER(uid->user_id)); if (name) { users = g_list_append (users, g_strdup (name)); flags = g_list_append (flags, GINT_TO_POINTER(C->admin_id == uid->user_id ? PURPLE_CBFLAGS_FOUNDER : PURPLE_CBFLAGS_NONE)); } } break; } case TGL_PEER_CHANNEL: { // fetch users GList *MS = g_hash_table_lookup (tls_get_data (TLS)->channel_members, GINT_TO_POINTER(tgl_get_peer_id (P->id))); while (MS) { struct tgp_channel_member *M = MS->data; const char *name = tgp_blist_lookup_purple_name (TLS, M->id); if (name) { users = g_list_append (users, g_strdup (name)); flags = g_list_append (flags, GINT_TO_POINTER(M->flags)); } MS = g_list_next (MS); }; break; } default: g_return_if_reached(); break; } purple_conv_chat_add_users (PURPLE_CONV_CHAT(conv), users, NULL, flags, FALSE); tgp_g_list_free_full (users, g_free); g_list_free (flags); } PurpleConversation *tgp_chat_show (struct tgl_state *TLS, tgl_peer_t *P) { PurpleConvChat *chat = NULL; // check if chat is already shown PurpleConversation *conv = purple_find_chat (tls_get_conn (TLS), tgl_get_peer_id (P->id)); if (conv) { chat = purple_conversation_get_chat_data (conv); if (chat && ! purple_conv_chat_has_left (chat)) { return conv; } } // join the chat now const char *name = NULL; if (tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { name = P->chat.print_title; } else if (tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL) { name = P->channel.print_title; } g_return_val_if_fail(name, NULL); conv = serv_got_joined_chat (tls_get_conn (TLS), tgl_get_peer_id (P->id), name); g_return_val_if_fail(conv, NULL); purple_conv_chat_clear_users (purple_conversation_get_chat_data (conv)); tgp_chat_add_all_users (TLS, conv, P); return conv; } int tgprpl_send_chat (PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags) { debug ("tgprpl_send_chat()"); tgl_peer_t *P = tgl_peer_get (gc_get_tls (gc), TGL_MK_CHAT(id)); if (! P) { P = tgl_peer_get (gc_get_tls (gc), TGL_MK_CHANNEL(id)); } g_return_val_if_fail(P != NULL, -1); // when the group receives a message it is obvious that the previous messages were read pending_reads_send_user (gc_get_tls (gc), P->id); return tgp_msg_send (gc_get_tls (gc), message, P->id); } unsigned int tgprpl_send_chat_typing (PurpleConversation *conv, PurpleTypingState typing, gpointer ignored) { PurpleConnection *gc = purple_conversation_get_gc (conv); tgl_peer_t *P; PurpleConvChat *chat; int id; if (!PURPLE_CONNECTION_IS_CONNECTED (gc)) { return 0; } if (g_strcmp0(purple_plugin_get_id (purple_connection_get_prpl (gc)), PLUGIN_ID)) { return 0; } debug ("tgprpl_send_chat_typing()"); chat = purple_conversation_get_chat_data (conv); id = purple_conv_chat_get_id (chat); P = tgl_peer_get (gc_get_tls (gc), TGL_MK_CHAT(id)); if (! P) { P = tgl_peer_get (gc_get_tls (gc), TGL_MK_CHANNEL(id)); } g_return_val_if_fail(P != NULL, -1); tgl_do_send_typing (gc_get_tls (gc), P->id, typing == PURPLE_TYPING ? tgl_typing_typing : tgl_typing_cancel, 0, 0); // when the group receives a typing notification it is obvious that the previous messages were read pending_reads_send_user (gc_get_tls (gc), P->id); return 2; } void update_chat_typing (struct tgl_state *TLS, struct tgl_user *U, struct tgl_chat *C, enum tgl_typing_status status) { debug ("update_chat_typing()"); PurpleConvChat *chat = NULL; PurpleConversation *conv = purple_find_chat (tls_get_conn (TLS), tgl_get_peer_id (C->id)); if (conv) { chat = purple_conversation_get_chat_data (conv); } g_return_if_fail(chat != NULL); const char *name = tgp_blist_lookup_purple_name (TLS, U->id); g_return_if_fail(name != NULL); PurpleConvChatBuddyFlags flags = purple_conv_chat_user_get_flags (chat, name); if (status == tgl_typing_typing) { flags |= PURPLE_CBFLAGS_TYPING; } else { flags &= ~PURPLE_CBFLAGS_TYPING; } purple_conv_chat_user_set_flags(chat, name, flags); } void tgprpl_kick_from_chat (PurpleConnection *gc, int id, const char *who) { debug ("tgprpl_kick_from_chat()"); tgl_peer_t *P = tgl_peer_get (gc_get_tls (gc), TGL_MK_CHAT(id)); if (! P) { P = tgl_peer_get (gc_get_tls (gc), TGL_MK_CHANNEL(id)); } g_return_if_fail(P != NULL); tgl_peer_t *other_id = tgp_blist_lookup_peer_get (gc_get_tls (gc), who); if (other_id == NULL) { return; } tgl_do_del_user_from_chat (gc_get_tls (gc), P->id, other_id->id, tgp_notify_on_error_gw, NULL); } GList *tgprpl_chat_join_info (PurpleConnection *gc) { struct proto_chat_entry *pce; pce = g_new0 (struct proto_chat_entry, 1); pce->label = _("Subject:"); pce->identifier = "subject"; pce->required = FALSE; GList *info = g_list_append (NULL, pce); pce = g_new0 (struct proto_chat_entry, 1); pce->label = _("Invite link:"); pce->identifier = "link"; pce->required = FALSE; info = g_list_append (info, pce); pce = g_new0 (struct proto_chat_entry, 1); pce->label = _("Chat ID:"); pce->identifier = "id"; pce->required = FALSE; return g_list_append (info, pce); } GHashTable *tgprpl_chat_info_defaults (PurpleConnection *gc, const char *chat_name) { debug ("tgprpl_chat_info_defaults()"); if (chat_name) { tgl_peer_t *P = tgl_peer_get_by_name (gc_get_tls (gc), chat_name); if (P) { return tgp_chat_info_new (gc_get_tls (gc), P); } warning ("Chat not found, returning empty defaults..."); } return g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); } void tgprpl_chat_join (PurpleConnection *gc, GHashTable *data) { debug ("tgprpl_chat_join()"); g_return_if_fail(data); // auto joins will cause chat joins at a time when the dialogue list is not ready, remember // those chats and join them once the dialogue list is fetched if (! gc_get_data (gc)->dialogues_ready) { const char *id = g_hash_table_lookup (data, "id"); if (id) { debug ("attempting to join chat %s while not ready, queue up for later", id); gc_get_data (gc)->pending_joins = g_list_append (gc_get_data (gc)->pending_joins, g_strdup (id)); } return; } // join existing chat by id when the user clicks on a chat in the buddy list void *value = g_hash_table_lookup (data, "id"); if (value && atoi (value)) { tgl_peer_t *P = tgl_peer_get (gc_get_tls (gc), TGL_MK_CHAT(atoi (value))); if (! P) { P = tgl_peer_get (gc_get_tls (gc), TGL_MK_CHANNEL(atoi (value))); } if (P) { debug ("type=%d", tgl_get_peer_type (P->id)); if (tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { debug ("joining chat by id %d ...", tgl_get_peer_id (P->id)); tgl_do_get_chat_info (gc_get_tls (gc), P->id, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL); } else { g_return_if_fail(tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL); debug ("joining channel by id %d ...", tgl_get_peer_id (P->id)); tgp_channel_load (gc_get_tls (gc), P, tgp_chat_on_loaded_channel_full_joining, NULL); } } else { warning ("Cannot join chat %d, peer not found...", atoi (value)); purple_serv_got_join_chat_failed (gc, data); } return; } // join chat by invite link provided in the chat join window const char *link = g_hash_table_lookup (data, "link"); if (str_not_empty (link)) { tgl_do_import_chat_link (gc_get_tls (gc), link, (int)strlen (link), tgp_notify_on_error_gw, NULL); return; } // if a chat with this name doesn't exist yet, prompt to create one const char *subject = g_hash_table_lookup (data, "subject"); if (str_not_empty (subject)) { tgl_peer_t *P = tgl_peer_get_by_name (gc_get_tls (gc), subject); if (! P) { // user creates a new chat by providing its subject the chat join window request_create_chat (gc_get_tls (gc), subject); return; } // handle joining chats by print_names as used by the Adium plugin if (tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { debug ("joining chat by subject %s ...", subject); tgl_do_get_chat_info (gc_get_tls (gc), P->id, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL); return; } else if (tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL) { debug ("joining channel by subject %s ...", subject); tgp_channel_load (gc_get_tls (gc), P, tgp_chat_on_loaded_channel_full_joining, NULL); return; } else { warning ("Cannot join chat %s, wrong peer type", subject); purple_serv_got_join_chat_failed (gc, data); } } } char *tgprpl_get_chat_name (GHashTable * data) { return g_strdup (g_hash_table_lookup (data, "subject")); } static void tgp_chat_roomlist_add (tgl_peer_t *P, void *extra) { connection_data *conn = extra; if ((tgl_get_peer_type (P->id) == TGL_PEER_CHAT || tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL) && !(P->flags & TGLPF_LEFT)) { char *id = g_strdup_printf ("%d", tgl_get_peer_id (P->id)); PurpleRoomlistRoom *room = purple_roomlist_room_new (PURPLE_ROOMLIST_ROOMTYPE_ROOM, P->chat.print_title, NULL); purple_roomlist_room_add_field (conn->roomlist, room, id); if (tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL) { purple_roomlist_room_add_field (conn->roomlist, room, GINT_TO_POINTER(0)); purple_roomlist_room_add_field (conn->roomlist, room, (P->channel.flags & TGLCHF_MEGAGROUP) ? _("Supergroup") : _("Channel")); } else { purple_roomlist_room_add_field (conn->roomlist, room, GINT_TO_POINTER(P->chat.users_num)); purple_roomlist_room_add_field (conn->roomlist, room, _("Group")); } purple_roomlist_room_add (conn->roomlist, room); g_free (id); } } void tgp_chat_roomlist_populate (struct tgl_state *TLS) { connection_data *conn = tls_get_data (TLS); g_return_if_fail(purple_roomlist_get_in_progress (conn->roomlist)); GList *fields = NULL; PurpleRoomlistField *f = purple_roomlist_field_new (PURPLE_ROOMLIST_FIELD_STRING, "", "id", TRUE); fields = g_list_append (fields, f); f = purple_roomlist_field_new (PURPLE_ROOMLIST_FIELD_INT, _("Users in chat"), "users", FALSE); fields = g_list_append (fields, f); f = purple_roomlist_field_new (PURPLE_ROOMLIST_FIELD_STRING, _("Type"), "type", FALSE); fields = g_list_append (fields, f); purple_roomlist_set_fields (conn->roomlist, fields); tgl_peer_iterator_ex (conn->TLS, tgp_chat_roomlist_add, conn); purple_roomlist_set_in_progress (conn->roomlist, FALSE); } PurpleRoomlist *tgprpl_roomlist_get_list (PurpleConnection *gc) { debug ("tgprpl_roomlist_get_list()"); connection_data *conn = gc_get_data (gc); if (conn->roomlist) { purple_roomlist_unref (conn->roomlist); } conn->roomlist = purple_roomlist_new (purple_connection_get_account (gc)); purple_roomlist_set_in_progress (conn->roomlist, TRUE); // spectrum2 calls this function when the account is still connection // all roomlists in progress are being initialised by tgp_on_ready if (conn->dialogues_ready) { tgp_chat_roomlist_populate (conn->TLS); } return conn->roomlist; } void tgprpl_roomlist_cancel (PurpleRoomlist *list) { g_return_if_fail(list->account); purple_roomlist_set_in_progress (list, FALSE); if (pa_get_data (list->account)->roomlist == list) { pa_get_data (list->account)->roomlist = NULL; purple_roomlist_unref (list); } } void tgp_chat_join_all_pending (struct tgl_state *TLS) { GList *pending; for (pending = tls_get_data (TLS)->pending_joins; pending != NULL; pending = g_list_next(pending)) { GHashTable *data = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (data, "id", pending->data); tgprpl_chat_join (tls_get_conn (TLS), data); g_hash_table_destroy (data); } if (tls_get_data (TLS)->pending_joins) { g_list_free (tls_get_data (TLS)->pending_joins); tls_get_data (TLS)->pending_joins = NULL; } } static void tgp_channel_loading_free (struct tgp_channel_loading *D) { if (D->callbacks) { g_list_free (D->callbacks); } if (D->extras) { g_list_free (D->extras); } free (D); } static void tgp_channel_load_finish (struct tgl_state *TLS, struct tgp_channel_loading *D, int success) { GList *cb = D->callbacks; GList *extra = D->extras; if (! g_list_length (D->members)) { struct tgp_channel_member *M = talloc0 (sizeof(struct tgp_channel_member)); M->id = TLS->our_id; D->members = g_list_append (D->members, M); } g_hash_table_replace (tls_get_data (TLS)->channel_members, GINT_TO_POINTER(tgl_get_peer_id (D->P->id)), D->members); while (cb) { if (cb->data) { ((void (*) (struct tgl_state *, void *, int, tgl_peer_t *)) cb->data) (TLS, extra->data, success, D->P); } cb = g_list_next(cb); extra = g_list_next(extra); } tgp_channel_loading_free (D); } static void tgp_channel_load_admins_done (struct tgl_state *TLS, void *extra, int success, int users_num, struct tgl_user **users) { debug ("tgp_channel_load_admins_done()"); struct tgp_channel_loading *D = extra; if (success) { GHashTable *HT = g_hash_table_new (g_direct_hash, g_direct_equal); int i; for (i = 0; i < users_num; i ++) { g_hash_table_insert (HT, GINT_TO_POINTER(tgl_get_peer_id (users[i]->id)), GINT_TO_POINTER(1)); } GList *MS = D->members; do { struct tgp_channel_member *M = MS->data; if (g_hash_table_lookup (HT, GINT_TO_POINTER(tgl_get_peer_id (M->id)))) { M->flags |= PURPLE_CBFLAGS_OP; } } while ((MS = g_list_next (MS))); g_hash_table_destroy (HT); } tgp_channel_load_finish (TLS, D, success); } static void tgp_channel_get_members_done (struct tgl_state *TLS, void *extra, int success, int users_num, struct tgl_user **users) { debug ("tgp_channel_load_members_done()"); struct tgp_channel_loading *D = extra; if (! success) { tgp_channel_load_finish (TLS, D, FALSE); return; } int i; for (i = 0; i < users_num; i ++) { struct tgp_channel_member *M = talloc0 (sizeof(struct tgp_channel_member)); M->id = users[i]->id; D->members = g_list_append (D->members, M); } tgl_do_channel_get_members (TLS, D->P->id, purple_account_get_int (tls_get_pa (TLS), TGP_KEY_CHANNEL_MEMBERS, TGP_DEFAULT_CHANNEL_MEMBERS), 0, 1, tgp_channel_load_admins_done, D); } static gint tgp_channel_find_higher_id (gconstpointer a, gconstpointer b) { return ((struct tgp_msg_loading *)a)->msg->server_id < GPOINTER_TO_INT(b); } static void tgp_channel_get_history_done (struct tgl_state *TLS, void *extra, int success, int size, struct tgl_message **list) { struct tgp_channel_loading *D = extra; if (success) { if (size > 0 && tgp_chat_get_last_server_id (TLS, D->P->id) < list[size - 1]->server_id) { tgp_chat_set_last_server_id (TLS, D->P->id, (int) list[size - 1]->server_id); } GList *where = g_queue_find_custom (tls_get_data (TLS)->new_messages, GINT_TO_POINTER(tgp_chat_get_last_server_id (TLS, D->P->id)), tgp_channel_find_higher_id); int i; for (i = size - 1; i >= 0; -- i) { if (list[i]->server_id > tgp_chat_get_last_server_id (TLS, D->P->id)) { tgp_msg_recv (TLS, list[i], where); } } } else { g_warn_if_reached(); // gap in history } if (D->P->flags & (TGLCHF_ADMIN | TGLCHF_MEGAGROUP)) { tgl_do_channel_get_members (TLS, D->P->id, purple_account_get_int (tls_get_pa (TLS), TGP_KEY_CHANNEL_MEMBERS, TGP_DEFAULT_CHANNEL_MEMBERS), 0, 0, tgp_channel_get_members_done, extra); } else { tgp_channel_load_finish (TLS, D, success); } } void tgp_channel_load (struct tgl_state *TLS, tgl_peer_t *P, void (*callback) (struct tgl_state *, void *, int, tgl_peer_t *), void *extra) { g_return_if_fail(tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL); gpointer ID = GINT_TO_POINTER(tgl_get_peer_id (P->id)); if (! g_hash_table_lookup (tls_get_data (TLS)->pending_channels, ID)) { struct tgp_channel_loading *D = talloc0 (sizeof(struct tgp_channel_loading)); D->P = P; D->callbacks = g_list_append (NULL, callback); D->extras = g_list_append (NULL, extra); D->remaining = 2; tgl_do_get_history_range (TLS, P->id, (int) tgp_chat_get_last_server_id (TLS, P->id), 0, TGP_CHANNEL_HISTORY_LIMIT, tgp_channel_get_history_done, D); g_hash_table_replace (tls_get_data (TLS)->pending_channels, ID, D); } else { if (! tgp_channel_loaded (TLS, P->id)) { struct tgp_channel_loading *D = g_hash_table_lookup (tls_get_data (TLS)->pending_channels, ID); D->callbacks = g_list_append (D->callbacks, callback); D->extras = g_list_append (D->extras, extra); } else { callback (TLS, extra, TRUE, P); } } } int tgp_channel_loaded (struct tgl_state *TLS, tgl_peer_id_t id) { return NULL != g_hash_table_lookup (tls_get_data (TLS)->channel_members, GINT_TO_POINTER(tgl_get_peer_id (id))); } static void update_chat (struct tgl_state *TLS, tgl_peer_t *C, unsigned flags, const char *group) { if (flags & TGL_UPDATE_CREATED) { tgp_blist_lookup_add (TLS, C->id, C->print_name); tgp_chat_blist_store (TLS, tgl_peer_get (TLS, C->id), group); } else { PurpleChat *PC = tgp_blist_chat_find (TLS, C->id); if (PC) { if (flags & TGL_UPDATE_TITLE) { purple_blist_alias_chat (PC, C->print_name); } if (flags & TGL_UPDATE_DELETED) { // TODO: test if this is actually executed on deletion purple_blist_remove_chat (PC); } if (flags & TGL_UPDATE_PHOTO) { tgp_info_update_photo (&PC->node, tgl_peer_get (TLS, C->id)); } } } } void update_channel_handler (struct tgl_state *TLS, struct tgl_channel *C, unsigned flags) { debug ("update_channel_handler() (%s)", print_flags_update (flags)); update_chat (TLS, tgl_peer_get (TLS, C->id), flags, _("Telegram Channels")); } void update_chat_handler (struct tgl_state *TLS, struct tgl_chat *C, unsigned flags) { debug ("update_chat_handler() (%s)", print_flags_update (flags)); update_chat (TLS, tgl_peer_get (TLS, C->id), flags, _("Telegram Chats")); } telegram-purple/tgp-chat.h000066400000000000000000000053431363674160100160570ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #ifndef __telegram_adium__tgp_chat__ #define __telegram_adium__tgp_chat__ #include "telegram-purple.h" struct tgp_channel_member { tgl_peer_id_t id; int flags; }; struct tgp_channel_loading { tgl_peer_t *P; GList *members; GList *callbacks; GList *extras; int remaining; }; tgl_peer_id_t tgp_chat_get_id (PurpleChat *C); int tgp_chat_has_id (PurpleChat *C); void tgp_chat_set_last_server_id (struct tgl_state *TLS, tgl_peer_id_t chat, int id); int tgp_chat_get_last_server_id (struct tgl_state *TLS, tgl_peer_id_t chat); PurpleChat *tgp_chat_blist_store (struct tgl_state *TLS, tgl_peer_t *P, const char *group); PurpleConversation *tgp_chat_show (struct tgl_state *TLS, tgl_peer_t *P); int tgprpl_send_chat (PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags); unsigned int tgprpl_send_chat_typing (PurpleConversation *conv, PurpleTypingState typing, gpointer ignored); char *tgprpl_get_chat_name (GHashTable *data); void tgprpl_chat_join (PurpleConnection *gc, GHashTable *data); GList *tgprpl_chat_join_info (PurpleConnection *gc); PurpleRoomlist *tgprpl_roomlist_get_list (PurpleConnection *gc); void tgprpl_roomlist_cancel (PurpleRoomlist *list); void tgp_chat_roomlist_populate (struct tgl_state *TLS); GHashTable *tgprpl_chat_info_defaults (PurpleConnection *gc, const char *chat_name); void tgp_chat_join_all_pending (struct tgl_state *TLS); void tgprpl_kick_from_chat (PurpleConnection *gc, int id, const char *who); void tgp_channel_load (struct tgl_state *TLS, tgl_peer_t *P, void (*callback) (struct tgl_state *, void *, int, tgl_peer_t *), void *extra); int tgp_channel_loaded (struct tgl_state *TLS, tgl_peer_id_t id); void update_channel_handler (struct tgl_state *TLS, struct tgl_channel *C, unsigned flags); void update_chat_handler (struct tgl_state *TLS, struct tgl_chat *C, unsigned flags); void update_chat_typing (struct tgl_state *TLS, struct tgl_user *U, struct tgl_chat *C, enum tgl_typing_status status); #endif telegram-purple/tgp-ft.c000066400000000000000000000275451363674160100155540ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #include #include "telegram-purple.h" static void tgprpl_xfer_free_data (struct tgp_xfer_send_data *data); static char *tgp_strdup_determine_filename (const char *mime, const char *caption, int flags, long long hash) { if (caption) { return g_strdup (caption); } const char *type = NULL; if (mime) { if (flags & TGLDF_VIDEO) { // video message type = "mp4"; } else if (flags & TGLDF_AUDIO) { // audio message type = "ogg"; } else { // document message type = tgp_mime_to_filetype (mime); } } if (! str_not_empty(type)) { if (flags & TGLDF_IMAGE) { type = "png"; } else if (flags & TGLDF_AUDIO) { type = "ogg"; } else if (flags & TGLDF_VIDEO) { type = "mp4"; } else if (flags & TGLDF_STICKER) { type = "webp"; } else { type = "bin"; } } return g_strdup_printf ("%" G_GINT64_MODIFIER "d.%s", (gint64) ABS(hash), type); } static void tgprpl_xfer_recv_on_finished (struct tgl_state *TLS, void *_data, int success, const char *filename) { debug ("tgprpl_xfer_recv_on_finished()"); struct tgp_xfer_send_data *data = _data; char *selected = g_strdup (purple_xfer_get_local_filename (data->xfer)); if (success) { debug ("purple_xfer_set_completed"); // always completed the file transfer to avoid a warning dialogue when closing (Adium) purple_xfer_set_bytes_sent (data->xfer, purple_xfer_get_size (data->xfer)); purple_xfer_set_completed (data->xfer, TRUE); if (! purple_xfer_is_canceled (data->xfer)) { purple_xfer_end (data->xfer); } } else { tgp_notify_on_error_gw (TLS, NULL, success); if (! purple_xfer_is_canceled (data->xfer)) { purple_xfer_cancel_remote (data->xfer); } failure ("recv xfer failed"); } data->loading = FALSE; data->xfer->data = NULL; purple_xfer_unref (data->xfer); tgprpl_xfer_free_data (data); debug ("moving transferred file from tgl directory %s to selected target %s", selected, filename); g_unlink (selected); //FIXME: try to copy when this fails g_rename (filename, selected); g_free (selected); } static void tgprpl_xfer_send_on_finished (struct tgl_state *TLS, void *_data, int success, struct tgl_message *M) { debug ("tgprpl_xfer_on_finished()"); struct tgp_xfer_send_data *data = _data; if (success) { if (! purple_xfer_is_canceled (data->xfer)) { debug ("purple_xfer_set_completed"); purple_xfer_set_bytes_sent (data->xfer, purple_xfer_get_size (data->xfer)); purple_xfer_set_completed (data->xfer, TRUE); purple_xfer_end (data->xfer); } write_secret_chat_file (TLS); } else { tgp_notify_on_error_gw (TLS, NULL, success); if (! purple_xfer_is_canceled (data->xfer)) { purple_xfer_cancel_remote (data->xfer); } failure ("send xfer failed"); } data->loading = FALSE; data->xfer->data = NULL; purple_xfer_unref (data->xfer); tgprpl_xfer_free_data (data); } static void tgprpl_xfer_canceled (PurpleXfer *X) { debug ("tgprpl_xfer_canceled()"); struct tgp_xfer_send_data *data = X->data; // the xfer data must not be freed when the transfer is still running, since there is no way to cancel // the running transfer and the callback still needs the xfer data. In that case transfer data will // be freed once the transfer finished or the account goes offline and all loading transfers are aborted. if (! data->loading) { data->xfer->data = NULL; tgprpl_xfer_free_data (data); } } static gboolean tgprpl_xfer_upload_progress (gpointer _data) { PurpleXfer *X = _data; struct tgp_xfer_send_data *data = X->data; connection_data *conn = data->conn; PurpleXferType type = purple_xfer_get_type (X); switch (type) { case PURPLE_XFER_SEND: purple_xfer_set_size (X, conn->TLS->cur_uploading_bytes); purple_xfer_set_bytes_sent (X, conn->TLS->cur_uploaded_bytes); purple_xfer_update_progress (X); debug ("PURPLE_XFER_SEND progress %d / %d", conn->TLS->cur_uploaded_bytes, conn->TLS->cur_uploading_bytes); if (conn->TLS->cur_uploaded_bytes == conn->TLS->cur_uploading_bytes) { data->timer = 0; return FALSE; } break; case PURPLE_XFER_RECEIVE: purple_xfer_set_size (X, conn->TLS->cur_downloading_bytes); purple_xfer_set_bytes_sent (X, conn->TLS->cur_downloaded_bytes); purple_xfer_update_progress (X); debug ("PURPLE_XFER_RECEIVE progress %d / %d", conn->TLS->cur_downloaded_bytes, conn->TLS->cur_downloading_bytes); if (conn->TLS->cur_downloading_bytes == conn->TLS->cur_downloaded_bytes) { data->timer = 0; return FALSE; } break; default: case PURPLE_XFER_UNKNOWN: failure ("ERROR: tgprpl_xfer_upload_progress xfer type PURPLE_XFER_UNKNOWN."); return FALSE; break; } return TRUE; } static void tgprpl_xfer_recv_init (PurpleXfer *X) { debug ("tgprpl_xfer_recv_init(): receiving xfer accepted."); struct tgp_xfer_send_data *data = X->data; struct tgl_state *TLS = data->conn->TLS; struct tgl_message *M = data->msg; struct tgl_document *D = M->media.document; tgl_peer_t *P = NULL; purple_xfer_start (X, -1, NULL, 0); const char *who = purple_xfer_get_remote_user (X); P = tgp_blist_lookup_peer_get (TLS, who); g_return_if_fail(P); // Prevent the xfer data from getting freed after cancelling to allow the file transfer to complete // without crashing. This is necessary cause loading the file in libtgl cannot be aborted once started. purple_xfer_ref (X); data->timer = purple_timeout_add (100, tgprpl_xfer_upload_progress, X); data->loading = TRUE; switch (M->media.type) { case tgl_message_media_document: tgl_do_load_document (TLS, D, tgprpl_xfer_recv_on_finished, data); break; case tgl_message_media_document_encr: tgl_do_load_encr_document (TLS, M->media.encr_document, tgprpl_xfer_recv_on_finished, data); break; case tgl_message_media_audio: tgl_do_load_audio (TLS, D, tgprpl_xfer_recv_on_finished, data); break; case tgl_message_media_video: tgl_do_load_video (TLS, D, tgprpl_xfer_recv_on_finished, data); break; default: failure ("Unknown message media type: %d, XFER not possible.", M->media.type); return; } } static void tgprpl_xfer_send_init (PurpleXfer *X) { debug ("tgprpl_xfer_send_init(): sending xfer accepted."); struct tgp_xfer_send_data *data; const char *file, *localfile, *who; tgl_peer_t *P; data = X->data; purple_xfer_start (X, -1, NULL, 0); file = purple_xfer_get_filename (X); localfile = purple_xfer_get_local_filename (X); who = purple_xfer_get_remote_user (X); debug ("xfer_on_init (file=%s, local=%s, who=%s)", file, localfile, who); P = tgp_blist_lookup_peer_get (data->conn->TLS, who); g_return_if_fail (P); if (tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT) { purple_xfer_error (PURPLE_XFER_SEND, data->conn->pa, who, _("Sorry, sending documents to encrypted chats not yet supported.")); purple_xfer_cancel_local (X); return; } unsigned long long int flags = TGL_SEND_MSG_FLAG_DOCUMENT_AUTO; if (tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL) { flags |= TGLMF_POST_AS_CHANNEL; } // see comment in tgprpl_xfer_recv_init() purple_xfer_ref (X); data->timer = purple_timeout_add (100, tgprpl_xfer_upload_progress, X); data->loading = TRUE; tgl_do_send_document (data->conn->TLS, P->id, (char*) localfile, NULL, 0, flags, tgprpl_xfer_send_on_finished, data); } static void tgprpl_xfer_init_data (PurpleXfer *X, connection_data *conn, struct tgl_message *msg) { if (!X->data) { struct tgp_xfer_send_data *data = g_malloc0 (sizeof (struct tgp_xfer_send_data)); data->xfer = X; data->conn = conn; data->msg = msg; X->data = data; } } static void tgprpl_xfer_free_data (struct tgp_xfer_send_data *data) { if (data->timer) { purple_input_remove (data->timer); } data->timer = 0; g_free (data); } void tgprpl_xfer_free_all (connection_data *conn) { GList *xfers = purple_xfers_get_all (); while (xfers) { PurpleXfer *xfer = xfers->data; if (purple_xfer_get_account (xfer) == conn->pa) { debug ("xfer: %s", xfer->filename); // cancel all non-completed file tranfsers to avoid them from being called // in future sessions, as they still contain references to already freed data. if (! purple_xfer_is_canceled (xfer) && ! purple_xfer_is_completed (xfer)) { purple_xfer_cancel_local (xfer); } // if a file transfer is still running while going offline, it will be canceled when // cleaning up libtgl memory. Since canceled file transfers are being kept (see // tgprpl_xfer_canceled() and tgprpl_xfer_recv_init()) those need to be freed now. struct tgp_xfer_send_data *data = xfer->data; if (data) { if (data->loading) { tgprpl_xfer_free_data (data); xfer->data = NULL; purple_xfer_unref (xfer); } else { g_warn_if_reached(); } } } xfers = g_list_next(xfers); } } PurpleXfer *tgprpl_new_xfer (PurpleConnection *gc, const char *who) { debug ("tgprpl_new_xfer()"); PurpleXfer *X = purple_xfer_new (purple_connection_get_account (gc), PURPLE_XFER_SEND, who); if (X) { purple_xfer_set_init_fnc (X, tgprpl_xfer_send_init); purple_xfer_set_cancel_send_fnc (X, tgprpl_xfer_canceled); tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), NULL); } return X; } static PurpleXfer *tgprpl_new_xfer_recv (PurpleConnection *gc, const char *who) { PurpleXfer *X = purple_xfer_new (purple_connection_get_account (gc), PURPLE_XFER_RECEIVE, who); purple_xfer_set_init_fnc (X, tgprpl_xfer_recv_init); purple_xfer_set_cancel_recv_fnc (X, tgprpl_xfer_canceled); return X; } void tgprpl_recv_file (PurpleConnection *gc, const char *who, struct tgl_message *M) { debug ("tgprpl_recv_file()"); g_return_if_fail (who); PurpleXfer *X = tgprpl_new_xfer_recv (gc, who); const char *mime_type, *caption; long long access_hash; int flags, size; if (M->media.type == tgl_message_media_document_encr) { mime_type = M->media.encr_document->mime_type; caption = M->media.encr_document->caption; access_hash = M->media.encr_document->access_hash; flags = M->media.encr_document->flags; size = M->media.encr_document->size; } else { mime_type = M->media.document->mime_type; caption = M->media.document->caption; access_hash = M->media.document->access_hash; flags = M->media.document->flags; size = M->media.document->size; } char *filename = tgp_strdup_determine_filename (mime_type, caption, flags, access_hash); purple_xfer_set_filename (X, filename); g_free (filename); purple_xfer_set_size (X, size); tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), M); purple_xfer_request (X); } void tgprpl_send_file (PurpleConnection * gc, const char *who, const char *file) { debug ("tgprpl_send_file()"); PurpleXfer *X = tgprpl_new_xfer (gc, who); if (file) { purple_xfer_request_accepted (X, file); debug ("starting xfer..."); } else { purple_xfer_request (X); } } telegram-purple/tgp-ft.h000066400000000000000000000022761363674160100155530ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #ifndef __telegram_adium__tgp_ft__ #define __telegram_adium__tgp_ft__ #include #include #include "tgp-structs.h" PurpleXfer *tgprpl_new_xfer (PurpleConnection * gc, const char *who); void tgprpl_send_file (PurpleConnection * gc, const char *who, const char *file); void tgprpl_recv_file (PurpleConnection * gc, const char *who, struct tgl_message *M); void tgprpl_xfer_free_all (connection_data *conn); #endif telegram-purple/tgp-info.c000066400000000000000000000162451363674160100160710ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2016 */ #include "tgp-info.h" // load photo static void tgp_info_update_photo_id (PurpleBlistNode *node, long long photo) { char *llid = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) photo); debug ("tgp_info_update_photo_id %s", llid); purple_blist_node_set_string (node, TGP_INFO_PHOTO_ID, llid); g_free (llid); } static void tgp_info_load_photo_done (struct tgl_state *TLS, void *extra, int success, const char *filename) { tgl_peer_t *P = extra; g_return_if_fail(success); gchar *img = NULL; size_t len; GError *err = NULL; g_file_get_contents (filename, &img, &len, &err); if (err) { failure ("getting file contents for %s failed: %s", filename, err->message); return; } if (tgl_get_peer_type (P->id) == TGL_PEER_USER || tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT) { PurpleBuddy *B = tgp_blist_buddy_find (TLS, P->id); g_return_if_fail(B); purple_buddy_icons_set_for_user (tls_get_pa (TLS), purple_buddy_get_name (B), (guchar*) img, len, NULL); tgp_info_update_photo_id (&B->node, P->user.photo_big.local_id); } else { PurpleChat *C = tgp_blist_chat_find (TLS, P->id); g_return_if_fail(C); purple_buddy_icons_node_set_custom_icon (&C->node, (guchar*) img, len); tgp_info_update_photo_id (&C->node, P->user.photo_big.local_id); } } // update photo void tgp_info_update_photo (PurpleBlistNode *node, tgl_peer_t *P) { tgl_peer_t *parent = NULL; // FIXME: test if this works for encrypted chats long long photo = P->user.photo_big.local_id; const char *old = purple_blist_node_get_string (node, TGP_INFO_PHOTO_ID); if (old) { long long id = 0; id = atoll (old); if (id == photo) { debug ("photo id for %s hasn't changed %lld", parent ? parent->print_name : P->print_name, id); return; } } if (photo != 0 && pbn_get_data (node) != NULL) { // FIXME: Monkey-patched condition, I have no idea why this is NULL sometimes. tgl_do_load_file_location (pbn_get_data (node)->TLS, &P->user.photo_big, tgp_info_load_photo_done, P); } else { // set empty photo purple_buddy_icons_node_set_custom_icon_from_file (node, NULL); tgp_info_update_photo_id (node, photo); } } // show user info static void tgp_info_load_channel_done (struct tgl_state *TLS, void *extra, int success, struct tgl_channel *C) { g_return_if_fail(success); PurpleNotifyUserInfo *info = purple_notify_user_info_new (); if (str_not_empty (C->about)) { purple_notify_user_info_add_pair (info, _("Description"), C->about); } if (str_not_empty (C->username)) { char *link = g_strdup_printf ("https://telegram.me/%s", C->username); purple_notify_user_info_add_pair (info, _("Link"), link); g_free (link); } if (str_not_empty (C->print_title)) { purple_notify_user_info_add_pair (info, _("Print Title"), C->print_title); } char *admins = g_strdup_printf ("%d", C->admins_count); purple_notify_user_info_add_pair (info, _("Administrators"), admins); g_free (admins); char *participants = g_strdup_printf ("%d", C->participants_count); purple_notify_user_info_add_pair (info, _("Participants"), participants); g_free (participants); char *kicked = g_strdup_printf ("%d", C->kicked_count); purple_notify_user_info_add_pair (info, _("Kicked"), kicked); g_free (kicked); purple_notify_userinfo (tls_get_conn (TLS), tgp_blist_lookup_purple_name (TLS, C->id), info, NULL, NULL); } static void tgp_info_load_user_done (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U) { g_return_if_fail(success); // user info PurpleNotifyUserInfo *info = purple_notify_user_info_new (); if (str_not_empty (U->first_name) && str_not_empty (U->last_name)) { purple_notify_user_info_add_pair (info, _("First name"), U->first_name); purple_notify_user_info_add_pair (info, _("Last name"), U->last_name); } else { purple_notify_user_info_add_pair (info, _("Name"), U->print_name); } if (str_not_empty (U->username)) { char *username = g_strdup_printf ("@%s", U->username); purple_notify_user_info_add_pair (info, _("Username"), username); g_free (username); } char *status = tgp_format_user_status (&U->status); purple_notify_user_info_add_pair (info, _("Last seen"), status); g_free (status); if (str_not_empty (U->phone)) { char *phone = g_strdup_printf ("+%s", U->phone); purple_notify_user_info_add_pair (info, _("Phone"), phone); g_free (phone); } // secret chat info tgl_peer_t *O = extra; if (O && tgl_get_peer_type (O->id) == TGL_PEER_ENCR_CHAT) { struct tgl_secret_chat *secret = &O->encr_chat; if (secret->state == sc_waiting) { purple_notify_user_info_add_pair (info, "", _("Waiting for the user to get online...")); } else { const char *ttl_key = _("Self destruction timer"); if (secret->ttl) { char *ttl = g_strdup_printf ("%d", secret->ttl); purple_notify_user_info_add_pair (info, ttl_key, ttl); g_free (ttl); } else { purple_notify_user_info_add_pair (info, ttl_key, _("Timer is not enabled.")); } if (secret->first_key_sha[0]) { int sha1key = tgp_visualize_key (TLS, secret->first_key_sha); if (sha1key != -1) { char *ident_icon = tgp_format_img (sha1key); purple_notify_user_info_add_pair (info, _("Secret key"), ident_icon); g_free(ident_icon); } } } } const char *who = NULL; if (tgl_get_peer_type (O->id) == TGL_PEER_ENCR_CHAT) { who = tgp_blist_lookup_purple_name (TLS, O->id); } else { who = tgp_blist_lookup_purple_name (TLS, U->id); } purple_notify_userinfo (tls_get_conn (TLS), who, info, NULL, NULL); } void tgprpl_info_show (PurpleConnection *gc, const char *who) { tgl_peer_t *P = tgp_blist_lookup_peer_get (gc_get_data (gc)->TLS, who); if (P) { switch (tgl_get_peer_type (P->id)) { case TGL_PEER_ENCR_CHAT: { tgl_peer_t *parent = tgp_encr_chat_get_partner (gc_get_tls (gc), &P->encr_chat); if (parent) { tgl_do_get_user_info (gc_get_tls (gc), parent->id, 0, tgp_info_load_user_done, P); } break; } case TGL_PEER_CHANNEL: tgl_do_get_channel_info (gc_get_tls (gc), P->id, FALSE, tgp_info_load_channel_done, P); break; case TGL_PEER_USER: tgl_do_get_user_info (gc_get_tls (gc), P->id, 0, tgp_info_load_user_done, P); break; } } } telegram-purple/tgp-info.h000066400000000000000000000017761363674160100161010ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2016 */ #ifndef tgp_info_h #define tgp_info_h #include "telegram-purple.h" #define TGP_INFO_PHOTO_ID "tgp_photo_id" void tgp_info_update_photo (PurpleBlistNode *node, tgl_peer_t *P); void tgprpl_info_show (PurpleConnection *gc, const char *who); #endif telegram-purple/tgp-msg.c000066400000000000000000001131241363674160100157160ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2016 */ #include "telegram-purple.h" #include #include #include #if !GLIB_CHECK_VERSION(2,30,0) gchar * g_utf8_substring (const gchar *str, glong start_pos, glong end_pos) { gchar *start, *end, *out; start = g_utf8_offset_to_pointer (str, start_pos); end = g_utf8_offset_to_pointer (start, end_pos - start_pos); out = g_malloc (end - start + 1); memcpy (out, start, end - start); out[end - start] = 0; return out; } #endif static char *tgp_msg_service_display (struct tgl_state *TLS, struct tgl_message *M) { g_return_val_if_fail(M && M->flags & TGLMF_SERVICE, NULL); connection_data *conn = TLS->ev_base; char *txt = NULL; tgl_peer_t *fromPeer = tgl_peer_get (TLS, M->from_id); g_return_val_if_fail(fromPeer != NULL, NULL); const char *txt_user = fromPeer->print_name; switch (M->action.type) { case tgl_message_action_chat_create: txt = g_strdup_printf (_("%2$s created chat %1$s."), M->action.title, txt_user); break; case tgl_message_action_chat_edit_title: txt = g_strdup_printf (_("%2$s changed title to %1$s."), M->action.new_title, txt_user); break; case tgl_message_action_chat_edit_photo: txt = g_strdup_printf (_("%s changed photo."), txt_user); break; case tgl_message_action_chat_delete_photo: txt = g_strdup_printf (_("%s deleted photo."), txt_user); break; case tgl_message_action_chat_add_user_by_link: { tgl_peer_t *actionPeer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user)); if (actionPeer) { char *alias = actionPeer->print_name; PurpleConversation *conv = purple_find_chat (conn->gc, tgl_get_peer_id (M->to_id)); txt = g_strdup_printf (_("%1$s added user %2$s by link."), alias, txt_user); if (conv) { p2tgl_conv_add_user (TLS, conv, tgl_get_peer_id (fromPeer->id), NULL, 0, FALSE); } return txt; } break; } case tgl_message_action_chat_add_users: { int i; for (i = 0; i < M->action.user_num; ++i) { tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.users[i])); if (peer) { char *alias = peer->print_name; txt = g_strdup_printf (_("%2$s added user %1$s."), alias, txt_user); PurpleConversation *conv = purple_find_chat (conn->gc, tgl_get_peer_id (M->to_id)); if (conv) { p2tgl_conv_add_user (TLS, conv, M->action.users[i], NULL, 0, FALSE); } } } break; } case tgl_message_action_chat_delete_user: { tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user)); if (peer) { tgl_peer_t *chatPeer = tgl_peer_get (TLS, M->to_id); g_return_val_if_fail(tgl_get_peer_type (chatPeer->id) == TGL_PEER_CHAT, NULL); // make sure that the chat is showing before deleting the user, otherwise the chat will be // initialised after removing the chat and the chat will still contain the deleted user PurpleConversation *conv = tgp_chat_show (TLS, chatPeer); if (conv) { char *alias = peer->print_name; const char *aliasLeft = tgp_blist_lookup_purple_name (TLS, TGL_MK_USER (M->action.user)); if (tgl_get_peer_id (M->from_id) != tgl_get_peer_id (peer->id)) { txt = g_strdup_printf (_("%2$s deleted user %1$s."), alias, txt_user); } g_return_val_if_fail (aliasLeft, NULL); purple_conv_chat_remove_user (purple_conversation_get_chat_data (conv), aliasLeft, txt); if (M->action.user == tgl_get_peer_id (TLS->our_id)) { purple_conv_chat_left (purple_conversation_get_chat_data (conv)); } // conv_del_user already printed a message, prevent a redundant message // from being printed by returning NULL g_free (txt); return NULL; } char *alias = peer->print_name; if (tgl_get_peer_id (M->from_id) != tgl_get_peer_id (peer->id)) { txt = g_strdup_printf (_("%2$s deleted user %1$s."), alias, txt_user); } } break; } case tgl_message_action_set_message_ttl: txt = g_strdup_printf (P_("%2$s set self destruction timer to %1$d second.", "%2$s set self destruction timer to %1$d seconds.", M->action.ttl), M->action.ttl, txt_user); break; case tgl_message_action_read_messages: txt = g_strdup_printf (P_("%2$s marked %1$d message read.", "%2$s marked %1$d messages read.", M->action.read_cnt), M->action.read_cnt, txt_user); break; case tgl_message_action_delete_messages: txt = g_strdup_printf (P_("%2$s deleted %1$d message.", "%2$s deleted %1$d messages.", M->action.delete_cnt), M->action.delete_cnt, txt_user); break; case tgl_message_action_screenshot_messages: txt = g_strdup_printf (P_("%2$s made a screenshot of %1$d message.", "%2$s made a screenshot of %1$d messages.", M->action.screenshot_cnt), M->action.screenshot_cnt, txt_user); break; case tgl_message_action_channel_create: { txt = g_strdup_printf (_("Channel %1$s created"), M->action.title); // FIXME: check if this makes sense tgp_chat_blist_store (TLS, fromPeer, _("Telegram Channels")); break; } default: g_warn_if_reached(); break; } return txt; } static char *format_geo_link_osm (double lat, double lon) { // assure that the floats are formatted with a dot char *loc = setlocale (LC_NUMERIC, NULL); setlocale (LC_NUMERIC, "en_US"); debug ("old locale: %s", loc); char *link = g_strdup_printf ("https://www.openstreetmap.org/?mlat=%.6lf&mlon=%.6lf#map=17/%.6lf/%.6lf", lat, lon, lat, lon); // restore old locale setlocale (LC_NUMERIC, loc); return link; } static char *tgp_msg_file_display (const char *path, const char *filename, const char* caption, const char *mime, long long size) { gchar *format; gchar *capt = g_markup_escape_text (caption, -1); gchar *pth = g_markup_escape_text (path, -1); gchar *fle = g_markup_escape_text (filename, -1); gchar *mme = g_markup_escape_text (mime, -1); gchar *fsize = #if GLIB_CHECK_VERSION(2,30,0) /* 'g_format_size' only exists since 2.30.0. */ g_format_size (size) #elif GLIB_CHECK_VERSION(2,16,0) /* 'g_format_size_for_display' only exists since 2.16.0. * We compile on Windows with glib 2.28.8. */ g_format_size_for_display (size) #else /* even older */ #error "Too outdated glib version!" #endif ; if (g_strcmp0(purple_core_get_ui(), "BitlBee") == 0) { format = g_strdup_printf ("[%s file://%s %s %s %s]", capt, pth, fle, mme, fsize); } else { format = g_strdup_printf ("[%s %s %s %s]", capt, pth, fle, mme, fsize); } g_free (capt); g_free (pth); g_free (fle); g_free (mme); g_free (fsize); return format; } static void tgp_msg_send_done (struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M) { if (! success) { char *err = _("Sending message failed."); warning (err); if (M) { tgp_msg_special_out (TLS, err, M->to_id, PURPLE_MESSAGE_ERROR | PURPLE_MESSAGE_NO_LOG); } assert (callback_extra != NULL); warning ("Code %d: %s\n", TLS->error_code, TLS->error); warning ("Message was: %s\n", (char *) callback_extra); return; } write_files_schedule (TLS); } static gboolean tgp_msg_send_schedule_cb (gpointer data) { connection_data *conn = data; conn->out_timer = 0; struct tgp_msg_sending *D = NULL; while ((D = g_queue_peek_head (conn->out_messages))) { g_queue_pop_head (conn->out_messages); unsigned long long flags = TGLMF_HTML; if (tgl_get_peer_type (D->to) == TGL_PEER_CHANNEL && !(tgl_peer_get (conn->TLS, D->to)->channel.flags & TGLCHF_MEGAGROUP)) { flags |= TGLMF_POST_AS_CHANNEL; } // secret chats do not unescape html if (tgl_get_peer_type (D->to) == TGL_PEER_ENCR_CHAT) { gchar *unescaped = purple_unescape_html (D->msg); g_free (D->msg); D->msg = unescaped; } tgl_do_send_message (D->TLS, D->to, D->msg, (int)strlen (D->msg), flags, NULL, tgp_msg_send_done, D->msg); tgp_msg_sending_free (D); } return FALSE; } static void tgp_msg_send_schedule (struct tgl_state *TLS, const char *chunk, tgl_peer_id_t to) { g_queue_push_tail (tls_get_data (TLS)->out_messages, tgp_msg_sending_init (TLS, g_strdup (chunk), to)); if (tls_get_data (TLS)->out_timer) { purple_timeout_remove (tls_get_data (TLS)->out_timer); } tls_get_data (TLS)->out_timer = purple_timeout_add (0, tgp_msg_send_schedule_cb, tls_get_data (TLS)); } void tgp_msg_special_out (struct tgl_state *TLS, const char *msg, tgl_peer_id_t to_id, int flags) { if (tgl_get_peer_type (to_id) == TGL_PEER_CHAT) { tgp_chat_got_in (TLS, tgl_peer_get (TLS, to_id), to_id, msg, flags, time(0)); } else { // Regular IM conversations will not display specialized message flags like PURPLE_MESSAGE_ERROR or // PURPLE_MESSAGE_SYSTEM correctly when using serv_got_in, therefore it is necessary to use the underlying // conversation directly. const char *name = tgp_blist_lookup_purple_name (TLS, to_id); PurpleConversation *conv = p2tgl_find_conversation_with_account (TLS, to_id); g_return_if_fail (name); if (! conv) { // if the conversation isn't open yet, create one with that name conv = purple_conversation_new (PURPLE_CONV_TYPE_IM, tls_get_pa (TLS), name); } purple_conversation_write (conv, name, msg, flags, time(0)); } } void send_inline_picture_done (struct tgl_state *TLS, void *extra, int success, struct tgl_message *msg) { if (!success) { char *errormsg = g_strdup_printf ("%d: %s", TLS->error_code, TLS->error); failure (errormsg); purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, _("Sending image failed."), errormsg, NULL, NULL, NULL); g_free (errormsg); return; } } static GList *tgp_msg_imgs_parse (const char *msg) { GList *imgs = NULL; int i; int len = (int) strlen (msg); for (i = 0; i < len; i ++) { if (len - i >= 4 && (! memcmp (msg + i, " 0) { PurpleStoredImage *psi = purple_imgstore_find_by_id (img); if (psi) { imgs = g_list_append (imgs, psi); } else { g_warn_if_reached(); } } } else { g_warn_if_reached(); } i = e; } } return imgs; } static char *tgp_msg_markdown_convert (const char *msg) { int len = (int) strlen (msg); char *html = g_new0(gchar, 3 * len); // strip any known-breaking html tags #define STRIP_BROKEN_HTML(PREFIX,SUFFIX) \ if (g_str_has_prefix (msg, (PREFIX)) && g_str_has_suffix (msg, (SUFFIX))) { \ msg += sizeof(PREFIX) - 1; \ len -= (sizeof(PREFIX) - 1) + (sizeof(SUFFIX) - 1); \ } STRIP_BROKEN_HTML("",""); // more STRIP_BROKEN_HTML invocations here, if necessary #undef STRIP_BROKEN_HTML int open = FALSE; int i, j; for (i = 0, j = 0; i < len; i ++) { // markdown for bold and italic doesn't seem to work with non-bots, therefore only parse code-tags if (len - i < 3 || (memcmp (msg + i, "```", 3))) { html[j ++] = msg[i]; } else { i += 2; if (! open) { assert(j + 6 < 3 * len); memcpy(html + j, "", 6); j += 6; } else { assert(j + 7 < 3 * len); memcpy(html + j, "", 7); j += 7; } open = ! open; } } html[j] = 0; return html; } int tgp_msg_send (struct tgl_state *TLS, const char *message, tgl_peer_id_t to) { // send all inline images GList *imgs = tgp_msg_imgs_parse (message); debug ("parsed %d images in messages", g_list_length (imgs)); while (imgs) { PurpleStoredImage *psi = imgs->data; gchar *tmp = g_build_filename (g_get_tmp_dir(), purple_imgstore_get_filename (psi), NULL) ; GError *err = NULL; gconstpointer data = purple_imgstore_get_data (psi); g_file_set_contents (tmp, data, purple_imgstore_get_size (psi), &err); if (! err) { debug ("sending img='%s'", tmp); tgl_do_send_document (TLS, to, tmp, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO | (tgl_get_peer_type (to) == TGL_PEER_CHANNEL) ? TGLMF_POST_AS_CHANNEL : 0, send_inline_picture_done, NULL); } else { failure ("error=%s", err->message); g_warn_if_reached(); } imgs = g_list_next(imgs); } // replace markdown with html char *html = g_strstrip(tgp_msg_markdown_convert (message)); // check message length int size = (int) g_utf8_strlen (html, -1); if (size == 0) { g_free (html); return 0; // fail quietly on empty messages } if (size > TGP_MAX_MSG_SIZE * TGP_DEFAULT_MAX_MSG_SPLIT_COUNT) { g_free (html); return -E2BIG; } // send big message as multiple chunks int start = 0; while (size > start) { int end = start + (int)TGP_MAX_MSG_SIZE; if (end > size) { end = size; } char *chunk = g_utf8_substring (html, start, end); tgp_msg_send_schedule (TLS, chunk, to); start = end; } g_free (html); // return 0 to assure that the picture is not echoed, since // it will already be echoed with the outgoing message return 0; } //Some media messages provide captions for the media. If the caption is supported and not empty, //this adds it to the already generated supplemental text. //Frees the old version of the text and returns the new one. char *tgp_msg_add_media_caption(char *current_text, struct tgl_message *M) { if (!M) return current_text; //safety //Only some types of media have caption field -- others may have garbage (check tgl_layout.h/tgl_message_media) switch (M->media.type) { //Certainly have caption case tgl_message_media_photo: case tgl_message_media_document: case tgl_message_media_audio: //stored as documents case tgl_message_media_video: //stored as documents break; //Do not have captions or we're not sure case tgl_message_media_none: case tgl_message_media_document_encr: case tgl_message_media_geo: case tgl_message_media_venue: case tgl_message_media_contact: case tgl_message_media_webpage: case tgl_message_media_unsupported: default: return current_text; } //No caption if (!str_not_empty (M->media.caption)) return current_text; char *old = current_text; if (str_not_empty (current_text)) { current_text = g_strdup_printf ("%s
%s", old, M->media.caption); } else { current_text = g_strdup(M->media.caption); } g_free (old); return current_text; } static char *tgp_msg_photo_display (struct tgl_state *TLS, const char *filename, int *flags) { connection_data *conn = TLS->ev_base; int img = p2tgl_imgstore_add_with_id (filename); if (img <= 0) { failure ("Cannot display picture, adding to imgstore failed."); return NULL; } used_images_add (conn, img); if (g_strcmp0(purple_core_get_ui(), "BitlBee") == 0) { *flags |= PURPLE_MESSAGE_SYSTEM; return g_strdup_printf (_("file://%s"), filename); } else { *flags |= PURPLE_MESSAGE_IMAGES; return tgp_format_img (img); } } static char *tgp_msg_sticker_display (struct tgl_state *TLS, tgl_peer_id_t from, const char *filename, int *flags) { char *text = NULL; #ifdef HAVE_LIBWEBP connection_data *conn = TLS->ev_base; int img = p2tgl_imgstore_add_with_id_webp ((char *) filename); if (img <= 0) { failure ("Cannot display sticker, adding to imgstore failed"); return NULL; } used_images_add (conn, img); text = tgp_format_img (img); *flags |= PURPLE_MESSAGE_IMAGES; #else const char *txt_user = tgp_blist_lookup_purple_name (TLS, from); g_return_val_if_fail (txt_user, NULL); text = g_strdup_printf (_("%s sent a sticker."), txt_user); *flags |= PURPLE_MESSAGE_SYSTEM; #endif return text; } //`reply` and `replyee` can be NULL if it comes to that static char *tgp_msg_reply_display (struct tgl_state *TLS, tgl_peer_t *replyee, struct tgl_message *reply, const char *message) { g_return_val_if_fail(message, NULL); // the text quoted by the reply char *quote = NULL; // Degrade gracefully if the caller doesn't have the quoted message -- // at least display the reply itself if (!reply) { quote = g_strdup(_("[message unavailable]")); } else if (reply->flags & TGLMF_SERVICE) { quote = tgp_msg_service_display (TLS, reply); g_return_val_if_fail(quote == NULL, NULL); } else { switch (reply->media.type) { case tgl_message_media_none: quote = purple_markup_escape_text (reply->message, strlen (reply->message)); tgp_replace (quote, '\n', ' '); break; case tgl_message_media_photo: quote = g_strdup(_("[photo]")); break; case tgl_message_media_audio: quote = g_strdup(_("[audio]")); break; case tgl_message_media_video: quote = g_strdup(_("[video]")); break; case tgl_message_media_document: case tgl_message_media_document_encr: quote = g_strdup(_("[document]")); break; case tgl_message_media_geo: case tgl_message_media_venue: quote = g_strdup(_("[position]")); // TODO: render break; case tgl_message_media_contact: quote = g_strdup(_("[contact]")); // TODO: render break; case tgl_message_media_webpage: quote = g_strdup(_("[webpage]")); break; case tgl_message_media_unsupported: quote = g_strdup(_("[unsupported media]")); break; default: g_warn_if_reached(); return NULL; break; } } if (reply) quote = tgp_msg_add_media_caption(quote, reply); //add media caption if present // the combined reply // insert line-break in non-adium clients to display // all lines of the quotation on the same level const char *br = ""; #ifndef __ADIUM_ br = "
"; #endif char *value = NULL; if (replyee) { const char *name = replyee->print_name; value = g_strdup_printf (_("%s> %s wrote:
> %s
%s"), br, name, quote, message); } else { value = g_strdup_printf (_("%s> Unknown user wrote:
> %s
%s"), br, quote, message); } g_free (quote); return value; } static void tgp_msg_display (struct tgl_state *TLS, struct tgp_msg_loading *C) { struct tgl_message *M = C->msg; char *text = NULL; int flags = 0; if (M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) { return; } if (!(M->flags & TGLMF_CREATED)) { return; } if (!tgl_get_peer_type (M->to_id)) { warning ("Bad msg\n"); return; } #ifdef __ADIUM_ // prevent double messages in Adium >= v1.6 if (tgp_outgoing_msg (TLS, M) && tgl_get_peer_type (M->to_id) != TGL_PEER_CHANNEL && tgl_get_peer_type (M->to_id) != TGL_PEER_CHAT) { return; } #endif // filter empty messages or messages with invalid recipients if (! M->message || !tgl_get_peer_type (M->to_id)) { return; } // Mark messages that contain a mention as if they contained our current nick name // FIXME: doesn't work in Adium if (M->flags & TGLMF_MENTION) { flags |= PURPLE_MESSAGE_NICK; } // Mark carbons of our own messages if (tgp_our_msg (TLS, M)) { flags |= PURPLE_MESSAGE_SEND; flags &= ~PURPLE_MESSAGE_RECV; } else { flags |= PURPLE_MESSAGE_RECV; } // handle messages that failed to load if (C->error) { const char *err = C->error_msg; if (! err) { err = _("failed loading message"); } tgp_msg_special_out (TLS, err, tgp_our_msg (TLS, M) ? M->from_id : M->to_id, PURPLE_MESSAGE_ERROR); return; } // format the message text if (M->flags & TGLMF_SERVICE) { text = tgp_msg_service_display (TLS, M); flags |= PURPLE_MESSAGE_SYSTEM; } else switch (M->media.type) { case tgl_message_media_none: if (str_not_empty (M->message)) { text = purple_markup_escape_text (M->message, strlen (M->message)); } break; case tgl_message_media_photo: if (M->media.photo) { g_return_if_fail(C->data != NULL); text = tgp_msg_photo_display (TLS, C->data, &flags); } break; case tgl_message_media_document: case tgl_message_media_video: case tgl_message_media_audio: if (M->media.document->flags & TGLDF_STICKER) { g_return_if_fail(C->data != NULL); text = tgp_msg_sticker_display (TLS, M->from_id, C->data, &flags); } else if (M->media.document->flags & TGLDF_IMAGE && !(M->media.document->flags & TGLDF_ANIMATED)) { g_return_if_fail(C->data != NULL); text = tgp_msg_photo_display (TLS, C->data, &flags); } else { // Automatically loaded files have C->data set to the file path if (C->data) { const char* path = C->data; // Content of a file transfer const char *caption = _("document"); if (M->media.document->flags & TGLDF_AUDIO) { // Content of a file transfer caption = _("audio"); } else if (M->media.document->flags & TGLDF_ANIMATED) { // Content of a file transfer caption = _("animation"); } else if (M->media.document->flags & TGLDF_VIDEO) { // Content of a file transfer caption = _("video"); } const char *filename = M->media.document->caption; if (! str_not_empty (filename)) { // audio and video snippets recorded from Telegram don't have captions const char *segment = path + strlen(path) - 1; while (segment > (char *)path && *segment != G_DIR_SEPARATOR) { segment --; } if (g_strcmp0(purple_core_get_ui(), "BitlBee") == 0) { chmod(filename, 0444); } filename = segment + 1; } const char *mime = ""; if (str_not_empty (M->media.document->mime_type)) { mime = M->media.document->mime_type; } text = tgp_msg_file_display (path, filename, caption, mime, M->media.document->size); } else { if (! tgp_our_msg (TLS, M) && ! tls_get_ft_discard (TLS)) { tgprpl_recv_file (tls_get_conn (TLS), tgp_blist_lookup_purple_name (TLS, M->from_id), M); } return; } } break; case tgl_message_media_document_encr: if (M->media.encr_document->flags & TGLDF_STICKER) { g_return_if_fail(C->data != NULL); text = tgp_msg_sticker_display (TLS, M->from_id, C->data, &flags); } if (M->media.encr_document->flags & TGLDF_IMAGE) { g_return_if_fail(C->data != NULL); text = tgp_msg_photo_display (TLS, C->data, &flags); } else { if (! tgp_our_msg (TLS, M)) { if (C->data) { // Content of a file transfer text = tgp_msg_file_display (C->data, M->media.encr_document->caption, _("document"), M->media.encr_document->mime_type, M->media.encr_document->size); } else { tgprpl_recv_file (tls_get_conn (TLS), tgp_blist_lookup_purple_name (TLS, M->to_id), M); return; } } } break; case tgl_message_media_contact: text = g_strdup_printf ("%s %s %s", M->media.first_name, M->media.last_name, M->media.phone); break; case tgl_message_media_venue: { char *address = NULL; if (M->media.venue.address && strcmp (M->media.venue.title, M->media.venue.address)) { address = g_strdup_printf (" %s", M->media.venue.address); } char *pos = format_geo_link_osm (M->media.venue.geo.latitude, M->media.geo.longitude); text = g_strdup_printf ("%s%s", pos, M->media.venue.title ? M->media.venue.title : "", address ? address : ""); if (address) { g_free (address); } g_free (pos); break; } case tgl_message_media_geo: { char *pos = format_geo_link_osm (M->media.venue.geo.latitude, M->media.geo.longitude); text = g_strdup_printf ("%s", pos, pos); g_free (pos); break; } case tgl_message_media_webpage: { char *msg = g_strdup (M->message); text = purple_markup_escape_text (msg, strlen (msg)); g_free (msg); break; } default: warning ("received unknown media type: %d", M->media.type); break; } text = tgp_msg_add_media_caption(text, M); //add media caption if present if (tgl_get_peer_type (M->to_id) != TGL_PEER_ENCR_CHAT && tgl_get_peer_type (M->to_id) != TGL_PEER_CHANNEL && ! (M->flags & TGLMF_UNREAD)) { // why? flags |= PURPLE_MESSAGE_DELAYED; } // TODO: is that a problem? // some service messages (like removing/adding users from chats) might print the message // text through other means and leave the text empty if (! str_not_empty (text)) { return; } // forwarded messages if (tgl_get_peer_type (M->fwd_from_id) != TGL_PEER_UNKNOWN) { debug("forwarded message: fwd_from_id=%d", tgl_get_peer_id(M->fwd_from_id)); // may be NULL tgl_peer_t *FP = tgl_peer_get (TLS, M->fwd_from_id); // do not run this through tgp_message_reply_display! it doesn't handle media, forwards are all about media // keep the full body we've generated char *tmp = text; if (FP) { const char *name = FP->print_name; text = g_strdup_printf (_("> Forwarded from %s:
> %s"), name, text); } else { text = g_strdup_printf (_("> Forwarded:
> %s"), text); } g_free (tmp); g_return_if_fail(text != NULL); } // replys if (M->reply_id) { debug("message reply: reply_id=%d", M->reply_id); tgl_message_id_t msg_id = M->permanent_id; msg_id.id = M->reply_id; struct tgl_message *reply = tgl_message_get (TLS, &msg_id); //The quoted message should have been prefetched by tgp_msg_recv() //but if we don't have it, at least display the reply itself tgl_peer_t *replyee = NULL; if (reply) { replyee = tgl_peer_get (TLS, reply->from_id); g_return_if_fail(replyee != NULL); }; char *tmp = text; text = tgp_msg_reply_display(TLS, replyee, reply, tmp); g_free (tmp); g_return_if_fail(text != NULL); } // display the message to the user switch (tgl_get_peer_type (M->to_id)) { case TGL_PEER_CHANNEL: { tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); g_return_if_fail(P != NULL); if (P->channel.flags & TGLCHF_MEGAGROUP) { // sender is the group tgp_chat_got_in (TLS, P, M->from_id, text, flags, M->date); } else { // sender is the channel itself tgp_chat_got_in (TLS, P, P->id, text, flags, M->date); } break; } case TGL_PEER_CHAT: { tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); g_return_if_fail(P != NULL); tgp_chat_got_in (TLS, P, (flags & PURPLE_MESSAGE_SEND) ? M->to_id : M->from_id, text, flags, M->date); break; } case TGL_PEER_ENCR_CHAT: { p2tgl_got_im_combo (TLS, (flags & PURPLE_MESSAGE_SEND) ? M->to_id : M->from_id, text, flags, M->date); break; } case TGL_PEER_USER: { p2tgl_got_im_combo (TLS, (flags & PURPLE_MESSAGE_SEND) ? M->to_id : M->from_id, text, flags, M->date); break; } } g_free (text); } static time_t tgp_msg_oldest_relevant_ts (struct tgl_state *TLS) { connection_data *conn = TLS->ev_base; int days = purple_account_get_int (conn->pa, TGP_KEY_HISTORY_RETRIEVAL_THRESHOLD, TGP_DEFAULT_HISTORY_RETRIEVAL_THRESHOLD); return days > 0 ? tgp_time_n_days_ago (days) : 0; } static void tgp_msg_process_in_ready (struct tgl_state *TLS) { connection_data *conn = TLS->ev_base; struct tgp_msg_loading *C; while ((C = g_queue_peek_head (conn->new_messages))) { if (C->pending) { break; } g_queue_pop_head (conn->new_messages); tgp_msg_display (TLS, C); pending_reads_add (TLS, C->msg); if (C->data) { g_free (C->data); } if (C->error_msg) { g_free (C->error_msg); } tgp_msg_loading_free (C); } pending_reads_send_all (TLS); debug ("tgp_msg_process_in_ready, queue size=%d", g_queue_get_length (conn->new_messages)); } static void tgp_msg_on_loaded_document (struct tgl_state *TLS, void *extra, int success, const char *filename) { debug ("tgp_msg_on_loaded_document()"); struct tgp_msg_loading *C = extra; if (success) { C->data = (void *) g_strdup (filename); } else { g_warn_if_reached(); C->error = TRUE; C->error_msg = g_strdup (_("loading document or picture failed")); } -- C->pending; tgp_msg_process_in_ready (TLS); } static void tgp_msg_on_loaded_chat_full (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *chat) { debug ("tgp_msg_on_loaded_chat_full()"); if (! success) { // foreign user's names won't be displayed in the user list g_warn_if_reached(); } struct tgp_msg_loading *C = extra; -- C->pending; tgp_msg_process_in_ready (TLS); } static void tgp_msg_on_loaded_channel_history (struct tgl_state *TLS, void *extra, int success, tgl_peer_t *P) { struct tgp_msg_loading *C = extra; -- C->pending; tgp_msg_process_in_ready (TLS); } //A callback for when tgp_do_load_message finishes preloading a requested message static void tgp_msg_on_loaded_message_for_cache(struct tgl_state *TLS, void *extra, int success, struct tgl_message *M) { struct tgp_msg_loading *C = extra; -- C->pending; //Do nothing: The message is cached automatically by the underlying library //and we don't want to pass it to tgp_msg_recv() for display tgp_msg_process_in_ready (TLS); } /* static void tgp_msg_on_loaded_user_full (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U) { debug ("tgp_msg_on_loaded_user_full()"); struct tgp_msg_loading *C = extra; -- C->pending; tgp_msg_process_in_ready (TLS); } */ /* Libpurple message history is immutable and cannot be changed after printing a message. TGP currently keeps the first-in first-out queue *new_messages* to ensure that the messages are being printed in the correct order. When its necessary to fetch additional info (like attached pictures) before this can be done, the queue will hold all newer messages until the old message was completely loaded. */ void tgp_msg_recv (struct tgl_state *TLS, struct tgl_message *M, GList *before) { debug ("tgp_msg_recv before=%p server_id=%lld", before, M->server_id); if (M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) { return; } if (!(M->flags & TGLMF_CREATED)) { return; } if (!(M->flags & TGLMF_UNREAD) && M->date != 0 && M->date < tgp_msg_oldest_relevant_ts (TLS)) { debug ("Message from %d on %d too old, ignored.", tgl_get_peer_id (M->from_id), M->date); return; } struct tgp_msg_loading *C = tgp_msg_loading_init (M); /* For non-channels telegram ensures that tgp receives the messages in the correct order, but in channels there may be holes that need to be filled before the message log can be printed. This means that the queue may not be processed until all historic messages have been fetched and the messages have been inserted into the correct position of the queue */ if (tgl_get_peer_type (C->msg->from_id) == TGL_PEER_CHANNEL || tgl_get_peer_type (C->msg->to_id) == TGL_PEER_CHANNEL) { tgl_peer_id_t id = tgl_get_peer_type (C->msg->from_id) == TGL_PEER_CHANNEL ? C->msg->from_id : C->msg->to_id; if (! tgp_channel_loaded (TLS, id)) { ++ C->pending; tgp_channel_load (TLS, tgl_peer_get (TLS, id), tgp_msg_on_loaded_channel_history, C); } if (tgp_chat_get_last_server_id (TLS, id) >= C->msg->server_id) { info ("dropping duplicate channel messages server_id=%lld", C->msg->server_id); return; } if (tgp_chat_get_last_server_id (TLS, id) == (int) C->msg->server_id - 1) { tgp_chat_set_last_server_id (TLS, id, (int) C->msg->server_id); } } if (! (M->flags & TGLMF_SERVICE)) { // handle all messages that need to load content before they can be displayed if (M->media.type != tgl_message_media_none) { switch (M->media.type) { case tgl_message_media_photo: { // include the "bad photo" check from telegram-cli interface.c:3287 to avoid crashes // when fetching history. TODO: find out the reason for this behavior if (M->media.photo) { ++ C->pending; tgl_do_load_photo (TLS, M->media.photo, tgp_msg_on_loaded_document, C); } break; } // documents that are stickers or images will be displayed just like regular photo messages // and need to be loaded beforehand case tgl_message_media_document: case tgl_message_media_video: case tgl_message_media_audio: if (M->media.document->flags & (TGLDF_STICKER | TGLDF_IMAGE)) { ++ C->pending; tgl_do_load_document (TLS, M->media.document, tgp_msg_on_loaded_document, C); } else { // adium doesn't support printing an inline file link to the downloaded file #ifndef __ADIUM_ if (M->media.document->size <= tls_get_ft_threshold (TLS) || tls_get_ft_autoload (TLS)) { ++ C->pending; if (M->media.document->flags & TGLDF_AUDIO) { tgl_do_load_audio (TLS, M->media.document, tgp_msg_on_loaded_document, C); } else if (M->media.document->flags & TGLDF_VIDEO) { tgl_do_load_video (TLS, M->media.document, tgp_msg_on_loaded_document, C); } else { tgl_do_load_document (TLS, M->media.document, tgp_msg_on_loaded_document, C); } } #endif } break; case tgl_message_media_document_encr: if (M->media.encr_document->flags & TGLDF_STICKER || M->media.encr_document->flags & TGLDF_IMAGE) { ++ C->pending; tgl_do_load_encr_document (TLS, M->media.encr_document, tgp_msg_on_loaded_document, C); } break; case tgl_message_media_geo: // TODO: load geo thumbnail break; default: // prevent Clang warnings ... break; } } } /* To display a chat, the full name of every single user is needed, but the updates received from the server only contain the names of users mentioned in the events. In order to display a messages we always need to fetch the full chat info first. If the user list is empty, this means that we still haven't fetched the full chat information. Assure that there is only one chat info request for every chat to avoid causing FLOOD_WAIT_X errors that will lead to delays or dropped messages */ gpointer to_ptr = GINT_TO_POINTER(tgl_get_peer_id (M->to_id)); if (! g_hash_table_lookup (tls_get_data (TLS)->pending_chat_info, to_ptr)) { if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) { tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); g_warn_if_fail(P); if (P && ! P->chat.user_list_size) { ++ C->pending; tgl_do_get_chat_info (TLS, M->to_id, FALSE, tgp_msg_on_loaded_chat_full, C); g_hash_table_replace (tls_get_data (TLS)->pending_chat_info, to_ptr, to_ptr); } } } //Reply processing requires quoted messages to also be available if (M->reply_id) { ++ C->pending; tgl_message_id_t msg_id = M->permanent_id; msg_id.id = M->reply_id; tgl_do_get_message(TLS, &msg_id, tgp_msg_on_loaded_message_for_cache, C); } GList *b = g_queue_find (tls_get_data (TLS)->new_messages, before); if (b) { struct tgp_msg_loading *M = before->data; debug ("inserting before server_id=%lld", M->msg->server_id); g_queue_insert_before (tls_get_data (TLS)->new_messages, b, C); } else { g_queue_push_tail (tls_get_data (TLS)->new_messages, C); } tgp_msg_process_in_ready (TLS); } telegram-purple/tgp-msg.h000066400000000000000000000032041363674160100157200ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #ifndef __telegram_adium__tgp_msg__ #define __telegram_adium__tgp_msg__ /** * Process a message and display it * * Loads embedded ressources like pictures or document thumbnails and ensures that * that all messages are still displayed in the original incoming order. */ void tgp_msg_recv (struct tgl_state *TLS, struct tgl_message *M, GList *before); /** * Process a message and send it to the peer * * Removes all HTML escape chars and HTML markup, finds embedded images and sends * them as pictures and splits up messages that are too big for single Telegram * messages. */ int tgp_msg_send (struct tgl_state *TLS, const char *msg, tgl_peer_id_t to); /** * Print a special message in the conversation with a peer assuring that special flags are displayed */ void tgp_msg_special_out (struct tgl_state *TLS, const char *msg, tgl_peer_id_t to_id, int flags); #endif telegram-purple/tgp-net.c000066400000000000000000000336221363674160100157220ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman, Matthias Jentsch 2013-2015 */ #define _GNU_SOURCE #include #include #include #include #ifndef WIN32 #include #include #include #include #include #include #else #include #endif #include #include #include #include #include #include #include "telegram-purple.h" #include #ifndef POLLRDHUP #define POLLRDHUP 0 #endif #define PING_TIMEOUT 15 #define CONNECT_TIMEOUT 5 static void fail_connection (struct connection *c); static void restart_connection (struct connection *c); static void start_ping_timer (struct connection *c); static void conn_try_write (gpointer arg, gint source, PurpleInputCondition cond); static void try_read (struct connection *c); static void try_write (struct connection *c); static int ping_alarm (gpointer arg) { struct connection *c = arg; debug ("ping alarm"); assert (c->state == conn_failed || c->state == conn_ready || c->state == conn_connecting); if (tglt_get_double_time () - c->last_receive_time > 6 * PING_TIMEOUT) { warning ("fail connection: reason: ping timeout"); c->state = conn_failed; fail_connection (c); return FALSE; } else if (tglt_get_double_time () - c->last_receive_time > 3 * PING_TIMEOUT && c->state == conn_ready) { tgl_do_send_ping (c->TLS, c); return TRUE; } else { return TRUE; } } static void stop_ping_timer (struct connection *c) { purple_timeout_remove (c->ping_ev); c->ping_ev = -1; } static void start_ping_timer (struct connection *c) { c->ping_ev = purple_timeout_add_seconds (PING_TIMEOUT, ping_alarm, c); } static int fail_alarm (gpointer arg) { struct connection *c = arg; c->in_fail_timer = 0; restart_connection (c); return FALSE; } static void start_fail_timer (struct connection *c) { if (c->in_fail_timer) { return; } c->in_fail_timer = 1; c->fail_ev = purple_timeout_add_seconds (CONNECT_TIMEOUT, fail_alarm, c); } static struct connection_buffer *new_connection_buffer (int size) { struct connection_buffer *b = malloc (sizeof (*b)); memset (b, 0, sizeof (*b)); b->start = malloc (size); b->end = b->start + size; b->rptr = b->wptr = b->start; return b; } static void delete_connection_buffer (struct connection_buffer *b) { free (b->start); free (b); } int tgln_write_out (struct connection *c, const void *_data, int len) { // debug ( "write_out: %d bytes\n", len); const unsigned char *data = _data; if (!len) { return 0; } assert (len > 0); int x = 0; if (!c->out_bytes) { assert (c->write_ev == -1); c->write_ev = purple_input_add (c->fd, PURPLE_INPUT_WRITE, conn_try_write, c); } if (!c->out_head) { struct connection_buffer *b = new_connection_buffer (1 << 20); c->out_head = c->out_tail = b; } while (len) { if (c->out_tail->end - c->out_tail->wptr >= len) { memcpy (c->out_tail->wptr, data, len); c->out_tail->wptr += len; c->out_bytes += len; return x + len; } else { int y = c->out_tail->end - c->out_tail->wptr; assert (y < len); memcpy (c->out_tail->wptr, data, y); x += y; len -= y; data += y; struct connection_buffer *b = new_connection_buffer (1 << 20); c->out_tail->next = b; b->next = 0; c->out_tail = b; c->out_bytes += y; } } return x; } int tgln_read_in (struct connection *c, void *_data, int len) { unsigned char *data = _data; if (!len) { return 0; } assert (len > 0); if (len > c->in_bytes) { len = c->in_bytes; } int x = 0; while (len) { int y = c->in_head->wptr - c->in_head->rptr; if (y > len) { memcpy (data, c->in_head->rptr, len); c->in_head->rptr += len; c->in_bytes -= len; return x + len; } else { memcpy (data, c->in_head->rptr, y); c->in_bytes -= y; x += y; data += y; len -= y; void *old = c->in_head; c->in_head = c->in_head->next; if (!c->in_head) { c->in_tail = 0; } delete_connection_buffer (old); } } return x; } int tgln_read_in_lookup (struct connection *c, void *_data, int len) { unsigned char *data = _data; if (!len || !c->in_bytes) { return 0; } assert (len > 0); if (len > c->in_bytes) { len = c->in_bytes; } int x = 0; struct connection_buffer *b = c->in_head; while (len) { int y = b->wptr - b->rptr; if (y >= len) { memcpy (data, b->rptr, len); return x + len; } else { memcpy (data, b->rptr, y); x += y; data += y; len -= y; b = b->next; } } return x; } void tgln_flush_out (struct connection *c) { } static void rotate_port (struct connection *c) { switch (c->port) { case 443: c->port = 80; break; case 80: c->port = 25; break; case 25: c->port = 443; break; } } static void conn_try_read (gpointer arg, gint source, PurpleInputCondition cond) { struct connection *c = arg; // debug ("Try read. Fd = %d\n", c->fd); try_read (c); } static void conn_try_write (gpointer arg, gint source, PurpleInputCondition cond) { struct connection *c = arg; struct tgl_state *TLS = c->TLS; if (c->state == conn_connecting) { c->state = conn_ready; c->methods->ready (TLS, c); } try_write (c); if (!c->out_bytes) { purple_input_remove (c->write_ev); c->write_ev = -1; } } static void net_on_connected (gpointer arg, gint fd, const gchar *error_message) { struct connection *c = arg; // debug ("connect result: %d\n", fd); if (c->fail_ev >= 0) { purple_timeout_remove (c->fail_ev); c->fail_ev = -1; } if (fd == -1) { const char *msg = "Connection not possible, either your network or a Telegram data center is down, or the" " Telegram network configuration has changed."; warning (msg); return; } c->fd = fd; c->read_ev = purple_input_add (fd, PURPLE_INPUT_READ, conn_try_read, c); unsigned char byte = 0xef; assert (tgln_write_out (c, &byte, 1) == 1); c->last_receive_time = tglt_get_double_time (); start_ping_timer (c); } static void net_on_connected_assert_success (gpointer arg, gint fd, const gchar *error_message) { struct connection *c = arg; if (c->fail_ev >= 0) { purple_timeout_remove (c->fail_ev); c->fail_ev = -1; } if (fd == -1) { struct tgl_state *TLS = c->TLS; info ("Connection to main data center (%d) %s:%d not possible\n", c->dc->id, c->ip, c->port); purple_connection_error_reason (tls_get_conn (TLS), PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Cannot connect to main server")); return; } net_on_connected (arg, fd, error_message); } struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods) { struct connection *c = malloc (sizeof (*c)); memset (c, 0, sizeof (*c)); c->TLS = TLS; c->fd = -1; c->state = conn_connecting; c->last_receive_time = tglt_get_double_time (); c->ip = strdup (host); c->flags = 0; c->port = port; c->ping_ev = -1; c->fail_ev = -1; c->write_ev = -1; c->read_ev = -1; c->dc = dc; c->session = session; c->methods = methods; c->prpl_data = purple_proxy_connect (tls_get_conn (TLS), tls_get_pa (TLS), host, port, TLS->dc_working_num == dc->id ? net_on_connected_assert_success : net_on_connected, c); start_fail_timer (c); return c; } static void restart_connection (struct connection *c) { debug("restart_connection()"); if (tglt_get_double_time () - c->last_receive_time > 6 * PING_TIMEOUT) { purple_connection_error_reason (tls_get_conn (c->TLS), PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Cannot connect to server: Ping timeout.")); return; } purple_proxy_connect_cancel (c->prpl_data); c->prpl_data = purple_proxy_connect (tls_get_conn (c->TLS), tls_get_pa (c->TLS), c->ip, c->port, c->TLS->dc_working_num == c->dc->id ? net_on_connected_assert_success : net_on_connected, c); } static void fail_connection (struct connection *c) { if (c->state == conn_ready) { stop_ping_timer (c); } if (c->write_ev >= 0) { purple_input_remove (c->write_ev); c->write_ev = -1; } if (c->read_ev >= 0) { purple_input_remove (c->read_ev); c->read_ev = -1; } rotate_port (c); struct connection_buffer *b = c->out_head; while (b) { struct connection_buffer *d = b; b = b->next; delete_connection_buffer (d); } b = c->in_head; while (b) { struct connection_buffer *d = b; b = b->next; delete_connection_buffer (d); } c->out_head = c->out_tail = c->in_head = c->in_tail = 0; c->state = conn_failed; c->out_bytes = c->in_bytes = 0; c->prpl_data = NULL; info ("Lost connection to server ... %s:%d\n", c->ip, c->port); purple_connection_error_reason (tls_get_conn (c->TLS), PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Lost connection to the server...")); } static void try_write (struct connection *c) { // debug ("try write: fd = %d\n", c->fd); int x = 0; while (c->out_head) { int r = send (c->fd, (const char *)c->out_head->rptr, c->out_head->wptr - c->out_head->rptr, 0); if (r >= 0) { x += r; c->out_head->rptr += r; if (c->out_head->rptr != c->out_head->wptr) { break; } struct connection_buffer *b = c->out_head; c->out_head = b->next; if (!c->out_head) { c->out_tail = 0; } delete_connection_buffer (b); } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { info ("fail_connection: write_error %s\n", g_strerror(errno)); fail_connection (c); return; } else { break; } } } // debug ("Sent %d bytes to %d\n", x, c->fd); c->out_bytes -= x; } static void try_rpc_read (struct connection *c) { assert (c->in_head); struct tgl_state *TLS = c->TLS; while (1) { if (c->in_bytes < 1) { return; } unsigned len = 0; unsigned t = 0; assert (tgln_read_in_lookup (c, &len, 1) == 1); if (len >= 1 && len <= 0x7e) { if (c->in_bytes < (int)(1 + 4 * len)) { return; } } else { if (c->in_bytes < 4) { return; } assert (tgln_read_in_lookup (c, &len, 4) == 4); len = (len >> 8); if (c->in_bytes < (int)(4 + 4 * len)) { return; } len = 0x7f; } if (len >= 1 && len <= 0x7e) { assert (tgln_read_in (c, &t, 1) == 1); assert (t == len); assert (len >= 1); } else { assert (len == 0x7f); assert (tgln_read_in (c, &len, 4) == 4); len = (len >> 8); assert (len >= 1); } len *= 4; int op; assert (tgln_read_in_lookup (c, &op, 4) == 4); if (c->methods->execute (TLS, c, op, len) < 0) { return; } } } static void try_read (struct connection *c) { // debug ( "try read: fd = %d\n", c->fd); if (!c->in_tail) { c->in_head = c->in_tail = new_connection_buffer (1 << 20); } #ifdef EVENT_V1 struct timeval tv = {5, 0}; event_add (c->read_ev, &tv); #endif int x = 0; while (1) { int r = recv (c->fd, (char *)c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr, 0); if (r > 0) { c->last_receive_time = tglt_get_double_time (); stop_ping_timer (c); start_ping_timer (c); } if (r >= 0) { c->in_tail->wptr += r; x += r; if (c->in_tail->wptr != c->in_tail->end) { break; } struct connection_buffer *b = new_connection_buffer (1 << 20); c->in_tail->next = b; c->in_tail = b; } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { debug ("fail_connection: read_error %s\n", strerror(errno)); fail_connection (c); return; } else { break; } } } // debug ("Received %d bytes from %d\n", x, c->fd); c->in_bytes += x; if (x) { try_rpc_read (c); } } static void incr_out_packet_num (struct connection *c) { c->out_packet_num ++; } static struct tgl_dc *get_dc (struct connection *c) { return c->dc; } static struct tgl_session *get_session (struct connection *c) { return c->session; } static void tgln_free (struct connection *c) { if (c->ip) { free (c->ip); } struct connection_buffer *b = c->out_head; while (b) { struct connection_buffer *d = b; b = b->next; delete_connection_buffer (d); } b = c->in_head; while (b) { struct connection_buffer *d = b; b = b->next; delete_connection_buffer (d); } if (c->ping_ev >= 0) { purple_timeout_remove (c->ping_ev); c->ping_ev = -1; } if (c->fail_ev >= 0) { purple_timeout_remove (c->fail_ev); c->fail_ev = -1; } if (c->read_ev >= 0) { purple_input_remove (c->read_ev); } if (c->write_ev >= 0) { purple_input_remove (c->write_ev); } if (c->fd >= 0) { close (c->fd); } c->fd = -1; } struct tgl_net_methods tgp_conn_methods = { .write_out = tgln_write_out, .read_in = tgln_read_in, .read_in_lookup = tgln_read_in_lookup, .flush_out = tgln_flush_out, .incr_out_packet_num = incr_out_packet_num, .get_dc = get_dc, .get_session = get_session, .create_connection = tgln_create_connection, .free = tgln_free }; telegram-purple/tgp-net.h000066400000000000000000000043171363674160100157260ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2014 */ #ifndef __NET_H__ #define __NET_H__ struct connection_buffer { unsigned char *start; unsigned char *end; unsigned char *rptr; unsigned char *wptr; struct connection_buffer *next; }; enum conn_state { conn_none, conn_connecting, conn_ready, conn_failed, conn_stopped }; struct connection { int fd; char *ip; int port; int flags; enum conn_state state; int ipv6[4]; struct connection_buffer *in_head; struct connection_buffer *in_tail; struct connection_buffer *out_head; struct connection_buffer *out_tail; int in_bytes; int out_bytes; int packet_num; int out_packet_num; int last_connect_time; int in_fail_timer; struct mtproto_methods *methods; struct tgl_state *TLS; struct tgl_session *session; struct tgl_dc *dc; void *extra; int ping_ev; int fail_ev; int read_ev; int write_ev; double last_receive_time; void *prpl_data; }; int tgln_write_out (struct connection *c, const void *data, int len); void tgln_flush_out (struct connection *c); int tgln_read_in (struct connection *c, void *data, int len); int tgln_read_in_lookup (struct connection *c, void *data, int len); extern struct tgl_net_methods tgp_conn_methods; struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods); #define GET_DC(c) (c->session->dc) #endif telegram-purple/tgp-request.c000066400000000000000000000417311363674160100166240ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #include "telegram-purple.h" static struct request_values_data *request_values_data_init (struct tgl_state *TLS, void *callback, void *arg, int num_values) { struct request_values_data *data = talloc0 (sizeof (struct request_values_data)); data->TLS = TLS; data->callback = callback; data->arg = arg; data->num_values = num_values; return data; } static void request_code_entered (struct request_values_data *data, const gchar *code) { char *stripped = g_strstrip (purple_markup_strip_html (code)); debug ("sending code: '%s'\n", stripped); data->callback (data->TLS, (const char **)&stripped, data->arg); g_free (stripped); } static void request_canceled_disconnect (struct request_values_data *data) { purple_connection_error_reason (tls_get_conn (data->TLS), PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, "registration canceled"); free (data); } static void request_canceled (struct request_values_data *data) { free (data); } static void request_code (struct tgl_state *TLS, void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) { debug ("client is not registered, registering..."); char *explanation = _("Telegram wants to verify your " "identity. Please enter the login code that you have received via SMS."); if (purple_account_get_bool (tls_get_pa (TLS), "compat-verification", 0) || !purple_request_input (tls_get_conn (TLS), _("Login code"), _("Enter login code"), explanation, NULL, 0, 0, _("the code"), _("OK"), G_CALLBACK(request_code_entered), _("Cancel"), G_CALLBACK(request_canceled_disconnect), tls_get_pa (TLS), NULL, NULL, request_values_data_init (TLS, callback, arg, 0))) { // the purple request API is not supported, create a new conversation (the Telegram system account "Telegram") to // prompt the user for the code. tls_get_data (TLS)->request_code_data = request_values_data_init (TLS, callback, arg, 0); purple_connection_set_state (tls_get_conn (TLS), PURPLE_CONNECTED); PurpleConversation *conv = purple_conversation_new (PURPLE_CONV_TYPE_IM, tls_get_pa (TLS), "Telegram"); purple_conversation_write (conv, "Telegram", explanation, PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_SYSTEM, 0); } } static void request_name (struct tgl_state *TLS, void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg); static void request_name_code_entered (struct request_values_data *data, PurpleRequestFields* fields) { char *names[] = { g_strdup ("y"), // input line is a y/n choice g_strstrip (g_strdup (purple_request_fields_get_string (fields, "first_name"))), g_strstrip (g_strdup (purple_request_fields_get_string (fields, "last_name"))) }; if (str_not_empty (names[1]) && str_not_empty (names[2])) { data->callback (data->TLS, (const char **) names, data->arg); } else { request_name (data->TLS, data->callback, data->arg); } int j; for (j = 0; j < 3; ++j) { g_free (names[j]); } free (data); } static void request_name (struct tgl_state *TLS, void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) { debug("Phone is not registered, registering..."); PurpleRequestFields *fields = purple_request_fields_new (); PurpleRequestField *field = 0; PurpleRequestFieldGroup *group = purple_request_field_group_new (_("Registration")); field = purple_request_field_string_new ("first_name", _("First name"), "", 0); purple_request_field_group_add_field (group, field); field = purple_request_field_string_new ("last_name", _("Last name"), "", 0); purple_request_field_group_add_field (group, field); purple_request_fields_add_group (fields, group); if (!purple_request_fields (tls_get_conn (TLS), _("Register"), _("Please register your phone number."), NULL, fields, _("OK"), G_CALLBACK(request_name_code_entered), _("Cancel"), G_CALLBACK(request_canceled_disconnect), tls_get_pa (TLS), NULL, NULL, request_values_data_init(TLS, callback, arg, 0))) { // purple_request API not available const char *error = _("Phone number is not registered. Please register your phone on a different client."); purple_connection_error_reason (tls_get_conn (TLS), PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, error); purple_notify_error (_telegram_protocol, _("Not registered"), _("Not registered"), error); } } static void request_password_entered (struct request_values_data *data, char *password) { data->callback (data->TLS, (const char **) &password, data->arg); free (data); } void request_password (struct tgl_state *TLS, void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) { if (! purple_request_input (tls_get_conn (TLS), _("Password needed"), _("Password needed"), _("Enter password for two factor authentication"), NULL, FALSE, TRUE, NULL, _("Ok"), G_CALLBACK(request_password_entered), _("Cancel"), G_CALLBACK(request_canceled_disconnect), tls_get_pa (TLS), NULL, NULL, request_values_data_init (TLS, callback, arg, 0))) { const char *error = _("No password set for two factor authentication. Please enter it in the extended settings."); purple_connection_error_reason (tls_get_conn (TLS), PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, error); purple_notify_error (_telegram_protocol, _("Password invalid"), _("Password invalid"), error); } } static void accept_secret_chat_cb (struct accept_secret_chat_data *data) { tgl_do_accept_encr_chat_request (data->TLS, data->U, write_secret_chat_gw, 0); free (data); } static void decline_secret_chat_cb (struct accept_secret_chat_data *data) { bl_do_peer_delete (data->TLS, data->U->id); purple_blist_remove_buddy (tgp_blist_buddy_find (data->TLS, data->U->id)); free (data); } void request_accept_secret_chat (struct tgl_state *TLS, struct tgl_secret_chat *U) { tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER(U->user_id)); g_return_if_fail (P); struct accept_secret_chat_data *data = talloc0 (sizeof (struct accept_secret_chat_data)); data->TLS = TLS; data->U = U; gchar *message = g_strdup_printf (_("Accept secret chat '%s' on this device?"), U->print_name); purple_request_accept_cancel (tls_get_conn (TLS), _("Secret chat"), message, _("Secret chats can only have one " "end point. If you accept a secret chat on this device, its messages will not be available anywhere " "else. If you decline, you can still accept the chat on other devices."), 0, tls_get_pa (TLS), P->print_name, NULL, data, G_CALLBACK(accept_secret_chat_cb), G_CALLBACK(decline_secret_chat_cb)); g_free (message); } static void create_group_chat_cb (struct request_values_data *data, PurpleRequestFields* fields) { // FIXME: Oh god. const char *users[3] = { purple_request_fields_get_string (fields, "user1"), purple_request_fields_get_string (fields, "user2"), purple_request_fields_get_string (fields, "user3") }; tgp_create_group_chat_by_usernames (data->TLS, data->arg, users, 3, FALSE); g_free (data->arg); free (data); } static void cancel_group_chat_cb (struct request_values_data *data) { g_free (data->arg); free (data); } void request_create_chat (struct tgl_state *TLS, const char *subject) { // Telegram doesn't allow to create chats with only one user, so we need to force // the user to specify at least one other one. PurpleRequestFields* fields = purple_request_fields_new (); PurpleRequestFieldGroup* group = purple_request_field_group_new ( _("Invite at least one additional user by specifying\n their full name (autocompletion available).\nYou can add more users once" " the chat was created.")); PurpleRequestField *field = purple_request_field_string_new ("user1", _("Username"), NULL, FALSE); purple_request_field_set_type_hint (field, "screenname"); purple_request_field_group_add_field (group, field); field = purple_request_field_string_new ("user2", _("Username"), NULL, FALSE); purple_request_field_set_type_hint (field, "screenname"); purple_request_field_group_add_field (group, field); field = purple_request_field_string_new ("user3", _("Username"), NULL, FALSE); purple_request_field_set_type_hint (field, "screenname"); purple_request_field_group_add_field (group, field); purple_request_fields_add_group (fields, group); purple_request_fields (tls_get_conn (TLS), _("Create group chat"), _("Invite users"), NULL, fields, _("OK"), G_CALLBACK(create_group_chat_cb), _("Cancel"), G_CALLBACK(cancel_group_chat_cb), tls_get_pa (TLS), NULL, NULL, request_values_data_init (TLS, NULL, (void *) g_strdup (subject), 0)); } static void request_cur_and_new_password_ok (struct request_values_data *data, PurpleRequestFields* fields) { const char *names[3] = { purple_request_fields_get_string (fields, "current"), purple_request_fields_get_string (fields, "new1"), purple_request_fields_get_string (fields, "new2") }; data->callback(data->TLS, names, data->arg); free (data); } void request_cur_and_new_password (struct tgl_state *TLS, void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) { PurpleRequestFields* fields = purple_request_fields_new (); PurpleRequestFieldGroup* group = purple_request_field_group_new (_("Change password")); PurpleRequestField *field = purple_request_field_string_new ("current", _("Current"), NULL, FALSE); purple_request_field_string_set_masked (field, TRUE); purple_request_field_group_add_field (group, field); field = purple_request_field_string_new ("new1", _("Password"), NULL, FALSE); purple_request_field_string_set_masked (field, TRUE); purple_request_field_group_add_field (group, field); field = purple_request_field_string_new ("new2", _("Confirm"), NULL, FALSE); purple_request_field_string_set_masked (field, TRUE); purple_request_field_group_add_field (group, field); purple_request_fields_add_group (fields, group); purple_request_fields (tls_get_conn (TLS), _("Change password"), _("Change password"), NULL, fields, _("OK"), G_CALLBACK(request_cur_and_new_password_ok), _("Cancel"), G_CALLBACK(request_canceled), tls_get_pa (TLS), NULL, NULL, request_values_data_init (TLS, callback, arg, 0)); } static void request_new_password_ok (struct request_values_data *data, PurpleRequestFields* fields) { const char *names[2] = { purple_request_fields_get_string (fields, "new1"), purple_request_fields_get_string (fields, "new2") }; data->callback(data->TLS, names, data->arg); free (data); } void request_new_password (struct tgl_state *TLS, void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) { PurpleRequestFields* fields = purple_request_fields_new (); PurpleRequestFieldGroup* group = purple_request_field_group_new (_("New password")); PurpleRequestField * field = purple_request_field_string_new ("new1", _("Password"), NULL, FALSE); purple_request_field_string_set_masked (field, TRUE); purple_request_field_group_add_field (group, field); field = purple_request_field_string_new ("new2", _("Confirm"), NULL, FALSE); purple_request_field_string_set_masked (field, TRUE); purple_request_field_group_add_field (group, field); purple_request_fields_add_group (fields, group); purple_request_fields (tls_get_conn (TLS), _("New password"), _("New password"), NULL, fields, _("OK"), G_CALLBACK(request_new_password_ok), _("Cancel"), G_CALLBACK(request_canceled), tls_get_pa (TLS), NULL, NULL, request_values_data_init (TLS, callback, arg, 0)); } void request_value (struct tgl_state *TLS, enum tgl_value_type type, const char *prompt, int num_values, void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) { debug ("tgl requests user input, tgl_value_type: %d, prompt: %s, count: %d", type, prompt, num_values); switch (type) { case tgl_cur_password: { const char *P = purple_account_get_string (tls_get_pa(TLS), TGP_KEY_PASSWORD_TWO_FACTOR, NULL); if (str_not_empty (P)) { if (tls_get_data (TLS)->password_retries ++ < 1) { callback (TLS, &P, arg); return; } } request_password (TLS, callback, arg); break; } case tgl_cur_and_new_password: request_cur_and_new_password (TLS, callback, arg); break; case tgl_new_password: request_new_password (TLS, callback, arg); break; case tgl_register_info: request_name (TLS, callback, arg); break; case tgl_code: request_code (TLS, callback, arg); break; case tgl_phone_number: { // if we arrive here for the second time the specified phone number is not valid. We do not // ask for the phone number directly, cause in that case the account would still be created // named with the invalid phone number, even though the login will work tgp_error_if_false (TLS, tls_get_data (TLS)->login_retries++ < 1, _("Invalid phone number"), _("Please enter only numbers in the international phone number format, " "a leading + following by the country prefix and the phone number.\n" "Do not use any other special chars.")); const char *username = purple_account_get_username (tls_get_pa (TLS)); callback (TLS, &username, arg); break; } case tgl_bot_hash: assert (FALSE && "we are not a bot"); break; } } // delete contact static void request_delete_contact_ok (struct request_values_data *data, PurpleRequestFields* fields) { tgl_peer_t *P = data->arg; g_return_if_fail(P); switch (tgl_get_peer_type (P->id)) { case TGL_PEER_CHAT: g_warn_if_fail (P->chat.flags & TGLCF_LEFT); leave_and_delete_chat (data->TLS, P); break; case TGL_PEER_ENCR_CHAT: tgl_do_discard_secret_chat (data->TLS, &P->encr_chat, NULL, NULL); break; case TGL_PEER_USER: g_warn_if_fail(P->user.flags & TGLUF_CONTACT); tgl_do_del_contact (data->TLS, P->id, tgp_notify_on_error_gw, NULL); break; case TGL_PEER_CHANNEL: g_warn_if_fail(P->channel.flags & TGLCHF_CREATOR); if (! (P->channel.flags & TGLCHF_LEFT)) { tgl_do_leave_channel (data->TLS, P->id, tgp_notify_on_error_gw, NULL); } break; default: g_warn_if_reached(); break; } free (data); } static void request_delete_contact_cancel (struct request_values_data *data, PurpleRequestFields* fields) { free (data); } void tgprpl_request_delete_contact (PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { const char *title1 = NULL, *title2 = NULL, *msg = NULL; g_return_if_fail(buddy); struct tgl_state *TLS = gc_get_tls (gc); tgl_peer_t *P = tgp_blist_buddy_get_peer (buddy); g_return_if_fail(P); switch (tgl_get_peer_type (P->id)) { case TGL_PEER_CHAT: if (! (P->chat.flags & TGLCF_LEFT)) { title1 = _("Leave Chat"); title2 = title1; msg = _("Do you want to leave this chat permanently?"); } break; case TGL_PEER_ENCR_CHAT: title1 = _("Abort Secret Chat"); title2 = title1; msg = _("Do you want to terminate this secret chat permanently?"); break; case TGL_PEER_USER: if (P->user.flags & TGLUF_CONTACT) { title1 = _("Delete Contact"); title2 = title1; msg = _("Do you want to remove this user from your global contact list?"); } break; case TGL_PEER_CHANNEL: if (P->channel.flags & TGLCHF_CREATOR) { /* FIXME: Support destorying channels title1 = _("Destroy Channel"); title2 = title1; msg = _("You are admin of this channel, do you want to delete it permanently?"); */ } else { if (! (P->channel.flags & TGLCHF_LEFT)) { title1 = _("Leave Channel"); title2 = title1; msg = _("Do you want to leave this channel?"); } } break; default: g_warn_if_reached(); break; } if (msg) { purple_request_ok_cancel(tls_get_conn (TLS), title1, title2, msg, 0, tls_get_pa (TLS), tgp_blist_lookup_purple_name (TLS, P->id), NULL, (void *) request_values_data_init (TLS, 0, P, 0), request_delete_contact_ok, request_delete_contact_cancel); } } // add new contact void request_add_contact (struct tgl_state *TLS) { } telegram-purple/tgp-request.h000066400000000000000000000031111363674160100166170ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #ifndef tgp_request_h #define tgp_request_h #include #include #include "tgp-structs.h" struct request_values_data { struct tgl_state *TLS; void (*callback) (struct tgl_state *TLS, const char *string[], void *arg); void *arg; int num_values; }; struct accept_secret_chat_data { struct tgl_state *TLS; struct tgl_secret_chat *U; }; void request_value (struct tgl_state *TLS, enum tgl_value_type type, const char *prompt, int num_values, void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg); void request_accept_secret_chat (struct tgl_state *TLS, struct tgl_secret_chat *U); void request_create_chat (struct tgl_state *TLS, const char *subject); void tgprpl_request_delete_contact (PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); #endif telegram-purple/tgp-structs.c000066400000000000000000000117321363674160100166410ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #include "telegram-base.h" static void tgl_do_mark_read_gw (gpointer key, gpointer value, gpointer data) { tgl_peer_id_t to = * (tgl_peer_id_t *)value; info ("tgl_do_mark_read (%d)", tgl_get_peer_id (to)); tgl_do_mark_read ((struct tgl_state *) data, to, tgp_notify_on_error_gw, NULL); } void pending_reads_send_all (struct tgl_state *TLS) { if (! purple_account_get_bool (tls_get_pa (TLS), TGP_KEY_SEND_READ_NOTIFICATIONS, TGP_DEFAULT_SEND_READ_NOTIFICATIONS)) { debug ("automatic read recipes disabled, not sending recipes"); return; } if (! p2tgl_status_is_present (purple_account_get_active_status (tls_get_pa (TLS)))) { debug ("user is not present, not sending recipes"); return; } debug ("sending all pending recipes"); g_hash_table_foreach (tls_get_data (TLS)->pending_reads, tgl_do_mark_read_gw, TLS); g_hash_table_remove_all (tls_get_data (TLS)->pending_reads); } void pending_reads_send_user (struct tgl_state *TLS, tgl_peer_id_t id) { if (g_hash_table_remove (tls_get_data (TLS)->pending_reads, GINT_TO_POINTER (tgl_get_peer_id (id)))) { info ("tgl_do_mark_read (%d)", tgl_get_peer_id (id)); tgl_do_mark_read (TLS, id, tgp_notify_on_error_gw, NULL); } } void pending_reads_add (struct tgl_state *TLS, struct tgl_message *M) { tgl_peer_id_t *copy = g_new (tgl_peer_id_t, 1); if (tgl_get_peer_type (M->to_id) == TGL_PEER_USER) { *copy = M->from_id; } else { *copy = M->to_id; } g_hash_table_replace (tls_get_data (TLS)->pending_reads, GINT_TO_POINTER (tgl_get_peer_id (*copy)), copy); } static void used_image_free (gpointer data) { purple_imgstore_unref_by_id (GPOINTER_TO_INT(data)); } void used_images_add (connection_data *data, gint imgid) { data->used_images = g_list_append (data->used_images, GINT_TO_POINTER(imgid)); } void tgp_msg_loading_free (gpointer data) { struct tgp_msg_loading *C = data; free (C); } struct tgp_msg_loading *tgp_msg_loading_init (struct tgl_message *M) { struct tgp_msg_loading *C = talloc0 (sizeof (struct tgp_msg_loading)); C->pending = 0; C->msg = M; C->data = NULL; return C; } struct tgp_msg_sending *tgp_msg_sending_init (struct tgl_state *TLS, char *M, tgl_peer_id_t to) { struct tgp_msg_sending *C = malloc (sizeof (struct tgp_msg_sending)); C->TLS = TLS; C->msg = M; C->to = to; return C; } void tgp_msg_sending_free (gpointer data) { struct tgp_msg_sending *C = data; if (C->msg) { g_free (C->msg); } free (C); } connection_data *connection_data_init (struct tgl_state *TLS, PurpleConnection *gc, PurpleAccount *pa) { connection_data *conn = g_new0 (connection_data, 1); conn->TLS = TLS; conn->gc = gc; conn->pa = pa; conn->new_messages = g_queue_new (); conn->out_messages = g_queue_new (); conn->pending_reads = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); conn->pending_chat_info = g_hash_table_new (g_direct_hash, g_direct_equal); conn->pending_channels = g_hash_table_new (g_direct_hash, g_direct_equal); conn->id_to_purple_name = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); conn->purple_name_to_id = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); conn->channel_members = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (void (*) (gpointer)) g_list_free); return conn; } void *connection_data_free (connection_data *conn) { if (conn->write_timer) { purple_timeout_remove (conn->write_timer); } if (conn->login_timer) { purple_timeout_remove (conn->login_timer); } if (conn->out_timer) { purple_timeout_remove (conn->out_timer); } tgp_g_queue_free_full (conn->new_messages, tgp_msg_loading_free); tgp_g_queue_free_full (conn->out_messages, tgp_msg_sending_free); tgp_g_list_free_full (conn->used_images, used_image_free); tgp_g_list_free_full (conn->pending_joins, g_free); g_hash_table_destroy (conn->pending_reads); g_hash_table_destroy (conn->pending_chat_info); g_hash_table_destroy (conn->pending_channels); g_hash_table_destroy (conn->id_to_purple_name); g_hash_table_destroy (conn->purple_name_to_id); g_hash_table_destroy (conn->channel_members); tgprpl_xfer_free_all (conn); g_free (conn->TLS->base_path); tgl_free_all (conn->TLS); free (conn); return NULL; } telegram-purple/tgp-structs.h000066400000000000000000000047661363674160100166570ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #ifndef __telegram_adium__tgp_data__ #define __telegram_adium__tgp_data__ #include "purple.h" #include #include typedef struct { struct tgl_state *TLS; char *hash; PurpleAccount *pa; PurpleConnection *gc; int updated; GQueue *new_messages; GQueue *out_messages; GHashTable *pending_reads; GList *used_images; guint write_timer; guint login_timer; guint out_timer; struct request_values_data *request_code_data; int password_retries; int login_retries; PurpleRoomlist *roomlist; GHashTable *pending_chat_info; GHashTable *pending_channels; GHashTable *id_to_purple_name; GHashTable *purple_name_to_id; GHashTable *channel_members; GList *pending_joins; int dialogues_ready; } connection_data; struct tgp_xfer_send_data { int timer; int loading; PurpleXfer *xfer; connection_data *conn; struct tgl_message *msg; }; struct tgp_msg_loading { int pending; struct tgl_message *msg; void *data; int error; char *error_msg; }; struct tgp_msg_sending { struct tgl_state *TLS; tgl_peer_id_t to; gchar *msg; }; void pending_reads_send_all (struct tgl_state *TLS); void pending_reads_add (struct tgl_state *TLS, struct tgl_message *M); void pending_reads_send_user (struct tgl_state *TLS, tgl_peer_id_t id); void used_images_add (connection_data *data, gint imgid); void *connection_data_free (connection_data *conn); connection_data *connection_data_init (struct tgl_state *TLS, PurpleConnection *gc, PurpleAccount *pa); struct tgp_msg_loading *tgp_msg_loading_init (struct tgl_message *M); struct tgp_msg_sending *tgp_msg_sending_init (struct tgl_state *TLS, char *M, tgl_peer_id_t to); void tgp_msg_loading_free (gpointer data); void tgp_msg_sending_free (gpointer data); #endif telegram-purple/tgp-timers.c000066400000000000000000000041061363674160100164320ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #include #include #include #include struct tgl_timer { struct tgl_state *TLS; void (*cb)(struct tgl_state *, void *); void *arg; int fd; }; static int timer_alarm (gpointer arg) { struct tgl_timer *t = arg; t->fd = -1; t->cb (t->TLS, t->arg); return FALSE; } static struct tgl_timer *tgl_timer_alloc (struct tgl_state *TLS, void (*cb)(struct tgl_state *TLS, void *arg), void *arg) { struct tgl_timer *t = malloc (sizeof (*t)); t->TLS = TLS; t->cb = cb; t->arg = arg; t->fd = -1; return t; } static void tgl_timer_delete (struct tgl_timer *t); static void tgl_timer_insert (struct tgl_timer *t, double p) { tgl_timer_delete (t); if (p < 0) { p = 0; } if (p < 1) { t->fd = purple_timeout_add (1000 * p, timer_alarm, t); } else { t->fd = purple_timeout_add_seconds (p, timer_alarm, t); } } static void tgl_timer_delete (struct tgl_timer *t) { if (t->fd >= 0) { purple_timeout_remove (t->fd); t->fd = -1; } } static void tgl_timer_free (struct tgl_timer *t) { if (t->fd >= 0) { tgl_timer_delete (t); } free (t); } struct tgl_timer_methods tgp_timers = { .alloc = tgl_timer_alloc, .insert = tgl_timer_insert, .remove = tgl_timer_delete, .free = tgl_timer_free }; telegram-purple/tgp-timers.h000066400000000000000000000016721363674160100164440ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2014 */ #ifndef __TGL_TIMERS_H__ #define __TGL_TIMERS_H__ #include "tgl.h" extern struct tgl_timer_methods tgp_timers; #endif telegram-purple/tgp-utils.c000066400000000000000000000073311363674160100162720ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #include "telegram-purple.h" const char *format_time (time_t date) { // TODO: Inline this function for better readability? struct tm *datetime = localtime(&date); // This should be the language's timestamp format. This is preceded by a colon. return purple_utf8_strftime (_("%d.%m.%Y %H:%M"), datetime); } char *tgp_format_img (int imgstore) { const char *br = "
"; //
's look ugly in Adium, but no
will look ugly in Pidgin #ifdef __ADIUM_ br = ""; #endif return g_strdup_printf ("%s", br, imgstore); } char *tgp_format_user_status (struct tgl_user_status *status) { char *when; switch (status->online) { case -1: when = g_strdup_printf ("%s", format_time (status->when)); break; case -2: // This is preceded by a colon. when = g_strdup (_("recently")); break; case -3: // This is preceded by a colon. when = g_strdup (_("last week")); break; case -4: // This is preceded by a colon. when = g_strdup (_("last month")); break; default: // This is preceded by a colon. It refers to a point on time. when = g_strdup (_("unknown")); break; } return when; } int str_not_empty (const char *string) { return string && string[0] != '\0'; } int tgp_outgoing_msg (struct tgl_state *TLS, struct tgl_message *M) { return (M->flags & TGLMF_SESSION_OUTBOUND); } int tgp_our_msg (struct tgl_state *TLS, struct tgl_message *M) { return tgl_get_peer_id (TLS->our_id) == tgl_get_peer_id (M->from_id); } tgl_peer_t *tgp_encr_chat_get_partner (struct tgl_state *TLS, struct tgl_secret_chat *chat) { return tgl_peer_get (TLS, TGL_MK_USER(chat->admin_id == tgl_get_peer_id (TLS->our_id) ? chat->user_id : chat->admin_id)); } long tgp_time_n_days_ago (int days) { return time(NULL) - 24 * 3600 * days; }; void tgp_g_queue_free_full (GQueue *queue, GDestroyNotify free_func) { void *entry; while ((entry = g_queue_pop_head(queue))) { free_func (entry); } g_queue_free (queue); } #if GLIB_CHECK_VERSION(2,28,0) void tgp_g_list_free_full (GList *list, GDestroyNotify free_func) { if (list) { g_list_free_full (list, free_func); } } #else void tgp_g_list_free_full (GList *list, GDestroyNotify free_func) { if (list) { g_list_foreach (list, (GFunc)free_func, NULL); g_list_free (list); } } #endif const char *tgp_mime_to_filetype (const char *mime) { int len = (int) strlen (mime); int i; for (i = 0; i < len - 1; i ++) { if (mime[i] == '/') { return mime + i + 1; } } return NULL; } int tgp_startswith (const char *str, const char *with) { if (! str || !with) { return FALSE; } int slen = strlen (str), wlen = strlen (with); if (wlen > slen) { return FALSE; } while (*with) if (*str++ != *with++) { return FALSE; } return TRUE; } void tgp_replace (char *string, char what, char with) { char *p = string; while (*(p ++)) { if (*p == what) { *p = with; } } } telegram-purple/tgp-utils.h000066400000000000000000000035051363674160100162760ustar00rootroot00000000000000/* This file is part of telegram-purple 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 02111-1301 USA Copyright Matthias Jentsch 2014-2015 */ #ifndef __telegram_adium__tgp_util__ #define __telegram_adium__tgp_util__ #include "tgp-structs.h" #include #include #include #include tgl_peer_t *tgp_encr_chat_get_partner (struct tgl_state *TLS, struct tgl_secret_chat *chat); /** * Return whether this message was created by our client in this session */ int tgp_outgoing_msg (struct tgl_state *TLS, struct tgl_message *M); /** * Return whether this message was created by the current user */ int tgp_our_msg (struct tgl_state *TLS, struct tgl_message *M); const char *format_time (time_t date); char *tgp_format_img (int imgstore); char *tgp_format_user_status (struct tgl_user_status *status); int str_not_empty (const char *string); long tgp_time_n_days_ago (int days); void tgp_g_queue_free_full (GQueue *queue, GDestroyNotify free_func); void tgp_g_list_free_full (GList *list, GDestroyNotify free_func); const char *tgp_mime_to_filetype (const char *mime); int tgp_startswith (const char *str, const char *with); void tgp_replace (char *string, char what, char with); #endif pax_global_header00006660000000000000000000000064135722720010014511gustar00rootroot0000000000000052 comment=05f34091e8273d9689a882e2d16d1fda94b29331 telegram-purple/tgl/000077500000000000000000000000001357227200100147505ustar00rootroot00000000000000telegram-purple/tgl/.gitignore000066400000000000000000000001501357227200100167340ustar00rootroot00000000000000Makefile autom4te.cache config.h config.log config.status .idea/ nbproject/ bin/ objs/ dep/ auto/ libs/ telegram-purple/tgl/.travis.yml000066400000000000000000000001131357227200100170540ustar00rootroot00000000000000language: c compiler: - gcc - clang script: - ./configure - make telegram-purple/tgl/CHANGELOG000066400000000000000000000011051357227200100161570ustar00rootroot000000000000002.0.3 * updated to layer 31 (bot support) * changed signature of contact_search method 2.0.2 * fixed small bugs * added block/unblock user method 2.0.1 * store error code for last operation in TLS->error/TLS->error_code * make interface more consitent * deleted outdated *_ex functions * fixed bugs * support for layer 28: * support for new pts system * support for new read system * support for passwords * support replies * support photo captions * support group links 1.2.1 * fixed registration/login problem * added extension to downloads 1.2.0 * layer 22 support telegram-purple/tgl/LICENSE000066400000000000000000000624251357227200100157660ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. one line to give the library's name and an idea of what it does. Copyright (C) year name of author This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. signature of Ty Coon, 1 April 1990 Ty Coon, President of Vice That's all there is to it! telegram-purple/tgl/Makefile.in000066400000000000000000000123471357227200100170240ustar00rootroot00000000000000srcdir=@srcdir@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ @OPENSSL_LDFLAGS@ CPPFLAGS=@CPPFLAGS@ @OPENSSL_INCLUDES@ DEFS=@DEFS@ COMPILE_FLAGS=${CFLAGS} ${CPFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -Wno-unused-parameter -fPIC -D_FORTIFY_SOURCE=2 EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ @OPENSSL_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} DEP=dep AUTO=auto OBJ=objs LIB=libs EXE=bin DIR_LIST=${DEP} ${DEP}/crypto ${AUTO} ${EXE} ${OBJ} ${OBJ}/crypto ${LIB} ${DEP}/auto ${OBJ}/auto LIB_LIST=${LIB}/libtgl.a ${LIB}/libtgl.so TGL_OBJECTS=${OBJ}/mtproto-common.o ${OBJ}/mtproto-client.o ${OBJ}/mtproto-key.o ${OBJ}/queries.o ${OBJ}/structures.o ${OBJ}/binlog.o ${OBJ}/tgl.o ${OBJ}/updates.o ${OBJ}/tg-mime-types.o ${OBJ}/mtproto-utils.o ${OBJ}/crypto/bn_openssl.o ${OBJ}/crypto/bn_altern.o ${OBJ}/crypto/rsa_pem_openssl.o ${OBJ}/crypto/rsa_pem_altern.o ${OBJ}/crypto/md5_openssl.o ${OBJ}/crypto/md5_altern.o ${OBJ}/crypto/sha_openssl.o ${OBJ}/crypto/sha_altern.o ${OBJ}/crypto/aes_openssl.o ${OBJ}/crypto/aes_altern.o @EXTRA_OBJECTS@ TGL_OBJECTS_AUTO=${OBJ}/auto/auto-skip.o ${OBJ}/auto/auto-fetch.o ${OBJ}/auto/auto-store.o ${OBJ}/auto/auto-autocomplete.o ${OBJ}/auto/auto-types.o ${OBJ}/auto/auto-fetch-ds.o ${OBJ}/auto/auto-free-ds.o ${OBJ}/auto/auto-store-ds.o ${OBJ}/auto/auto-print-ds.o TLD_OBJECTS=${OBJ}/dump-tl-file.o GENERATE_OBJECTS=${OBJ}/generate.o COMMON_OBJECTS=${OBJ}/tools.o ${OBJ}/crypto/rand_openssl.o ${OBJ}/crypto/rand_altern.o ${OBJ}/crypto/err_openssl.o ${OBJ}/crypto/err_altern.o OBJ_C=${GENERATE_OBJECTS} ${COMMON_OBJECTS} ${TGL_OBJECTS} ${TLD_OBJECTS} DEPENDENCE=$(subst ${OBJ}/,${DEP}/,$(patsubst %.o,%.d,${OBJ_C})) DEPENDENCE_LIST=${DEPENDENCE} INCLUDE=-I. -I${srcdir} CC=@CC@ AR=@AR@ # Check if -fstack-protector-strong is supported before enabling it STACK_PROTECTOR_UNSUPPORTED = $(shell $(CC) -fstack-protector-strong 2>&1 | grep -c 'stack-protector-strong') ifeq "$(STACK_PROTECTOR_UNSUPPORTED)" "0" CFLAGS += -fstack-protector-strong endif # Check if -frandom-seed is supported before enabling it RANDOM_SEED_UNSUPPORTED = $(shell $(CC) -frandom-seed=77e0418a98676b76729b50fe91cc1f250c14fd8f664f8430649487a6f918926d 2>&1 | grep -c 'random-seed') ifeq "$(RANDOM_SEED_UNSUPPORTED)" "0" CFLAGS += -frandom-seed=0x$$(sha256sum $< | cut -f1 -d" ") endif # Check if -ffile-prefix-map is supported before enabling it FILE_PREFIX_MAP_UNSUPPORTED = $(shell $(CC) -ffile-prefix-map=/foo/bar/baz=/quux 2>&1 | grep -c 'file-prefix-map') ifeq "$(FILE_PREFIX_MAP_UNSUPPORTED)" "0" # FIXME CFLAGS += "-ffile-prefix-map=$(realpath ${srcdir})=tgl" endif .SUFFIXES: .SUFFIXES: .c .h .o all: ${LIB_LIST} create_dirs_and_headers: ${DIR_LIST} ${AUTO}/auto-skip.h ${AUTO}/auto-fetch.h ${AUTO}/auto-store.h ${AUTO}/auto-autocomplete.h ${AUTO}/auto-types.h create_dirs: ${DIR_LIST} dump-tl: ${EXE}/dump-tl-file include ${srcdir}/Makefile.tl-parser ${DIR_LIST}: @test -d $@ || mkdir -p $@ -include ${DEPENDENCE_LIST} ${TGL_OBJECTS}: ${AUTO}/constants.h ${AUTO}/auto-skip.h ${AUTO}/auto-fetch.h ${AUTO}/auto-store.h ${AUTO}/auto-autocomplete.h ${AUTO}/auto-types.h ${AUTO}/auto-fetch-ds.h ${AUTO}/auto-free-ds.h ${AUTO}/auto-store-ds.h ${AUTO}/auto-print-ds.h ${OBJ_C}: ${OBJ}/%.o: ${srcdir}/%.c | create_dirs ${CC} ${INCLUDE} ${COMPILE_FLAGS} -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $< ${TGL_OBJECTS_AUTO}: ${OBJ}/auto/%.o: ${AUTO}/%.c | create_dirs ${CC} ${INCLUDE} ${COMPILE_FLAGS} -iquote ${srcdir}/tgl -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $< ${LIB}/libtgl.a: ${TGL_OBJECTS} ${COMMON_OBJECTS} ${TGL_OBJECTS_AUTO} rm -f $@ && ${AR} ruv $@ $^ ${LIB}/libtgl.so: ${TGL_OBJECTS} ${COMMON_OBJECTS} ${TGL_OBJECTS_AUTO} ${CC} -shared -o $@ $^ ${LINK_FLAGS} ${EXE}/generate: ${GENERATE_OBJECTS} ${COMMON_OBJECTS} ${CC} ${GENERATE_OBJECTS} ${COMMON_OBJECTS} ${LINK_FLAGS} -o $@ ${AUTO}/scheme.tlo: ${AUTO}/scheme.tl ${EXE}/tl-parser ${EXE}/tl-parser -e $@ ${AUTO}/scheme.tl ${AUTO}/scheme.tl: ${srcdir}/scheme.tl ${srcdir}/encrypted_scheme.tl ${srcdir}/binlog.tl ${srcdir}/mtproto.tl ${srcdir}/append.tl | ${AUTO} cat $^ > $@ ${AUTO}/scheme2.tl: ${AUTO}/scheme.tl ${EXE}/tl-parser ${EXE}/tl-parser -E ${AUTO}/scheme.tl 2> $@ || ( cat $@ && rm $@ && false ) ${AUTO}/auto.c: ${AUTO}/scheme.tlo ${EXE}/generate ${EXE}/generate ${AUTO}/scheme.tlo > $@ ${AUTO}/auto-%.c: ${AUTO}/scheme.tlo ${EXE}/generate auto/constants.h ${AUTO}/auto-%.h | create_dirs_and_headers ${EXE}/generate -g $(patsubst ${AUTO}/auto-%.c,%,$@) ${AUTO}/scheme.tlo > $@ || ( rm $@ && false ) ${AUTO}/auto-%.h: ${AUTO}/scheme.tlo ${EXE}/generate ${EXE}/generate -g $(patsubst ${AUTO}/auto-%.h,%-header,$@) ${AUTO}/scheme.tlo > $@ || ( rm $@ && false ) ${AUTO}/constants.h: ${AUTO}/scheme2.tl ${srcdir}/gen_constants_h.awk awk -f ${srcdir}/gen_constants_h.awk < $< > $@ ${EXE}/dump-tl-file: ${OBJ}/auto/auto.o ${TLD_OBJECTS} ${CC} ${OBJ}/auto/auto.o ${TLD_OBJECTS} ${LINK_FLAGS} -o $@ clean: rm -rf ${DIR_LIST} distclean: rm -rf ${DIR_LIST} config.h config.log config.status mime-types.c: mime.types @echo xxd -i mime.types > mime-types.c @if command -v xxd >/dev/null 2>&1 ; then \ xxd -i mime.types > mime-types.c ; \ else \ echo "# No xxd installed! Trying to skip ..." ; \ test -r $@ ; \ fi telegram-purple/tgl/Makefile.tl-parser000066400000000000000000000004641357227200100203240ustar00rootroot00000000000000TL_PARSER_OBJECTS=${OBJ}/tl-parser.o ${OBJ}/tlc.o ${TL_PARSER_OBJECTS}: ${OBJ}/%.o: ${srcdir}/tl-parser/%.c | create_dirs ${CC} ${INCLUDE} ${COMPILE_FLAGS} -iquote ${srcdir}/tl-parser -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $< ${EXE}/tl-parser: ${TL_PARSER_OBJECTS} ${CC} $^ ${LINK_FLAGS} -o $@ telegram-purple/tgl/README.md000066400000000000000000000033511357227200100162310ustar00rootroot00000000000000# Telegram library This is library that handles Telegram API and protocol. > This is a fork of [vysheng's repository](https://github.com/vysheng/tgl). This variant focuses mostly on the use for the [purple plugin](https://github.com/majn/telegram-purple). If you're looking for client CLI implementation, check [TG repository](https://github.com/vysheng/tg) instead. Build status: | Repository | Status| | ------------------------------------------------------ | ----- | | [vysheng](https://github.com/vysheng/tgl) (main) | [![Build Status](https://travis-ci.org/vysheng/tgl.svg)](https://travis-ci.org/vysheng/tgl) | | [kenorb-contrib](https://github.com/kenorb-contrib/tgl) | [![Build Status](https://travis-ci.org/kenorb-contrib/tgl.svg)](https://travis-ci.org/kenorb-contrib/tgl) | | [majn](https://github.com/majn/tgl) | [![Build Status](https://travis-ci.org/majn/tgl.svg)](https://travis-ci.org/majn/tgl) | Current versions: - `scheme.tl`: Layer 38 - `encrypted_scheme.tl`: Layer 23 ### API, Protocol documentation Documentation for Telegram API is available here: https://core.telegram.org/api Documentation for MTproto protocol is available here: https://core.telegram.org/mtproto ### Installation Clone this GitHub repository with `--recursive` parameter to clone submodules. git clone --recursive https://github.com/majn/tgl.git && cd tgl #### Linux and BSDs Install libs: openssl, zlib if you want to use provided net/timers then install libevent and add --enable-libevent key to configure You can also avoid the OpenSSL dependency: Install gcrypt (>= 1.60, Debian derivates know it as "libgcrypt20-dev"), and add --disable-openssl key to configure Then, ./configure make telegram-purple/tgl/append.tl000066400000000000000000000011201357227200100165520ustar00rootroot00000000000000---types--- decryptedMessageMediaVideoL12#4cee6ef3 str_thumb:bytes thumb_w:int thumb_h:int duration:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageMediaAudioL12#6080758f duration:int size:int key:bytes iv:bytes = DecryptedMessageMedia; updateMsgUpdate id:int pts:int pts_count:int = Update; messageMediaPhotoL27#c8c45a2a photo:Photo = MessageMedia; messageMediaVideoL27#a2d24290 video:Video = MessageMedia; //messageMediaDocumentL27#2fda2204 document:Document = MessageMedia; //messageMediaAudioL27#c6b68300 audio:Audio = MessageMedia; ---functions--- telegram-purple/tgl/auto-static-autocomplete.c000066400000000000000000000034571357227200100220610ustar00rootroot00000000000000#include #include "config.h" #define IN_AUTOCOMPLETE_H #include "auto-static-store.c" #undef IN_AUTOCOMPLETE_H static int autocomplete_mode; static char *autocomplete_string; static int (*autocomplete_fun)(const char *, int, int, char **); static void set_autocomplete_string (const char *s) { if (autocomplete_string) { free (autocomplete_string); } autocomplete_string = strdup (s); assert (autocomplete_string); autocomplete_mode = 1; } static void set_autocomplete_type (int (*f)(const char *, int, int, char **)) { autocomplete_fun = f; autocomplete_mode = 2; } #define MAX_FVARS 100 static struct paramed_type *fvars[MAX_FVARS]; static int fvars_pos; static void add_var_to_be_freed (struct paramed_type *P) { assert (fvars_pos < MAX_FVARS); fvars[fvars_pos ++] = P; } static void free_vars_to_be_freed (void) { int i; for (i = 0; i < fvars_pos; i++) { tgl_paramed_type_free (fvars[i]); } fvars_pos = 0; } int tglf_extf_autocomplete (struct tgl_state *TLS, const char *text, int text_len, int index, char **R, char *data, int data_len) { #ifdef DISABLE_EXTF (void) free_vars_to_be_freed; assert (0); return 0; #else if (index == -1) { buffer_pos = data; buffer_end = data + data_len; autocomplete_mode = 0; local_next_token (); struct paramed_type *P = autocomplete_function_any (); free_vars_to_be_freed (); if (P) { tgl_paramed_type_free (P); } } if (autocomplete_mode == 0) { return -1; } int len = strlen (text); if (autocomplete_mode == 1) { if (index >= 0) { return -1; } index = 0; if (!strncmp (text, autocomplete_string, len)) { *R = strdup (autocomplete_string); assert (*R); return index; } else { return -1; } } else { return autocomplete_fun (text, len, index, R); } #endif } telegram-purple/tgl/auto-static-fetch.c000066400000000000000000000045171357227200100204470ustar00rootroot00000000000000#include #include "config.h" static int multiline_output = 1; static int multiline_offset; static int multiline_offset_size = 2; static int disable_field_names; #define OUT_BUF_SIZE (1 << 25) static char out_buf[OUT_BUF_SIZE]; static int out_buf_pos; #define eprintf(...) \ do { \ out_buf_pos += snprintf (out_buf + out_buf_pos, OUT_BUF_SIZE - out_buf_pos, __VA_ARGS__);\ assert (out_buf_pos < OUT_BUF_SIZE);\ } while (0)\ static int valid_utf8_char (const char *str) { unsigned char c = (unsigned char) *str; int n = 0; if ((c & 0x80) == 0x00) { n = 0; } else if ((c & 0xe0) == 0xc0) { n = 1; } else if ((c & 0xf0) == 0xe0) { n = 2; } else if ((c & 0xf8) == 0xf0) { n = 3; } else if ((c & 0xfc) == 0xf8) { n = 4; } else if ((c & 0xfe) == 0xfc) { n = 5; } else { return -1; } int i; for (i = 0; i < n; i ++) { if ((((unsigned char)(str[i + 1])) & 0xc0) != 0x80) { return -1; } } return n + 1; } static void print_escaped_string (const char *str, int len) { eprintf ("\""); const char *end = str + len; while (str < end) { int n = valid_utf8_char (str); if (n < 0) { eprintf ("\\x%02x", (int)(unsigned char)*str); str ++; } else if (n >= 2) { int i; for (i = 0; i < n; i++) { eprintf ("%c", *(str ++)); } } else if (((unsigned char)*str) >= ' ' && *str != '"' && *str != '\\') { eprintf ("%c", *str); str ++; } else { switch (*str) { case '\n': eprintf("\\n"); break; case '\r': eprintf("\\r"); break; case '\t': eprintf("\\t"); break; case '\b': eprintf("\\b"); break; case '\a': eprintf("\\a"); break; case '\\': eprintf ("\\\\"); break; case '"': eprintf ("\\\""); break; default: eprintf ("\\x%02x", (int)(unsigned char)*str); break; } str ++; } } eprintf ("\""); } static void print_offset (void) { int i; for (i = 0; i < multiline_offset; i++) { eprintf (" "); } } char *tglf_extf_fetch (struct tgl_state *TLS, struct paramed_type *T) { #ifdef DISABLE_EXTF assert (0); return 0; #else out_buf_pos = 0; if (fetch_type_any (T) < 0) { return 0; } return out_buf; #endif } telegram-purple/tgl/auto-static-print-ds.c000066400000000000000000000045521357227200100211150ustar00rootroot00000000000000#include "config.h" #ifdef DISABLE_EXTF #error "EXTF disabled, so nothing uses auto-print anymore." #endif static int multiline_output = 1; static int multiline_offset; static int multiline_offset_size = 2; static int disable_field_names; #define OUT_BUF_SIZE (1 << 25) static char out_buf[OUT_BUF_SIZE]; static int out_buf_pos; #define eprintf(...) \ do { \ out_buf_pos += snprintf (out_buf + out_buf_pos, OUT_BUF_SIZE - out_buf_pos, __VA_ARGS__);\ assert (out_buf_pos < OUT_BUF_SIZE);\ } while (0)\ static int valid_utf8_char (const char *str) { unsigned char c = (unsigned char) *str; int n = 0; if ((c & 0x80) == 0x00) { n = 0; } else if ((c & 0xe0) == 0xc0) { n = 1; } else if ((c & 0xf0) == 0xe0) { n = 2; } else if ((c & 0xf8) == 0xf0) { n = 3; } else if ((c & 0xfc) == 0xf8) { n = 4; } else if ((c & 0xfe) == 0xfc) { n = 5; } else { return -1; } int i; for (i = 0; i < n; i ++) { if ((((unsigned char)(str[i + 1])) & 0xc0) != 0x80) { return -1; } } return n + 1; } static void print_escaped_string (const char *str, int len) { eprintf ("\""); const char *end = str + len; while (str < end) { int n = valid_utf8_char (str); if (n < 0) { eprintf ("\\x%02x", (int)(unsigned char)*str); str ++; } else if (n >= 2) { int i; for (i = 0; i < n; i++) { eprintf ("%c", *(str ++)); } } else if (((unsigned char)*str) >= ' ' && *str != '"' && *str != '\\') { eprintf ("%c", *str); str ++; } else { switch (*str) { case '\n': eprintf("\\n"); break; case '\r': eprintf("\\r"); break; case '\t': eprintf("\\t"); break; case '\b': eprintf("\\b"); break; case '\a': eprintf("\\a"); break; case '\\': eprintf ("\\\\"); break; case '"': eprintf ("\\\""); break; default: eprintf ("\\x%02x", (int)(unsigned char)*str); break; } str ++; } } eprintf ("\""); } static void print_offset (void) { int i; for (i = 0; i < multiline_offset; i++) { eprintf (" "); } } char *tglf_extf_print_ds (struct tgl_state *TLS, void *DS, struct paramed_type *T) { out_buf_pos = 0; if (print_ds_type_any (DS, T) < 0) { return 0; } return out_buf; } telegram-purple/tgl/auto-static-store.c000066400000000000000000000152671357227200100205160ustar00rootroot00000000000000#include #include "config.h" static int cur_token_len; static char *cur_token; static int cur_token_real_len; static int cur_token_quoted; #define expect_token(token,len) \ if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \ local_next_token (); #define expect_token_ptr(token,len) \ if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \ local_next_token (); #define expect_token_autocomplete(token,len) \ if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return -1; }\ if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \ local_next_token (); #define expect_token_ptr_autocomplete(token,len) \ if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return 0; }\ if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \ local_next_token (); static int is_int (void) { if (cur_token_len <= 0) { return 0; } char c = cur_token[cur_token_len]; cur_token[cur_token_len] = 0; char *p = 0; if (strtoll (cur_token, &p, 10)) {} cur_token[cur_token_len] = c; return p == cur_token + cur_token_len; } static long long get_int (void) { if (cur_token_len <= 0) { return 0; } char c = cur_token[cur_token_len]; cur_token[cur_token_len] = 0; char *p = 0; long long val = strtoll (cur_token, &p, 0); cur_token[cur_token_len] = c; return val; } static int is_double (void) { if (cur_token_len <= 0) { return 0; } char c = cur_token[cur_token_len]; cur_token[cur_token_len] = 0; char *p = 0; if (strtod (cur_token, &p)) {} cur_token[cur_token_len] = c; return p == cur_token + cur_token_len; } #ifndef IN_AUTOCOMPLETE_H static double get_double (void) { if (cur_token_len <= 0) { return 0; } char c = cur_token[cur_token_len]; cur_token[cur_token_len] = 0; char *p = 0; double val = strtod (cur_token, &p); cur_token[cur_token_len] = c; return val; } #endif static char *buffer_pos, *buffer_end; static int is_wspc (char c) { return c <= 32 && c > 0; } static void skip_wspc (void) { while (buffer_pos < buffer_end && is_wspc (*buffer_pos)) { buffer_pos ++; } } static int is_letter (char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-'; } static char exp_buffer[1 << 25];; static int exp_buffer_pos; static inline int is_hex (char c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); } static inline int hex2dec (char c) { if (c >= '0' && c <= '9') { return c - '0'; } else { return c - 'a' + 10; } } static void expand_backslashed (char *s, int len) { int backslashed = 0; exp_buffer_pos = 0; int i = 0; while (i < len) { assert (i + 3 <= (1 << 25)); if (backslashed) { backslashed = 0; switch (s[i ++]) { case 'n': exp_buffer[exp_buffer_pos ++] = '\n'; break; case 'r': exp_buffer[exp_buffer_pos ++] = '\r'; break; case 't': exp_buffer[exp_buffer_pos ++] = '\t'; break; case 'b': exp_buffer[exp_buffer_pos ++] = '\b'; break; case 'a': exp_buffer[exp_buffer_pos ++] = '\a'; break; case '\\': exp_buffer[exp_buffer_pos ++] = '\\'; break; case 'x': if (i + 2 > len || !is_hex (s[i]) || !is_hex (s[i + 1])) { exp_buffer_pos = -1; return; } exp_buffer[exp_buffer_pos ++] = hex2dec (s[i]) * 16 + hex2dec (s[i + 1]); i += 2; break; default: break; } } else { if (s[i] == '\\') { backslashed = 1; i ++; } else { exp_buffer[exp_buffer_pos ++] = s[i ++]; } } } } static void local_next_token (void) { skip_wspc (); cur_token_quoted = 0; if (buffer_pos >= buffer_end) { cur_token_len = -3; cur_token_real_len = 0; return; } char c = *buffer_pos; if (is_letter (c)) { cur_token = buffer_pos; while (buffer_pos < buffer_end && is_letter (*buffer_pos)) { buffer_pos ++; } if (buffer_pos < buffer_end) { cur_token_len = buffer_pos - cur_token; } else { cur_token_real_len = buffer_pos - cur_token; cur_token_len = -3; } return; } else if (c == '"') { cur_token_quoted = 1; cur_token = buffer_pos ++; int backslashed = 0; while (buffer_pos < buffer_end && (*buffer_pos != '"' || backslashed)) { if (*buffer_pos == '\\') { backslashed ^= 1; } else { backslashed = 0; } buffer_pos ++; } if (*buffer_pos == '"') { buffer_pos ++; expand_backslashed (cur_token + 1, buffer_pos - cur_token - 2); if (exp_buffer_pos < 0) { cur_token_len = -2; } else { cur_token_len = exp_buffer_pos; cur_token = exp_buffer; } } else { cur_token_len = -2; } return; } else { if (c) { cur_token = buffer_pos ++; cur_token_len = 1; } else { cur_token_len = -3; cur_token_real_len = 0; } } } static struct paramed_type *paramed_type_dup (struct paramed_type *P) { if (ODDP (P)) { return P; } struct paramed_type *R = malloc (sizeof (*R)); assert (R); R->type = malloc (sizeof (*R->type)); assert (R->type); memcpy (R->type, P->type, sizeof (*P->type)); R->type->id = strdup (P->type->id); assert (R->type->id); if (P->type->params_num) { R->params = malloc (sizeof (void *) * P->type->params_num); assert (R->params); int i; for (i = 0; i < P->type->params_num; i++) { R->params[i] = paramed_type_dup (P->params[i]); } } return R; } #ifndef IN_AUTOCOMPLETE_H void tgl_paramed_type_free (struct paramed_type *P) { if (ODDP (P)) { return; } if (P->type->params_num) { int i; for (i = 0; i < P->type->params_num; i++) { tgl_paramed_type_free (P->params[i]); } free (P->params); } free (P->type->id); free (P->type); free (P); } #else void tgl_paramed_type_free (struct paramed_type *P); #endif #ifndef IN_AUTOCOMPLETE_H struct paramed_type *tglf_extf_store (struct tgl_state *TLS, const char *data, int data_len) { #ifdef DISABLE_EXTF assert (0); return 0; #else buffer_pos = (char *)data; buffer_end = (char *)(data + data_len); local_next_token (); return store_function_any (); #endif } int tglf_store_type (struct tgl_state *TLS, const char *data, int data_len, struct paramed_type *P) { buffer_pos = (char *)data; buffer_end = (char *)(data + data_len); local_next_token (); return store_type_any (P); } #endif telegram-purple/tgl/auto-static.c000066400000000000000000000207541357227200100173610ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2014-2015 */ #include "mtproto-common.h" #include "config.h" #include #ifndef DISABLE_EXTF static int cur_token_len; static char *cur_token; static int cur_token_real_len; static int cur_token_quoted; #define expect_token(token,len) \ if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \ local_next_token (); #define expect_token_ptr(token,len) \ if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \ local_next_token (); #define expect_token_autocomplete(token,len) \ if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return -1; }\ if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \ local_next_token (); #define expect_token_ptr_autocomplete(token,len) \ if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return 0; }\ if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \ local_next_token (); static int autocomplete_mode; static char *autocomplete_string; static int (*autocomplete_fun)(const char *, int, int, char **); static void set_autocomplete_string (const char *s) { if (autocomplete_string) { free (autocomplete_string); } autocomplete_string = strdup (s); assert (autocomplete_string); autocomplete_mode = 1; } static void set_autocomplete_type (int (*f)(const char *, int, int, char **)) { autocomplete_fun = f; autocomplete_mode = 2; } static int is_int (void) { if (cur_token_len <= 0) { return 0; } char c = cur_token[cur_token_len]; cur_token[cur_token_len] = 0; char *p = 0; if (strtoll (cur_token, &p, 10)) {} cur_token[cur_token_len] = c; return p == cur_token + cur_token_len; } static long long get_int (void) { if (cur_token_len <= 0) { return 0; } char c = cur_token[cur_token_len]; cur_token[cur_token_len] = 0; char *p = 0; long long val = strtoll (cur_token, &p, 0); cur_token[cur_token_len] = c; return val; } static int is_double (void) { if (cur_token_len <= 0) { return 0; } char c = cur_token[cur_token_len]; cur_token[cur_token_len] = 0; char *p = 0; if (strtod (cur_token, &p)) {} cur_token[cur_token_len] = c; return p == cur_token + cur_token_len; } static double get_double (void) { if (cur_token_len <= 0) { return 0; } char c = cur_token[cur_token_len]; cur_token[cur_token_len] = 0; char *p = 0; double val = strtod (cur_token, &p); cur_token[cur_token_len] = c; return val; } static struct paramed_type *paramed_type_dup (struct paramed_type *P) { if (ODDP (P)) { return P; } struct paramed_type *R = malloc (sizeof (*R)); assert (R); R->type = malloc (sizeof (*R->type)); assert (R->type); memcpy (R->type, P->type, sizeof (*P->type)); R->type->id = strdup (P->type->id); assert (R->type->id); if (P->type->params_num) { R->params = malloc (sizeof (void *) * P->type->params_num); assert (R->params); int i; for (i = 0; i < P->type->params_num; i++) { R->params[i] = paramed_type_dup (P->params[i]); } } return R; } void tgl_paramed_type_free (struct paramed_type *P) { if (ODDP (P)) { return; } if (P->type->params_num) { int i; for (i = 0; i < P->type->params_num; i++) { tgl_paramed_type_free (P->params[i]); } free (P->params); } free (P->type->id); free (P->type); free (P); } static char *buffer_pos, *buffer_end; static int is_wspc (char c) { return c <= 32 && c > 0; } static void skip_wspc (void) { while (buffer_pos < buffer_end && is_wspc (*buffer_pos)) { buffer_pos ++; } } static int is_letter (char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-'; } static char exp_buffer[1 << 25];; static int exp_buffer_pos; static inline int is_hex (char c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); } static inline int hex2dec (char c) { if (c >= '0' && c <= '9') { return c - '0'; } else { return c - 'a' + 10; } } static void expand_backslashed (char *s, int len) { int backslashed = 0; exp_buffer_pos = 0; int i = 0; while (i < len) { assert (i + 3 <= (1 << 25)); if (backslashed) { backslashed = 0; switch (s[i ++]) { case 'n': exp_buffer[exp_buffer_pos ++] = '\n'; break; case 'r': exp_buffer[exp_buffer_pos ++] = '\r'; break; case 't': exp_buffer[exp_buffer_pos ++] = '\t'; break; case 'b': exp_buffer[exp_buffer_pos ++] = '\b'; break; case 'a': exp_buffer[exp_buffer_pos ++] = '\a'; break; case '\\': exp_buffer[exp_buffer_pos ++] = '\\'; break; case 'x': if (i + 2 > len || !is_hex (s[i]) || !is_hex (s[i + 1])) { exp_buffer_pos = -1; return; } exp_buffer[exp_buffer_pos ++] = hex2dec (s[i]) * 16 + hex2dec (s[i + 1]); i += 2; break; default: break; } } else { if (s[i] == '\\') { backslashed = 1; i ++; } else { exp_buffer[exp_buffer_pos ++] = s[i ++]; } } } } static void local_next_token (void) { skip_wspc (); cur_token_quoted = 0; if (buffer_pos >= buffer_end) { cur_token_len = -3; cur_token_real_len = 0; return; } char c = *buffer_pos; if (is_letter (c)) { cur_token = buffer_pos; while (buffer_pos < buffer_end && is_letter (*buffer_pos)) { buffer_pos ++; } if (buffer_pos < buffer_end) { cur_token_len = buffer_pos - cur_token; } else { cur_token_real_len = buffer_pos - cur_token; cur_token_len = -3; } return; } else if (c == '"') { cur_token_quoted = 1; cur_token = buffer_pos ++; int backslashed = 0; while (buffer_pos < buffer_end && (*buffer_pos != '"' || backslashed)) { if (*buffer_pos == '\\') { backslashed ^= 1; } else { backslashed = 0; } buffer_pos ++; } if (*buffer_pos == '"') { buffer_pos ++; expand_backslashed (cur_token + 1, buffer_pos - cur_token - 2); if (exp_buffer_pos < 0) { cur_token_len = -2; } else { cur_token_len = exp_buffer_pos; cur_token = exp_buffer; } } else { cur_token_len = -2; } return; } else { if (c) { cur_token = buffer_pos ++; cur_token_len = 1; } else { cur_token_len = -3; cur_token_real_len = 0; } } } #define MAX_FVARS 100 static struct paramed_type *fvars[MAX_FVARS]; static int fvars_pos; static void add_var_to_be_freed (struct paramed_type *P) { assert (fvars_pos < MAX_FVARS); fvars[fvars_pos ++] = P; } static void free_vars_to_be_freed (void) { int i; for (i = 0; i < fvars_pos; i++) { tgl_paramed_type_free (fvars[i]); } fvars_pos = 0; } int tglf_extf_autocomplete (struct tgl_state *TLS, const char *text, int text_len, int index, char **R, char *data, int data_len) { if (index == -1) { buffer_pos = data; buffer_end = data + data_len; autocomplete_mode = 0; local_next_token (); struct paramed_type *P = autocomplete_function_any (); free_vars_to_be_freed (); if (P) { tgl_paramed_type_free (P); } } if (autocomplete_mode == 0) { return -1; } int len = strlen (text); if (autocomplete_mode == 1) { if (index >= 0) { return -1; } index = 0; if (!strncmp (text, autocomplete_string, len)) { *R = strdup (autocomplete_string); assert (*R); return index; } else { return -1; } } else { return autocomplete_fun (text, len, index, R); } } #endif telegram-purple/tgl/auto.h000066400000000000000000000037521357227200100161000ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2014-2015 */ #ifndef __AUTO_H__ #define __AUTO_H__ #include "tools.h" struct tl_type_descr { unsigned name; char *id; int params_num; long long params_types; }; struct paramed_type { struct tl_type_descr *type; struct paramed_type **params; }; #define NAME_ARRAY 0x89932ad9 #define TYPE_TO_PARAM(NAME) (&(struct paramed_type) {.type = &tl_type_## NAME, .params=0}) #define TYPE_TO_PARAM_1(NAME,PARAM1) (&(struct paramed_type) {.type = &tl_type_## NAME, .params=(struct paramed_type *[1]){PARAM1}}) #define ODDP(x) (((long)(x)) & 1) #define EVENP(x) (!ODDP(x)) #define INT2PTR(x) (void *)(long)(((long)x) * 2 + 1) #define PTR2INT(x) ((((long)x) - 1) / 2) static inline void *memdup (const void *d, int len) { assert (d || !len); if (!d) { return NULL; } void *r = talloc (len); memcpy (r, d, len); return r; } #define DS_LVAL(x) ((x) ? *(x) : 0) #define DS_STR(x) ((x) ? (x)->data : NULL), ((x) ? (x)->len : 0) #define DS_RSTR(x) ((x) ? (x)->len : 0), ((x) ? (x)->data : NULL) #define DS_STR_DUP(x) memdup(((x) ? (x)->data : NULL), ((x) ? (x)->len + 1: 0)) #define DS_BVAL(x) ((x) && ((x)->magic == CODE_bool_true)) void tgl_paramed_type_free (struct paramed_type *P); #endif telegram-purple/tgl/binlog.c000066400000000000000000000714211357227200100163730ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "crypto/bn.h" #include "tgl-binlog.h" #include "mtproto-common.h" //#include "net.h" #include "mtproto-client.h" #include "mtproto-utils.h" #include "tgl.h" #include "auto.h" #include "auto/auto-types.h" #include "auto/auto-skip.h" #include "auto/auto-store-ds.h" #include "auto/auto-fetch-ds.h" #include "auto/auto-free-ds.h" #include "tgl-structures.h" #include "tgl-methods-in.h" #include "crypto/sha.h" static int mystreq1 (const char *a, const char *b, int l) { if ((int)strlen (a) != l) { return 1; } return memcmp (a, b, l); } void bl_do_dc_option (struct tgl_state *TLS, int flags, int id, const char *name, int l1, const char *ip, int l2, int port) /* {{{ */ { struct tgl_dc *DC = TLS->DC_list[id]; if (DC) { struct tgl_dc_option *O = DC->options[flags & 3]; while (O) { if (!strncmp (O->ip, ip, l2)) { return; } O = O->next; } } vlogprintf (E_NOTICE, "DC%d '%.*s' update: %.*s:%d\n", id, l1, name, l2, ip, port ); tglmp_alloc_dc (TLS, flags, id, tstrndup (ip, l2), port ); } /* }}} */ void bl_do_set_working_dc (struct tgl_state *TLS, int num) /* {{{ */ { assert (num > 0 && num <= MAX_DC_ID); TLS->DC_working = TLS->DC_list[num]; TLS->dc_working_num = num; } /* }}} */ void bl_do_dc_signed (struct tgl_state *TLS, int num) /* {{{ */ { assert (num > 0 && num <= MAX_DC_ID); assert (TLS->DC_list[num]); TLS->DC_list[num]->flags |= TGLDCF_LOGGED_IN; } /* }}} */ void bl_do_set_auth_key (struct tgl_state *TLS, int num, unsigned char *buf) /* {{{ */ { assert (num > 0 && num <= MAX_DC_ID); assert (TLS->DC_list[num]); if (TLS->DC_list[num]->auth_key != (char *)buf) memcpy (TLS->DC_list[num]->auth_key, buf, 256); static unsigned char sha1_buffer[20]; TGLC_sha1 ((void *)TLS->DC_list[num]->auth_key, 256, sha1_buffer); TLS->DC_list[num]->auth_key_id = *(long long *)(sha1_buffer + 12); TLS->DC_list[num]->flags |= TGLDCF_AUTHORIZED; } /* }}} */ void bl_do_set_our_id (struct tgl_state *TLS, tgl_peer_id_t id) /* {{{ */ { /*if (TLS->our_id.peer_type) { assert (!tgl_cmp_peer_id (TLS->our_id, id)); return; }*/ TLS->our_id = id; if (TLS->callback.our_id) { TLS->callback.our_id (TLS, TLS->our_id); } } /* }}} */ void bl_do_set_dh_params (struct tgl_state *TLS, int root, unsigned char prime[], int version) /* {{{ */ { if (TLS->encr_prime) { tfree (TLS->encr_prime, 256); TGLC_bn_free (TLS->encr_prime_bn); } TLS->encr_root = root; TLS->encr_prime = talloc (256); memcpy (TLS->encr_prime, prime, 256); TLS->encr_prime_bn = TGLC_bn_new (); TGLC_bn_bin2bn ((void *)TLS->encr_prime, 256, TLS->encr_prime_bn); TLS->encr_param_version = version; assert (tglmp_check_DH_params (TLS, TLS->encr_prime_bn, TLS->encr_root) >= 0); } /* }}} */ void bl_do_set_pts (struct tgl_state *TLS, int pts) /* {{{ */ { if (TLS->locks & TGL_LOCK_DIFF) { return; } if (pts <= TLS->pts) { return; } TLS->pts = pts; } /* }}} */ void bl_do_set_channel_pts (struct tgl_state *TLS, int id, int pts) /* {{{ */ { tgl_peer_t *E = tgl_peer_get (TLS, TGL_MK_CHANNEL (id)); if (!E || !(E->flags & TGLPF_CREATED)) { return; } if (E->flags & TGLCHF_DIFF) { return ; } if (E->channel.pts <= pts) { return; } E->channel.pts = pts; } /* }}} */ void bl_do_set_qts (struct tgl_state *TLS, int qts) /* {{{ */ { if (TLS->locks & TGL_LOCK_DIFF) { return; } if (qts <= TLS->qts) { return; } TLS->qts = qts; } /* }}} */ void bl_do_set_date (struct tgl_state *TLS, int date) /* {{{ */ { if (TLS->locks & TGL_LOCK_DIFF) { return; } if (date <= TLS->date) { return; } TLS->date = date; } /* }}} */ void bl_do_set_seq (struct tgl_state *TLS, int seq) /* {{{ */ { if (TLS->locks & TGL_LOCK_DIFF) { return; } if (seq <= TLS->seq) { return; } TLS->seq = seq; } /* }}} */ void bl_do_set_msg_id (struct tgl_state *TLS, tgl_message_id_t *old_id, tgl_message_id_t *new_id) /* {{{ */ { if (!memcmp (old_id, new_id, sizeof (tgl_message_id_t))) { return; } struct tgl_message *M = tgl_message_get (TLS, old_id); assert (M); if (M->flags & TGLMF_PENDING) { tglm_message_remove_unsent (TLS, M); M->flags &= ~TGLMF_PENDING; } tglm_message_remove_tree (TLS, M); tglm_message_del_peer (TLS, M); M->permanent_id = *new_id; if (tgl_message_get (TLS, new_id)) { tglm_message_del_use (TLS, M); tglm_message_del_temp_id (TLS, M); tglm_message_del_random_id (TLS, M); tgls_free_message (TLS, M); } else { tglm_message_insert_tree (TLS, M); tglm_message_add_peer (TLS, M); } M->server_id = new_id->id; } /* }}} */ void bl_do_chat_add_user (struct tgl_state *TLS, tgl_peer_id_t id, int version, int user, int inviter, int date) /* {{{ */ { tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P || !(P->flags & TGLPF_CREATED)) { return; } struct tgl_chat *C = &P->chat; if (C->user_list_version >= version || !C->user_list_version) { return; } int i; for (i = 0; i < C->user_list_size; i++) { if (C->user_list[i].user_id == user) { return; } } C->user_list_size ++; C->user_list = trealloc (C->user_list, 12 * C->user_list_size - 12, 12 * C->user_list_size); C->user_list[C->user_list_size - 1].user_id = user; C->user_list[C->user_list_size - 1].inviter_id = inviter; C->user_list[C->user_list_size - 1].date = date; C->user_list_version = version; if (TLS->callback.chat_update) { TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS); } } /* }}} */ void bl_do_chat_del_user (struct tgl_state *TLS, tgl_peer_id_t id, int version, int user) /* {{{ */ { tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P || !(P->flags & TGLPF_CREATED)) { return; } struct tgl_chat *C = &P->chat; if (C->user_list_version >= version || !C->user_list_version) { return; } int i; for (i = 0; i < C->user_list_size; i++) { if (C->user_list[i].user_id == user) { struct tgl_chat_user t; t = C->user_list[i]; C->user_list[i] = C->user_list[C->user_list_size - 1]; C->user_list[C->user_list_size - 1] = t; } } if (C->user_list[C->user_list_size - 1].user_id != user) { return; } assert (C->user_list[C->user_list_size - 1].user_id == user); C->user_list_size --; C->user_list = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size); C->user_list_version = version; if (TLS->callback.chat_update) { TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS); } } /* }}} */ void bl_do_edit_message (struct tgl_state *TLS, tgl_message_id_t *id, tgl_peer_id_t *from_id, tgl_peer_id_t *to_id, tgl_peer_id_t *fwd_from_id, int *fwd_date, int *date, const char *message, int message_len, struct tl_ds_message_media *media, struct tl_ds_message_action *action, int *reply_id, struct tl_ds_reply_markup *reply_markup, struct tl_ds_vector *entities, int flags) /* {{{ */ { assert (!(flags & 0xfffe0000)); struct tgl_message *M = tgl_message_get (TLS, id); assert (flags & TGLMF_CREATED); assert (!(flags & TGLMF_ENCRYPTED)); if (flags & (1 << 16)) { if (!M) { M = tglm_message_alloc (TLS, id); } M->server_id = id->id; assert (!(M->flags & TGLMF_CREATED)); } else { assert (M->flags & TGLMF_CREATED); } assert (M); assert (!(M->flags & TGLMF_ENCRYPTED)); if ((M->flags & TGLMF_PENDING) && !(flags & TGLMF_PENDING)){ tglm_message_remove_unsent (TLS, M); } if (!(M->flags & TGLMF_PENDING) && (flags & TGLMF_PENDING)){ tglm_message_insert_unsent (TLS, M); } if ((M->flags & TGLMF_UNREAD) && !(flags & TGLMF_UNREAD)) { M->flags = (flags & 0xffff) | TGLMF_UNREAD; } else { M->flags = (flags & 0xffff); } if (from_id) { M->from_id = *from_id; } else { if (!M->from_id.peer_type) { assert (to_id); M->from_id = *to_id; } } if (to_id) { assert (flags & 0x10000); M->to_id = *to_id; } if (date) { M->date = *date; } if (fwd_from_id) { assert (fwd_date); M->fwd_from_id = *fwd_from_id; M->fwd_date = *fwd_date;; } if (action) { tglf_fetch_message_action (TLS, &M->action, action); M->flags |= TGLMF_SERVICE; } if (message) { M->message_len = message_len; M->message = tstrndup (message, message_len); assert (!(M->flags & TGLMF_SERVICE)); } if (media) { tglf_fetch_message_media (TLS, &M->media, media); assert (!(M->flags & TGLMF_SERVICE)); } if (entities) { tglf_fetch_message_entities (TLS, M, entities); } if (reply_id) { M->reply_id = *reply_id; } if (flags & 0x10000) { tglm_message_insert (TLS, M); } if (!(flags & TGLMF_UNREAD) && (M->flags & TGLMF_UNREAD)) { tgls_messages_mark_read (TLS, M, M->flags & TGLMF_OUT, M->permanent_id.id); } if (reply_markup) { M->reply_markup = tglf_fetch_alloc_reply_markup (TLS, M->next, reply_markup); } if (M->flags & TGLMF_PENDING) { tgls_message_change_random_id (TLS, M, M->permanent_id.id); } if (!M->temp_id) { tgls_message_change_temp_id (TLS, M, ++TLS->last_temp_id); } } /* }}} */ void bl_do_edit_message_encr (struct tgl_state *TLS, tgl_message_id_t *id, tgl_peer_id_t *from_id, tgl_peer_id_t *to_id, int *date, const char *message, int message_len, struct tl_ds_decrypted_message_media *media, struct tl_ds_decrypted_message_action *action, struct tl_ds_encrypted_file *file, int flags) /* {{{ */ { clear_packet (); assert (!(flags & 0xfffe0000)); struct tgl_message *M = tgl_message_get (TLS, id); if (flags & (1 << 16)) { if (!M) { M = tglm_message_alloc (TLS, id); } else { assert (!(M->flags & TGLMF_CREATED)); } assert (!(M->flags & TGLMF_CREATED)); } else { assert (M->flags & TGLMF_CREATED); } assert (flags & TGLMF_CREATED); assert (flags & TGLMF_ENCRYPTED); if ((M->flags & TGLMF_PENDING) && !(flags & TGLMF_PENDING)){ tglm_message_remove_unsent (TLS, M); } if (!(M->flags & TGLMF_PENDING) && (flags & TGLMF_PENDING)){ tglm_message_insert_unsent (TLS, M); } M->flags = flags & 0xffff; if (from_id) { M->from_id = *from_id; } if (to_id) { assert (flags & 0x10000); M->to_id = *to_id; } if (date) { M->date = *date; } struct tgl_secret_chat *E = (void *)tgl_peer_get (TLS, M->to_id); assert (E); if (action) { tglf_fetch_message_action_encrypted (TLS, &M->action, action); M->flags |= TGLMF_SERVICE; } if (message) { M->message_len = message_len; M->message = tstrndup (message, message_len); assert (!(M->flags & TGLMF_SERVICE)); } if (media) { tglf_fetch_message_media_encrypted (TLS, &M->media, media); assert (!(M->flags & TGLMF_SERVICE)); } if (file) { tglf_fetch_encrypted_message_file (TLS, &M->media, file); assert (!(M->flags & TGLMF_SERVICE)); } if (action && !(M->flags & TGLMF_OUT) && M->action.type == tgl_message_action_notify_layer) { E->layer = M->action.layer; } if ((flags & TGLMF_CREATE) && (flags & TGLMF_OUT)) { E->out_seq_no ++; } if (flags & 0x10000) { tglm_message_insert (TLS, M); } } /* }}} */ void bl_do_message_delete (struct tgl_state *TLS, tgl_message_id_t *id) /* {{{ */ { struct tgl_message *M = tgl_message_get (TLS, id); if (!M) { return; } assert (M); if (M->flags & TGLMF_PENDING) { tglm_message_remove_unsent (TLS, M); M->flags &= ~TGLMF_PENDING; } tglm_message_remove_tree (TLS, M); tglm_message_del_peer (TLS, M); tglm_message_del_use (TLS, M); tglm_message_del_temp_id (TLS, M); tglm_message_del_random_id (TLS, M); tgls_free_message (TLS, M); } /* }}} */ void bl_do_msg_update (struct tgl_state *TLS, tgl_message_id_t *id) /* {{{ */ { struct tgl_message *M = tgl_message_get (TLS, id); if (!M) { return; } assert (M); if (!(M->flags & TGLMF_ENCRYPTED)) { if (TLS->max_msg_id < M->server_id) { TLS->max_msg_id = M->server_id; } } if (TLS->callback.msg_receive) { TLS->callback.msg_receive (TLS, M); } } /* }}} */ void bl_do_reset_authorization (struct tgl_state *TLS) /* {{{ */ { int i; for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i]) { struct tgl_dc *D = TLS->DC_list[i]; D->flags = 0; D->state = st_init; D->auth_key_id = D->temp_auth_key_id = 0; } TLS->seq = 0; TLS->qts = 0; } /* }}} */ void bl_do_encr_chat_exchange (struct tgl_state *TLS, tgl_peer_id_t id, long long *exchange_id, const void *key, int *state) /* {{{ */ { tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P) { return; } if (state) { P->encr_chat.exchange_state = *state; } if (exchange_id) { P->encr_chat.exchange_id = *exchange_id; } static unsigned char sha_buffer[20]; switch (P->encr_chat.exchange_state) { case tgl_sce_requested: memcpy (P->encr_chat.exchange_key, key, 256); break; case tgl_sce_accepted: memcpy (P->encr_chat.exchange_key, key, 256); TGLC_sha1 ((unsigned char *)P->encr_chat.exchange_key, 256, sha_buffer); P->encr_chat.exchange_key_fingerprint = *(long long *)(sha_buffer + 12); break; case tgl_sce_committed: memcpy (P->encr_chat.exchange_key, P->encr_chat.key, 256); P->encr_chat.exchange_key_fingerprint = P->encr_chat.key_fingerprint; memcpy (P->encr_chat.key, key, 256); TGLC_sha1 ((unsigned char *)P->encr_chat.key, 256, sha_buffer); P->encr_chat.key_fingerprint = *(long long *)(sha_buffer + 12); break; case tgl_sce_confirmed: P->encr_chat.exchange_state = tgl_sce_none; if (P->encr_chat.exchange_state != tgl_sce_committed) { memcpy (P->encr_chat.key, P->encr_chat.exchange_key, 256); P->encr_chat.key_fingerprint = P->encr_chat.exchange_key_fingerprint; } break; case tgl_sce_aborted: P->encr_chat.exchange_state = tgl_sce_none; if (P->encr_chat.exchange_state == tgl_sce_committed) { memcpy (P->encr_chat.key, P->encr_chat.exchange_key, 256); P->encr_chat.key_fingerprint = P->encr_chat.exchange_key_fingerprint; } break; default: assert (0); } } /* }}} */ void bl_do_user (struct tgl_state *TLS, int id, long long *access_hash, const char *first_name, int first_name_len, const char *last_name, int last_name_len, const char *phone, int phone_len, const char *username, int username_len, struct tl_ds_photo *photo, struct tl_ds_user_profile_photo *profile_photo, int *last_read_in, int *last_read_out, struct tl_ds_bot_info *bot_info, int flags) /* {{{ */ { tgl_peer_t *_U = tgl_peer_get (TLS, TGL_MK_USER (id)); unsigned updates = 0; if ((flags & TGLPF_CREATE) && (flags != TGL_FLAGS_UNCHANGED)) { if (!_U) { _U = talloc0 (sizeof (*_U)); _U->id = TGL_MK_USER (id); tglp_insert_user (TLS, _U); } else { assert (!(_U->flags & TGLPF_CREATED)); } updates |= TGL_UPDATE_CREATED; } else { assert (_U->flags & TGLPF_CREATED); } struct tgl_user *U = (void *)_U; if (flags == TGL_FLAGS_UNCHANGED) { flags = U->flags; } flags &= TGLUF_TYPE_MASK; if ((flags & TGLUF_TYPE_MASK) != (U->flags & TGLUF_TYPE_MASK)) { updates |= TGL_UPDATE_FLAGS; } U->flags = (U->flags & ~TGLUF_TYPE_MASK) | flags; if (access_hash && *access_hash != U->access_hash) { U->access_hash = *access_hash; U->id.access_hash = *access_hash; updates |= TGL_UPDATE_ACCESS_HASH; } if (first_name || last_name) { if (!U->first_name || !U->last_name || mystreq1 (U->first_name, first_name, first_name_len) || mystreq1 (U->last_name, last_name, last_name_len)) { if (U->first_name) { tfree_str (U->first_name); } U->first_name = tstrndup (first_name, first_name_len); if (U->last_name) { tfree_str (U->last_name); } U->last_name = tstrndup (last_name, last_name_len); updates |= TGL_UPDATE_NAME; if (U->print_name) { tglp_peer_delete_name (TLS, (void *)U); tfree_str (U->print_name); } U->print_name = TLS->callback.create_print_name (TLS, U->id, U->first_name, U->last_name, 0, 0); tglp_peer_insert_name (TLS, (void *)U); } } if (phone && (!U->phone || mystreq1 (U->phone, phone, phone_len))) { if (U->phone) { tfree_str (U->phone); } U->phone = tstrndup (phone, phone_len); updates |= TGL_UPDATE_PHONE; } if (username && (!U->username || mystreq1 (U->username, username, username_len))) { if (U->username) { tfree_str (U->username); } U->username = tstrndup (username, username_len); updates |= TGL_UPDATE_USERNAME; } if (photo) { if (!U->photo || U->photo->id != DS_LVAL (photo->id)) { if (U->photo) { tgls_free_photo (TLS, U->photo); } U->photo = tglf_fetch_alloc_photo (TLS, photo); U->flags |= TGLUF_HAS_PHOTO; } } if (profile_photo) { if (U->photo_id != DS_LVAL (profile_photo->photo_id)) { U->photo_id = DS_LVAL (profile_photo->photo_id); tglf_fetch_file_location (TLS, &U->photo_big, profile_photo->photo_big); tglf_fetch_file_location (TLS, &U->photo_small, profile_photo->photo_small); updates |= TGL_UPDATE_PHOTO; } } if (last_read_in) { U->last_read_in = *last_read_in; tgls_messages_mark_read (TLS, U->last, 0, U->last_read_in); } if (last_read_out) { U->last_read_out = *last_read_out; tgls_messages_mark_read (TLS, U->last, TGLMF_OUT, U->last_read_out); } if (bot_info) { if (!U->bot_info || U->bot_info->version != DS_LVAL (bot_info->version)) { if (U->bot_info) { tgls_free_bot_info (TLS, U->bot_info); } U->bot_info = tglf_fetch_alloc_bot_info (TLS, bot_info); } } if (TLS->callback.user_update && updates) { TLS->callback.user_update (TLS, U, updates); } } /* }}} */ void bl_do_chat (struct tgl_state *TLS, int id, const char *title, int title_len, int *user_num, int *date, int *version, struct tl_ds_vector *participants, struct tl_ds_chat_photo *chat_photo, struct tl_ds_photo *photo, int *admin, int *last_read_in, int *last_read_out, int flags) /* {{{ */ { tgl_peer_t *_U = tgl_peer_get (TLS, TGL_MK_CHAT (id)); unsigned updates = 0; if ((flags & TGLPF_CREATE) && (flags != TGL_FLAGS_UNCHANGED)) { if (!_U) { _U = talloc0 (sizeof (*_U)); _U->id = TGL_MK_CHAT (id); tglp_insert_chat (TLS, _U); } else { assert (!(_U->flags & TGLPF_CREATED)); } updates |= TGL_UPDATE_CREATED; } else { assert (_U->flags & TGLPF_CREATED); } struct tgl_chat *C = &_U->chat; if (flags == TGL_FLAGS_UNCHANGED) { flags = C->flags; } flags &= TGLCF_TYPE_MASK; if ((flags & TGLCF_TYPE_MASK) != (C->flags & TGLCF_TYPE_MASK)) { updates |= TGL_UPDATE_FLAGS; } C->flags = (C->flags & ~TGLCF_TYPE_MASK) | flags; if (title && (!C->title || mystreq1 (C->title, title, title_len))) { if (C->title) { tfree_str (C->title); } C->title = tstrndup (title, title_len); if (C->print_title) { tglp_peer_delete_name (TLS, (void *)C); tfree_str (C->print_title); } C->print_title = TLS->callback.create_print_name (TLS, C->id, C->title, 0, 0, 0); tglp_peer_insert_name (TLS, (void *)C); updates |= TGL_UPDATE_TITLE; } if (user_num) { C->users_num = *user_num; } if (date) { C->date = *date; } if (chat_photo && chat_photo->photo_big) { if (DS_LVAL (chat_photo->photo_big->secret) != C->photo_big.secret) { tglf_fetch_file_location (TLS, &C->photo_big, chat_photo->photo_big); tglf_fetch_file_location (TLS, &C->photo_small, chat_photo->photo_small); updates |= TGL_UPDATE_PHOTO; } } if (photo) { if (!C->photo || C->photo->id != DS_LVAL (photo->id)) { if (C->photo) { tgls_free_photo (TLS, C->photo); } C->photo = tglf_fetch_alloc_photo (TLS, photo); C->flags |= TGLPF_HAS_PHOTO; //updates |= TGL_UPDATE_PHOTO; } } if (admin && *admin != C->admin_id) { C->admin_id = *admin; updates |= TGL_UPDATE_ADMIN; } if (version) { assert (participants); if (*version > C->version) { C->version = *version; if (C->user_list) { tfree (C->user_list, 12 * C->user_list_size); } C->user_list_size = DS_LVAL (participants->f1); C->user_list = talloc (12 * C->user_list_size); int i; for (i = 0; i < C->user_list_size; i++) { struct tl_ds_chat_participant *DS_P = participants->f2[i]; C->user_list[i].user_id = DS_LVAL (DS_P->user_id); C->user_list[i].inviter_id = DS_LVAL (DS_P->inviter_id); C->user_list[i].date = DS_LVAL (DS_P->date); } updates |= TGL_UPDATE_MEMBERS; } } if (last_read_in) { C->last_read_in = *last_read_in; tgls_messages_mark_read (TLS, C->last, 0, C->last_read_in); } if (last_read_out) { C->last_read_out = *last_read_out; tgls_messages_mark_read (TLS, C->last, TGLMF_OUT, C->last_read_out); } if (TLS->callback.chat_update && updates) { TLS->callback.chat_update (TLS, C, updates); } } /* }}} */ void bl_do_encr_chat (struct tgl_state *TLS, int id, long long *access_hash, int *date, int *admin, int *user_id, void *key, void *g_key, void *first_key_id, int *state, int *ttl, int *layer, int *in_seq_no, int *last_in_seq_no, int *out_seq_no, long long *key_fingerprint, int flags, const char *print_name, int print_name_len) /* {{{ */ { tgl_peer_t *_U = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (id)); unsigned updates = 0; if ((flags & TGLPF_CREATE) && (flags != TGL_FLAGS_UNCHANGED)) { if (!_U) { _U = talloc0 (sizeof (*_U)); _U->id = TGL_MK_ENCR_CHAT (id); tglp_insert_encrypted_chat (TLS, _U); } else { assert (!(_U->flags & TGLPF_CREATED)); } updates |= TGL_UPDATE_CREATED; } else { assert (_U->flags & TGLPF_CREATED); } struct tgl_secret_chat *U = (void *)_U; if (flags == TGL_FLAGS_UNCHANGED) { flags = U->flags; } flags &= TGLECF_TYPE_MASK; if ((flags & TGLECF_TYPE_MASK) != (U->flags & TGLECF_TYPE_MASK)) { updates |= TGL_UPDATE_FLAGS; } U->flags = (U->flags & ~TGLECF_TYPE_MASK) | flags; if (access_hash && *access_hash != U->access_hash) { U->access_hash = *access_hash; U->id.access_hash = *access_hash; updates |= TGL_UPDATE_ACCESS_HASH; } if (date) { U->date = *date; } if (admin) { U->admin_id = *admin; } if (user_id) { U->user_id = *user_id; } if (key_fingerprint) { U->key_fingerprint = *key_fingerprint; } if (in_seq_no) { U->in_seq_no = *in_seq_no; } if (out_seq_no) { U->out_seq_no = *out_seq_no; } if (last_in_seq_no) { U->last_in_seq_no = *last_in_seq_no; } tgl_peer_t *Us = tgl_peer_get (TLS, TGL_MK_USER (U->user_id)); if (!U->print_name) { if (print_name) { U->print_name = tstrndup (print_name, print_name_len); } else { if (Us) { U->print_name = TLS->callback.create_print_name (TLS, TGL_MK_ENCR_CHAT (id), "!", Us->user.first_name, Us->user.last_name, 0); } else { static char buf[100]; tsnprintf (buf, 99, "user#%d", U->user_id); U->print_name = TLS->callback.create_print_name (TLS, TGL_MK_ENCR_CHAT (id), "!", buf, 0, 0); } tglp_peer_insert_name (TLS, (void *)U); } } if (g_key) { if (!U->g_key) { U->g_key = talloc (256); } memcpy (U->g_key, g_key, 256); } if (key) { memcpy (U->key, key, 256); } if (first_key_id) { memcpy (U->first_key_sha, first_key_id, 20); } if (state) { if (U->state == sc_waiting && *state == sc_ok) { tgl_do_create_keys_end (TLS, U); } if ((int)U->state != *state) { switch (*state) { case sc_request: updates |= TGL_UPDATE_REQUESTED; break; case sc_ok: updates |= TGL_UPDATE_WORKING; vlogprintf (E_WARNING, "Secret chat in ok state\n"); break; default: break; } } U->state = *state; } if (TLS->callback.secret_chat_update && updates) { TLS->callback.secret_chat_update (TLS, U, updates); } } /* }}} */ void bl_do_channel (struct tgl_state *TLS, int id, long long *access_hash, int *date, const char *title, int title_len, const char *username, int username_len, struct tl_ds_chat_photo *chat_photo, struct tl_ds_photo *photo, int *version, char *about, int about_len, int *participants_count, int *admins_count, int *kicked_count, int *last_read_in, int flags) /* {{{ */ { tgl_peer_t *_U = tgl_peer_get (TLS, TGL_MK_CHANNEL (id)); unsigned updates = 0; if ((flags & TGLPF_CREATE) && (flags != TGL_FLAGS_UNCHANGED)) { if (!_U) { _U = talloc0 (sizeof (*_U)); _U->id = TGL_MK_CHANNEL (id); tglp_insert_channel (TLS, _U); } else { assert (!(_U->flags & TGLPF_CREATED)); } updates |= TGL_UPDATE_CREATED; } else { assert (_U->flags & TGLPF_CREATED); } struct tgl_channel *C = &_U->channel; if (flags == TGL_FLAGS_UNCHANGED) { flags = C->flags; } flags &= TGLCHF_TYPE_MASK; if ((flags & TGLCHF_TYPE_MASK) != (C->flags & TGLCHF_TYPE_MASK)) { updates |= TGL_UPDATE_FLAGS; } C->flags = (C->flags & ~TGLCHF_TYPE_MASK) | flags; if (access_hash && *access_hash != C->access_hash) { C->access_hash = *access_hash; C->id.access_hash = *access_hash; updates |= TGL_UPDATE_ACCESS_HASH; } if (date) { C->date = *date; } if (title && (!C->title || mystreq1 (C->title, title, title_len))) { if (C->title) { tfree_str (C->title); } C->title = tstrndup (title, title_len); if (C->print_title) { tglp_peer_delete_name (TLS, (void *)C); tfree_str (C->print_title); } C->print_title = TLS->callback.create_print_name (TLS, C->id, C->title, 0, 0, 0); tglp_peer_insert_name (TLS, (void *)C); updates |= TGL_UPDATE_TITLE; } if (chat_photo) { if (chat_photo->photo_big && DS_LVAL (chat_photo->photo_big->secret) != C->photo_big.secret) { tglf_fetch_file_location (TLS, &C->photo_big, chat_photo->photo_big); tglf_fetch_file_location (TLS, &C->photo_small, chat_photo->photo_small); updates |= TGL_UPDATE_PHOTO; } } if (photo) { if (!C->photo || C->photo->id != DS_LVAL (photo->id)) { if (C->photo) { tgls_free_photo (TLS, C->photo); } C->photo = tglf_fetch_alloc_photo (TLS, photo); C->flags |= TGLPF_HAS_PHOTO; } } if (username) { if (!C->username || mystreq1 (C->username, username, username_len)) { if (C->username) { tfree_str (C->username); } C->username = tstrndup (username, username_len); updates |= TGL_UPDATE_USERNAME; } } if (about) { if (!C->about || mystreq1 (C->about, about, about_len)) { tfree_str (C->about); } C->about = tstrndup (about, about_len); } if (admins_count) { C->admins_count = *admins_count; } if (participants_count) { C->participants_count = *participants_count; } if (kicked_count) { C->kicked_count = *kicked_count; } if (last_read_in) { C->last_read_in = *last_read_in; tgls_messages_mark_read (TLS, C->last, 0, C->last_read_in); } if (TLS->callback.channel_update && updates) { TLS->callback.channel_update (TLS, C, updates); } } /* }}} */ void bl_do_peer_delete (struct tgl_state *TLS, tgl_peer_id_t id) /* {{{ */ { tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P || !(P->flags & TGLPF_CREATED)) { return; } if (P->flags & TGLPF_DELETED) { return; } P->flags |= TGLPF_DELETED; switch (id.peer_type) { case TGL_PEER_USER: if (TLS->callback.user_update) { TLS->callback.user_update (TLS, (void *)P, TGL_UPDATE_DELETED); } break; case TGL_PEER_CHAT: if (TLS->callback.chat_update) { TLS->callback.chat_update (TLS, (void *)P, TGL_UPDATE_DELETED); } break; case TGL_PEER_ENCR_CHAT: if (TLS->callback.secret_chat_update) { TLS->callback.secret_chat_update (TLS, (void *)P, TGL_UPDATE_DELETED); } break; case TGL_PEER_CHANNEL: if (TLS->callback.channel_update) { TLS->callback.channel_update (TLS, (void *)P, TGL_UPDATE_DELETED); } break; default: assert (0); } } /* }}} */ telegram-purple/tgl/binlog.tl000066400000000000000000000066641357227200100165770ustar00rootroot00000000000000---types--- binlog.encrKey key:64*[int] = binlog.EncrKey; binlog.peerUser = binlog.PeerType; binlog.peerChat = binlog.PeerType; binlog.peerChannel = binlog.PeerType; binlog.peer peer_type:binlog.PeerType peer_id:int = binlog.Peer; binlog.start = binlog.Update; binlog.authKey dc:int key:%binlog.EncrKey = binlog.Update; binlog.defaultDc dc:int = binlog.Update; binlog.dcSigned dc:int = binlog.Update; binlog.dcOption flags:int dc:int name:string ip:string port:int = binlog.Update; binlog.ourId id:int = binlog.Update; binlog.setDhParams root:int prime:%binlog.EncrKey version:int = binlog.Update; binlog.setPts pts:int = binlog.Update; binlog.setQts qts:int = binlog.Update; binlog.setDate date:int = binlog.Update; binlog.setSeq seq:int = binlog.Update; binlog.peerDelete peer:%binlog.Peer = binlog.Update; binlog.encrChat#84977251 flags:# id:int access_hash:flags.17?long date:flags.18?int admin:flags.19?int user_id:flags.20?int key:flags.21?%binlog.EncrKey g_key:flags.22?%binlog.EncrKey state:flags.23?int ttl:flags.24?int layer:flags.25?int in_seq_no:flags.26?int last_in_seq_no:flags.26?int out_seq_no:flags.26?int key_fingerprint:flags.27?long = binlog.Update; binlog.encrChatExchange#9d49488d flags:# id:int exchange_id:flags.17?long key:flags.18?%binlog.EncrKey state:flags.19?int = binlog.Update; binlog.user#127cf2f9 flags:# id:int access_hash:flags.17?long first_name:flags.18?string last_name:flags.18?string phone:flags.19?string username:flags.20?string photo:flags.21?Photo real_first_name:flags.22?string real_last_name:flags.22?string user_photo:flags.23?UserProfilePhoto last_read_in:flags.24?int last_read_out:flags.25?int bot_info:flags.26?BotInfo = binlog.Update; binlog.chat#0a10aa92 flags:# id:int title:flags.17?string user_num:flags.18?int date:flags.19?int version:flags.20?int participants:flags.20?(Vector ChatParticipant) chat_photo:flags.21?ChatPhoto photo:flags.22?Photo admin:flags.23?int last_read_in:flags.24?int last_read_out:flags.25?int = binlog.Update; binlog.channel flags:# id:int title:flags.17?string username:flags.18?string date:flags.19?int version:flags.20?int chat_photo:flags.21?ChatPhoto photo:flags.22?Photo about:flags.23?int last_read_in:flags.24?int admins_count:flags.25?int kicked_count:flags.26?int access_hash:flags.27?long = binlog.Update; binlog.chatAddParticipant id:int version:int user_id:int inviter_id:int date:int = binlog.Update; binlog.chatDelParticipant id:int version:int user_id:int = binlog.Update; binlog.setMsgId old_id:long new_id:int = binlog.Update; binlog.messageDelete lid:long = binlog.Update; binlog.messageNew#427cfcdb flags:# lid:long from:flags.17?%binlog.Peer to:flags.17?%binlog.Peer fwd_from_id:flags.18?%binlog.Peer fwd_date:flags.18?int date:flags.19?int message:flags.20?string media:flags.21?MessageMedia action:flags.22?MessageAction reply_id:flags.23?int reply_markup:flags.24?ReplyMarkup = binlog.Update; binlog.messageEncrNew#6cf7cabc flags:# lid:long from:flags.17?%binlog.Peer to:flags.17?%binlog.Peer //empty 18 bit date:flags.19?int message:flags.20?string encr_media:flags.21?DecryptedMessageMedia encr_action:flags.22?DecryptedMessageAction file:flags.23?EncryptedFile = binlog.Update; binlog.msgUpdate#6dd4d85f lid:long = binlog.Update; binlog.resetAuthorization = binlog.Update; ---functions--- telegram-purple/tgl/config.h.in000066400000000000000000000076551357227200100170100ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* disable extf queries */ #undef DISABLE_EXTF /* Use libevent v1 */ #undef EVENT_V1 /* Use libevent v2 */ #undef EVENT_V2 /* Define to 1 if you have the `alarm' function. */ #undef HAVE_ALARM /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the `endpwent' function. */ #undef HAVE_ENDPWENT /* Define to 1 if you have the header file. */ #undef HAVE_EXECINFO_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `event' library (-levent). */ #undef HAVE_LIBEVENT /* Define to 1 if you have the `gcrypt' library (-lgcrypt). */ #undef HAVE_LIBGCRYPT /* Define to 1 if you have `z' library (-lz) */ #undef HAVE_LIBZ /* Define to 1 if you have the header file. */ #undef HAVE_MACH_MACH_H /* Define to 1 if you have the `malloc' function. */ #undef HAVE_MALLOC /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the `realloc' function. */ #undef HAVE_REALLOC /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strndup' function. */ #undef HAVE_STRNDUP /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H /* Define to 1 if you have the `uname' function. */ #undef HAVE_UNAME /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* avoid OpenSSL entirely, use libgcrypt instead (this can't read *.pub files, though.) */ #undef TGL_AVOID_OPENSSL /* fixed for correct valgrind work */ #undef VALGRIND_FIXES /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if doesn't define. */ #undef uid_t telegram-purple/tgl/configure000077500000000000000000005070001357227200100166610ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for telegram-cli 1.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='telegram-cli' PACKAGE_TARNAME='telegram-cli' PACKAGE_VERSION='1.0' PACKAGE_STRING='telegram-cli 1.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="config.h.in" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS EXTRA_OBJECTS EXTRA_LIBS EGREP GREP CPP OPENSSL_LDFLAGS OPENSSL_LIBS OPENSSL_INCLUDES PKG_CONFIG AR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_openssl with_openssl with_zlib enable_extf enable_libevent enable_valgrind ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures telegram-cli 1.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/telegram-cli] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of telegram-cli 1.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-openssl disables OpenSSL, and don't link against it (this can't read *.pub files, though.) --enable-extf enables extended queries system --enable-libevent include libevent-based net and timers --enable-valgrind fixes for correct valgrind work Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-openssl=DIR root of the OpenSSL directory --with-zlib=DIR root directory path of zlib installation [defaults to /usr/local or /usr if not found in /usr/local] --without-zlib to disable zlib usage completely Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF telegram-cli configure 1.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by telegram-cli $as_me 1.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_openssl.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) # # DESCRIPTION # # Look for OpenSSL in a number of default spots, or in a user-selected # spot (via --with-openssl). Sets # # OPENSSL_INCLUDES to the include directives required # OPENSSL_LIBS to the -l directives required # OPENSSL_LDFLAGS to the -L or -R flags required # # and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately # # This macro sets OPENSSL_INCLUDES such that source files should use the # openssl/ directory in include directives: # # #include # # LICENSE # # Copyright (c) 2009,2010 Zmanda Inc. # Copyright (c) 2009,2010 Dustin J. Mitchell # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 8 # This is what autoupdate's m4 run will expand. It fires # the warning (with _au_warn_XXX), outputs it into the # updated configure.ac (with AC_DIAGNOSE), and then outputs # the replacement expansion. # This is an auxiliary macro that is also run when # autoupdate runs m4. It simply calls m4_warning, but # we need a wrapper so that each warning is emitted only # once. We break the quoting in m4_warning's argument in # order to expand this macro's arguments, not AU_DEFUN's. # Finally, this is the expansion that is picked up by # autoconf. It tells the user to run autoupdate, and # then outputs the replacement expansion. We do not care # about autoupdate's warning because that contains # information on what to do *after* running autoupdate. # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_zlib.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_ZLIB([action-if-found], [action-if-not-found]) # # DESCRIPTION # # This macro searches for an installed zlib library. If nothing was # specified when calling configure, it searches first in /usr/local and # then in /usr, /opt/local and /sw. If the --with-zlib=DIR is specified, # it will try to find it in DIR/include/zlib.h and DIR/lib/libz.a. If # --without-zlib is specified, the library is not searched at all. # # If either the header file (zlib.h) or the library (libz) is not found, # shell commands 'action-if-not-found' is run. If 'action-if-not-found' is # not specified, the configuration exits on error, asking for a valid zlib # installation directory or --without-zlib. # # If both header file and library are found, shell commands # 'action-if-found' is run. If 'action-if-found' is not specified, the # default action appends '-I${ZLIB_HOME}/include' to CPFLAGS, appends # '-L$ZLIB_HOME}/lib' to LDFLAGS, prepends '-lz' to LIBS, and calls # AC_DEFINE(HAVE_LIBZ). You should use autoheader to include a definition # for this symbol in a config.h file. Sample usage in a C/C++ source is as # follows: # # #ifdef HAVE_LIBZ # #include # #endif /* HAVE_LIBZ */ # # LICENSE # # Copyright (c) 2008 Loic Dachary # Copyright (c) 2010 Bastien Chevreux # # 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, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 14 # This is what autoupdate's m4 run will expand. It fires # the warning (with _au_warn_XXX), outputs it into the # updated configure.ac (with AC_DIAGNOSE), and then outputs # the replacement expansion. # This is an auxiliary macro that is also run when # autoupdate runs m4. It simply calls m4_warning, but # we need a wrapper so that each warning is emitted only # once. We break the quoting in m4_warning's argument in # order to expand this macro's arguments, not AU_DEFUN's. # Finally, this is the expansion that is picked up by # autoconf. It tells the user to run autoupdate, and # then outputs the replacement expansion. We do not care # about autoupdate's warning because that contains # information on what to do *after* running autoupdate. # Checks for programs. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="as_fn_error $? "No ar found. Huh?" "$LINENO" 5" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi # BSD locations for headers and libraries from packages, Linux locations for self-compiled stuff. CPPFLAGS="$CPPFLAGS -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" # Checks for libraries. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 $as_echo_n "checking for library containing clock_gettime... " >&6; } if ${ac_cv_search_clock_gettime+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_clock_gettime+:} false; then : break fi done if ${ac_cv_search_clock_gettime+:} false; then : else ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 $as_echo "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi EVENT_VER="" EXTRA_OBJECTS="" # OPENSSL_INCLUDES to the include directives required # OPENSSL_LIBS to the -l directives required # OPENSSL_LDFLAGS to the -L or -R flags required # Check whether --enable-openssl was given. if test "${enable_openssl+set}" = set; then : enableval=$enable_openssl; if test "x$enableval" = "xno" ; then $as_echo "#define TGL_AVOID_OPENSSL 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcry_mpi_snatch in -lgcrypt" >&5 $as_echo_n "checking for gcry_mpi_snatch in -lgcrypt... " >&6; } if ${ac_cv_lib_gcrypt_gcry_mpi_snatch+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgcrypt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gcry_mpi_snatch (); int main () { return gcry_mpi_snatch (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_gcrypt_gcry_mpi_snatch=yes else ac_cv_lib_gcrypt_gcry_mpi_snatch=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gcrypt_gcry_mpi_snatch" >&5 $as_echo "$ac_cv_lib_gcrypt_gcry_mpi_snatch" >&6; } if test "x$ac_cv_lib_gcrypt_gcry_mpi_snatch" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBGCRYPT 1 _ACEOF LIBS="-lgcrypt $LIBS" else as_fn_error $? "\"Need libgcrypt >= 1.60\"" "$LINENO" 5 fi else # Don't be annoying, so don't inform the user about --disable-openssl found=false # Check whether --with-openssl was given. if test "${with_openssl+set}" = set; then : withval=$with_openssl; case "$withval" in "" | y | ye | yes | n | no) as_fn_error $? "Invalid --with-openssl value" "$LINENO" 5 ;; *) ssldirs="$withval" ;; esac else # if pkg-config is installed and openssl has installed a .pc file, # then use that information and don't search ssldirs # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$PKG_CONFIG" != x""; then OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` if test $? = 0; then OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` found=true fi fi # no such luck; use some default ssldirs if ! $found; then ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" fi fi # note that we #include , so the OpenSSL headers have to be in # an 'openssl' subdirectory if ! $found; then OPENSSL_INCLUDES= for ssldir in $ssldirs; do { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $ssldir" >&5 $as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; } if test -f "$ssldir/include/openssl/ssl.h"; then OPENSSL_INCLUDES="-I$ssldir/include" OPENSSL_LDFLAGS="-L$ssldir/lib" OPENSSL_LIBS="-lssl -lcrypto" found=true { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } break else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi done # if the file wasn't found, well, go ahead and try the link anyway -- maybe # it will just work! fi # try the preprocessor and linker with our new flags, # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5 $as_echo_n "checking whether compiling and linking against OpenSSL works... " >&6; } echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&5 save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" LIBS="$OPENSSL_LIBS $LIBS" CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { SSL_new(NULL) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "No openssl found." "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" fi else found=false # Check whether --with-openssl was given. if test "${with_openssl+set}" = set; then : withval=$with_openssl; case "$withval" in "" | y | ye | yes | n | no) as_fn_error $? "Invalid --with-openssl value" "$LINENO" 5 ;; *) ssldirs="$withval" ;; esac else # if pkg-config is installed and openssl has installed a .pc file, # then use that information and don't search ssldirs # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x"$PKG_CONFIG" != x""; then OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` if test $? = 0; then OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` found=true fi fi # no such luck; use some default ssldirs if ! $found; then ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" fi fi # note that we #include , so the OpenSSL headers have to be in # an 'openssl' subdirectory if ! $found; then OPENSSL_INCLUDES= for ssldir in $ssldirs; do { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $ssldir" >&5 $as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; } if test -f "$ssldir/include/openssl/ssl.h"; then OPENSSL_INCLUDES="-I$ssldir/include" OPENSSL_LDFLAGS="-L$ssldir/lib" OPENSSL_LIBS="-lssl -lcrypto" found=true { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } break else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi done # if the file wasn't found, well, go ahead and try the link anyway -- maybe # it will just work! fi # try the preprocessor and linker with our new flags, # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5 $as_echo_n "checking whether compiling and linking against OpenSSL works... " >&6; } echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&5 save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" LIBS="$OPENSSL_LIBS $LIBS" CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { SSL_new(NULL) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "No openssl found. With --disable-openssl, libtgl will use libgcrypt instead." "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # # Handle user hints # { $as_echo "$as_me:${as_lineno-$LINENO}: checking if zlib is wanted" >&5 $as_echo_n "checking if zlib is wanted... " >&6; } zlib_places="/usr/local /usr /opt/local /sw" # Check whether --with-zlib was given. if test "${with_zlib+set}" = set; then : withval=$with_zlib; if test "$withval" != no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } if test -d "$withval" then zlib_places="$withval $zlib_places" else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sorry, $withval does not exist, checking usual places" >&5 $as_echo "$as_me: WARNING: Sorry, $withval does not exist, checking usual places" >&2;} fi else zlib_places= { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi # # Locate zlib, if wanted # if test -n "${zlib_places}" then # check the user supplied or any other more or less 'standard' place: # Most UNIX systems : /usr/local and /usr # MacPorts / Fink on OSX : /opt/local respectively /sw for ZLIB_HOME in ${zlib_places} ; do if test -f "${ZLIB_HOME}/include/zlib.h"; then break; fi ZLIB_HOME="" done ZLIB_OLD_LDFLAGS=$LDFLAGS ZLIB_OLD_CPPFLAGS=$CPPFLAGS if test -n "${ZLIB_HOME}"; then LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateEnd in -lz" >&5 $as_echo_n "checking for inflateEnd in -lz... " >&6; } if ${ac_cv_lib_z_inflateEnd+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inflateEnd (); int main () { return inflateEnd (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_inflateEnd=yes else ac_cv_lib_z_inflateEnd=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateEnd" >&5 $as_echo "$ac_cv_lib_z_inflateEnd" >&6; } if test "x$ac_cv_lib_z_inflateEnd" = xyes; then : zlib_cv_libz=yes else zlib_cv_libz=no fi ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes; then : zlib_cv_zlib_h=yes else zlib_cv_zlib_h=no fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test "$zlib_cv_libz" = "yes" && test "$zlib_cv_zlib_h" = "yes" then # # If both library and header were found, action-if-found # CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" LIBS="-lz $LIBS" $as_echo "#define HAVE_LIBZ 1" >>confdefs.h else # # If either header or library was not found, action-if-not-found # as_fn_error $? "No zlib found" "$LINENO" 5 fi fi # Check whether --enable-extf was given. if test "${enable_extf+set}" = set; then : enableval=$enable_extf; if test "x$enableval" = "xno" ; then $as_echo "#define DISABLE_EXTF 1" >>confdefs.h fi fi # Check whether --enable-libevent was given. if test "${enable_libevent+set}" = set; then : enableval=$enable_libevent; if test "x$enableval" = "xyes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for event_base_new in -levent" >&5 $as_echo_n "checking for event_base_new in -levent... " >&6; } if ${ac_cv_lib_event_event_base_new+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-levent $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char event_base_new (); int main () { return event_base_new (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_event_event_base_new=yes else ac_cv_lib_event_event_base_new=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_event_event_base_new" >&5 $as_echo "$ac_cv_lib_event_event_base_new" >&6; } if test "x$ac_cv_lib_event_event_base_new" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBEVENT 1 _ACEOF LIBS="-levent $LIBS" else as_fn_error $? "no libevent found" "$LINENO" 5 fi ac_fn_c_check_header_mongrel "$LINENO" "event2/event.h" "ac_cv_header_event2_event_h" "$ac_includes_default" if test "x$ac_cv_header_event2_event_h" = xyes; then : $as_echo "#define EVENT_V2 1" >>confdefs.h else ac_fn_c_check_header_mongrel "$LINENO" "event.h" "ac_cv_header_event_h" "$ac_includes_default" if test "x$ac_cv_header_event_h" = xyes; then : $as_echo "#define EVENT_V1 1" >>confdefs.h else as_fn_error $? "no libevent found" "$LINENO" 5 fi fi EXTRA_OBJECTS="${EXTRA_OBJECTS} objs/tgl-net.o objs/tgl-timers.o" fi fi # Check whether --enable-valgrind was given. if test "${enable_valgrind+set}" = set; then : enableval=$enable_valgrind; if test "x$enableval" = "xyes" ; then ac_fn_c_check_header_mongrel "$LINENO" "valgrind/memcheck.h" "ac_cv_header_valgrind_memcheck_h" "$ac_includes_default" if test "x$ac_cv_header_valgrind_memcheck_h" = xyes; then : $as_echo "#define VALGRIND_FIXES 1" >>confdefs.h fi fi fi # Checks for header files. for ac_header in fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # FreeBSD needs -lexecinfo for ac_header in execinfo.h do : ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default" if test "x$ac_cv_header_execinfo_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EXECINFO_H 1 _ACEOF tgl_found_execinfo_header=yes; break; fi done if test "x$tgl_found_execinfo_header" = "xyes"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace_symbols_fd" >&5 $as_echo_n "checking for library containing backtrace_symbols_fd... " >&6; } if ${ac_cv_search_backtrace_symbols_fd+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char backtrace_symbols_fd (); int main () { return backtrace_symbols_fd (); ; return 0; } _ACEOF for ac_lib in '' execinfo; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_backtrace_symbols_fd=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_backtrace_symbols_fd+:} false; then : break fi done if ${ac_cv_search_backtrace_symbols_fd+:} false; then : else ac_cv_search_backtrace_symbols_fd=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace_symbols_fd" >&5 $as_echo "$ac_cv_search_backtrace_symbols_fd" >&6; } ac_res=$ac_cv_search_backtrace_symbols_fd if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi # Checks for typedefs, structures, and compiler characteristics. ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if ${ac_cv_type_uid_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then : ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then $as_echo "#define uid_t int" >>confdefs.h $as_echo "#define gid_t int" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac # Checks for library functions. for ac_func in alarm endpwent malloc memset memmove mkdir realloc select socket strdup strndup uname do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by telegram-cli $as_me 1.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ telegram-cli config.status 1.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi telegram-purple/tgl/configure.ac000066400000000000000000000060621357227200100172420ustar00rootroot00000000000000AC_PREREQ([2.68]) AC_INIT([telegram-cli], [1.0]) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) m4_include([m4_ax_check_openssl.m4]) m4_include([m4_ax_check_zlib.m4]) # Checks for programs. AC_PROG_CC AC_CHECK_TOOL(AR, ar, [AC_MSG_ERROR([No ar found. Huh?])]) # BSD locations for headers and libraries from packages, Linux locations for self-compiled stuff. CPPFLAGS="$CPPFLAGS -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" # Checks for libraries. AC_SEARCH_LIBS([clock_gettime], [rt]) EVENT_VER="" EXTRA_OBJECTS="" # OPENSSL_INCLUDES to the include directives required # OPENSSL_LIBS to the -l directives required # OPENSSL_LDFLAGS to the -L or -R flags required AC_ARG_ENABLE(openssl,[ --disable-openssl disables OpenSSL, and don't link against it (this can't read *.pub files, though.)], [ if test "x$enableval" = "xno" ; then AC_DEFINE([TGL_AVOID_OPENSSL],[1],[avoid OpenSSL entirely, use libgcrypt instead (this can't read *.pub files, though.)]) AC_CHECK_LIB([gcrypt], [gcry_mpi_snatch], [], [AC_MSG_ERROR(["Need libgcrypt >= 1.60"])]) else # Don't be annoying, so don't inform the user about --disable-openssl AX_CHECK_OPENSSL(,[AC_MSG_ERROR([No openssl found.])]) fi ],[ AX_CHECK_OPENSSL(,[AC_MSG_ERROR([No openssl found. With --disable-openssl, libtgl will use libgcrypt instead.])]) ]) AX_CHECK_ZLIB(, [AC_MSG_ERROR([No zlib found])]) AC_ARG_ENABLE(extf,[ --enable-extf enables extended queries system], [ if test "x$enableval" = "xno" ; then AC_DEFINE([DISABLE_EXTF],[1],[disable extf queries]) fi ],[ ]) AC_ARG_ENABLE(libevent,[ --enable-libevent include libevent-based net and timers], [ if test "x$enableval" = "xyes" ; then AC_CHECK_LIB([event], [event_base_new], [], [AC_MSG_ERROR([no libevent found])]) AC_CHECK_HEADER(event2/event.h, [AC_DEFINE([EVENT_V2], [1], [Use libevent v2])], [ AC_CHECK_HEADER(event.h, [AC_DEFINE([EVENT_V1], [1], [Use libevent v1])], [AC_MSG_ERROR([no libevent found])]) ]) EXTRA_OBJECTS="${EXTRA_OBJECTS} objs/tgl-net.o objs/tgl-timers.o" fi ],[ ]) AC_ARG_ENABLE(valgrind,[ --enable-valgrind fixes for correct valgrind work], [ if test "x$enableval" = "xyes" ; then AC_CHECK_HEADER(valgrind/memcheck.h, [AC_DEFINE([VALGRIND_FIXES], [1], [fixed for correct valgrind work])], [ ]) fi ],[ ]) # Checks for header files. AC_CHECK_HEADERS([fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h]) # FreeBSD needs -lexecinfo AC_CHECK_HEADERS([execinfo.h], [tgl_found_execinfo_header=yes; break;]) AS_IF([test "x$tgl_found_execinfo_header" = "xyes"], [AC_SEARCH_LIBS([backtrace_symbols_fd], [execinfo])]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T AC_TYPE_UID_T AC_C_INLINE # Checks for library functions. AC_CHECK_FUNCS([alarm endpwent malloc memset memmove mkdir realloc select socket strdup strndup uname]) AC_SUBST(EXTRA_LIBS) AC_SUBST(EXTRA_OBJECTS) AC_CONFIG_FILES([Makefile]) AC_OUTPUT telegram-purple/tgl/crypto/000077500000000000000000000000001357227200100162705ustar00rootroot00000000000000telegram-purple/tgl/crypto/aes.h000066400000000000000000000026461357227200100172210ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #ifndef __TGL_CRYPTO_AES_H__ #define __TGL_CRYPTO_AES_H__ #include /* size_t */ #include "config.h" typedef struct TGLC_aes_key { char _dummy[ #ifdef TGL_AVOID_OPENSSL 32 #else 244 #endif ]; } TGLC_aes_key; void TGLC_aes_set_encrypt_key (const unsigned char *userKey, const int bits, TGLC_aes_key *key); void TGLC_aes_set_decrypt_key (const unsigned char *userKey, const int bits, TGLC_aes_key *key); void TGLC_aes_ige_encrypt (const unsigned char *in, unsigned char *out, size_t length, const TGLC_aes_key *key, unsigned char *ivec, const int enc); #endif telegram-purple/tgl/crypto/aes_altern.c000066400000000000000000000124171357227200100205560ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifdef TGL_AVOID_OPENSSL /* Marginally speed up compilation */ #define GCRYPT_NO_MPI_MACROS /* Fail-fast when something becomes deprecated. */ #define GCRYPT_NO_DEPRECATED #include #include #include "aes.h" #include "meta.h" #include "rand.h" #define AES_BLOCK_BITS 128 #define AES_BLOCK_BYTES (AES_BLOCK_BITS/8) #define AES_KEY_BITS 256 #define AES_KEY_BYTES (AES_KEY_BITS/8) typedef char check_struct_sizes[(sizeof (TGLC_aes_key) == AES_KEY_BYTES) - 1]; void TGLC_aes_set_encrypt_key (const unsigned char *userKey, const int bits, TGLC_aes_key *key) { assert (bits == AES_KEY_BITS); memcpy (key->_dummy, userKey, AES_KEY_BYTES); } void TGLC_aes_set_decrypt_key (const unsigned char *userKey, const int bits, TGLC_aes_key *key) { TGLC_aes_set_encrypt_key (userKey, bits, key); } // TODO: Try to use gcrypt's internal buf_xor? static void do_xor_block (const unsigned char *in, const unsigned char *with, unsigned char *out) { /* TODO: Referencing them as "size_t" (or whatever biggest numerical type available) is probably faster, but also more error-prone. */ int i; for (i = 0; i < 16; ++i) { *out++ = *in++ ^ *with++; } } static gcry_error_t do_ige_encrypt (const unsigned char *in, unsigned char *out, unsigned long n_blocks, gcry_cipher_hd_t cipher, unsigned char *ivec) { /* The docs say, at the end of section 2: * "OpenSSL uses the convention that the first block of the IV is x_0 * and the second block is y_0." * Well, no. This is a subtle error: FIRST comes the previous ENcrypted block, * THEN the DEcrypted block. * Also, keep a copy of the old cleartext, in case in == out. */ unsigned char buf[2 * 16]; unsigned char *prev_x = buf; unsigned char *cur_x = buf + 16; memcpy (prev_x, ivec + 16, 16); const unsigned char *prev_y = ivec; /* gcrypt doesn't allow overlapping buffers. Kudos to "reubensammut" for * noticing this. Note that this also works if in == out. */ unsigned char tmp[16]; unsigned long i; for (i = 0; i < n_blocks; ++i) { memcpy (cur_x, in, 16); /* Might overwrite 'in'. */ do_xor_block (in, prev_y, out); gcry_error_t gcry_error = gcry_cipher_encrypt (cipher, tmp, 16, out, 16); if (gcry_error) { return gcry_error; } do_xor_block (tmp, prev_x, out); prev_y = out; // encrypted is in 'out' in += 16; out += 16; // swap (tmp_x, cur_x); unsigned char *tmp_x = cur_x; cur_x = prev_x; prev_x = tmp_x; } if (n_blocks > 0) { /* OpenSSL updates the IV, so we do that, too. * One could avoid memcpy here, as it's only 16 bytes. */ memcpy (ivec + 16, prev_x, 16); memcpy (ivec, prev_y, 16); } return 0; } static gcry_error_t do_ige_decrypt (const unsigned char *in, unsigned char *out, unsigned long n_blocks, gcry_cipher_hd_t cipher, unsigned char *ivec) { /* Also, keep a copy of the old ciphertext, in case in == out. */ unsigned char buf[2 * 16]; unsigned char *prev_y = buf; unsigned char *cur_y = buf + 16; memcpy (prev_y, ivec, 16); const unsigned char *prev_x = ivec + 16; /* gcrypt doesn't allow overlapping buffers. Kudos to "reubensammut" for * noticing this. Note that this also works if in == out. */ unsigned char tmp[16]; unsigned long i; for (i = 0; i < n_blocks; ++i) { memcpy (cur_y, in, 16); /* Might overwrite 'in'. */ do_xor_block (in, prev_x, out); gcry_error_t gcry_error = gcry_cipher_decrypt (cipher, tmp, 16, out, 16); if (gcry_error) { return gcry_error; } do_xor_block (tmp, prev_y, out); prev_x = out; // decrypted is in 'out' in += 16; out += 16; // swap (tmp_y, cur_y); unsigned char *tmp_y = cur_y; cur_y = prev_y; prev_y = tmp_y; } /* Do not change ivec */ return 0; } /* Needs to be given an IV of length 2*AES_BLOCK_BYTES. */ void TGLC_aes_ige_encrypt (const unsigned char *in, unsigned char *out, size_t length, const TGLC_aes_key *key, unsigned char *ivec, const int enc) { assert (!(length % AES_BLOCK_BYTES)); /* Set it up. */ gcry_cipher_hd_t cipher; gcry_error_t gcry_error = gcry_cipher_open (&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 0); assert (!gcry_error); gcry_cipher_setkey (cipher, key->_dummy, AES_KEY_BYTES); if (enc) { gcry_error = do_ige_encrypt(in, out, length / AES_BLOCK_BYTES, cipher, ivec); } else { gcry_error = do_ige_decrypt(in, out, length / AES_BLOCK_BYTES, cipher, ivec); } assert (!gcry_error); gcry_cipher_close(cipher); } #endif telegram-purple/tgl/crypto/aes_openssl.c000066400000000000000000000032311357227200100207460ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifndef TGL_AVOID_OPENSSL #include #include "aes.h" #include "meta.h" typedef char check_struct_sizes[(sizeof (AES_KEY) == sizeof (TGLC_aes_key)) - 1]; TGLC_WRAPPER_ASSOC(aes_key,AES_KEY) void TGLC_aes_set_encrypt_key (const unsigned char *userKey, const int bits, TGLC_aes_key *key) { int success = AES_set_encrypt_key(userKey, bits, unwrap_aes_key (key)); assert (0 == success); } void TGLC_aes_set_decrypt_key (const unsigned char *userKey, const int bits, TGLC_aes_key *key) { int success = AES_set_decrypt_key(userKey, bits, unwrap_aes_key (key)); assert (0 == success); } void TGLC_aes_ige_encrypt (const unsigned char *in, unsigned char *out, size_t length, const TGLC_aes_key *key, unsigned char *ivec, const int enc) { AES_ige_encrypt (in, out, length, unwrap_aes_key (key), ivec, enc); } #endif telegram-purple/tgl/crypto/bn.h000066400000000000000000000037161357227200100170470ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #ifndef __TGL_CRYPTO_BN_H__ #define __TGL_CRYPTO_BN_H__ typedef struct TGLC_bn_ctx TGLC_bn_ctx; typedef struct TGLC_bn TGLC_bn; TGLC_bn_ctx *TGLC_bn_ctx_new (void); void TGLC_bn_ctx_free (TGLC_bn_ctx* ctx); TGLC_bn *TGLC_bn_new (void); void TGLC_bn_free (TGLC_bn *a); void TGLC_bn_clear_free (TGLC_bn *a); int TGLC_bn_cmp (const TGLC_bn *a, const TGLC_bn *b); int TGLC_bn_is_prime (const TGLC_bn *a, int checks, void (*callback) (int, int, void *), TGLC_bn_ctx *ctx, void *cb_arg); int TGLC_bn_bn2bin (const TGLC_bn *a, unsigned char *to); TGLC_bn * TGLC_bn_bin2bn(const unsigned char *s, int len, TGLC_bn *ret); int TGLC_bn_set_word (TGLC_bn *a, unsigned long w); unsigned long TGLC_bn_get_word (const TGLC_bn *a); int TGLC_bn_num_bits (const TGLC_bn *a); void TGLC_bn_sub (TGLC_bn *r, const TGLC_bn *a, const TGLC_bn *b); int TGLC_bn_div (TGLC_bn *dv, TGLC_bn *rem, const TGLC_bn *a, const TGLC_bn *d, TGLC_bn_ctx *ctx); int TGLC_bn_mod_exp (TGLC_bn *r, const TGLC_bn *a, const TGLC_bn *p, const TGLC_bn *m, TGLC_bn_ctx *ctx); #define TGLC_bn_num_bytes(a) ((TGLC_bn_num_bits(a)+7)/8) #define TGLC_bn_mod(rem,m,d,ctx) TGLC_bn_div(NULL,(rem),(m),(d),(ctx)) #endif telegram-purple/tgl/crypto/bn_altern.c000066400000000000000000000105611357227200100204030ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifdef TGL_AVOID_OPENSSL /* Fail-fast when something becomes deprecated. */ #define GCRYPT_NO_DEPRECATED #include #include #include "bn.h" #include "meta.h" // There is no "_ctx" equivalent in gcrypt. TGLC_WRAPPER_ASSOC(bn_ctx,int) TGLC_WRAPPER_ASSOC(bn,struct gcry_mpi) TGLC_bn_ctx *TGLC_bn_ctx_new (void) { /* Must not be the null pointer, but must never be dereferenced. Assume that "1" is an invalid address. */ return ((void *)1); } void TGLC_bn_ctx_free (TGLC_bn_ctx* ctx) { (void) ctx; } TGLC_bn *TGLC_bn_new (void) { // TODO: Determine how many bits should be pre-allocated. TGLC_bn *ret = wrap_bn (gcry_mpi_new (2048)); assert (ret); return ret; } void TGLC_bn_free (TGLC_bn *a) { gcry_mpi_release (unwrap_bn (a)); } void TGLC_bn_clear_free (TGLC_bn *a) { /* This only protects against accidental use-after-free. I don't see the point of clearing, since we're not operating in protected memory AND the most crucial fields are never cleared anyway. */ gcry_mpi_set_ui (unwrap_bn (a), 0); gcry_mpi_release (unwrap_bn (a)); } int TGLC_bn_cmp (const TGLC_bn *a, const TGLC_bn *b) { return gcry_mpi_cmp (unwrap_bn (a), unwrap_bn (b)); } int TGLC_bn_is_prime (const TGLC_bn *a, int checks, void (*callback) (int, int, void *), TGLC_bn_ctx *ctx, void *cb_arg) { assert (0 == checks); assert (NULL == callback); (void) ctx; assert (NULL == cb_arg); /* Second argument is ignored. * No really, here's what libgcrypt's source does: * (void)flags; */ gcry_error_t err = gcry_prime_check (unwrap_bn (a), 0); /* This is nasty. In essence, gcry returns a bool whether it is NOT a prime. */ return !err; } int TGLC_bn_bn2bin (const TGLC_bn *a, unsigned char *to) { const unsigned long num_bytes = TGLC_bn_num_bytes (a); gcry_error_t gcry_error = gcry_mpi_print (GCRYMPI_FMT_USG, to, num_bytes, NULL, unwrap_bn (a)); assert (!gcry_error); return num_bytes; } TGLC_bn *TGLC_bn_bin2bn(const unsigned char *s, int len, TGLC_bn *ret) { gcry_mpi_t ret_ptr = NULL; gcry_error_t gcry_error = gcry_mpi_scan (&ret_ptr, GCRYMPI_FMT_USG, s, len, NULL); assert (!gcry_error); assert (ret_ptr); if (!ret) { return wrap_bn (ret_ptr); } gcry_mpi_snatch (unwrap_bn (ret), ret_ptr); return ret; } int TGLC_bn_set_word (TGLC_bn *a, unsigned long w) { assert (a); gcry_mpi_set_ui (unwrap_bn (a), w); return 1; } unsigned long TGLC_bn_get_word (const TGLC_bn *a) { const unsigned long num_bytes = TGLC_bn_num_bytes (a); assert (sizeof (unsigned long) >= num_bytes); unsigned char tmp[sizeof (unsigned long)]; memset (tmp, 0, sizeof (unsigned long)); TGLC_bn_bn2bin (a, tmp + sizeof (unsigned long) - num_bytes); /* Inefficient, but runs a total of three times per connection. */ /* TODO: Optimize? */ unsigned long ret = 0; unsigned int i; for (i = 0; i < sizeof (unsigned long); ++i) { ret <<= 8; ret |= tmp[i]; } return ret; } int TGLC_bn_num_bits (const TGLC_bn *a) { return gcry_mpi_get_nbits (unwrap_bn (a)); } void TGLC_bn_sub (TGLC_bn *r, const TGLC_bn *a, const TGLC_bn *b) { gcry_mpi_sub (unwrap_bn (r), unwrap_bn (a), unwrap_bn (b)); } int TGLC_bn_div (TGLC_bn *dv, TGLC_bn *rem, const TGLC_bn *a, const TGLC_bn *d, TGLC_bn_ctx *ctx) { (void) ctx; gcry_mpi_div (unwrap_bn (dv), unwrap_bn (rem), unwrap_bn (a), unwrap_bn (d), 0); return 1; } int TGLC_bn_mod_exp (TGLC_bn *r, const TGLC_bn *a, const TGLC_bn *p, const TGLC_bn *m, TGLC_bn_ctx *ctx) { (void) ctx; gcry_mpi_powm (unwrap_bn (r), unwrap_bn (a), unwrap_bn (p), unwrap_bn (m)); return 1; } #endif telegram-purple/tgl/crypto/bn_openssl.c000066400000000000000000000053451357227200100206050ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifndef TGL_AVOID_OPENSSL #include #include #include "bn.h" #include "meta.h" TGLC_WRAPPER_ASSOC(bn_ctx,BN_CTX) TGLC_WRAPPER_ASSOC(bn,BIGNUM) TGLC_bn_ctx *TGLC_bn_ctx_new (void) { return wrap_bn_ctx (BN_CTX_new ()); } void TGLC_bn_ctx_free (TGLC_bn_ctx* ctx) { BN_CTX_free (unwrap_bn_ctx (ctx)); } TGLC_bn *TGLC_bn_new (void) { return wrap_bn (BN_new ()); } void TGLC_bn_free (TGLC_bn *a) { BN_free (unwrap_bn (a)); } void TGLC_bn_clear_free (TGLC_bn *a) { BN_clear_free (unwrap_bn (a)); } int TGLC_bn_cmp (const TGLC_bn *a, const TGLC_bn *b) { return BN_cmp (unwrap_bn (a), unwrap_bn (b)); } int TGLC_bn_is_prime (const TGLC_bn *a, int checks, void (*callback) (int, int, void *), TGLC_bn_ctx *ctx, void *cb_arg) { return BN_is_prime (unwrap_bn (a), checks, callback, unwrap_bn_ctx (ctx), cb_arg); } int TGLC_bn_bn2bin (const TGLC_bn *a, unsigned char *to) { return BN_bn2bin (unwrap_bn (a), to); } TGLC_bn * TGLC_bn_bin2bn(const unsigned char *s, int len, TGLC_bn *ret) { return wrap_bn (BN_bin2bn (s, len, unwrap_bn (ret))); } int TGLC_bn_set_word (TGLC_bn *a, unsigned long w) { return BN_set_word (unwrap_bn (a), w); } unsigned long TGLC_bn_get_word (const TGLC_bn *a) { return BN_get_word (unwrap_bn (a)); } int TGLC_bn_num_bits (const TGLC_bn *a) { return BN_num_bits (unwrap_bn (a)); } void TGLC_bn_sub (TGLC_bn *r, const TGLC_bn *a, const TGLC_bn *b) { int res = BN_sub (unwrap_bn (r), unwrap_bn (a), unwrap_bn (b)); assert (res); } int TGLC_bn_div (TGLC_bn *dv, TGLC_bn *rem, const TGLC_bn *a, const TGLC_bn *d, TGLC_bn_ctx *ctx) { return BN_div (unwrap_bn (dv), unwrap_bn (rem), unwrap_bn (a), unwrap_bn (d), unwrap_bn_ctx (ctx)); } int TGLC_bn_mod_exp (TGLC_bn *r, const TGLC_bn *a, const TGLC_bn *p, const TGLC_bn *m, TGLC_bn_ctx *ctx) { return BN_mod_exp (unwrap_bn (r), unwrap_bn (a), unwrap_bn (p), unwrap_bn (m), unwrap_bn_ctx (ctx)); } #endif telegram-purple/tgl/crypto/err.h000066400000000000000000000021111357227200100172240ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #ifndef __TGL_CRYPTO_ERR_H__ #define __TGL_CRYPTO_ERR_H__ #include void TGLC_err_print_errors_fp (FILE *fp); // Don't want to include tgl.h just for this struct tgl_state; // Init crypto backend, log to TLS int TGLC_init (struct tgl_state *TLS); #endif telegram-purple/tgl/crypto/err_altern.c000066400000000000000000000045201357227200100205720ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifdef TGL_AVOID_OPENSSL #include #include "../tgl.h" #include "../tgl-inner.h" #include "err.h" void TGLC_err_print_errors_fp (FILE *fp) { // Can't print anything meaningful, so don't. (void) fp; } int TGLC_init (struct tgl_state *TLS) { vlogprintf (E_NOTICE, "Init gcrypt\n"); // https://gnupg.org/documentation/manuals/gcrypt/Initializing-the-library.html // https://lists.gnupg.org/pipermail/gcrypt-devel/2003-August/000458.html if (gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { // Someone else already *completed* it. vlogprintf (E_NOTICE, "Init gcrypt: already initialized -- good\n"); return 0; } if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P)) { // Someone else already *started* it without *completing*. vlogprintf (E_WARNING, "Init gcrypt: already started *but not completed* by third party -- bad\n"); vlogprintf (E_WARNING, "Init gcrypt: ... not trying to init gcrypt then.\n"); return 0; } if (!gcry_check_version (GCRYPT_VERSION)) { vlogprintf (E_ERROR, "Init gcrypt: version mismatch!\n"); return -1; } gcry_error_t err = gcry_control (GCRYCTL_DISABLE_SECMEM, NULL, 0); if (err != GPG_ERR_NO_ERROR) { vlogprintf (E_ERROR, "Init gcrypt: secmem failed?!\n"); return -1; } /* Tell Libgcrypt that initialization has completed. */ err = gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); if (err != GPG_ERR_NO_ERROR) { vlogprintf (E_ERROR, "Init gcrypt: init failed?!\n"); return -1; } return 0; } #endif telegram-purple/tgl/crypto/err_openssl.c000066400000000000000000000022511357227200100207670ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifndef TGL_AVOID_OPENSSL #include #include "../tgl.h" #include "../tgl-inner.h" #include "err.h" void TGLC_err_print_errors_fp (FILE *fp) { ERR_print_errors_fp (fp); } int TGLC_init (struct tgl_state *TLS) { // Doesn't seem to need any initialization. vlogprintf (6, "Init OpenSSL (no-op)\n"); return 0; } #endif telegram-purple/tgl/crypto/md5.h000066400000000000000000000017471357227200100171370ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #ifndef __TGL_CRYPTO_MD5_H__ #define __TGL_CRYPTO_MD5_H__ #include /* size_t */ void TGLC_md5 (const unsigned char *d, size_t n, unsigned char *md); #endif telegram-purple/tgl/crypto/md5_altern.c000066400000000000000000000022461357227200100204720ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifdef TGL_AVOID_OPENSSL /* Marginally speed up compilation */ #define GCRYPT_NO_MPI_MACROS /* Fail-fast when something becomes deprecated. */ #define GCRYPT_NO_DEPRECATED #include #include "md5.h" void TGLC_md5 (const unsigned char *d, size_t n, unsigned char *md) { gcry_md_hash_buffer (GCRY_MD_MD5, md, d, n); } #endif telegram-purple/tgl/crypto/md5_openssl.c000066400000000000000000000017711357227200100206720ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifndef TGL_AVOID_OPENSSL #include #include "md5.h" void TGLC_md5(const unsigned char *d, size_t n, unsigned char *md) { MD5(d, n, md); } #endif telegram-purple/tgl/crypto/meta.h000066400000000000000000000056521357227200100173770ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #ifndef CRYPTO_META_H_ #define CRYPTO_META_H_ #include /* All this wrapping/unwrapping solves a fundamental problem: * - The libtgl implementation wants access to the TGLC_* types. * - The libtgl implementation should not see any other definitions from any * external crypto library (to make sure no symbol slips "through" during the * OpenSSL-to-gcrypt transition). * - Most TGLC_* types (3 out of 4 types) are exclusively used as pointers * throughout the libtgl source, in a way to allow for incomplete types. * - The CORE type (e.g. BIGNUM from ) may be incomplete, * even for tglc. * This means the standard approaches don't work: * - TGLC_NAME can't be a typedef to CORE, since CORE shouldn't even be visible * from libtgl. * - TGLC_NAME can't be a pointer to CORE, same reason. Also, it would require * a significant amount of rewriting (error-prone work). * - TGLC_NAME can't be a void pointer. Retain type checking! * - So TGLC_NAME *must* be an incomplete custom struct. * However, this ensues the following ugliness. * * The standard doesn't explicitly allow it, but there's a pretty good argument * that casting ptr-to-some-struct to ptr-to-other-struct is *probably* okay for * most compilers: https://stackoverflow.com/a/8702750/3070326 */ #define TGLC_WRAPPER_ASSOC(NAME,CORE) \ static TGLC_ ## NAME *wrap_ ## NAME (const CORE *p) \ __attribute__ ((unused)); \ static CORE *unwrap_ ## NAME (const TGLC_ ## NAME *p) \ __attribute__ ((unused)); \ static CORE *unwrap_ ## NAME (const TGLC_ ## NAME *p) { \ return (CORE *)p; \ } \ static TGLC_ ## NAME *wrap_ ## NAME (const CORE *p) { \ return (TGLC_ ## NAME *)p; \ } #endif /* CRYPTO_META_H_ */ telegram-purple/tgl/crypto/rand.h000066400000000000000000000020561357227200100173700ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #ifndef __TGL_CRYPTO_RAND_H__ #define __TGL_CRYPTO_RAND_H__ void TGLC_rand_add (const void *buf, int num, double entropy); int TGLC_rand_bytes (unsigned char *buf, int num); int TGLC_rand_pseudo_bytes (unsigned char *buf, int num); #endif telegram-purple/tgl/crypto/rand_altern.c000066400000000000000000000030041357227200100207220ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifdef TGL_AVOID_OPENSSL /* Marginally speed up compilation */ #define GCRYPT_NO_MPI_MACROS /* Fail-fast when something becomes deprecated. */ #define GCRYPT_NO_DEPRECATED #include #include #include "rand.h" void TGLC_rand_add (const void *buf, int num, double entropy) { (void) entropy; // TODO: Translate half-broken "entropy" into gcry's "quality". gcry_random_add_bytes (buf, num, 50); } int TGLC_rand_bytes (unsigned char *buf, int num) { gcry_randomize (buf, num, GCRY_STRONG_RANDOM); return 1; // Don't ask why. } int TGLC_rand_pseudo_bytes (unsigned char *buf, int num) { gcry_create_nonce (buf, num); return 0; // Don't ask why. } #endif telegram-purple/tgl/crypto/rand_openssl.c000066400000000000000000000023011357227200100211170ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifndef TGL_AVOID_OPENSSL #include #include "rand.h" void TGLC_rand_add (const void *buf, int num, double entropy) { RAND_add (buf, num, entropy); } int TGLC_rand_bytes (unsigned char *buf, int num) { return RAND_bytes (buf, num); } int TGLC_rand_pseudo_bytes (unsigned char *buf, int num) { return RAND_pseudo_bytes (buf, num); } #endif telegram-purple/tgl/crypto/rsa_pem.h000066400000000000000000000022731357227200100200730ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #ifndef __TGL_CRYPTO_RSA_H__ #define __TGL_CRYPTO_RSA_H__ #include /* FILE */ #include "bn.h" typedef struct TGLC_rsa TGLC_rsa; TGLC_rsa *TGLC_rsa_new (unsigned long e, int n_bytes, const unsigned char *n); TGLC_bn *TGLC_rsa_n (TGLC_rsa *); TGLC_bn *TGLC_rsa_e (TGLC_rsa *); void TGLC_rsa_free (TGLC_rsa *); TGLC_rsa *TGLC_pem_read_RSAPublicKey (FILE *fp); #endif telegram-purple/tgl/crypto/rsa_pem_altern.c000066400000000000000000000044401357227200100214310ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifdef TGL_AVOID_OPENSSL #include #include "meta.h" #include "rsa_pem.h" #include "../tools.h" /* talloc */ struct TGLC_rsa { TGLC_bn *n; TGLC_bn *e; }; TGLC_rsa *TGLC_rsa_new (unsigned long e, int n_bytes, const unsigned char *n) { assert (n_bytes > 0 && n_bytes < 5000); TGLC_rsa *ret = talloc (sizeof (TGLC_rsa)); ret->e = TGLC_bn_new (); TGLC_bn_set_word (ret->e, e); ret->n = TGLC_bn_bin2bn (n, n_bytes, NULL); assert (n_bytes == TGLC_bn_num_bytes (ret->n)); return ret; } #define RSA_GETTER(M) \ TGLC_bn *TGLC_rsa_ ## M (TGLC_rsa *key) { \ return key->M; \ } \ RSA_GETTER(n); RSA_GETTER(e); void TGLC_rsa_free (TGLC_rsa *key) { if (key->e) { TGLC_bn_free (key->e); } if (key->n) { TGLC_bn_free (key->n); } tfree (key, sizeof (TGLC_rsa)); } TGLC_rsa *TGLC_pem_read_RSAPublicKey (FILE *fp) { /* * Reading PEM format involves ASN.1 and is hard. libgcrypt doesn't support it. * The dependency on oh-so-freaking-much code just to parse static data that * will never change is not justified. Let the caller figure out how to resolve * this (telegram-purple does so by using libpurple's built-in functions), and * ignore any PEM files. */ (void) fp; return NULL; } #endif telegram-purple/tgl/crypto/rsa_pem_openssl.c000066400000000000000000000053301357227200100216260ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifndef TGL_AVOID_OPENSSL //#include /* NULL */ #include #include #include "bn.h" #include "meta.h" #include "rsa_pem.h" #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2070000fL)) int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { /* If the fields n and e in r are NULL, the corresponding input * parameters MUST be non-NULL for n and e. d may be * left NULL (in case only the public key is used). */ if ((r->n == NULL && n == NULL) || (r->e == NULL && e == NULL)) return 0; if (n != NULL) { BN_free(r->n); r->n = n; } if (e != NULL) { BN_free(r->e); r->e = e; } if (d != NULL) { BN_free(r->d); r->d = d; } return 1; } void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) { if (n != NULL) *n = r->n; if (e != NULL) *e = r->e; if (d != NULL) *d = r->d; } #endif TGLC_WRAPPER_ASSOC(rsa,RSA) // TODO: Refactor crucial struct-identity into its own header. TGLC_WRAPPER_ASSOC(bn,BIGNUM) TGLC_rsa *TGLC_rsa_new (unsigned long e, int n_bytes, const unsigned char *n) { RSA *ret = RSA_new (); TGLC_bn* e_tglcbn = TGLC_bn_new (); TGLC_bn_set_word (e_tglcbn, e); RSA_set0_key(ret, unwrap_bn (TGLC_bn_bin2bn (n, n_bytes, NULL)), unwrap_bn(e_tglcbn), NULL); return wrap_rsa (ret); } TGLC_bn *TGLC_rsa_n (TGLC_rsa * key) { const BIGNUM *n; RSA_get0_key( unwrap_rsa(key), &n, NULL, NULL); return wrap_bn(n); } TGLC_bn *TGLC_rsa_e (TGLC_rsa * key) { const BIGNUM *e; RSA_get0_key( unwrap_rsa(key), NULL, &e, NULL); return wrap_bn(e); } void TGLC_rsa_free (TGLC_rsa *p) { RSA_free (unwrap_rsa (p)); } TGLC_rsa *TGLC_pem_read_RSAPublicKey (FILE *fp) { return wrap_rsa (PEM_read_RSAPublicKey (fp, NULL, NULL, NULL)); } #endif telegram-purple/tgl/crypto/sha.h000066400000000000000000000020601357227200100172120ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #ifndef __TGL_CRYPTO_SHA_H__ #define __TGL_CRYPTO_SHA_H__ #include /* size_t */ void TGLC_sha1 (const unsigned char *d, size_t n, unsigned char *md); void TGLC_sha256 (const unsigned char *d, size_t n, unsigned char *md); #endif telegram-purple/tgl/crypto/sha_altern.c000066400000000000000000000024451357227200100205610ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifdef TGL_AVOID_OPENSSL /* Marginally speed up compilation */ #define GCRYPT_NO_MPI_MACROS /* Fail-fast when something becomes deprecated. */ #define GCRYPT_NO_DEPRECATED #include #include "sha.h" void TGLC_sha1 (const unsigned char *d, size_t n, unsigned char *md) { gcry_md_hash_buffer (GCRY_MD_SHA1, md, d, n); } void TGLC_sha256 (const unsigned char *d, size_t n, unsigned char *md) { gcry_md_hash_buffer (GCRY_MD_SHA256, md, d, n); } #endif telegram-purple/tgl/crypto/sha_openssl.c000066400000000000000000000021351357227200100207530ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Ben Wiederhake 2015 */ #include "config.h" #ifndef TGL_AVOID_OPENSSL #include #include "sha.h" void TGLC_sha1 (const unsigned char *d, size_t n, unsigned char *md) { SHA1 (d, n, md); } void TGLC_sha256 (const unsigned char *d, size_t n, unsigned char *md) { SHA256 (d, n, md); } #endif telegram-purple/tgl/encrypted_scheme.tl000066400000000000000000000051051357227200100206330ustar00rootroot00000000000000---types--- decryptedMessageMediaEmpty#89f5c4a = DecryptedMessageMedia; decryptedMessageMediaPhoto#32798a8c str_thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageMediaGeoPoint#35480a59 latitude:double longitude:double = DecryptedMessageMedia; decryptedMessageMediaContact#588a0a97 phone_number:string first_name:string last_name:string user_id:int = DecryptedMessageMedia; decryptedMessageActionSetMessageTTL#a1733aec ttl_seconds:int = DecryptedMessageAction; decryptedMessageMediaDocument#b095434b str_thumb:bytes thumb_w:int thumb_h:int file_name:string mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageActionReadMessages#c4f40be random_ids:Vector = DecryptedMessageAction; decryptedMessageActionDeleteMessages#65614304 random_ids:Vector = DecryptedMessageAction; decryptedMessageActionScreenshotMessages#8ac1f475 random_ids:Vector = DecryptedMessageAction; decryptedMessageActionFlushHistory#6719e45c = DecryptedMessageAction; decryptedMessage#204d3878 random_id:long ttl:int message:string media:DecryptedMessageMedia = DecryptedMessage; decryptedMessageService#73164160 random_id:long action:DecryptedMessageAction = DecryptedMessage; decryptedMessageMediaVideo#524a415d str_thumb:bytes thumb_w:int thumb_h:int duration:int mime_type:string w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageMediaAudio#57e0a9cb duration:int mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageLayer#1be31789 random_bytes:bytes layer:int in_seq_no:int out_seq_no:int message:DecryptedMessage = DecryptedMessageLayer; decryptedMessageActionResend#511110b0 start_seq_no:int end_seq_no:int = DecryptedMessageAction; decryptedMessageActionNotifyLayer#f3048883 layer:int = DecryptedMessageAction; decryptedMessageActionTyping#ccb27641 action:SendMessageAction = DecryptedMessageAction; decryptedMessageActionRequestKey#f3c9611b exchange_id:long g_a:bytes = DecryptedMessageAction; decryptedMessageActionAcceptKey#6fe1735b exchange_id:long g_b:bytes key_fingerprint:long = DecryptedMessageAction; decryptedMessageActionAbortKey#dd05ec6b exchange_id:long = DecryptedMessageAction; decryptedMessageActionCommitKey#ec2e0b9b exchange_id:long key_fingerprint:long = DecryptedMessageAction; decryptedMessageActionNoop#a82fdd63 = DecryptedMessageAction; decryptedMessageMediaExternalDocument#fa95b0dd id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector = DecryptedMessageMedia; ---functions--- telegram-purple/tgl/errors000066400000000000000000000012741357227200100162130ustar00rootroot00000000000000type of errors that tgl can set: EPROTO: server returned error for query. Some kinds of error (such as FLOOD_WAIT) tgl can handle by itself, but others it can not. In most cases it means bug in tgl or invalid parameter supplied to method (such as message id). On BSD, EPROTO is not defined. Whenever EPROTO is not #define'd, tgl uses EIO instead. EINVAL: tgl detected invalid argument supplied before sending query to server. For example user instead of chat or bad msg id. ENOENT: tgl received empty response from server. For example when user tried to get message by id EBADF: tgl can not open file on disk or file is empty E2BIG: supplied file is too big ENOTCONN: no public keys available telegram-purple/tgl/event-old.h000066400000000000000000000032711357227200100170210ustar00rootroot00000000000000#ifndef __EVENT_OLD_H__ #define __EVENT_OLD_H__ #include #include #define BEV_EVENT_READ EVBUFFER_READ #define BEV_EVENT_WRITE EVBUFFER_WRITE #define BEV_EVENT_EOF EVBUFFER_EOF #define BEV_EVENT_ERROR EVBUFFER_ERROR #define BEV_EVENT_TIMEOUT EVBUFFER_TIMEOUT typedef int evutil_socket_t; static inline struct event *event_new (struct event_base *base, int fd, int what, void(*callback)(int, short, void *), void *arg) __attribute__ ((unused)); static inline struct event *event_new (struct event_base *base, int fd, int what, void(*callback)(int, short, void *), void *arg) { struct event *ev = malloc (sizeof (*ev)); event_set (ev, fd, what, callback, arg); event_base_set (base, ev); return ev; } static inline struct event *evtimer_new (struct event_base *base, void(*callback)(int, short, void *), void *arg) __attribute__ ((unused)); static inline struct event *evtimer_new (struct event_base *base, void(*callback)(int, short, void *), void *arg) { struct event *ev = malloc (sizeof (*ev)); event_set (ev, -1, 0, callback, arg); event_base_set (base, ev); return ev; } static void event_free (struct event *ev) __attribute__ ((unused)); static void event_free (struct event *ev) { event_del (ev); free (ev); } static struct bufferevent *bufferevent_socket_new (struct event_base *base, int fd, int flags) __attribute__ ((unused)); static struct bufferevent *bufferevent_socket_new (struct event_base *base, int fd, int flags) { assert (!flags); struct bufferevent *bev = bufferevent_new(fd, 0, 0, 0, 0); bufferevent_base_set (base, bev); return bev; } static inline void *event_get_callback_arg(const struct event *ev) { return ev->ev_arg; } #endif telegram-purple/tgl/gen_constants_h.awk000066400000000000000000000025521357227200100206340ustar00rootroot00000000000000BEGIN { print "/*"; print " This file is part of telegram-client."; print ""; print " Telegram-client is free software: you can redistribute it and/or modify"; print " it under the terms of the GNU General Public License as published by"; print " the Free Software Foundation, either version 2 of the License, or"; print " (at your option) any later version."; print ""; print " Telegram-client is distributed in the hope that it will be useful,"; print " but WITHOUT ANY WARRANTY; without even the implied warranty of"; print " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"; print " GNU General Public License for more details."; print ""; print " You should have received a copy of the GNU General Public License"; print " along with this telegram-client. If not, see ."; print ""; print " Copyright Vitaly Valtman 2013"; print "*/"; print "#ifndef CONSTANTS_H"; print "#define CONSTANTS_H"; } // { if (split ($1, a, "#") == 2) { gsub (/[ABCDEFGHIJKLMNOPQRSTUVWXYZ]/, "_&", a[1]); gsub (/[.]/, "_", a[1]); if (a[2] in h) { print "ERROR: Duplicate magic " a[2] " for define " a[1] " and " h[a[2]] > "/dev/stderr" exit 1; } h[a[2]] = a[1]; print "#define", "CODE_" tolower(a[1]), "0x" a[2]; } } END { print "#endif"; } telegram-purple/tgl/generate.c000066400000000000000000003154411357227200100167160ustar00rootroot00000000000000/* This file is part of tgl-libary/generate Tgl-library/generate 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. Tgl-library/generate 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 tgl-library/generate. If not, see . Copyright Vitaly Valtman 2014-2015 It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) Copyright 2012-2013 Vkontakte Ltd 2012-2013 Vitaliy Valtman */ #define _GNU_SOURCE #include "config.h" #include #include #ifdef HAVE_EXECINFO_H #include #endif #include #include #include #include #include #include #include #include #if defined(_MSC_VER) || defined(__MINGW32__) /* Find the length of STRING, but scan at most MAXLEN characters. If no '\0' terminator is found in that many characters, return MAXLEN. */ size_t strnlen (const char *string, size_t maxlen) { const char *end = memchr (string, '\0', maxlen); return end ? (size_t)(end - string) : maxlen; } char *strndup (const char *s, size_t n) { size_t len = strnlen (s, n); char *new = malloc (len + 1); if (new == NULL) return NULL; new[len] = '\0'; return memcpy (new, s, len); } #define INT64_PRINTF_MODIFIER "I64" #else #define INT64_PRINTF_MODIFIER "ll" #endif #include "tl-parser/tl-tl.h" #include "generate.h" #include "tree.h" int header; #define tl_type_name_cmp(a,b) (a->name > b->name ? 1 : a->name < b->name ? -1 : 0) DEFINE_TREE (tl_type, struct tl_type *, tl_type_name_cmp, 0) DEFINE_TREE (tl_combinator, struct tl_combinator *, tl_type_name_cmp, 0) struct tree_tl_type *type_tree; struct tree_tl_combinator *function_tree; void tl_function_insert_by_name (struct tl_combinator *c) { function_tree = tree_insert_tl_combinator (function_tree, c, rand ()); } struct tl_type *tl_type_get_by_name (int name) { static struct tl_type t; t.name = name; return tree_lookup_tl_type (type_tree, &t); } void tl_type_insert_by_name (struct tl_type *t) { type_tree = tree_insert_tl_type (type_tree, t, rand ()); } int is_empty (struct tl_type *t) { if (t->name == NAME_INT || t->name == NAME_LONG || t->name == NAME_DOUBLE || t->name == NAME_STRING) { return 1; } if (t->constructors_num != 1) { return 0; } int count = 0; int i; struct tl_combinator *c = t->constructors[0]; for (i = 0; i < c->args_num; i++) { if (!(c->args[i]->flags & FLAG_OPT_VAR)) { count ++; } } return count == 1; } static char buf[1 << 20]; int buf_size; int *buf_ptr = (int *)buf; int *buf_end; #ifndef DISABLE_EXTF int skip_only = 0; #else int skip_only = 1; #endif int verbosity; int get_int (void) { assert (buf_ptr < buf_end); return *(buf_ptr ++); } long long get_long (void) { assert (buf_ptr + 1 < buf_end); long long r = *(long long *)buf_ptr; buf_ptr += 2; return r; } static void *malloc0 (int size) { void *r = malloc (size); assert (r); memset (r, 0, size); return r; } char *get_string (void) { int l = *(unsigned char *)buf_ptr; assert (l != 0xff); char *res; int tlen = 0; if (l == 0xfe) { l = ((unsigned)get_int ()) >> 8; res = (char *)buf_ptr; tlen = l; } else { res = ((char *)buf_ptr) + 1; tlen = 1 + l; } int len = l; tlen += ((-tlen) & 3); assert (!(tlen & 3)); buf_ptr += tlen / 4; assert (buf_ptr <= buf_end); char *r = strndup (res, len); assert (r); return r; } int tn, fn, cn; struct tl_type **tps; struct tl_combinator **fns; struct tl_tree *read_tree (int *var_num); struct tl_tree *read_nat_expr (int *var_num); struct tl_tree *read_type_expr (int *var_num); int read_args_list (struct arg **args, int args_num, int *var_num); #define use_var_nat_full_form(x) 0 void *int_to_var_nat_const_init (long long x) { if (use_var_nat_full_form (x)) { struct tl_tree_nat_const *T = malloc (sizeof (*T)); assert (T); T->self.flags = 0; T->self.methods = &tl_pnat_const_full_methods; T->value = x; return T; } else { return (void *)(long)(x * 2 - 0x80000001l); } } long long var_nat_const_to_int (void *x) { if (((long)x) & 1) { return (((long)x) + 0x80000001l) / 2; } else { return ((struct tl_tree_nat_const *)x)->value; } } int tl_tree_type_type (struct tl_tree *x) { return NODE_TYPE_TYPE; } int tl_tree_type_array (struct tl_tree *x) { return NODE_TYPE_ARRAY; } int tl_tree_type_nat_const (struct tl_tree *x) { return NODE_TYPE_NAT_CONST; } int tl_tree_type_var_num (struct tl_tree *x) { return NODE_TYPE_VAR_NUM; } int tl_tree_type_var_type (struct tl_tree *x) { return NODE_TYPE_VAR_TYPE; } struct tl_tree_methods tl_var_num_methods = { .type = tl_tree_type_var_num }; struct tl_tree_methods tl_var_type_methods = { .type = tl_tree_type_var_type }; struct tl_tree_methods tl_type_methods = { .type = tl_tree_type_type }; struct tl_tree_methods tl_nat_const_methods = { .type = tl_tree_type_nat_const }; struct tl_tree_methods tl_array_methods = { .type = tl_tree_type_array }; struct tl_tree_methods tl_ptype_methods = { .type = tl_tree_type_type }; struct tl_tree_methods tl_parray_methods = { .type = tl_tree_type_array }; struct tl_tree_methods tl_pvar_num_methods = { .type = tl_tree_type_var_num }; struct tl_tree_methods tl_pvar_type_methods = { .type = tl_tree_type_var_type }; struct tl_tree_methods tl_nat_const_full_methods = { .type = tl_tree_type_nat_const }; struct tl_tree_methods tl_pnat_const_full_methods = { .type = tl_tree_type_nat_const }; struct tl_tree *read_num_const (int *var_num) { return (void *)int_to_var_nat_const_init (get_int ()); } void print_c_type_name (struct tl_tree *t, char *offset, int in) { int x = TL_TREE_METHODS(t)->type (t); if (x == NODE_TYPE_VAR_TYPE) { printf ("void *"); return; } if (x == NODE_TYPE_ARRAY) { struct tl_tree_array *a = (void *)t; assert (a->args_num == 1); print_c_type_name (a->args[0]->type, offset, in); printf ("*"); return; } struct tl_type *T = ((struct tl_tree_type *)t)->type; if (!strcmp (T->id, "Vector") && in) { printf ("struct {\n"); printf ("%s int *cnt;\n", offset); printf ("%s ", offset); print_c_type_name (((struct tl_tree_type *)t)->children[0], offset, in); printf ("*data;\n"); printf ("%s} *", offset); return; } if (!strcmp (T->id, "Long")) { printf ("long long *"); return; } if (!strcmp (T->id, "#") || !strcmp (T->id, "Int")) { printf ("int *"); return; } if (!strcmp (T->id, "Double")) { printf ("double *"); return; } if (!strcmp (T->id, "String") || !strcmp (T->id, "Bytes")) { /*printf ("struct {\n"); printf ("%s int len;\n", offset); printf ("%s char *data;\n", offset); printf ("%s} *", offset); return;*/ printf ("struct tl_ds_string *"); return; } printf ("struct tl_ds_%s *", T->print_id); } int gen_uni_skip (struct tl_tree *t, char *cur_name, int *vars, int first, int fun) { assert (t); int x = TL_TREE_METHODS (t)->type (t); int l = 0; int i; int j; struct tl_tree_type *t1; struct tl_tree_array *t2; int y; int L = strlen (cur_name); char *fail = fun == 1 ? "return 0;" : fun == -1 ? "return;" : "return -1;"; switch (x) { case NODE_TYPE_TYPE: t1 = (void *)t; if (!first) { printf (" if (ODDP(%s) || %s->type->name != 0x%08x) { %s }\n", cur_name, cur_name, t1->type->name, fail); } else { printf (" if (ODDP(%s) || (%s->type->name != 0x%08x && %s->type->name != 0x%08x)) { %s }\n", cur_name, cur_name, t1->type->name, cur_name, ~t1->type->name, fail); } for (i = 0; i < t1->children_num; i++) { sprintf (cur_name + L, "->params[%d]", i); gen_uni_skip (t1->children[i], cur_name, vars, 0, fun); cur_name[L] = 0; } return 0; case NODE_TYPE_NAT_CONST: printf (" if (EVENP(%s) || ((long)%s) != %" INT64_PRINTF_MODIFIER "d) { %s }\n", cur_name, cur_name, var_nat_const_to_int (t) * 2 + 1, fail); return 0; case NODE_TYPE_ARRAY: printf (" if (ODDP(%s) || %s->type->name != TL_TYPE_ARRAY) { %s }\n", cur_name, cur_name, fail); t2 = (void *)t; sprintf (cur_name + L, "->params[0]"); y = gen_uni_skip (t2->multiplicity, cur_name, vars, 0, fun); cur_name[L] = 0; sprintf (cur_name + L, "->params[1]"); y += gen_uni_skip (t2->args[0]->type, cur_name, vars, 0, fun); cur_name[L] = 0; return 0; case NODE_TYPE_VAR_TYPE: printf (" if (ODDP(%s)) { %s }\n", cur_name, fail); i = ((struct tl_tree_var_type *)t)->var_num; if (!vars[i]) { printf (" struct paramed_type *var%d = %s; assert (var%d);\n", i, cur_name, i); vars[i] = 1; } else if (vars[i] == 1) { printf (" if (compare_types (var%d, %s) < 0) { %s }\n", i, cur_name, fail); } else { assert (0); return -1; } return l; case NODE_TYPE_VAR_NUM: printf (" if (EVENP(%s)) { %s }\n", cur_name, fail); i = ((struct tl_tree_var_num *)t)->var_num; j = ((struct tl_tree_var_num *)t)->dif; if (!vars[i]) { printf (" struct paramed_type *var%d = ((void *)%s) + %d; assert (var%d);\n", i, cur_name, 2 * j, i); vars[i] = 2; } else if (vars[i] == 2) { printf (" if (var%d != ((void *)%s) + %d) { %s }\n", i, cur_name, 2 * j, fail); } else { assert (0); return -1; } return 0; default: assert (0); return -1; } } void print_offset (int len) { int i; for (i = 0; i < len; i++) { printf (" "); } } int gen_create (struct tl_tree *t, int *vars, int offset) { int x = TL_TREE_METHODS (t)->type (t); int i; struct tl_tree_type *t1; struct tl_tree_array *t2; switch (x) { case NODE_TYPE_TYPE: print_offset (offset); printf ("&(struct paramed_type){\n"); print_offset (offset + 2); t1 = (void *)t; if (t1->self.flags & FLAG_BARE) { printf (".type = &(struct tl_type_descr) {.name = 0x%08x, .id = \"Bare_%s\", .params_num = %d, .params_types = %" INT64_PRINTF_MODIFIER "d},\n", ~t1->type->name, t1->type->id, t1->type->arity, t1->type->params_types); } else { printf (".type = &(struct tl_type_descr) {.name = 0x%08x, .id = \"%s\", .params_num = %d, .params_types = %" INT64_PRINTF_MODIFIER "d},\n", t1->type->name, t1->type->id, t1->type->arity, t1->type->params_types); } if (t1->children_num) { print_offset (offset + 2); printf (".params = (struct paramed_type *[]){\n"); for (i = 0; i < t1->children_num; i++) { assert (gen_create (t1->children[i], vars, offset + 4) >= 0); printf (",\n"); } print_offset (offset + 2); printf ("}\n"); } else { print_offset (offset + 2); printf (".params = 0,\n"); } print_offset (offset); printf ("}"); return 0; case NODE_TYPE_NAT_CONST: print_offset (offset); printf ("INT2PTR (%d)", (int)var_nat_const_to_int (t)); return 0; case NODE_TYPE_ARRAY: print_offset (offset); printf ("&(struct paramed_type){\n"); print_offset (offset + 2); t2 = (void *)t; printf (".type = &(struct tl_type_descr) {.name = NAME_ARRAY, .id = \"array\", .params_num = 2, .params_types = 1},\n"); print_offset (offset + 2); printf (".params = (struct paramed_type **){\n"); gen_create (t2->multiplicity, vars, offset + 4); printf (",\n"); gen_create (t2->args[0]->type, vars, offset + 4); printf (",\n"); print_offset (offset + 2); printf ("}\n"); print_offset (offset); printf ("}"); return 0; case NODE_TYPE_VAR_TYPE: print_offset (offset); printf ("var%d", ((struct tl_tree_var_type *)t)->var_num); return 0; case NODE_TYPE_VAR_NUM: print_offset (offset); printf ("((void *)var%d) + %d", ((struct tl_tree_var_type *)t)->var_num, 2 * ((struct tl_tree_var_num *)t)->dif); return 0; default: assert (0); return -1; } } int gen_field_skip (struct arg *arg, int *vars, int num) { assert (arg); char *offset = " "; int o = 0; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; o = 2; } if (arg->var_num >= 0) { assert (TL_TREE_METHODS (arg->type)->type (arg->type) == NODE_TYPE_TYPE); int t = ((struct tl_tree_type *)arg->type)->type->name; if (t == NAME_VAR_TYPE) { fprintf (stderr, "Not supported yet\n"); assert (0); } else { assert (t == NAME_VAR_NUM); if (vars[arg->var_num] == 0) { printf ("%sif (in_remaining () < 4) { return -1;}\n", offset); printf ("%sstruct paramed_type *var%d = INT2PTR (fetch_int ());\n", offset, arg->var_num); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sif (in_remaining () < 4) { return -1;}\n", offset); printf ("%sif (vars%d != INT2PTR (fetch_int ())) { return -1; }\n", offset, arg->var_num); } else { assert (0); return -1; } } } else { int t = TL_TREE_METHODS (arg->type)->type (arg->type); if (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE) { printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (arg->type, vars, 2 + o) >= 0); printf (";\n"); int bare = arg->flags & FLAG_BARE; if (!bare && t == NODE_TYPE_TYPE) { bare = ((struct tl_tree_type *)arg->type)->self.flags & FLAG_BARE; } if (!bare) { printf ("%sif (skip_type_%s (field%d) < 0) { return -1;}\n", offset, t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num); } else { printf ("%sif (skip_type_bare_%s (field%d) < 0) { return -1;}\n", offset, t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num); } } else { assert (t == NODE_TYPE_ARRAY); printf ("%sint multiplicity%d = PTR2INT (\n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->multiplicity, vars, 2 + o) >= 0); printf ("%s);\n", offset); printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->args[0]->type, vars, 2 + o) >= 0); printf (";\n"); printf ("%swhile (multiplicity%d -- > 0) {\n", offset, num); printf ("%s if (skip_type_%s (field%d) < 0) { return -1;}\n", offset, "any", num); printf ("%s}\n", offset); } } if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } int gen_field_fetch (struct arg *arg, int *vars, int num, int empty) { assert (arg); char *offset = " "; int o = 0; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; o = 2; } if (!empty) { printf("%sif (multiline_output >= 2) { print_offset (); }\n", offset); } if (arg->id && strlen (arg->id) && !empty) { printf ("%sif (!disable_field_names) { eprintf (\" %s :\"); }\n", offset, arg->id); } if (arg->var_num >= 0) { assert (TL_TREE_METHODS (arg->type)->type (arg->type) == NODE_TYPE_TYPE); int t = ((struct tl_tree_type *)arg->type)->type->name; if (t == NAME_VAR_TYPE) { fprintf (stderr, "Not supported yet\n"); assert (0); } else { assert (t == NAME_VAR_NUM); if (vars[arg->var_num] == 0) { printf ("%sif (in_remaining () < 4) { return -1;}\n", offset); printf ("%seprintf (\" %%d\", prefetch_int ());\n", offset); printf ("%sstruct paramed_type *var%d = INT2PTR (fetch_int ());\n", offset, arg->var_num); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sif (in_remaining () < 4) { return -1;}\n", offset); printf ("%seprintf (\" %%d\", prefetch_int ());\n", offset); printf ("%sif (vars%d != INT2PTR (fetch_int ())) { return -1; }\n", offset, arg->var_num); } else { assert (0); return -1; } } } else { int t = TL_TREE_METHODS (arg->type)->type (arg->type); if (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE) { printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (arg->type, vars, 2 + o) >= 0); printf (";\n"); int bare = arg->flags & FLAG_BARE; if (!bare && t == NODE_TYPE_TYPE) { bare = ((struct tl_tree_type *)arg->type)->self.flags & FLAG_BARE; } if (!bare) { printf ("%sif (fetch_type_%s (field%d) < 0) { return -1;}\n", offset, t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num); } else { printf ("%sif (fetch_type_bare_%s (field%d) < 0) { return -1;}\n", offset, t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num); } } else { assert (t == NODE_TYPE_ARRAY); printf ("%sint multiplicity%d = PTR2INT (\n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->multiplicity, vars, 2 + o) >= 0); printf ("%s);\n", offset); printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->args[0]->type, vars, 2 + o) >= 0); printf (";\n"); printf ("%seprintf (\" [\");\n", offset); printf ("%sif (multiline_output >= 1) { eprintf (\"\\n\"); }\n", offset); printf ("%sif (multiline_output >= 1) { multiline_offset += multiline_offset_size;}\n", offset); printf ("%swhile (multiplicity%d -- > 0) {\n", offset, num); printf ("%s if (multiline_output >= 1) { print_offset (); }\n", offset); printf ("%s if (fetch_type_%s (field%d) < 0) { return -1;}\n", offset, "any", num); printf ("%s if (multiline_output >= 1) { eprintf (\"\\n\"); }\n", offset); printf ("%s}\n", offset); printf ("%sif (multiline_output >= 1) { multiline_offset -= multiline_offset_size; print_offset ();}\n", offset); printf ("%seprintf (\" ]\");\n", offset); } } if (!empty) { printf("%sif (multiline_output >= 2) { eprintf (\"\\n\"); }\n", offset); } if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } int gen_field_store (struct arg *arg, int *vars, int num, int from_func, int empty) { assert (arg); char *offset = " "; int o = 0; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; o = 2; } char *fail = from_func ? "0" : "-1"; char *expect = from_func ? "expect_token_ptr" : "expect_token"; if (arg->id && strlen (arg->id) > 0 && !empty) { printf ("%sif (cur_token_len >= 0 && cur_token_len == %d && !cur_token_quoted && !memcmp (cur_token, \"%s\", cur_token_len)) {\n", offset, (int)(strlen (arg->id)), arg->id); printf ("%s local_next_token ();\n", offset); printf ("%s %s (\":\", 1);\n", offset, expect); printf ("%s}\n", offset); } if (arg->var_num >= 0) { printf ("%sif (cur_token_len < 0) { return %s; }\n", offset, fail); assert (TL_TREE_METHODS (arg->type)->type (arg->type) == NODE_TYPE_TYPE); int t = ((struct tl_tree_type *)arg->type)->type->name; if (t == NAME_VAR_TYPE) { fprintf (stderr, "Not supported yet\n"); assert (0); } else { assert (t == NAME_VAR_NUM); if (vars[arg->var_num] == 0) { printf ("%sif (!is_int ()) { return %s;}\n", offset, fail); printf ("%sstruct paramed_type *var%d = INT2PTR (get_int ());\n", offset, arg->var_num); printf ("%sout_int (get_int ());\n", offset); printf ("%sassert (var%d);\n", offset, arg->var_num); printf ("%slocal_next_token ();\n", offset); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sif (!is_int ()) { return %s;}\n", offset, fail); printf ("%sif (vars%d != INT2PTR (get_int ())) { return %s; }\n", offset, arg->var_num, fail); printf ("%sout_int (get_int ());\n", offset); printf ("%slocal_next_token ();\n", offset); } else { assert (0); return -1; } } } else { int t = TL_TREE_METHODS (arg->type)->type (arg->type); if (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE) { printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (arg->type, vars, 2 + o) >= 0); printf (";\n"); int bare = arg->flags & FLAG_BARE; if (!bare && t == NODE_TYPE_TYPE) { bare = ((struct tl_tree_type *)arg->type)->self.flags & FLAG_BARE; } if (!bare) { printf ("%sif (store_type_%s (field%d) < 0) { return %s;}\n", offset, t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num, fail); } else { printf ("%sif (store_type_bare_%s (field%d) < 0) { return %s;}\n", offset, t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num, fail); } } else { printf ("%s%s (\"[\", 1);\n", offset, expect); assert (t == NODE_TYPE_ARRAY); printf ("%sint multiplicity%d = PTR2INT (\n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->multiplicity, vars, 2 + o) >= 0); printf ("%s);\n", offset); printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->args[0]->type, vars, 2 + o) >= 0); printf (";\n"); printf ("%swhile (multiplicity%d -- > 0) {\n", offset, num); printf ("%s if (store_type_%s (field%d) < 0) { return %s;}\n", offset, "any", num, fail); printf ("%s}\n", offset); printf ("%s%s (\"]\", 1);\n", offset, expect); } } if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } int gen_field_autocomplete (struct arg *arg, int *vars, int num, int from_func, int empty) { assert (arg); char *offset = " "; int o = 0; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; o = 2; } char *fail = from_func ? "0" : "-1"; char *expect = from_func ? "expect_token_ptr_autocomplete" : "expect_token_autocomplete"; if (arg->id && strlen (arg->id) > 0 && !empty) { printf ("%sif (cur_token_len == -3 && cur_token_real_len <= %d && !cur_token_quoted && !memcmp (cur_token, \"%s\", cur_token_real_len)) {\n", offset, (int)(strlen (arg->id)), arg->id); printf ("%s set_autocomplete_string (\"%s\");\n", offset, arg->id); printf ("%s return %s;\n", offset, fail); printf ("%s}\n", offset); printf ("%sif (cur_token_len >= 0 && cur_token_len == %d && !memcmp (cur_token, \"%s\", cur_token_len)) {\n", offset, (int)(strlen (arg->id)), arg->id); printf ("%s local_next_token ();\n", offset); printf ("%s %s (\":\", 1);\n", offset, expect); printf ("%s}\n", offset); } if (arg->var_num >= 0) { printf ("%sif (cur_token_len < 0) { return %s; }\n", offset, fail); assert (TL_TREE_METHODS (arg->type)->type (arg->type) == NODE_TYPE_TYPE); int t = ((struct tl_tree_type *)arg->type)->type->name; if (t == NAME_VAR_TYPE) { fprintf (stderr, "Not supported yet\n"); assert (0); } else { assert (t == NAME_VAR_NUM); if (vars[arg->var_num] == 0) { printf ("%sif (!is_int ()) { return %s;}\n", offset, fail); printf ("%sstruct paramed_type *var%d = INT2PTR (get_int ());\n", offset, arg->var_num); printf ("%sassert (var%d);\n", offset, arg->var_num); printf ("%slocal_next_token ();\n", offset); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sif (!is_int ()) { return %s;}\n", offset, fail); printf ("%sif (vars%d != INT2PTR (get_int ())) { return %s; }\n", offset, arg->var_num, fail); printf ("%slocal_next_token ();\n", offset); } else { assert (0); return -1; } } } else { int t = TL_TREE_METHODS (arg->type)->type (arg->type); if (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE) { printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (arg->type, vars, 2 + o) >= 0); printf (";\n"); int bare = arg->flags & FLAG_BARE; if (!bare && t == NODE_TYPE_TYPE) { bare = ((struct tl_tree_type *)arg->type)->self.flags & FLAG_BARE; } if (!bare) { printf ("%sif (autocomplete_type_%s (field%d) < 0) { return %s;}\n", offset, t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num, fail); } else { printf ("%sif (autocomplete_type_bare_%s (field%d) < 0) { return %s;}\n", offset, t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num, fail); } } else { printf ("%s%s (\"[\", 1);\n", offset, expect); assert (t == NODE_TYPE_ARRAY); printf ("%sint multiplicity%d = PTR2INT (\n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->multiplicity, vars, 2 + o) >= 0); printf ("%s);\n", offset); printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->args[0]->type, vars, 2 + o) >= 0); printf (";\n"); printf ("%swhile (multiplicity%d -- > 0) {\n", offset, num); printf ("%s if (autocomplete_type_%s (field%d) < 0) { return %s;}\n", offset, "any", num, fail); printf ("%s}\n", offset); printf ("%s%s (\"]\", 1);\n", offset, expect); } } if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } int gen_field_fetch_ds (struct arg *arg, int *vars, int num, int empty) { assert (arg); char *offset = " "; int o = 0; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; o = 2; } if (arg->var_num >= 0) { assert (TL_TREE_METHODS (arg->type)->type (arg->type) == NODE_TYPE_TYPE); int t = ((struct tl_tree_type *)arg->type)->type->name; if (t == NAME_VAR_TYPE) { fprintf (stderr, "Not supported yet\n"); assert (0); } else { assert (t == NAME_VAR_NUM); printf ("%sassert (in_remaining () >= 4);\n", offset); if (arg->id && strlen (arg->id)) { printf ("%sresult->%s = talloc (4);", offset, arg->id); printf ("%s*result->%s = prefetch_int ();", offset, arg->id); } else { printf ("%sresult->f%d = talloc (4);", offset, num - 1); printf ("%s*result->f%d = prefetch_int ();", offset, num - 1); } if (vars[arg->var_num] == 0) { printf ("%sstruct paramed_type *var%d = INT2PTR (fetch_int ());\n", offset, arg->var_num); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sassert (vars%d == INT2PTR (fetch_int ()));\n", offset, arg->var_num); } else { assert (0); return -1; } } } else { int t = TL_TREE_METHODS (arg->type)->type (arg->type); if (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE) { printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (arg->type, vars, 2 + o) >= 0); printf (";\n"); int bare = arg->flags & FLAG_BARE; if (!bare && t == NODE_TYPE_TYPE) { bare = ((struct tl_tree_type *)arg->type)->self.flags & FLAG_BARE; } if (arg->id && strlen (arg->id)) { printf ("%sresult->%s = ", offset, arg->id); } else { printf ("%sresult->f%d = ", offset, num - 1); } if (t == NODE_TYPE_TYPE && !strcmp (((struct tl_tree_type *)arg->type)->type->id, "Vector")) { printf ("(void *)"); } if (!bare) { printf ("fetch_ds_type_%s (field%d);\n", t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num); } else { printf ("fetch_ds_type_bare_%s (field%d);\n", t == NODE_TYPE_VAR_TYPE ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num); } } else { assert (t == NODE_TYPE_ARRAY); printf ("%sint multiplicity%d = PTR2INT (\n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->multiplicity, vars, 2 + o) >= 0); printf ("%s);\n", offset); printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->args[0]->type, vars, 2 + o) >= 0); printf (";\n"); if (arg->id && strlen (arg->id)) { printf ("%sresult->%s = ", offset, arg->id); } else { printf ("%sresult->f%d = ", offset, num - 1); } printf ("talloc0 (multiplicity%d * sizeof (void *));\n", num); printf ("%s{\n", offset); printf ("%s int i = 0;\n", offset); printf ("%s while (i < multiplicity%d) {\n", offset, num); if (arg->id && strlen (arg->id)) { printf ("%s result->%s[i ++] =", offset, arg->id); } else { printf ("%s result->f%d[i ++] = ", offset, num - 1); } printf ("fetch_ds_type_%s (field%d);\n", "any", num); printf ("%s }\n", offset); printf ("%s}\n", offset); } } if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } int gen_field_free_ds (struct arg *arg, int *vars, int num, int empty) { assert (arg); char *offset = " "; int o = 0; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; o = 2; } if (arg->var_num >= 0) { assert (TL_TREE_METHODS (arg->type)->type (arg->type) == NODE_TYPE_TYPE); int t = ((struct tl_tree_type *)arg->type)->type->name; if (t == NAME_VAR_TYPE) { fprintf (stderr, "Not supported yet\n"); assert (0); } else { assert (t == NAME_VAR_NUM); if (arg->id && strlen (arg->id)) { if (vars[arg->var_num] == 0) { printf ("%sstruct paramed_type *var%d = INT2PTR (*D->%s);\n", offset, arg->var_num, arg->id); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sassert (vars%d == INT2PTR (*D->%s));\n", offset, arg->var_num, arg->id); } printf ("%stfree (D->%s, sizeof (*D->%s));\n", offset, arg->id, arg->id); } else { if (vars[arg->var_num] == 0) { printf ("%sstruct paramed_type *var%d = INT2PTR (*D->f%d);\n", offset, arg->var_num, num - 1); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sassert (vars%d == *D->f%d);\n", offset, arg->var_num, num - 1); } printf ("%stfree (D->f%d, sizeof (*D->f%d));\n", offset, num - 1, num - 1); } } } else { int t = TL_TREE_METHODS (arg->type)->type (arg->type); if (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE) { printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (arg->type, vars, 2 + o) >= 0); printf (";\n"); int any = (t == NODE_TYPE_VAR_TYPE) || ((struct tl_tree_type *)arg->type)->type->name == NAME_VECTOR; if (arg->id && strlen (arg->id)) { printf ("%sfree_ds_type_%s (D->%s, field%d);\n", offset, any ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, arg->id, num); } else { printf ("%sfree_ds_type_%s (D->f%d, field%d);\n", offset, any ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, num - 1, num); } } else { assert (t == NODE_TYPE_ARRAY); printf ("%sint multiplicity%d = PTR2INT (\n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->multiplicity, vars, 2 + o) >= 0); printf ("%s);\n", offset); printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->args[0]->type, vars, 2 + o) >= 0); printf (";\n"); printf ("%s{\n", offset); printf ("%s int i = 0;\n", offset); printf ("%s while (i < multiplicity%d) {\n", offset, num); if (arg->id && strlen (arg->id)) { printf ("%s free_ds_type_%s (D->%s[i ++], field%d);\n", offset, "any", arg->id, num); } else { printf ("%s free_ds_type_%s (D->f%d[i ++], field%d);\n", offset, "any", num - 1, num); } printf ("%s }\n", offset); printf ("%s}\n", offset); if (arg->id && strlen (arg->id)) { printf ("%stfree (D->%s, sizeof (void *) * multiplicity%d);\n", offset, arg->id, num); } else { printf ("%stfree (D->f%d, sizeof (void *) * multiplicity%d);\n", offset, num - 1, num); } } } if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } int gen_field_store_ds (struct arg *arg, int *vars, int num, int empty) { assert (arg); char *offset = " "; int o = 0; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; o = 2; } if (arg->var_num >= 0) { assert (TL_TREE_METHODS (arg->type)->type (arg->type) == NODE_TYPE_TYPE); int t = ((struct tl_tree_type *)arg->type)->type->name; if (t == NAME_VAR_TYPE) { fprintf (stderr, "Not supported yet\n"); assert (0); } else { assert (t == NAME_VAR_NUM); if (arg->id && strlen (arg->id)) { if (vars[arg->var_num] == 0) { printf ("%sstruct paramed_type *var%d = INT2PTR (*D->%s);\n", offset, arg->var_num, arg->id); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sassert (vars%d == INT2PTR (*D->%s));\n", offset, arg->var_num, arg->id); } printf ("%sout_int (PTR2INT (var%d));\n", offset, arg->var_num); } else { if (vars[arg->var_num] == 0) { printf ("%sstruct paramed_type *var%d = INT2PTR (*D->f%d);\n", offset, arg->var_num, num - 1); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sassert (vars%d == *D->f%d);\n", offset, arg->var_num, num - 1); } printf ("%sout_int (PTR2INT (var%d));\n", offset, arg->var_num); } } } else { int t = TL_TREE_METHODS (arg->type)->type (arg->type); if (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE) { int bare = arg->flags & FLAG_BARE; if (!bare && t == NODE_TYPE_TYPE) { bare = ((struct tl_tree_type *)arg->type)->self.flags & FLAG_BARE; } printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (arg->type, vars, 2 + o) >= 0); printf (";\n"); int any = (t == NODE_TYPE_VAR_TYPE); int vec = ((struct tl_tree_type *)arg->type)->type->name == NAME_VECTOR; if (arg->id && strlen (arg->id)) { printf ("%sstore_ds_type_%s%s (%sD->%s, field%d);\n", offset, bare ? "bare_" : "", any ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, vec ? "(void *)" : "", arg->id, num); } else { printf ("%sstore_ds_type_%s%s (%sD->f%d, field%d);\n", offset, bare ? "bare_" : "", any ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, vec ? "(void *)" : "", num - 1, num); } } else { assert (t == NODE_TYPE_ARRAY); printf ("%sint multiplicity%d = PTR2INT (\n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->multiplicity, vars, 2 + o) >= 0); printf ("%s);\n", offset); printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->args[0]->type, vars, 2 + o) >= 0); printf (";\n"); printf ("%s{\n", offset); printf ("%s int i = 0;\n", offset); printf ("%s while (i < multiplicity%d) {\n", offset, num); if (arg->id && strlen (arg->id)) { printf ("%s store_ds_type_%s (D->%s[i ++], field%d);\n", offset, "any", arg->id, num); } else { printf ("%s store_ds_type_%s (D->f%d[i ++], field%d);\n", offset, "any", num - 1, num); } printf ("%s }\n", offset); printf ("%s}\n", offset); } } if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } int gen_field_print_ds (struct arg *arg, int *vars, int num, int empty) { assert (arg); char *offset = " "; int o = 0; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; o = 2; } if (!empty) { printf("%sif (multiline_output >= 2) { print_offset (); }\n", offset); } if (arg->id && strlen (arg->id) && !empty) { printf ("%sif (!disable_field_names) { eprintf (\" %s :\"); }\n", offset, arg->id); } if (arg->var_num >= 0) { assert (TL_TREE_METHODS (arg->type)->type (arg->type) == NODE_TYPE_TYPE); int t = ((struct tl_tree_type *)arg->type)->type->name; if (t == NAME_VAR_TYPE) { fprintf (stderr, "Not supported yet\n"); assert (0); } else { if (arg->id && strlen (arg->id)) { if (vars[arg->var_num] == 0) { printf ("%sstruct paramed_type *var%d = INT2PTR (*DS->%s);\n", offset, arg->var_num, arg->id); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sassert (vars%d == INT2PTR (*DS->%s));\n", offset, arg->var_num, arg->id); } } else { if (vars[arg->var_num] == 0) { printf ("%sstruct paramed_type *var%d = INT2PTR (*DS->f%d);\n", offset, arg->var_num, num - 1); vars[arg->var_num] = 2; } else if (vars[arg->var_num] == 2) { printf ("%sassert (vars%d == *DS->f%d);\n", offset, arg->var_num, num - 1); } } printf ("%seprintf (\" %%d\", (int)PTR2INT (var%d));\n", offset, arg->var_num); } } else { int t = TL_TREE_METHODS (arg->type)->type (arg->type); if (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE) { printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (arg->type, vars, 2 + o) >= 0); printf (";\n"); int bare = arg->flags & FLAG_BARE; if (!bare && t == NODE_TYPE_TYPE) { bare = ((struct tl_tree_type *)arg->type)->self.flags & FLAG_BARE; } int any = (t == NODE_TYPE_VAR_TYPE); int vec = ((struct tl_tree_type *)arg->type)->type->name == NAME_VECTOR; if (arg->id && strlen (arg->id)) { printf ("%sprint_ds_type_%s%s (%sDS->%s, field%d);\n", offset, bare ? "bare_" : "", any ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, vec ? "(void *)" : "", arg->id, num); } else { printf ("%sprint_ds_type_%s%s (%sDS->f%d, field%d);\n", offset, bare ? "bare_" : "", any ? "any" : ((struct tl_tree_type *)arg->type)->type->print_id, vec ? "(void *)" : "", num - 1, num); } } else { assert (t == NODE_TYPE_ARRAY); printf ("%sint multiplicity%d = PTR2INT (\n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->multiplicity, vars, 2 + o) >= 0); printf ("%s);\n", offset); printf ("%sstruct paramed_type *field%d = \n", offset, num); assert (gen_create (((struct tl_tree_array *)arg->type)->args[0]->type, vars, 2 + o) >= 0); printf (";\n"); printf ("%seprintf (\" [\");\n", offset); printf ("%sif (multiline_output >= 1) { eprintf (\"\\n\"); }\n", offset); printf ("%sif (multiline_output >= 1) { multiline_offset += multiline_offset_size;}\n", offset); printf ("%s{\n", offset); printf ("%s int i = 0;\n", offset); printf ("%s while (i < multiplicity%d) {\n", offset, num); printf ("%s if (multiline_output >= 1) { print_offset (); }\n", offset); if (arg->id && strlen (arg->id)) { printf ("%s print_ds_type_%s (DS->%s[i ++], field%d);\n", offset, "any", arg->id, num); } else { printf ("%s print_ds_type_%s (DS->f%d[i ++], field%d);\n", offset, "any", num - 1, num); } printf ("%s if (multiline_output >= 1) { eprintf (\"\\n\"); }\n", offset); printf ("%s }\n", offset); printf ("%s}\n", offset); printf ("%sif (multiline_output >= 1) { multiline_offset -= multiline_offset_size; print_offset ();}\n", offset); printf ("%seprintf (\" ]\");\n", offset); } } if (!empty) { printf("%sif (multiline_output >= 2) { eprintf (\"\\n\"); }\n", offset); } if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } int gen_field_autocomplete_excl (struct arg *arg, int *vars, int num, int from_func) { assert (arg); assert (arg->var_num < 0); char *offset = " "; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; } char *fail = from_func ? "0" : "-1"; char *expect = from_func ? "expect_token_ptr_autocomplete" : "expect_token_autocomplete"; if (arg->id && strlen (arg->id) > 0) { printf ("%sif (cur_token_len == -3 && cur_token_real_len <= %d && !cur_token_quoted && !memcmp (cur_token, \"%s\", cur_token_real_len)) {\n", offset, (int)(strlen (arg->id)), arg->id); printf ("%s set_autocomplete_string (\"%s\");\n", offset, arg->id); printf ("%s return %s;\n", offset, fail); printf ("%s}\n", offset); printf ("%sif (cur_token_len >= 0 && cur_token_len == %d && !memcmp (cur_token, \"%s\", cur_token_len)) {\n", offset, (int)(strlen (arg->id)), arg->id); printf ("%s local_next_token ();\n", offset); printf ("%s %s (\":\", 1);\n", offset, expect); printf ("%s}\n", offset); } int t = TL_TREE_METHODS (arg->type)->type (arg->type); assert (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE); printf ("%sstruct paramed_type *field%d = autocomplete_function_any ();\n", offset, num); printf ("%sif (!field%d) { return 0; }\n", offset, num); printf ("%sadd_var_to_be_freed (field%d);\n", offset, num); static char s[20]; sprintf (s, "field%d", num); gen_uni_skip (arg->type, s, vars, 1, 1); if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } int gen_field_store_excl (struct arg *arg, int *vars, int num, int from_func) { assert (arg); assert (arg->var_num < 0); char *offset = " "; if (arg->exist_var_num >= 0) { printf (" if (PTR2INT (var%d) & (1 << %d)) {\n", arg->exist_var_num, arg->exist_var_bit); offset = " "; } char *expect = from_func ? "expect_token_ptr" : "expect_token"; if (arg->id && strlen (arg->id) > 0) { printf ("%sif (cur_token_len >= 0 && cur_token_len == %d && !cur_token_quoted && !memcmp (cur_token, \"%s\", cur_token_len)) {\n", offset, (int)(strlen (arg->id)), arg->id); printf ("%s local_next_token ();\n", offset); printf ("%s %s (\":\", 1);\n", offset, expect); printf ("%s}\n", offset); } int t = TL_TREE_METHODS (arg->type)->type (arg->type); assert (t == NODE_TYPE_TYPE || t == NODE_TYPE_VAR_TYPE); printf ("%sstruct paramed_type *field%d = store_function_any ();\n", offset, num); printf ("%sif (!field%d) { return 0; }\n", offset, num); static char s[20]; sprintf (s, "field%d", num); gen_uni_skip (arg->type, s, vars, 1, 1); if (arg->exist_var_num >= 0) { printf (" }\n"); } return 0; } void gen_constructor_skip (struct tl_combinator *c) { printf ("int skip_constructor_%s (struct paramed_type *T) {\n", c->print_id); int i; for (i = 0; i < c->args_num; i++) if (c->args[i]->flags & FLAG_EXCL) { printf (" return -1;\n"); printf ("}\n"); return; } static char s[10000]; sprintf (s, "T"); int *vars = malloc0 (c->var_num * 4);; gen_uni_skip (c->result, s, vars, 1, 0); if (c->name == NAME_INT) { printf (" if (in_remaining () < 4) { return -1;}\n"); printf (" fetch_int ();\n"); printf (" return 0;\n"); printf ("}\n"); return; } else if (c->name == NAME_LONG) { printf (" if (in_remaining () < 8) { return -1;}\n"); printf (" fetch_long ();\n"); printf (" return 0;\n"); printf ("}\n"); return; } else if (c->name == NAME_STRING) { printf (" int l = prefetch_strlen ();\n"); printf (" if (l < 0) { return -1;}\n"); printf (" fetch_str (l);\n"); printf (" return 0;\n"); printf ("}\n"); return; } else if (c->name == NAME_DOUBLE) { printf (" if (in_remaining () < 8) { return -1;}\n"); printf (" fetch_double ();\n"); printf (" return 0;\n"); printf ("}\n"); return; } for (i = 0; i < c->args_num; i++) if (!(c->args[i]->flags & FLAG_OPT_VAR)) { assert (gen_field_skip (c->args[i], vars, i + 1) >= 0); } free (vars); printf (" return 0;\n"); printf ("}\n"); } void gen_constructor_fetch (struct tl_combinator *c) { printf ("int fetch_constructor_%s (struct paramed_type *T) {\n", c->print_id); int i; for (i = 0; i < c->args_num; i++) if (c->args[i]->flags & FLAG_EXCL) { printf (" return -1;\n"); printf ("}\n"); return; } static char s[10000]; sprintf (s, "T"); int *vars = malloc0 (c->var_num * 4);; gen_uni_skip (c->result, s, vars, 1, 0); if (c->name == NAME_INT) { printf (" if (in_remaining () < 4) { return -1;}\n"); printf (" eprintf (\" %%d\", fetch_int ());\n"); printf (" return 0;\n"); printf ("}\n"); return; } else if (c->name == NAME_LONG) { printf (" if (in_remaining () < 8) { return -1;}\n"); printf (" eprintf (\" %%" INT64_PRINTF_MODIFIER "d\", fetch_long ());\n"); printf (" return 0;\n"); printf ("}\n"); return; } else if (c->name == NAME_STRING) { printf (" static char buf[1 << 22];\n"); printf (" int l = prefetch_strlen ();\n"); printf (" if (l < 0 || (l >= (1 << 22) - 2)) { return -1; }\n"); printf (" memcpy (buf, fetch_str (l), l);\n"); printf (" buf[l] = 0;\n"); printf (" print_escaped_string (buf, l);\n"); printf (" return 0;\n"); printf ("}\n"); return; } else if (c->name == NAME_DOUBLE) { printf (" if (in_remaining () < 8) { return -1;}\n"); printf (" eprintf (\" %%lf\", fetch_double ());\n"); printf (" return 0;\n"); printf ("}\n"); return; } assert (c->result->methods->type (c->result) == NODE_TYPE_TYPE); int empty = is_empty (((struct tl_tree_type *)c->result)->type); if (!empty) { printf (" eprintf (\" %s\");\n", c->id); printf (" if (multiline_output >= 2) { eprintf (\"\\n\"); }\n"); } for (i = 0; i < c->args_num; i++) if (!(c->args[i]->flags & FLAG_OPT_VAR)) { assert (gen_field_fetch (c->args[i], vars, i + 1, empty) >= 0); } free (vars); printf (" return 0;\n"); printf ("}\n"); } void gen_constructor_store (struct tl_combinator *c) { printf ("int store_constructor_%s (struct paramed_type *T) {\n", c->print_id); int i; for (i = 0; i < c->args_num; i++) if (c->args[i]->flags & FLAG_EXCL) { printf (" return -1;\n"); printf ("}\n"); return; } static char s[10000]; sprintf (s, "T"); int *vars = malloc0 (c->var_num * 4);; assert (c->var_num <= 10); gen_uni_skip (c->result, s, vars, 1, 0); if (c->name == NAME_INT) { printf (" if (is_int ()) {\n"); printf (" out_int (get_int ());\n"); printf (" local_next_token ();\n"); printf (" return 0;\n"); printf (" } else {\n"); printf (" return -1;\n"); printf (" }\n"); printf ("}\n"); return; } else if (c->name == NAME_LONG) { printf (" if (is_int ()) {\n"); printf (" out_long (get_int ());\n"); printf (" local_next_token ();\n"); printf (" return 0;\n"); printf (" } else {\n"); printf (" return -1;\n"); printf (" }\n"); printf ("}\n"); return; } else if (c->name == NAME_STRING) { printf (" if (cur_token_len >= 0) {\n"); printf (" out_cstring (cur_token, cur_token_len);\n"); printf (" local_next_token ();\n"); printf (" return 0;\n"); printf (" } else {\n"); printf (" return -1;\n"); printf (" }\n"); printf ("}\n"); return; } else if (c->name == NAME_DOUBLE) { printf (" if (is_double ()) {\n"); printf (" out_double (get_double());\n"); printf (" local_next_token ();\n"); printf (" return 0;\n"); printf (" } else {\n"); printf (" return -1;\n"); printf (" }\n"); printf ("}\n"); return; } int empty = is_empty (((struct tl_tree_type *)c->result)->type); for (i = 0; i < c->args_num; i++) if (!(c->args[i]->flags & FLAG_OPT_VAR)) { assert (gen_field_store (c->args[i], vars, i + 1, 0, empty) >= 0); } free (vars); printf (" return 0;\n"); printf ("}\n"); } void gen_constructor_autocomplete (struct tl_combinator *c) { printf ("int autocomplete_constructor_%s (struct paramed_type *T) {\n", c->print_id); int i; for (i = 0; i < c->args_num; i++) if (c->args[i]->flags & FLAG_EXCL) { printf (" return -1;\n"); printf ("}\n"); return; } static char s[10000]; sprintf (s, "T"); int *vars = malloc0 (c->var_num * 4);; assert (c->var_num <= 10); gen_uni_skip (c->result, s, vars, 1, 0); if (c->name == NAME_INT) { printf (" if (is_int ()) {\n"); printf (" local_next_token ();\n"); printf (" return 0;\n"); printf (" } else {\n"); printf (" return -1;\n"); printf (" }\n"); printf ("}\n"); return; } else if (c->name == NAME_LONG) { printf (" if (is_int ()) {\n"); printf (" local_next_token ();\n"); printf (" return 0;\n"); printf (" } else {\n"); printf (" return -1;\n"); printf (" }\n"); printf ("}\n"); return; } else if (c->name == NAME_STRING) { printf (" if (cur_token_len >= 0) {\n"); printf (" local_next_token ();\n"); printf (" return 0;\n"); printf (" } else {\n"); printf (" return -1;\n"); printf (" }\n"); printf ("}\n"); return; } else if (c->name == NAME_DOUBLE) { printf (" if (is_double ()) {\n"); printf (" local_next_token ();\n"); printf (" return 0;\n"); printf (" } else {\n"); printf (" return -1;\n"); printf (" }\n"); printf ("}\n"); return; } int empty = is_empty (((struct tl_tree_type *)c->result)->type); for (i = 0; i < c->args_num; i++) if (!(c->args[i]->flags & FLAG_OPT_VAR)) { assert (gen_field_autocomplete (c->args[i], vars, i + 1, 0, empty) >= 0); } free (vars); printf (" return 0;\n"); printf ("}\n"); } void gen_constructor_fetch_ds (struct tl_combinator *c) { print_c_type_name (c->result, "", 0); printf ("fetch_ds_constructor_%s (struct paramed_type *T) {\n", c->print_id); int i; for (i = 0; i < c->args_num; i++) if (c->args[i]->flags & FLAG_EXCL) { printf (" assert (0);\n"); printf ("}\n"); return; } static char s[10000]; sprintf (s, "T"); int *vars = malloc0 (c->var_num * 4);; gen_uni_skip (c->result, s, vars, 1, 1); printf (" "); print_c_type_name (c->result, " ", 0); printf (" result = talloc0 (sizeof (*result));\n"); struct tl_type *T = ((struct tl_tree_type *)c->result)->type; if (T->constructors_num > 1) { printf (" result->magic = 0x%08x;\n", c->name); } if (c->name == NAME_INT) { printf (" assert (in_remaining () >= 4);\n"); printf (" *result = fetch_int ();\n"); printf (" return result;\n"); printf ("}\n"); return; } else if (c->name == NAME_LONG) { printf (" assert (in_remaining () >= 8);\n"); printf (" *result = fetch_long ();\n"); printf (" return result;\n"); printf ("}\n"); return; } else if (c->name == NAME_STRING || c->name == NAME_BYTES) { printf (" assert (in_remaining () >= 4);\n"); printf (" int l = prefetch_strlen ();\n"); printf (" assert (l >= 0);\n"); printf (" result->len = l;\n"); printf (" result->data = talloc (l + 1);\n"); printf (" result->data[l] = 0;\n"); printf (" memcpy (result->data, fetch_str (l), l);\n"); printf (" return result;\n"); printf ("}\n"); return; } else if (c->name == NAME_DOUBLE) { printf (" assert (in_remaining () >= 8);\n"); printf (" *result = fetch_double ();\n"); printf (" return result;\n"); printf ("}\n"); return; } assert (c->result->methods->type (c->result) == NODE_TYPE_TYPE); int empty = is_empty (((struct tl_tree_type *)c->result)->type); for (i = 0; i < c->args_num; i++) if (!(c->args[i]->flags & FLAG_OPT_VAR)) { assert (gen_field_fetch_ds (c->args[i], vars, i + 1, empty) >= 0); } free (vars); printf (" return result;\n"); printf ("}\n"); } void gen_constructor_free_ds (struct tl_combinator *c) { printf ("void free_ds_constructor_%s (", c->print_id); print_c_type_name (c->result, "", 0); printf ("D, struct paramed_type *T) {\n"); int i; for (i = 0; i < c->args_num; i++) if (c->args[i]->flags & FLAG_EXCL) { printf (" assert (0);\n"); printf ("}\n"); return; } static char s[10000]; sprintf (s, "T"); int *vars = malloc0 (c->var_num * 4);; gen_uni_skip (c->result, s, vars, 1, -1); //printf (" "); //print_c_type_name (c->result, " ", 0); //printf (" result = talloc0 (sizeof (*result));\n"); //struct tl_type *T = ((struct tl_tree_type *)c->result)->type; if (c->name == NAME_INT) { printf (" tfree (D, sizeof (*D));\n"); printf ("}\n"); return; } else if (c->name == NAME_LONG) { printf (" tfree (D, sizeof (*D));\n"); printf ("}\n"); return; } else if (c->name == NAME_STRING || c->name == NAME_BYTES) { printf (" tfree (D->data, D->len + 1);\n"); printf (" tfree (D, sizeof (*D));\n"); printf ("}\n"); return; } else if (c->name == NAME_DOUBLE) { printf (" tfree (D, sizeof (*D));\n"); printf ("}\n"); return; } assert (c->result->methods->type (c->result) == NODE_TYPE_TYPE); int empty = is_empty (((struct tl_tree_type *)c->result)->type); for (i = 0; i < c->args_num; i++) if (!(c->args[i]->flags & FLAG_OPT_VAR)) { assert (gen_field_free_ds (c->args[i], vars, i + 1, empty) >= 0); } printf (" tfree (D, sizeof (*D));\n"); free (vars); printf ("}\n"); } void gen_constructor_store_ds (struct tl_combinator *c) { printf ("void store_ds_constructor_%s (", c->print_id); print_c_type_name (c->result, "", 0); printf ("D, struct paramed_type *T) {\n"); int i; for (i = 0; i < c->args_num; i++) if (c->args[i]->flags & FLAG_EXCL) { printf (" assert (0);\n"); printf ("}\n"); return; } static char s[10000]; sprintf (s, "T"); int *vars = malloc0 (c->var_num * 4);; gen_uni_skip (c->result, s, vars, 1, -1); //printf (" "); //print_c_type_name (c->result, " ", 0); //printf (" result = talloc0 (sizeof (*result));\n"); //struct tl_type *T = ((struct tl_tree_type *)c->result)->type; if (c->name == NAME_INT) { printf (" out_int (*D);\n"); printf ("}\n"); return; } else if (c->name == NAME_LONG) { printf (" out_long (*D);\n"); printf ("}\n"); return; } else if (c->name == NAME_STRING || c->name == NAME_BYTES) { printf (" out_cstring (D->data, D->len);\n"); printf ("}\n"); return; } else if (c->name == NAME_DOUBLE) { printf (" out_double (*D);\n"); printf ("}\n"); return; } assert (c->result->methods->type (c->result) == NODE_TYPE_TYPE); int empty = is_empty (((struct tl_tree_type *)c->result)->type); for (i = 0; i < c->args_num; i++) if (!(c->args[i]->flags & FLAG_OPT_VAR)) { assert (gen_field_store_ds (c->args[i], vars, i + 1, empty) >= 0); } free (vars); printf ("}\n"); } void gen_constructor_print_ds (struct tl_combinator *c) { printf ("int print_ds_constructor_%s (", c->print_id); print_c_type_name (c->result, "", 0); printf ("DS, struct paramed_type *T) {\n"); int i; for (i = 0; i < c->args_num; i++) if (c->args[i]->flags & FLAG_EXCL) { printf (" return -1;\n"); printf ("}\n"); return; } static char s[10000]; sprintf (s, "T"); int *vars = malloc0 (c->var_num * 4);; gen_uni_skip (c->result, s, vars, 1, 0); if (c->name == NAME_INT) { printf (" eprintf (\" %%d\", *DS);\n"); printf (" return 0;\n"); printf ("}\n"); return; } else if (c->name == NAME_LONG) { printf (" eprintf (\" %%" INT64_PRINTF_MODIFIER "d\", *DS);\n"); printf (" return 0;\n"); printf ("}\n"); return; } else if (c->name == NAME_STRING || c->name == NAME_BYTES) { printf (" print_escaped_string (DS->data, DS->len);\n"); printf (" return 0;\n"); printf ("}\n"); return; } else if (c->name == NAME_DOUBLE) { printf (" eprintf (\" %%lf\", *DS);\n"); printf (" return 0;\n"); printf ("}\n"); return; } assert (c->result->methods->type (c->result) == NODE_TYPE_TYPE); int empty = is_empty (((struct tl_tree_type *)c->result)->type); if (!empty) { printf (" eprintf (\" %s\");\n", c->id); printf (" if (multiline_output >= 2) { eprintf (\"\\n\"); }\n"); } for (i = 0; i < c->args_num; i++) if (!(c->args[i]->flags & FLAG_OPT_VAR)) { assert (gen_field_print_ds (c->args[i], vars, i + 1, empty) >= 0); } free (vars); printf (" return 0;\n"); printf ("}\n"); } void gen_type_skip (struct tl_type *t) { printf ("int skip_type_%s (struct paramed_type *T) {\n", t->print_id); printf (" if (in_remaining () < 4) { return -1;}\n"); printf (" int magic = fetch_int ();\n"); printf (" switch (magic) {\n"); int i; for (i = 0; i < t->constructors_num; i++) { printf (" case 0x%08x: return skip_constructor_%s (T);\n", t->constructors[i]->name, t->constructors[i]->print_id); } printf (" default: return -1;\n"); printf (" }\n"); printf ("}\n"); printf ("int skip_type_bare_%s (struct paramed_type *T) {\n", t->print_id); if (t->constructors_num > 1) { printf (" int *save_in_ptr = in_ptr;\n"); for (i = 0; i < t->constructors_num; i++) { printf (" if (skip_constructor_%s (T) >= 0) { return 0; }\n", t->constructors[i]->print_id); printf (" in_ptr = save_in_ptr;\n"); } } else { for (i = 0; i < t->constructors_num; i++) { printf (" if (skip_constructor_%s (T) >= 0) { return 0; }\n", t->constructors[i]->print_id); } } printf (" return -1;\n"); printf ("}\n"); } void gen_type_fetch (struct tl_type *t) { int empty = is_empty (t);; printf ("int fetch_type_%s (struct paramed_type *T) {\n", t->print_id); printf (" if (in_remaining () < 4) { return -1;}\n"); if (!empty) { printf (" if (multiline_output >= 2) { multiline_offset += multiline_offset_size; }\n"); printf (" eprintf (\" (\");\n"); } printf (" int magic = fetch_int ();\n"); printf (" int res = -1;\n"); printf (" switch (magic) {\n"); int i; for (i = 0; i < t->constructors_num; i++) { printf (" case 0x%08x: res = fetch_constructor_%s (T); break;\n", t->constructors[i]->name, t->constructors[i]->print_id); } printf (" default: return -1;\n"); printf (" }\n"); if (!empty) { printf (" if (res >= 0) {\n"); printf (" if (multiline_output >= 2) { multiline_offset -= multiline_offset_size; print_offset (); }\n"); printf (" eprintf (\" )\");\n"); //printf (" if (multiline_output >= 2) { printf (\"\\n\"); }\n"); printf (" }\n"); } printf (" return res;\n"); printf ("}\n"); printf ("int fetch_type_bare_%s (struct paramed_type *T) {\n", t->print_id); if (t->constructors_num > 1) { printf (" int *save_in_ptr = in_ptr;\n"); if (!empty) { printf (" if (multiline_output >= 2) { multiline_offset += multiline_offset_size; }\n"); } for (i = 0; i < t->constructors_num; i++) { printf (" if (skip_constructor_%s (T) >= 0) { in_ptr = save_in_ptr; %sassert (!fetch_constructor_%s (T)); %sreturn 0; }\n", t->constructors[i]->print_id, empty ? "" : "eprintf (\" (\"); ", t->constructors[i]->print_id , empty ? "" : "if (multiline_output >= 2) { multiline_offset -= multiline_offset_size; print_offset (); } eprintf (\" )\");"); printf (" in_ptr = save_in_ptr;\n"); } } else { for (i = 0; i < t->constructors_num; i++) { if (!empty) { printf (" if (multiline_output >= 2) { multiline_offset += multiline_offset_size; }\n"); printf (" eprintf (\" (\");\n"); } printf (" if (fetch_constructor_%s (T) >= 0) { %sreturn 0; }\n", t->constructors[i]->print_id, empty ? "" : "if (multiline_output >= 2) { multiline_offset -= multiline_offset_size; print_offset (); } eprintf (\" )\");" ); } } printf (" return -1;\n"); printf ("}\n"); } void gen_type_store (struct tl_type *t) { int empty = is_empty (t);; int k = 0; for (k = 0; k < 2; k++) { printf ("int store_type_%s%s (struct paramed_type *T) {\n", k == 0 ? "" : "bare_", t->print_id); if (empty) { if (!k) { printf (" out_int (0x%08x);\n", t->constructors[0]->name); } printf (" if (store_constructor_%s (T) < 0) { return -1; }\n", t->constructors[0]->print_id); printf (" return 0;\n"); printf ("}\n"); } else { printf (" expect_token (\"(\", 1);\n"); printf (" if (cur_token_len < 0) { return -1; }\n"); printf (" if (cur_token_len < 0) { return -1; }\n"); int i; for (i = 0; i < t->constructors_num; i++) { printf (" if (cur_token_len == %d && !memcmp (cur_token, \"%s\", cur_token_len)) {\n", (int)strlen (t->constructors[i]->id), t->constructors[i]->id); if (!k) { printf (" out_int (0x%08x);\n", t->constructors[i]->name); } printf (" local_next_token ();\n"); printf (" if (store_constructor_%s (T) < 0) { return -1; }\n", t->constructors[i]->print_id); printf (" expect_token (\")\", 1);\n"); printf (" return 0;\n"); printf (" }\n"); } /*if (t->constructors_num == 1) { printf (" if (!force) {\n"); if (!k) { printf (" out_int (0x%08x);\n", t->constructors[0]->name); } printf (" if (store_constructor_%s (T) < 0) { return -1; }\n", t->constructors[0]->print_id); printf (" expect_token (\")\", 1);\n"); printf (" return 0;\n"); printf (" }\n"); }*/ printf (" return -1;\n"); printf ("}\n"); } } } void gen_type_autocomplete (struct tl_type *t) { int empty = is_empty (t);; int k = 0; for (k = 0; k < 2; k++) { printf ("int autocomplete_type_%s%s (struct paramed_type *T) {\n", k == 0 ? "" : "bare_", t->print_id); if (empty) { printf (" if (autocomplete_constructor_%s (T) < 0) { return -1; }\n", t->constructors[0]->print_id); printf (" return 0;\n"); printf ("}\n"); } else { printf (" expect_token_autocomplete (\"(\", 1);\n"); printf (" if (cur_token_len == -3) { set_autocomplete_type (do_autocomplete_type_%s); return -1; }\n", t->print_id); printf (" if (cur_token_len < 0) { return -1; }\n"); int i; for (i = 0; i < t->constructors_num; i++) { printf (" if (cur_token_len == %d && !memcmp (cur_token, \"%s\", cur_token_len)) {\n", (int)strlen (t->constructors[i]->id), t->constructors[i]->id); printf (" local_next_token ();\n"); printf (" if (autocomplete_constructor_%s (T) < 0) { return -1; }\n", t->constructors[i]->print_id); printf (" expect_token_autocomplete (\")\", 1);\n"); printf (" return 0;\n"); printf (" }\n"); } /*if (t->constructors_num == 1) { printf (" if (!force) {\n"); printf (" if (autocomplete_constructor_%s (T) < 0) { return -1; }\n", t->constructors[0]->print_id); printf (" expect_token_autocomplete (\")\", 1);\n"); printf (" return 0;\n"); printf (" }\n"); }*/ printf (" return -1;\n"); printf ("}\n"); } } } void gen_type_fetch_ds (struct tl_type *t) { //int empty = is_empty (t);; print_c_type_name (t->constructors[0]->result, "", 0); printf ("fetch_ds_type_%s (struct paramed_type *T) {\n", t->print_id); printf (" assert (in_remaining () >= 4);\n"); printf (" int magic = fetch_int ();\n"); printf (" switch (magic) {\n"); int i; for (i = 0; i < t->constructors_num; i++) { printf (" case 0x%08x: return fetch_ds_constructor_%s (T); break;\n", t->constructors[i]->name, t->constructors[i]->print_id); } printf (" default: assert (0); return NULL;\n"); printf (" }\n"); printf ("}\n"); print_c_type_name (t->constructors[0]->result, "", 0); printf ("fetch_ds_type_bare_%s (struct paramed_type *T) {\n", t->print_id); if (t->constructors_num > 1) { printf (" int *save_in_ptr = in_ptr;\n"); for (i = 0; i < t->constructors_num; i++) { printf (" if (skip_constructor_%s (T) >= 0) { in_ptr = save_in_ptr; return fetch_ds_constructor_%s (T); }\n", t->constructors[i]->print_id, t->constructors[i]->print_id); } } else { printf (" return fetch_ds_constructor_%s (T);\n", t->constructors[0]->print_id); } printf (" assert (0);\n"); printf (" return NULL;\n"); printf ("}\n"); } void gen_type_free_ds (struct tl_type *t) { printf ("void free_ds_type_%s (", t->print_id); print_c_type_name (t->constructors[0]->result, "", 0); printf ("D, struct paramed_type *T) {\n"); if (t->constructors_num > 1) { printf (" switch (D->magic) {\n"); int i; for (i = 0; i < t->constructors_num; i++) { printf (" case 0x%08x: free_ds_constructor_%s (D, T); return; \n", t->constructors[i]->name, t->constructors[i]->print_id); } printf (" default: assert (0);\n"); printf (" }\n"); } else { printf (" free_ds_constructor_%s (D, T); return; \n", t->constructors[0]->print_id); } printf ("}\n"); } void gen_type_store_ds (struct tl_type *t) { int k; for (k = 0; k < 2; k++) { if (k == 0) { printf ("void store_ds_type_%s (", t->print_id); } else { printf ("void store_ds_type_bare_%s (", t->print_id); } print_c_type_name (t->constructors[0]->result, "", 0); printf ("D, struct paramed_type *T) {\n"); if (t->constructors_num > 1) { if (k == 0) { printf (" out_int (D->magic);\n"); } printf (" switch (D->magic) {\n"); int i; for (i = 0; i < t->constructors_num; i++) { printf (" case 0x%08x: store_ds_constructor_%s (D, T); return; \n", t->constructors[i]->name, t->constructors[i]->print_id); } printf (" default: assert (0);\n"); printf (" }\n"); } else { if (k == 0) { printf (" out_int (0x%08x);\n", t->constructors[0]->name); } printf (" store_ds_constructor_%s (D, T); return; \n", t->constructors[0]->print_id); } printf ("}\n"); } } void gen_type_print_ds (struct tl_type *t) { int empty = is_empty (t);; int k; for (k = 0; k < 2; k++) { printf ("int print_ds_type_%s%s (", k ? "bare_" : "", t->print_id); print_c_type_name (t->constructors[0]->result, "", 0); printf ("DS, struct paramed_type *T) {\n"); printf (" int res;\n"); if (!empty) { printf (" if (multiline_output >= 2) { multiline_offset += multiline_offset_size; }\n"); printf (" eprintf (\" (\");\n"); } if (t->constructors_num > 1) { printf (" switch (DS->magic) {\n"); int i; for (i = 0; i < t->constructors_num; i++) { printf (" case 0x%08x: res = print_ds_constructor_%s (DS, T); break;\n", t->constructors[i]->name, t->constructors[i]->print_id); } printf (" default: return -1;\n"); printf (" }\n"); } else { printf (" res = print_ds_constructor_%s (DS, T);\n", t->constructors[0]->print_id); } if (!empty) { printf (" if (res >= 0) {\n"); printf (" if (multiline_output >= 2) { multiline_offset -= multiline_offset_size; print_offset (); }\n"); printf (" eprintf (\" )\");\n"); //printf (" if (multiline_output >= 2) { printf (\"\\n\"); }\n"); printf (" }\n"); } printf (" return res;\n"); printf ("}\n"); } } void gen_function_store (struct tl_combinator *f) { printf ("struct paramed_type *store_function_%s (void) {\n", f->print_id); int i; int *vars = malloc0 (f->var_num * 4);; assert (f->var_num <= 10); for (i = 0; i < f->args_num; i++) if (!(f->args[i]->flags & FLAG_OPT_VAR)) { if (f->args[i]->flags & FLAG_EXCL) { assert (gen_field_store_excl (f->args[i], vars, i + 1, 1) >= 0); } else { assert (gen_field_store (f->args[i], vars, i + 1, 1, 0) >= 0); } } printf (" struct paramed_type *R = \n"); assert (gen_create (f->result, vars, 2) >= 0); printf (";\n"); free (vars); printf (" return paramed_type_dup (R);\n"); printf ("}\n"); } void gen_function_autocomplete (struct tl_combinator *f) { printf ("struct paramed_type *autocomplete_function_%s (void) {\n", f->print_id); int i; int *vars = malloc0 (f->var_num * 4);; assert (f->var_num <= 10); for (i = 0; i < f->args_num; i++) if (!(f->args[i]->flags & FLAG_OPT_VAR)) { if (f->args[i]->flags & FLAG_EXCL) { assert (gen_field_autocomplete_excl (f->args[i], vars, i + 1, 1) >= 0); } else { assert (gen_field_autocomplete (f->args[i], vars, i + 1, 1, 0) >= 0); } } printf (" struct paramed_type *R = \n"); assert (gen_create (f->result, vars, 2) >= 0); printf (";\n"); free (vars); printf (" return paramed_type_dup (R);\n"); printf ("}\n"); } void gen_type_do_autocomplete (struct tl_type *t) { printf ("int do_autocomplete_type_%s (const char *text, int text_len, int index, char **R) {\n", t->print_id); printf (" index ++;\n"); int i; for (i = 0; i < t->constructors_num; i++) { printf (" if (index == %d) { if (!strncmp (text, \"%s\", text_len)) { *R = tstrdup (\"%s\"); return index; } else { index ++; }}\n", i, t->constructors[i]->id, t->constructors[i]->id); } printf (" *R = 0;\n"); printf (" return 0;\n"); printf ("}\n"); } struct tl_tree *read_num_var (int *var_num) { struct tl_tree_var_num *T = malloc0 (sizeof (*T)); T->self.flags = 0; T->self.methods = &tl_pvar_num_methods;; T->dif = get_int (); T->var_num = get_int (); if (T->var_num >= *var_num) { *var_num = T->var_num + 1; } assert (!(T->self.flags & FLAG_NOVAR)); return (void *)T; } struct tl_tree *read_type_var (int *var_num) { struct tl_tree_var_type *T = malloc0 (sizeof (*T)); T->self.methods = &tl_pvar_type_methods; T->var_num = get_int (); T->self.flags = get_int (); if (T->var_num >= *var_num) { *var_num = T->var_num + 1; } assert (!(T->self.flags & (FLAG_NOVAR | FLAG_BARE))); return (void *)T; } struct tl_tree *read_array (int *var_num) { struct tl_tree_array *T = malloc0 (sizeof (*T)); T->self.methods = &tl_parray_methods; T->self.flags = 0; T->multiplicity = read_nat_expr (var_num); assert (T->multiplicity); T->args_num = get_int (); assert (T->args_num >= 0 && T->args_num <= 1000); T->args = malloc0 (sizeof (void *) * T->args_num); assert (read_args_list (T->args, T->args_num, var_num) >= 0); T->self.flags |= FLAG_NOVAR; int i; for (i = 0; i < T->args_num; i++) { if (!(T->args[i]->flags & FLAG_NOVAR)) { T->self.flags &= ~FLAG_NOVAR; } } return (void *)T; } struct tl_tree *read_type (int *var_num) { struct tl_tree_type *T = malloc0 (sizeof (*T)); T->self.methods = &tl_ptype_methods; T->type = tl_type_get_by_name (get_int ()); assert (T->type); T->self.flags = get_int (); T->children_num = get_int (); assert (T->type->arity == T->children_num); T->children = malloc0 (sizeof (void *) * T->children_num); int i; T->self.flags |= FLAG_NOVAR; for (i = 0; i < T->children_num; i++) { int t = get_int (); if (t == (int)TLS_EXPR_NAT) { assert ((T->type->params_types & (1 << i))); T->children[i] = read_nat_expr (var_num); } else if (t == (int)TLS_EXPR_TYPE) { assert (!(T->type->params_types & (1 << i))); T->children[i] = read_type_expr (var_num); } else { assert (0); } if (!TL_IS_NAT_VAR (T->children[i]) && !(T->children[i]->flags & FLAG_NOVAR)) { T->self.flags &= ~FLAG_NOVAR; } } return (void *)T; } struct tl_tree *read_tree (int *var_num) { int x = get_int (); if (verbosity >= 2) { fprintf (stderr, "read_tree: constructor = 0x%08x\n", x); } switch (x) { case TLS_TREE_NAT_CONST: return read_num_const (var_num); case TLS_TREE_NAT_VAR: return read_num_var (var_num); case TLS_TREE_TYPE_VAR: return read_type_var (var_num); case TLS_TREE_TYPE: return read_type (var_num); case TLS_TREE_ARRAY: return read_array (var_num); default: if (verbosity) { fprintf (stderr, "x = %d\n", x); } assert (0); return 0; } } struct tl_tree *read_type_expr (int *var_num) { int x = get_int (); if (verbosity >= 2) { fprintf (stderr, "read_type_expr: constructor = 0x%08x\n", x); } switch (x) { case TLS_TYPE_VAR: return read_type_var (var_num); case TLS_TYPE_EXPR: return read_type (var_num); case TLS_ARRAY: return read_array (var_num); default: if (verbosity) { fprintf (stderr, "x = %d\n", x); } assert (0); return 0; } } struct tl_tree *read_nat_expr (int *var_num) { int x = get_int (); if (verbosity >= 2) { fprintf (stderr, "read_nat_expr: constructor = 0x%08x\n", x); } switch (x) { case TLS_NAT_CONST: return read_num_const (var_num); case TLS_NAT_VAR: return read_num_var (var_num); default: if (verbosity) { fprintf (stderr, "x = %d\n", x); } assert (0); return 0; } } struct tl_tree *read_expr (int *var_num) { int x = get_int (); if (verbosity >= 2) { fprintf (stderr, "read_nat_expr: constructor = 0x%08x\n", x); } switch (x) { case TLS_EXPR_NAT: return read_nat_expr (var_num); case TLS_EXPR_TYPE: return read_type_expr (var_num); default: if (verbosity) { fprintf (stderr, "x = %d\n", x); } assert (0); return 0; } } int read_args_list (struct arg **args, int args_num, int *var_num) { int i; for (i = 0; i < args_num; i++) { args[i] = malloc0 (sizeof (struct arg)); args[i]->exist_var_num = -1; args[i]->exist_var_bit = 0; assert (get_int () == TLS_ARG_V2); args[i]->id = get_string (); args[i]->flags = get_int (); if (args[i]->flags & 2) { args[i]->flags &= ~2; args[i]->flags |= (1 << 20); } if (args[i]->flags & 4) { args[i]->flags &= ~4; args[i]->var_num = get_int (); } else { args[i]->var_num = -1; } int x = args[i]->flags & 6; args[i]->flags &= ~6; if (x & 2) { args[i]->flags |= 4; } if (x & 4) { args[i]->flags |= 2; } if (args[i]->var_num >= *var_num) { *var_num = args[i]->var_num + 1; } if (args[i]->flags & FLAG_OPT_FIELD) { args[i]->exist_var_num = get_int (); args[i]->exist_var_bit = get_int (); } args[i]->type = read_type_expr (var_num); assert (args[i]->type); if (args[i]->var_num < 0 && args[i]->exist_var_num < 0 && (TL_IS_NAT_VAR(args[i]->type) || (args[i]->type->flags & FLAG_NOVAR))) { args[i]->flags |= FLAG_NOVAR; } } return 1; } int read_combinator_args_list (struct tl_combinator *c) { c->args_num = get_int (); if (verbosity >= 2) { fprintf (stderr, "c->id = %s, c->args_num = %d\n", c->id, c->args_num); } assert (c->args_num >= 0 && c->args_num <= 1000); c->args = malloc0 (sizeof (void *) * c->args_num); c->var_num = 0; return read_args_list (c->args, c->args_num, &c->var_num); } int read_combinator_right (struct tl_combinator *c) { assert (get_int () == TLS_COMBINATOR_RIGHT_V2); c->result = read_type_expr (&c->var_num); assert (c->result); return 1; } int read_combinator_left (struct tl_combinator *c) { int x = get_int (); if (x == (int)TLS_COMBINATOR_LEFT_BUILTIN) { c->args_num = 0; c->var_num = 0; c->args = 0; return 1; } else if (x == TLS_COMBINATOR_LEFT) { return read_combinator_args_list (c); } else { assert (0); return -1; } } char *gen_print_id (const char *id) { static char s[1000]; char *ptr = s; int first = 1; while (*id) { if (*id == '.') { *(ptr ++) = '_'; } else if (*id >= 'A' && *id <= 'Z') { if (!first && *(ptr - 1) != '_') { *(ptr ++) = '_'; } *(ptr ++) = *id - 'A' + 'a'; } else { *(ptr ++) = *id; } id ++; first = 0; } *ptr = 0; return s; } struct tl_combinator *read_combinators (int v) { struct tl_combinator *c = malloc0 (sizeof (*c)); c->name = get_int (); c->id = get_string (); c->print_id = strdup (gen_print_id (c->id)); assert (c->print_id); //char *s = c->id; //while (*s) { if (*s == '.') { *s = '_'; } ; s ++;} int x = get_int (); struct tl_type *t = tl_type_get_by_name (x); assert (t || (!x && v == 3)); if (v == 2) { assert (t->extra < t->constructors_num); t->constructors[t->extra ++] = c; c->is_fun = 0; } else { assert (v == 3); tl_function_insert_by_name (c); c->is_fun = 1; } assert (read_combinator_left (c) >= 0); assert (read_combinator_right (c) >= 0); return c; } struct tl_type *read_types (void) { struct tl_type *t = malloc0 (sizeof (*t)); t->name = get_int (); t->id = get_string (); t->print_id = strdup (gen_print_id (t->id)); assert (t->print_id); t->constructors_num = get_int (); assert (t->constructors_num >= 0 && t->constructors_num <= 1000); t->constructors = malloc0 (sizeof (void *) * t->constructors_num); t->flags = get_int (); t->arity = get_int (); t->params_types = get_long (); // params_types t->extra = 0; tl_type_insert_by_name (t); return t; } char *gen_what[1000]; int gen_what_cnt; void gen_skip_header (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { printf ("int skip_constructor_%s (struct paramed_type *T);\n", tps[i]->constructors[j]->print_id); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("int skip_type_%s (struct paramed_type *T);\n", tps[i]->print_id); printf ("int skip_type_bare_%s (struct paramed_type *T);\n", tps[i]->print_id); } printf ("int skip_type_any (struct paramed_type *T);\n"); } void gen_skip_source (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("#include \"auto/auto-skip.h\"\n"); printf ("#include \"mtproto-common.h\"\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { gen_constructor_skip (tps[i]->constructors[j]); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { gen_type_skip (tps[i]); } printf ("int skip_type_any (struct paramed_type *T) {\n"); printf (" switch (T->type->name) {\n"); for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type") && tps[i]->name) { printf (" case 0x%08x: return skip_type_%s (T);\n", tps[i]->name, tps[i]->print_id); printf (" case 0x%08x: return skip_type_bare_%s (T);\n", ~tps[i]->name, tps[i]->print_id); } printf (" default: return -1; }\n"); printf ("}\n"); } void gen_fetch_header (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("#include \n"); printf ("struct tgl_state;\n"); printf ("char *tglf_extf_fetch (struct tgl_state *TLS, struct paramed_type *T);\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { printf ("int fetch_constructor_%s (struct paramed_type *T);\n", tps[i]->constructors[j]->print_id); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("int fetch_type_%s (struct paramed_type *T);\n", tps[i]->print_id); printf ("int fetch_type_bare_%s (struct paramed_type *T);\n", tps[i]->print_id); } printf ("int fetch_type_any (struct paramed_type *T);\n"); } void gen_fetch_source (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("#include \"auto/auto-fetch.h\"\n"); printf ("#include \"auto/auto-skip.h\"\n"); printf ("#include \"auto-static-fetch.c\"\n"); printf ("#include \"mtproto-common.h\"\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { gen_constructor_fetch (tps[i]->constructors[j]); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { gen_type_fetch (tps[i]); } printf ("int fetch_type_any (struct paramed_type *T) {\n"); printf (" switch (T->type->name) {\n"); for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type") && tps[i]->name) { printf (" case 0x%08x: return fetch_type_%s (T);\n", tps[i]->name, tps[i]->print_id); printf (" case 0x%08x: return fetch_type_bare_%s (T);\n", ~tps[i]->name, tps[i]->print_id); } printf (" default: return -1; }\n"); printf ("}\n"); } void gen_store_header (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("struct paramed_type *tglf_extf_store (struct tgl_state *TLS, const char *data, int data_len);\n"); printf ("int tglf_store_type (struct tgl_state *TLS, const char *work, int work_len, struct paramed_type *P);\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { printf ("int store_constructor_%s (struct paramed_type *T);\n", tps[i]->constructors[j]->print_id); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("int store_type_%s (struct paramed_type *T);\n", tps[i]->print_id); printf ("int store_type_bare_%s (struct paramed_type *T);\n", tps[i]->print_id); } for (i = 0; i < fn; i++) { printf ("struct paramed_type *store_function_%s (void);\n", fns[i]->print_id); } printf ("int store_type_any (struct paramed_type *T);\n"); printf ("struct paramed_type *store_function_any (void);\n"); } void gen_store_source (void ) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("#include \"mtproto-common.h\"\n"); printf ("#include \"auto/auto-store.h\"\n"); printf ("#include \"auto-static-store.c\"\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { gen_constructor_store (tps[i]->constructors[j]); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { gen_type_store (tps[i]); } for (i = 0; i < fn; i++) { gen_function_store (fns[i]); } printf ("int store_type_any (struct paramed_type *T) {\n"); printf (" switch (T->type->name) {\n"); for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type") && tps[i]->name) { printf (" case 0x%08x: return store_type_%s (T);\n", tps[i]->name, tps[i]->print_id); printf (" case 0x%08x: return store_type_bare_%s (T);\n", ~tps[i]->name, tps[i]->print_id); } printf (" default: return -1; }\n"); printf ("}\n"); printf ("struct paramed_type *store_function_any (void) {\n"); printf (" if (cur_token_len != 1 || *cur_token != '(') { return 0; }\n"); printf (" local_next_token ();\n"); printf (" if (cur_token_len == 1 || *cur_token == '.') { \n"); printf (" local_next_token ();\n"); printf (" if (cur_token_len != 1 || *cur_token != '=') { return 0; }\n"); printf (" local_next_token ();\n"); printf (" };\n"); printf (" if (cur_token_len < 0) { return 0; }\n"); for (i = 0; i < fn; i++) { printf (" if (cur_token_len == %d && !memcmp (cur_token, \"%s\", cur_token_len)) {\n", (int)strlen (fns[i]->id), fns[i]->id); printf (" out_int (0x%08x);\n", fns[i]->name); printf (" local_next_token ();\n"); printf (" struct paramed_type *P = store_function_%s ();\n", fns[i]->print_id); printf (" if (!P) { return 0; }\n"); printf (" if (cur_token_len != 1 || *cur_token != ')') { return 0; }\n"); printf (" local_next_token ();\n"); printf (" return P;\n"); printf (" }\n"); } printf (" return 0;\n"); printf ("}\n"); } void gen_autocomplete_header (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("int tglf_extf_autocomplete (struct tgl_state *TLS, const char *text, int text_len, int index, char **R, char *data, int data_len);\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { printf ("int autocomplete_constructor_%s (struct paramed_type *T);\n", tps[i]->constructors[j]->print_id); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("int autocomplete_type_%s (struct paramed_type *T);\n", tps[i]->print_id); printf ("int do_autocomplete_type_%s (const char *text, int len, int index, char **R);\n", tps[i]->print_id); printf ("int autocomplete_type_bare_%s (struct paramed_type *T);\n", tps[i]->print_id); } printf ("int autocomplete_type_any (struct paramed_type *T);\n"); printf ("struct paramed_type *autocomplete_function_any (void);\n"); } void gen_autocomplete_source (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("#include \"mtproto-common.h\"\n"); printf ("#include \"auto/auto-autocomplete.h\"\n"); printf ("#include \"auto-static-autocomplete.c\"\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { gen_constructor_autocomplete (tps[i]->constructors[j]); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { gen_type_autocomplete (tps[i]); gen_type_do_autocomplete (tps[i]); } for (i = 0; i < fn; i++) { gen_function_autocomplete (fns[i]); } printf ("int autocomplete_type_any (struct paramed_type *T) {\n"); printf (" switch (T->type->name) {\n"); for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type") && tps[i]->name) { printf (" case 0x%08x: return autocomplete_type_%s (T);\n", tps[i]->name, tps[i]->print_id); printf (" case 0x%08x: return autocomplete_type_bare_%s (T);\n", ~tps[i]->name, tps[i]->print_id); } printf (" default: return -1; }\n"); printf ("}\n"); printf ("int do_autocomplete_function (const char *text, int text_len, int index, char **R) {\n"); printf (" index ++;\n"); for (i = 0; i < fn; i++) { printf (" if (index == %d) { if (!strncmp (text, \"%s\", text_len)) { *R = tstrdup (\"%s\"); return index; } else { index ++; }}\n", i, fns[i]->id, fns[i]->id); } printf (" *R = 0;\n"); printf (" return 0;\n"); printf ("}\n"); printf ("struct paramed_type *autocomplete_function_any (void) {\n"); printf (" expect_token_ptr_autocomplete (\"(\", 1);\n"); printf (" if (cur_token_len == -3) { set_autocomplete_type (do_autocomplete_function); }\n"); printf (" if (cur_token_len < 0) { return 0; }\n"); for (i = 0; i < fn; i++) { printf (" if (cur_token_len == %d && !memcmp (cur_token, \"%s\", cur_token_len)) {\n", (int)strlen (fns[i]->id), fns[i]->id); printf (" local_next_token ();\n"); printf (" struct paramed_type *P = autocomplete_function_%s ();\n", fns[i]->print_id); printf (" if (!P) { return 0; }\n"); printf (" expect_token_ptr_autocomplete (\")\", 1);\n"); printf (" return P;\n"); printf (" }\n"); } printf (" return 0;\n"); printf ("}\n"); } void gen_types_header (void) { printf ("#ifndef __AUTO_TYPES_H__\n"); printf ("#define __AUTO_TYPES_H__\n"); printf ("#include \"auto.h\"\n"); int i; for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("extern struct tl_type_descr tl_type_%s;\n", tps[i]->print_id); printf ("extern struct tl_type_descr tl_type_bare_%s;\n", tps[i]->print_id); } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("struct tl_ds_%s {\n", tps[i]->print_id); if (!strcmp (tps[i]->id, "String") || !strcmp (tps[i]->id, "Bytes")) { printf (" int len;\n"); printf (" char *data;\n"); printf ("};\n"); continue; } int j; if (tps[i]->constructors_num > 1) { printf (" unsigned magic;\n"); } for (j = 0; j < tps[i]->constructors_num; j++) { struct tl_combinator *c = tps[i]->constructors[j]; int k; for (k = 0; k < c->args_num; k++) { if ((c->args[k]->flags & FLAG_OPT_VAR)) { continue; } if (c->args[k]->id && strlen (c->args[k]->id) && j > 0) { int l; int ok = 1; for (l = 0; l < j && ok; l++) { int m; struct tl_combinator *d = tps[i]->constructors[l]; for (m = 0; m < d->args_num && ok; m++) { if (d->args[m]->id && !strcmp (d->args[m]->id, c->args[k]->id)) { ok = 0; } } } if (!ok) { continue; } } printf (" "); print_c_type_name (c->args[k]->type, " ", 1); if (!c->args[k]->id || !strlen (c->args[k]->id)) { assert (!j); printf ("f%d;\n", k); } else { printf ("%s;\n", c->args[k]->id); } } } printf ("};\n"); } printf ("#endif\n"); } void gen_types_source (void) { printf ("#include \"auto.h\"\n"); int i; for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("struct tl_type_descr tl_type_%s = {\n", tps[i]->print_id); printf (" .name = 0x%08x,\n", tps[i]->name); printf (" .id = \"%s\"\n,", tps[i]->id); printf (" .params_num = %d,\n", tps[i]->arity); printf (" .params_types = %" INT64_PRINTF_MODIFIER "d\n", tps[i]->params_types); printf ("};\n"); printf ("struct tl_type_descr tl_type_bare_%s = {\n", tps[i]->print_id); printf (" .name = 0x%08x,\n", ~tps[i]->name); printf (" .id = \"Bare_%s\",\n", tps[i]->id); printf (" .params_num = %d,\n", tps[i]->arity); printf (" .params_types = %" INT64_PRINTF_MODIFIER "d\n", tps[i]->params_types); printf ("};\n"); } } void gen_fetch_ds_source (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("#include \"auto/auto-fetch-ds.h\"\n"); printf ("#include \"auto/auto-skip.h\"\n"); printf ("#include \"auto/auto-types.h\"\n"); printf ("#include \"mtproto-common.h\"\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { gen_constructor_fetch_ds (tps[i]->constructors[j]); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { gen_type_fetch_ds (tps[i]); } printf ("void *fetch_ds_type_any (struct paramed_type *T) {\n"); printf (" switch (T->type->name) {\n"); for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type") && tps[i]->name) { printf (" case 0x%08x: return fetch_ds_type_%s (T);\n", tps[i]->name, tps[i]->print_id); printf (" case 0x%08x: return fetch_ds_type_bare_%s (T);\n", ~tps[i]->name, tps[i]->print_id); } printf (" default: return NULL; }\n"); printf ("}\n"); } void gen_fetch_ds_header (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("#include \n"); printf ("struct tgl_state;\n"); //printf ("char *tglf_extf_fetch (struct tgl_state *TLS, struct paramed_type *T);\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { print_c_type_name (tps[i]->constructors[j]->result, "", 0); printf ("fetch_ds_constructor_%s (struct paramed_type *T);\n", tps[i]->constructors[j]->print_id); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { print_c_type_name (tps[i]->constructors[0]->result, "", 0); printf ("fetch_ds_type_%s (struct paramed_type *T);\n", tps[i]->print_id); print_c_type_name (tps[i]->constructors[0]->result, "", 0); printf ("fetch_ds_type_bare_%s (struct paramed_type *T);\n", tps[i]->print_id); } printf ("void *fetch_ds_type_any (struct paramed_type *T);\n"); } void gen_free_ds_source (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("#include \"auto/auto-free-ds.h\"\n"); printf ("#include \"auto/auto-skip.h\"\n"); printf ("#include \"auto/auto-types.h\"\n"); printf ("#include \"mtproto-common.h\"\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { gen_constructor_free_ds (tps[i]->constructors[j]); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { gen_type_free_ds (tps[i]); } printf ("void free_ds_type_any (void *D, struct paramed_type *T) {\n"); printf (" switch (T->type->name) {\n"); for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type") && tps[i]->name) { printf (" case 0x%08x: free_ds_type_%s (D, T); return;\n", tps[i]->name, tps[i]->print_id); printf (" case 0x%08x: free_ds_type_%s (D, T); return;\n", ~tps[i]->name, tps[i]->print_id); } printf (" default: return; }\n"); printf ("}\n"); } void gen_free_ds_header (void) { printf ("#include \"auto.h\"\n"); printf ("#include \"auto/auto-types.h\"\n"); printf ("#include \n"); printf ("#include \n"); printf ("struct tgl_state;\n"); //printf ("char *tglf_extf_fetch (struct tgl_state *TLS, struct paramed_type *T);\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { printf ("void free_ds_constructor_%s (", tps[i]->constructors[j]->print_id); print_c_type_name (tps[i]->constructors[j]->result, "", 0); printf ("D, struct paramed_type *T);\n"); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("void free_ds_type_%s (", tps[i]->print_id); print_c_type_name (tps[i]->constructors[0]->result, "", 0); printf ("D, struct paramed_type *T);\n"); } printf ("void free_ds_type_any (void *D, struct paramed_type *T);\n"); } void gen_store_ds_source (void) { printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("#include \"auto/auto-store-ds.h\"\n"); printf ("#include \"auto/auto-skip.h\"\n"); printf ("#include \"auto/auto-types.h\"\n"); printf ("#include \"mtproto-common.h\"\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { gen_constructor_store_ds (tps[i]->constructors[j]); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { gen_type_store_ds (tps[i]); } printf ("void store_ds_type_any (void *D, struct paramed_type *T) {\n"); printf (" switch (T->type->name) {\n"); for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type") && tps[i]->name) { printf (" case 0x%08x: store_ds_type_%s (D, T); return;\n", tps[i]->name, tps[i]->print_id); printf (" case 0x%08x: store_ds_type_bare_%s (D, T); return;\n", ~tps[i]->name, tps[i]->print_id); } printf (" default: return; }\n"); printf ("}\n"); } void gen_store_ds_header (void) { printf ("#include \"auto.h\"\n"); printf ("#include \"auto/auto-types.h\"\n"); printf ("#include \n"); printf ("#include \n"); printf ("struct tgl_state;\n"); //printf ("char *tglf_extf_fetch (struct tgl_state *TLS, struct paramed_type *T);\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { printf ("void store_ds_constructor_%s (", tps[i]->constructors[j]->print_id); print_c_type_name (tps[i]->constructors[j]->result, "", 0); printf ("D, struct paramed_type *T);\n"); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("void store_ds_type_%s (", tps[i]->print_id); print_c_type_name (tps[i]->constructors[0]->result, "", 0); printf ("D, struct paramed_type *T);\n"); printf ("void store_ds_type_bare_%s (", tps[i]->print_id); print_c_type_name (tps[i]->constructors[0]->result, "", 0); printf ("D, struct paramed_type *T);\n"); } printf ("void store_ds_type_any (void *D, struct paramed_type *T);\n"); } void gen_print_ds_header (void) { printf ("#include \"config.h\"\n"); printf ("#ifndef DISABLE_EXTF\n"); printf ("\n"); printf ("#include \"auto.h\"\n"); printf ("#include \"auto-types.h\"\n"); printf ("#include \n"); printf ("#include \n"); printf ("struct tgl_state;\n"); printf ("char *tglf_extf_print_ds (struct tgl_state *TLS, void *DS, struct paramed_type *T);\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { printf ("int print_ds_constructor_%s (", tps[i]->constructors[j]->print_id); print_c_type_name (tps[i]->constructors[j]->result, "", 0); printf ("DS, struct paramed_type *T);\n"); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { printf ("int print_ds_type_%s (", tps[i]->print_id); print_c_type_name (tps[i]->constructors[0]->result, "", 0); printf ("DS, struct paramed_type *T);\n"); printf ("int print_ds_type_bare_%s (", tps[i]->print_id); print_c_type_name (tps[i]->constructors[0]->result, "", 0); printf ("DS, struct paramed_type *T);\n"); } printf ("int print_ds_type_any (void *DS, struct paramed_type *T);\n"); printf ("#endif\n"); } void gen_print_ds_source (void) { printf ("#include \"config.h\"\n"); printf ("#ifndef DISABLE_EXTF\n"); printf ("\n"); printf ("#include \"auto.h\"\n"); printf ("#include \n"); printf ("\n"); printf ("#include \"auto/auto-print-ds.h\"\n"); printf ("#include \"auto/auto-skip.h\"\n"); printf ("#include \"auto-static-print-ds.c\"\n"); printf ("#include \"mtproto-common.h\"\n"); int i, j; for (i = 0; i < tn; i++) { for (j = 0; j < tps[i]->constructors_num; j ++) { gen_constructor_print_ds (tps[i]->constructors[j]); } } for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { gen_type_print_ds (tps[i]); } printf ("int print_ds_type_any (void *DS, struct paramed_type *T) {\n"); printf (" switch (T->type->name) {\n"); for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type") && tps[i]->name) { printf (" case 0x%08x: return print_ds_type_%s (DS, T);\n", tps[i]->name, tps[i]->print_id); printf (" case 0x%08x: return print_ds_type_bare_%s (DS, T);\n", ~tps[i]->name, tps[i]->print_id); } printf (" default: return -1; }\n"); printf ("}\n"); printf ("#endif\n"); } int parse_tlo_file (void) { buf_end = buf_ptr + (buf_size / 4); assert (get_int () == TLS_SCHEMA_V2); get_int (); // version get_int (); // date tn = 0; fn = 0; cn = 0; int i; tn = get_int (); assert (tn >= 0 && tn < 10000); tps = malloc0 (sizeof (void *) * tn); if (verbosity >= 2) { fprintf (stderr, "Found %d types\n", tn); } for (i = 0; i < tn; i++) { assert (get_int () == TLS_TYPE); tps[i] = read_types (); assert (tps[i]); } cn = get_int (); assert (cn >= 0); if (verbosity >= 2) { fprintf (stderr, "Found %d constructors\n", cn); } for (i = 0; i < cn; i++) { assert (get_int () == TLS_COMBINATOR); assert (read_combinators (2)); } fn = get_int (); assert (fn >= 0 && fn < 10000); fns = malloc0 (sizeof (void *) * fn); if (verbosity >= 2) { fprintf (stderr, "Found %d functions\n", fn); } for (i = 0; i < fn; i++) { assert (get_int () == TLS_COMBINATOR); fns[i] = read_combinators (3); assert (fns[i]); } assert (buf_ptr == buf_end); int j; for (i = 0; i < tn; i++) if (tps[i]->id[0] != '#' && strcmp (tps[i]->id, "Type")) { tps[i]->name = 0; for (j = 0; j < tps[i]->constructors_num; j ++) { tps[i]->name ^= tps[i]->constructors[j]->name; } } for (i = 0; i < gen_what_cnt; i++) { if (!strcmp (gen_what[i], "fetch")) { gen_fetch_source (); } else if (!strcmp (gen_what[i], "fetch-header")) { gen_fetch_header (); } else if (!strcmp (gen_what[i], "skip")) { gen_skip_source (); } else if (!strcmp (gen_what[i], "skip-header")) { gen_skip_header (); } else if (!strcmp (gen_what[i], "store")) { gen_store_source (); } else if (!strcmp (gen_what[i], "store-header")) { gen_store_header (); } else if (!strcmp (gen_what[i], "autocomplete")) { gen_autocomplete_source (); } else if (!strcmp (gen_what[i], "autocomplete-header")) { gen_autocomplete_header (); } else if (!strcmp (gen_what[i], "types")) { gen_types_source (); } else if (!strcmp (gen_what[i], "types-header")) { gen_types_header (); } else if (!strcmp (gen_what[i], "fetch-ds")) { gen_fetch_ds_source (); } else if (!strcmp (gen_what[i], "fetch-ds-header")) { gen_fetch_ds_header (); } else if (!strcmp (gen_what[i], "free-ds")) { gen_free_ds_source (); } else if (!strcmp (gen_what[i], "free-ds-header")) { gen_free_ds_header (); } else if (!strcmp (gen_what[i], "store-ds")) { gen_store_ds_source (); } else if (!strcmp (gen_what[i], "store-ds-header")) { gen_store_ds_header (); } else if (!strcmp (gen_what[i], "print-ds")) { gen_print_ds_source (); } else if (!strcmp (gen_what[i], "print-ds-header")) { gen_print_ds_header (); } else { assert (0); } } return 0; } void usage (void) { printf ("usage: generate [-v] [-h] \n" ); exit (2); } void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); void logprintf (const char *format __attribute__ ((unused)), ...) { } /* void hexdump (int *in_ptr, int *in_end) { int *ptr = in_ptr; while (ptr < in_end) { printf (" %08x", *(ptr ++)); } printf ("\n"); }*/ #ifdef HAVE_EXECINFO_H void print_backtrace (void) { void *buffer[255]; const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); backtrace_symbols_fd (buffer, calls, 1); } #else void print_backtrace (void) { if (write (1, "No libexec. Backtrace disabled\n", 32) < 0) { // Sad thing } } #endif void sig_segv_handler (int signum __attribute__ ((unused))) { if (write (1, "SIGSEGV received\n", 18) < 0) { // Sad thing } print_backtrace (); exit (EXIT_FAILURE); } void sig_abrt_handler (int signum __attribute__ ((unused))) { if (write (1, "SIGABRT received\n", 18) < 0) { // Sad thing } print_backtrace (); exit (EXIT_FAILURE); } static int read_all (int fd, void *buf, size_t len) { unsigned int rs = 0; while(rs < len) { int rval = read (fd, buf + rs, len - rs); if (rval == 0) { break; } if (rval < 0) { return rval; } rs += rval; } return rs; } #ifndef O_BINARY #define O_BINARY 0 #endif int main (int argc, char **argv) { signal (SIGSEGV, sig_segv_handler); signal (SIGABRT, sig_abrt_handler); int i; while ((i = getopt (argc, argv, "vhHg:")) != -1) { switch (i) { case 'h': usage (); return 2; case 'v': verbosity++; break; case 'H': header ++; break; case 'g': assert (gen_what_cnt < 1000); gen_what[gen_what_cnt ++] = optarg; break; } } if (argc != optind + 1) { usage (); } int fd = open (argv[optind], O_RDONLY | O_BINARY); if (fd < 0) { fprintf (stderr, "Can not open file '%s'. Error %s\n", argv[optind], strerror(errno)); exit (1); } buf_size = read_all (fd, buf, (1 << 20)); if (fd == (1 << 20)) { fprintf (stderr, "Too big tlo file\n"); exit (2); } return parse_tlo_file (); } telegram-purple/tgl/generate.h000066400000000000000000000102121357227200100167070ustar00rootroot00000000000000/* This file is part of tgl-libary/generate Tgl-library/generate 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. Tgl-library/generate 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 tgl-library/generate. If not, see . Copyright Vitaly Valtman 2014-2015 It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) Copyright 2012-2013 Vkontakte Ltd 2012-2013 Vitaliy Valtman */ #ifndef __GENERATE_H__ #define __GENERATE_H__ struct tl_combinator; struct tl_type { // struct tl_type_methods *methods; char *id; char *print_id; unsigned name; int arity; int flags; int constructors_num; struct tl_combinator **constructors; long long params_types; int extra; }; #define NODE_TYPE_TYPE 1 #define NODE_TYPE_NAT_CONST 2 #define NODE_TYPE_VAR_TYPE 3 #define NODE_TYPE_VAR_NUM 4 #define NODE_TYPE_ARRAY 5 #define MAX_COMBINATOR_VARS 64 #define NAME_VAR_NUM 0x70659eff #define NAME_VAR_TYPE 0x2cecf817 #define NAME_INT 0xa8509bda #define NAME_LONG 0x22076cba #define NAME_DOUBLE 0x2210c154 #define NAME_STRING 0xb5286e24 #define NAME_VECTOR 0x1cb5c415 #define NAME_MAYBE_TRUE 0x3f9c8ef8 #define NAME_MAYBE_FALSE 0x27930a7b #define NAME_BOOL_FALSE 0xbc799737 #define NAME_BOOL_TRUE 0x997275b5 #define NAME_BYTES 0x0ee1379f #define FLAG_OPT_VAR (1 << 17) #define FLAG_EXCL (1 << 18) #define FLAG_OPT_FIELD (1 << 20) #define FLAG_NOVAR (1 << 21) #define FLAG_BARE 1 #define FLAGS_MASK ((1 << 16) - 1) #define FLAG_DEFAULT_CONSTRUCTOR (1 << 25) #define FLAG_NOCONS (1 << 1) extern struct tl_tree_methods tl_nat_const_methods; extern struct tl_tree_methods tl_nat_const_full_methods; extern struct tl_tree_methods tl_pnat_const_full_methods; extern struct tl_tree_methods tl_array_methods; extern struct tl_tree_methods tl_type_methods; extern struct tl_tree_methods tl_parray_methods; extern struct tl_tree_methods tl_ptype_methods; extern struct tl_tree_methods tl_var_num_methods; extern struct tl_tree_methods tl_var_type_methods; extern struct tl_tree_methods tl_pvar_num_methods; extern struct tl_tree_methods tl_pvar_type_methods; #define TL_IS_NAT_VAR(x) (((long)x) & 1) #define TL_TREE_METHODS(x) (TL_IS_NAT_VAR (x) ? &tl_nat_const_methods : ((struct tl_tree *)(x))->methods) #define DEC_REF(x) (TL_TREE_METHODS(x)->dec_ref ((void *)x)) #define INC_REF(x) (TL_TREE_METHODS(x)->inc_ref ((void *)x)) #define TYPE(x) (TL_TREE_METHODS(x)->type ((void *)x)) typedef unsigned long long tl_tree_hash_t; struct tl_tree; struct tl_tree_methods { int (*type)(struct tl_tree *T); int (*eq)(struct tl_tree *T, struct tl_tree *U); void (*inc_ref)(struct tl_tree *T); void (*dec_ref)(struct tl_tree *T); }; struct tl_tree { int ref_cnt; int flags; //tl_tree_hash_t hash; struct tl_tree_methods *methods; }; /* struct tl_tree_nat_const { struct tl_tree self; int value; };*/ struct tl_tree_type { struct tl_tree self; struct tl_type *type; int children_num; struct tl_tree **children; }; struct tl_tree_array { struct tl_tree self; struct tl_tree *multiplicity; int args_num; struct arg **args; }; struct tl_tree_var_type { struct tl_tree self; int var_num; }; struct tl_tree_var_num { struct tl_tree self; int var_num; int dif; }; struct tl_tree_nat_const { struct tl_tree self; long long value; }; struct arg { char *id; int var_num; int flags; int exist_var_num; int exist_var_bit; struct tl_tree *type; }; struct tl_combinator { //struct tl_combinator_methods *methods; char *id; char *print_id; unsigned name; int is_fun; int var_num; int args_num; struct arg **args; struct tl_tree *result; void **IP; void **fIP; int IP_len; int fIP_len; }; #endif telegram-purple/tgl/m4_ax_check_openssl.m4000066400000000000000000000101321357227200100211170ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_openssl.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) # # DESCRIPTION # # Look for OpenSSL in a number of default spots, or in a user-selected # spot (via --with-openssl). Sets # # OPENSSL_INCLUDES to the include directives required # OPENSSL_LIBS to the -l directives required # OPENSSL_LDFLAGS to the -L or -R flags required # # and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately # # This macro sets OPENSSL_INCLUDES such that source files should use the # openssl/ directory in include directives: # # #include # # LICENSE # # Copyright (c) 2009,2010 Zmanda Inc. # Copyright (c) 2009,2010 Dustin J. Mitchell # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 8 AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) AC_DEFUN([AX_CHECK_OPENSSL], [ found=false AC_ARG_WITH([openssl], [AS_HELP_STRING([--with-openssl=DIR], [root of the OpenSSL directory])], [ case "$withval" in "" | y | ye | yes | n | no) AC_MSG_ERROR([Invalid --with-openssl value]) ;; *) ssldirs="$withval" ;; esac ], [ # if pkg-config is installed and openssl has installed a .pc file, # then use that information and don't search ssldirs AC_PATH_PROG([PKG_CONFIG], [pkg-config]) if test x"$PKG_CONFIG" != x""; then OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` if test $? = 0; then OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` found=true fi fi # no such luck; use some default ssldirs if ! $found; then ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" fi ] ) # note that we #include , so the OpenSSL headers have to be in # an 'openssl' subdirectory if ! $found; then OPENSSL_INCLUDES= for ssldir in $ssldirs; do AC_MSG_CHECKING([for openssl/ssl.h in $ssldir]) if test -f "$ssldir/include/openssl/ssl.h"; then OPENSSL_INCLUDES="-I$ssldir/include" OPENSSL_LDFLAGS="-L$ssldir/lib" OPENSSL_LIBS="-lssl -lcrypto" found=true AC_MSG_RESULT([yes]) break else AC_MSG_RESULT([no]) fi done # if the file wasn't found, well, go ahead and try the link anyway -- maybe # it will just work! fi # try the preprocessor and linker with our new flags, # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS AC_MSG_CHECKING([whether compiling and linking against OpenSSL works]) echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD save_LIBS="$LIBS" save_LDFLAGS="$LDFLAGS" save_CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" LIBS="$OPENSSL_LIBS $LIBS" CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" AC_LINK_IFELSE( [AC_LANG_PROGRAM([#include ], [SSL_new(NULL)])], [ AC_MSG_RESULT([yes]) $1 ], [ AC_MSG_RESULT([no]) $2 ]) CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" AC_SUBST([OPENSSL_INCLUDES]) AC_SUBST([OPENSSL_LIBS]) AC_SUBST([OPENSSL_LDFLAGS]) ]) telegram-purple/tgl/m4_ax_check_zlib.m4000066400000000000000000000124501357227200100204010ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_zlib.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_ZLIB([action-if-found], [action-if-not-found]) # # DESCRIPTION # # This macro searches for an installed zlib library. If nothing was # specified when calling configure, it searches first in /usr/local and # then in /usr, /opt/local and /sw. If the --with-zlib=DIR is specified, # it will try to find it in DIR/include/zlib.h and DIR/lib/libz.a. If # --without-zlib is specified, the library is not searched at all. # # If either the header file (zlib.h) or the library (libz) is not found, # shell commands 'action-if-not-found' is run. If 'action-if-not-found' is # not specified, the configuration exits on error, asking for a valid zlib # installation directory or --without-zlib. # # If both header file and library are found, shell commands # 'action-if-found' is run. If 'action-if-found' is not specified, the # default action appends '-I${ZLIB_HOME}/include' to CPFLAGS, appends # '-L$ZLIB_HOME}/lib' to LDFLAGS, prepends '-lz' to LIBS, and calls # AC_DEFINE(HAVE_LIBZ). You should use autoheader to include a definition # for this symbol in a config.h file. Sample usage in a C/C++ source is as # follows: # # #ifdef HAVE_LIBZ # #include # #endif /* HAVE_LIBZ */ # # LICENSE # # Copyright (c) 2008 Loic Dachary # Copyright (c) 2010 Bastien Chevreux # # 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, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 14 AU_ALIAS([CHECK_ZLIB], [AX_CHECK_ZLIB]) AC_DEFUN([AX_CHECK_ZLIB], # # Handle user hints # [AC_MSG_CHECKING(if zlib is wanted) zlib_places="/usr/local /usr /opt/local /sw" AC_ARG_WITH([zlib], [ --with-zlib=DIR root directory path of zlib installation @<:@defaults to /usr/local or /usr if not found in /usr/local@:>@ --without-zlib to disable zlib usage completely], [if test "$withval" != no ; then AC_MSG_RESULT(yes) if test -d "$withval" then zlib_places="$withval $zlib_places" else AC_MSG_WARN([Sorry, $withval does not exist, checking usual places]) fi else zlib_places= AC_MSG_RESULT(no) fi], [AC_MSG_RESULT(yes)]) # # Locate zlib, if wanted # if test -n "${zlib_places}" then # check the user supplied or any other more or less 'standard' place: # Most UNIX systems : /usr/local and /usr # MacPorts / Fink on OSX : /opt/local respectively /sw for ZLIB_HOME in ${zlib_places} ; do if test -f "${ZLIB_HOME}/include/zlib.h"; then break; fi ZLIB_HOME="" done ZLIB_OLD_LDFLAGS=$LDFLAGS ZLIB_OLD_CPPFLAGS=$CPPFLAGS if test -n "${ZLIB_HOME}"; then LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" fi AC_LANG_SAVE AC_LANG_C AC_CHECK_LIB([z], [inflateEnd], [zlib_cv_libz=yes], [zlib_cv_libz=no]) AC_CHECK_HEADER([zlib.h], [zlib_cv_zlib_h=yes], [zlib_cv_zlib_h=no]) AC_LANG_RESTORE if test "$zlib_cv_libz" = "yes" && test "$zlib_cv_zlib_h" = "yes" then # # If both library and header were found, action-if-found # m4_ifblank([$1],[ CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" LIBS="-lz $LIBS" AC_DEFINE([HAVE_LIBZ], [1], [Define to 1 if you have `z' library (-lz)]) ],[ # Restore variables LDFLAGS="$ZLIB_OLD_LDFLAGS" CPPFLAGS="$ZLIB_OLD_CPPFLAGS" $1 ]) else # # If either header or library was not found, action-if-not-found # m4_default([$2],[ AC_MSG_ERROR([either specify a valid zlib installation with --with-zlib=DIR or disable zlib usage with --without-zlib]) ]) fi fi ]) telegram-purple/tgl/mime-types.c000066400000000000000000011770621357227200100172230ustar00rootroot00000000000000unsigned char mime_types[] = { 0x23, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x6d, 0x61, 0x70, 0x73, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x28, 0x73, 0x29, 0x2e, 0x0a, 0x23, 0x20, 0x41, 0x6c, 0x74, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x61, 0x73, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x62, 0x65, 0x6c, 0x6f, 0x77, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x62, 0x6f, 0x74, 0x68, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x28, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x29, 0x20, 0x75, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x0a, 0x23, 0x20, 0x41, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x67, 0x75, 0x69, 0x64, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x77, 0x61, 0x72, 0x64, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x20, 0x69, 0x74, 0x20, 0x65, 0x61, 0x73, 0x69, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x0a, 0x23, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x20, 0x22, 0x6e, 0x65, 0x77, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x20, 0x20, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x0a, 0x23, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x20, 0x73, 0x6f, 0x20, 0x63, 0x68, 0x6f, 0x6f, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6d, 0x20, 0x63, 0x61, 0x72, 0x65, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x2e, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x52, 0x46, 0x43, 0x20, 0x34, 0x32, 0x38, 0x38, 0x2e, 0x0a, 0x23, 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x20, 0x69, 0x73, 0x20, 0x61, 0x74, 0x20, 0x3c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x61, 0x6e, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x78, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x2e, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x28, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x64, 0x29, 0x09, 0x09, 0x09, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x23, 0x20, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x09, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x31, 0x64, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x64, 0x2d, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x33, 0x67, 0x70, 0x70, 0x2d, 0x69, 0x6d, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x65, 0x77, 0x2d, 0x69, 0x6e, 0x73, 0x65, 0x74, 0x09, 0x09, 0x09, 0x65, 0x7a, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x78, 0x77, 0x61, 0x72, 0x65, 0x09, 0x09, 0x09, 0x09, 0x61, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x74, 0x6f, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x61, 0x74, 0x6f, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x74, 0x6f, 0x6d, 0x63, 0x61, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x61, 0x74, 0x6f, 0x6d, 0x63, 0x61, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x6d, 0x61, 0x69, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x74, 0x6f, 0x6d, 0x73, 0x76, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x61, 0x74, 0x6f, 0x6d, 0x73, 0x76, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x2d, 0x73, 0x6d, 0x74, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x65, 0x65, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x61, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x61, 0x6c, 0x73, 0x2d, 0x31, 0x38, 0x34, 0x30, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x63, 0x6d, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x63, 0x78, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x63, 0x63, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x64, 0x6d, 0x69, 0x2d, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x09, 0x09, 0x09, 0x63, 0x64, 0x6d, 0x69, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x64, 0x6d, 0x69, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x09, 0x09, 0x09, 0x63, 0x64, 0x6d, 0x69, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x64, 0x6d, 0x69, 0x2d, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x63, 0x64, 0x6d, 0x69, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x64, 0x6d, 0x69, 0x2d, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x09, 0x09, 0x09, 0x09, 0x63, 0x64, 0x6d, 0x69, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x64, 0x6d, 0x69, 0x2d, 0x71, 0x75, 0x65, 0x75, 0x65, 0x09, 0x09, 0x09, 0x09, 0x63, 0x64, 0x6d, 0x69, 0x71, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x65, 0x61, 0x2d, 0x32, 0x30, 0x31, 0x38, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x65, 0x6c, 0x6c, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x66, 0x77, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x6e, 0x72, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x70, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x73, 0x74, 0x61, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x73, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x75, 0x2d, 0x73, 0x65, 0x65, 0x6d, 0x65, 0x09, 0x09, 0x09, 0x09, 0x63, 0x75, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x79, 0x62, 0x65, 0x72, 0x63, 0x61, 0x73, 0x68, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x61, 0x76, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x64, 0x61, 0x76, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x63, 0x61, 0x2d, 0x72, 0x66, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x65, 0x63, 0x2d, 0x64, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x69, 0x63, 0x6f, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x6e, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x6f, 0x63, 0x62, 0x6f, 0x6f, 0x6b, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x64, 0x62, 0x6b, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x73, 0x6b, 0x70, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x73, 0x73, 0x63, 0x2b, 0x64, 0x65, 0x72, 0x09, 0x09, 0x09, 0x09, 0x64, 0x73, 0x73, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x73, 0x73, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x64, 0x73, 0x73, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x76, 0x63, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x63, 0x6d, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x09, 0x09, 0x09, 0x09, 0x65, 0x63, 0x6d, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x64, 0x69, 0x2d, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x64, 0x69, 0x2d, 0x78, 0x31, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x64, 0x69, 0x66, 0x61, 0x63, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x6d, 0x6d, 0x61, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6d, 0x6d, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x70, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x70, 0x75, 0x62, 0x2b, 0x7a, 0x69, 0x70, 0x09, 0x09, 0x09, 0x09, 0x65, 0x70, 0x75, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x73, 0x68, 0x6f, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x78, 0x69, 0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x78, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x61, 0x73, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x65, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x61, 0x73, 0x74, 0x73, 0x6f, 0x61, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x62, 0x32, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x62, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x69, 0x74, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x74, 0x64, 0x70, 0x66, 0x72, 0x09, 0x09, 0x09, 0x09, 0x70, 0x66, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x67, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x70, 0x78, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x67, 0x70, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x78, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x67, 0x78, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x68, 0x32, 0x32, 0x34, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x68, 0x65, 0x6c, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x73, 0x74, 0x75, 0x64, 0x69, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x73, 0x74, 0x6b, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x62, 0x65, 0x2d, 0x6b, 0x65, 0x79, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x62, 0x65, 0x2d, 0x70, 0x6b, 0x67, 0x2d, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x62, 0x65, 0x2d, 0x70, 0x70, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x67, 0x65, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x6d, 0x2d, 0x69, 0x73, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x6e, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x63, 0x6d, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x6f, 0x62, 0x6a, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x76, 0x6e, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x6e, 0x6b, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x69, 0x6e, 0x6b, 0x20, 0x69, 0x6e, 0x6b, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x6f, 0x74, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x70, 0x66, 0x69, 0x78, 0x09, 0x09, 0x09, 0x09, 0x69, 0x70, 0x66, 0x69, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x70, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x73, 0x75, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x2d, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x09, 0x09, 0x09, 0x6a, 0x61, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x2d, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x09, 0x09, 0x73, 0x65, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x2d, 0x76, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x6d, 0x6c, 0x2b, 0x6a, 0x73, 0x6f, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x73, 0x6f, 0x6e, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6b, 0x70, 0x6d, 0x6c, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6b, 0x70, 0x6d, 0x6c, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6c, 0x6f, 0x73, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x73, 0x74, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x63, 0x2d, 0x62, 0x69, 0x6e, 0x68, 0x65, 0x78, 0x34, 0x30, 0x09, 0x09, 0x09, 0x68, 0x71, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x63, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x70, 0x72, 0x6f, 0x09, 0x09, 0x09, 0x63, 0x70, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x63, 0x77, 0x72, 0x69, 0x74, 0x65, 0x69, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x64, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x61, 0x64, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x72, 0x63, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x72, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x72, 0x63, 0x78, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x72, 0x63, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x61, 0x20, 0x6e, 0x62, 0x20, 0x6d, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x6d, 0x6c, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x6d, 0x6c, 0x2d, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x61, 0x74, 0x68, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x2d, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x75, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x6d, 0x73, 0x6b, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x6d, 0x73, 0x6b, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x72, 0x65, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6d, 0x73, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x62, 0x6f, 0x78, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x62, 0x6f, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x6d, 0x73, 0x63, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x69, 0x6e, 0x6b, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x69, 0x6e, 0x6b, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x69, 0x6e, 0x6b, 0x34, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x6d, 0x65, 0x74, 0x61, 0x34, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x65, 0x74, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x65, 0x74, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x69, 0x6b, 0x65, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x64, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x6f, 0x64, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x73, 0x73, 0x2d, 0x6b, 0x65, 0x79, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x73, 0x73, 0x2d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x70, 0x32, 0x31, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x32, 0x31, 0x20, 0x6d, 0x70, 0x32, 0x31, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x70, 0x34, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x70, 0x34, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x70, 0x65, 0x67, 0x34, 0x2d, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x70, 0x65, 0x67, 0x34, 0x2d, 0x69, 0x6f, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x70, 0x65, 0x67, 0x34, 0x2d, 0x69, 0x6f, 0x64, 0x2d, 0x78, 0x6d, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x73, 0x63, 0x2d, 0x69, 0x76, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x73, 0x63, 0x2d, 0x6d, 0x69, 0x78, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x09, 0x09, 0x09, 0x09, 0x64, 0x6f, 0x63, 0x20, 0x64, 0x6f, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6d, 0x78, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x78, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6e, 0x61, 0x73, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x2d, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x6e, 0x66, 0x6f, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6e, 0x73, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x09, 0x62, 0x69, 0x6e, 0x20, 0x64, 0x6d, 0x73, 0x20, 0x6c, 0x72, 0x66, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x73, 0x6f, 0x20, 0x64, 0x69, 0x73, 0x74, 0x20, 0x64, 0x69, 0x73, 0x74, 0x7a, 0x20, 0x70, 0x6b, 0x67, 0x20, 0x62, 0x70, 0x6b, 0x20, 0x64, 0x75, 0x6d, 0x70, 0x20, 0x65, 0x6c, 0x63, 0x20, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x64, 0x61, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x64, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x65, 0x62, 0x70, 0x73, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x6f, 0x70, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x67, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x67, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x6d, 0x64, 0x6f, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x6d, 0x64, 0x6f, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x6e, 0x65, 0x6e, 0x6f, 0x74, 0x65, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x6e, 0x65, 0x74, 0x6f, 0x63, 0x20, 0x6f, 0x6e, 0x65, 0x74, 0x6f, 0x63, 0x32, 0x20, 0x6f, 0x6e, 0x65, 0x74, 0x6d, 0x70, 0x20, 0x6f, 0x6e, 0x65, 0x70, 0x6b, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x78, 0x70, 0x73, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x78, 0x70, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2d, 0x6f, 0x70, 0x73, 0x2d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x78, 0x65, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x64, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x70, 0x64, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x67, 0x70, 0x2d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x09, 0x09, 0x09, 0x70, 0x67, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x67, 0x70, 0x2d, 0x6b, 0x65, 0x79, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x67, 0x70, 0x2d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x09, 0x09, 0x09, 0x61, 0x73, 0x63, 0x20, 0x73, 0x69, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x69, 0x63, 0x73, 0x2d, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x09, 0x09, 0x09, 0x09, 0x70, 0x72, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x69, 0x64, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x69, 0x64, 0x66, 0x2d, 0x64, 0x69, 0x66, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x63, 0x73, 0x31, 0x30, 0x09, 0x09, 0x09, 0x09, 0x70, 0x31, 0x30, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x63, 0x73, 0x37, 0x2d, 0x6d, 0x69, 0x6d, 0x65, 0x09, 0x09, 0x09, 0x09, 0x70, 0x37, 0x6d, 0x20, 0x70, 0x37, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x63, 0x73, 0x37, 0x2d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x09, 0x09, 0x09, 0x70, 0x37, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x63, 0x73, 0x38, 0x09, 0x09, 0x09, 0x09, 0x70, 0x38, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x69, 0x78, 0x2d, 0x61, 0x74, 0x74, 0x72, 0x2d, 0x63, 0x65, 0x72, 0x74, 0x09, 0x09, 0x09, 0x61, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x69, 0x78, 0x2d, 0x63, 0x65, 0x72, 0x74, 0x09, 0x09, 0x09, 0x09, 0x63, 0x65, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x69, 0x78, 0x2d, 0x63, 0x72, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x63, 0x72, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x69, 0x78, 0x2d, 0x70, 0x6b, 0x69, 0x70, 0x61, 0x74, 0x68, 0x09, 0x09, 0x09, 0x70, 0x6b, 0x69, 0x70, 0x61, 0x74, 0x68, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6b, 0x69, 0x78, 0x63, 0x6d, 0x70, 0x09, 0x09, 0x09, 0x09, 0x70, 0x6b, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6c, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x70, 0x6c, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6f, 0x63, 0x2d, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x09, 0x09, 0x09, 0x09, 0x61, 0x69, 0x20, 0x65, 0x70, 0x73, 0x20, 0x70, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x61, 0x6c, 0x76, 0x65, 0x73, 0x74, 0x72, 0x61, 0x6e, 0x64, 0x2e, 0x74, 0x69, 0x74, 0x72, 0x61, 0x78, 0x2d, 0x73, 0x68, 0x65, 0x65, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x63, 0x77, 0x77, 0x09, 0x09, 0x09, 0x09, 0x63, 0x77, 0x77, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x6e, 0x70, 0x72, 0x65, 0x6e, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x70, 0x6c, 0x75, 0x63, 0x6b, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x72, 0x64, 0x66, 0x2d, 0x78, 0x6d, 0x6c, 0x2d, 0x63, 0x72, 0x79, 0x70, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x78, 0x73, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x73, 0x6b, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x70, 0x73, 0x6b, 0x63, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x71, 0x73, 0x69, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x64, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x72, 0x64, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x6e, 0x66, 0x6f, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x72, 0x69, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x78, 0x2d, 0x6e, 0x67, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x2d, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x09, 0x09, 0x72, 0x6e, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2d, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x72, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x2d, 0x64, 0x69, 0x66, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x72, 0x6c, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x69, 0x73, 0x63, 0x6f, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x6c, 0x6d, 0x69, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x6c, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x72, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x70, 0x6b, 0x69, 0x2d, 0x67, 0x68, 0x6f, 0x73, 0x74, 0x62, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x09, 0x09, 0x09, 0x67, 0x62, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x70, 0x6b, 0x69, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x09, 0x09, 0x09, 0x6d, 0x66, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x70, 0x6b, 0x69, 0x2d, 0x72, 0x6f, 0x61, 0x09, 0x09, 0x09, 0x09, 0x72, 0x6f, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x70, 0x6b, 0x69, 0x2d, 0x75, 0x70, 0x64, 0x6f, 0x77, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x73, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x72, 0x73, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x73, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x72, 0x73, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x74, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x72, 0x74, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x74, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x61, 0x6d, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x61, 0x6d, 0x6c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x62, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x73, 0x62, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x63, 0x76, 0x70, 0x2d, 0x63, 0x76, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x09, 0x09, 0x09, 0x73, 0x63, 0x71, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x63, 0x76, 0x70, 0x2d, 0x63, 0x76, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x09, 0x09, 0x09, 0x73, 0x63, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x63, 0x76, 0x70, 0x2d, 0x76, 0x70, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x09, 0x09, 0x09, 0x73, 0x70, 0x71, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x63, 0x76, 0x70, 0x2d, 0x76, 0x70, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x09, 0x09, 0x09, 0x73, 0x70, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x64, 0x70, 0x09, 0x09, 0x09, 0x09, 0x09, 0x73, 0x64, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x74, 0x2d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x74, 0x2d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x09, 0x09, 0x73, 0x65, 0x74, 0x70, 0x61, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x74, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x74, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x09, 0x09, 0x73, 0x65, 0x74, 0x72, 0x65, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x68, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x73, 0x68, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x69, 0x65, 0x76, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x6c, 0x61, 0x74, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x6d, 0x69, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x6d, 0x69, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x73, 0x6d, 0x69, 0x20, 0x73, 0x6d, 0x69, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x6f, 0x61, 0x70, 0x2b, 0x66, 0x61, 0x73, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x65, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x6f, 0x61, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x70, 0x61, 0x72, 0x71, 0x6c, 0x2d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x09, 0x09, 0x09, 0x72, 0x71, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x70, 0x61, 0x72, 0x71, 0x6c, 0x2d, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x73, 0x72, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x70, 0x69, 0x72, 0x69, 0x74, 0x73, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x72, 0x67, 0x73, 0x09, 0x09, 0x09, 0x09, 0x67, 0x72, 0x61, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x72, 0x67, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x67, 0x72, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x72, 0x75, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x73, 0x72, 0x75, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x73, 0x64, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x73, 0x73, 0x64, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x73, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x73, 0x73, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x61, 0x70, 0x65, 0x78, 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x61, 0x70, 0x65, 0x78, 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x69, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x74, 0x65, 0x69, 0x20, 0x74, 0x65, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x75, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x68, 0x72, 0x61, 0x75, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x74, 0x66, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2d, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x65, 0x64, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x09, 0x09, 0x09, 0x74, 0x73, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x76, 0x65, 0x2d, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x75, 0x6c, 0x70, 0x66, 0x65, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x63, 0x61, 0x72, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x65, 0x6d, 0x6d, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x69, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x67, 0x70, 0x70, 0x2e, 0x62, 0x73, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x67, 0x70, 0x70, 0x2e, 0x70, 0x69, 0x63, 0x2d, 0x62, 0x77, 0x2d, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x09, 0x09, 0x70, 0x6c, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x67, 0x70, 0x70, 0x2e, 0x70, 0x69, 0x63, 0x2d, 0x62, 0x77, 0x2d, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x09, 0x09, 0x70, 0x73, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x67, 0x70, 0x70, 0x2e, 0x70, 0x69, 0x63, 0x2d, 0x62, 0x77, 0x2d, 0x76, 0x61, 0x72, 0x09, 0x09, 0x09, 0x70, 0x76, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x67, 0x70, 0x70, 0x2e, 0x73, 0x6d, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x67, 0x70, 0x70, 0x32, 0x2e, 0x62, 0x63, 0x6d, 0x63, 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x67, 0x70, 0x70, 0x32, 0x2e, 0x73, 0x6d, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x67, 0x70, 0x70, 0x32, 0x2e, 0x74, 0x63, 0x61, 0x70, 0x09, 0x09, 0x09, 0x74, 0x63, 0x61, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x6d, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x2d, 0x69, 0x74, 0x2d, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x09, 0x09, 0x70, 0x77, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x63, 0x63, 0x70, 0x61, 0x63, 0x2e, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x79, 0x2e, 0x61, 0x73, 0x6f, 0x09, 0x09, 0x61, 0x73, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x63, 0x63, 0x70, 0x61, 0x63, 0x2e, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x79, 0x2e, 0x69, 0x6d, 0x70, 0x09, 0x09, 0x69, 0x6d, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x63, 0x75, 0x63, 0x6f, 0x62, 0x6f, 0x6c, 0x09, 0x09, 0x09, 0x61, 0x63, 0x75, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x63, 0x75, 0x63, 0x6f, 0x72, 0x70, 0x09, 0x09, 0x09, 0x09, 0x61, 0x74, 0x63, 0x20, 0x61, 0x63, 0x75, 0x74, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x61, 0x69, 0x72, 0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2b, 0x7a, 0x69, 0x70, 0x09, 0x61, 0x69, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x2e, 0x66, 0x63, 0x64, 0x74, 0x09, 0x09, 0x66, 0x63, 0x64, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x66, 0x78, 0x70, 0x09, 0x09, 0x09, 0x66, 0x78, 0x70, 0x20, 0x66, 0x78, 0x70, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x78, 0x64, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x78, 0x64, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x78, 0x66, 0x64, 0x66, 0x09, 0x09, 0x09, 0x78, 0x66, 0x64, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x65, 0x74, 0x68, 0x65, 0x72, 0x2e, 0x69, 0x6d, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x68, 0x2d, 0x62, 0x61, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x68, 0x65, 0x61, 0x64, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x09, 0x09, 0x09, 0x61, 0x68, 0x65, 0x61, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x69, 0x72, 0x7a, 0x69, 0x70, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x61, 0x7a, 0x66, 0x09, 0x09, 0x61, 0x7a, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x69, 0x72, 0x7a, 0x69, 0x70, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x61, 0x7a, 0x73, 0x09, 0x09, 0x61, 0x7a, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x2e, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x09, 0x09, 0x09, 0x61, 0x7a, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x73, 0x2e, 0x61, 0x63, 0x63, 0x09, 0x09, 0x61, 0x63, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x6d, 0x69, 0x67, 0x61, 0x2e, 0x61, 0x6d, 0x69, 0x09, 0x09, 0x09, 0x61, 0x6d, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x6d, 0x75, 0x6e, 0x64, 0x73, 0x65, 0x6e, 0x2e, 0x6d, 0x61, 0x7a, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x09, 0x09, 0x61, 0x70, 0x6b, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x6e, 0x73, 0x65, 0x72, 0x2d, 0x77, 0x65, 0x62, 0x2d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2d, 0x69, 0x73, 0x73, 0x75, 0x65, 0x2d, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x09, 0x63, 0x69, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x6e, 0x73, 0x65, 0x72, 0x2d, 0x77, 0x65, 0x62, 0x2d, 0x66, 0x75, 0x6e, 0x64, 0x73, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x09, 0x66, 0x74, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x6e, 0x74, 0x69, 0x78, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x09, 0x09, 0x61, 0x74, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x6d, 0x70, 0x6b, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x6d, 0x70, 0x65, 0x67, 0x75, 0x72, 0x6c, 0x09, 0x09, 0x09, 0x6d, 0x33, 0x75, 0x38, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x72, 0x61, 0x73, 0x74, 0x72, 0x61, 0x2e, 0x73, 0x77, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x72, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x73, 0x77, 0x69, 0x09, 0x09, 0x73, 0x77, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x73, 0x74, 0x72, 0x61, 0x65, 0x61, 0x2d, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x69, 0x6f, 0x74, 0x61, 0x09, 0x09, 0x69, 0x6f, 0x74, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x09, 0x09, 0x09, 0x61, 0x65, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x76, 0x69, 0x73, 0x74, 0x61, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x69, 0x63, 0x65, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x73, 0x73, 0x09, 0x09, 0x6d, 0x70, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x2e, 0x65, 0x70, 0x2e, 0x6f, 0x6f, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x62, 0x6d, 0x69, 0x09, 0x09, 0x09, 0x09, 0x62, 0x6d, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x62, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x09, 0x09, 0x09, 0x72, 0x65, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x61, 0x62, 0x2d, 0x6a, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x2d, 0x63, 0x70, 0x64, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x2d, 0x6c, 0x69, 0x70, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6f, 0x2e, 0x74, 0x68, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x63, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x63, 0x6f, 0x6e, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x68, 0x65, 0x6d, 0x64, 0x72, 0x61, 0x77, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x63, 0x64, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x68, 0x69, 0x70, 0x6e, 0x75, 0x74, 0x73, 0x2e, 0x6b, 0x61, 0x72, 0x61, 0x6f, 0x6b, 0x65, 0x2d, 0x6d, 0x6d, 0x64, 0x09, 0x09, 0x6d, 0x6d, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x6c, 0x6c, 0x61, 0x09, 0x09, 0x09, 0x63, 0x64, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x69, 0x72, 0x70, 0x61, 0x63, 0x6b, 0x2e, 0x69, 0x73, 0x64, 0x6e, 0x2d, 0x65, 0x78, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6c, 0x61, 0x79, 0x6d, 0x6f, 0x72, 0x65, 0x09, 0x09, 0x09, 0x63, 0x6c, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6c, 0x6f, 0x61, 0x6e, 0x74, 0x6f, 0x2e, 0x72, 0x70, 0x39, 0x09, 0x09, 0x09, 0x72, 0x70, 0x39, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6c, 0x6f, 0x6e, 0x6b, 0x2e, 0x63, 0x34, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x09, 0x09, 0x09, 0x63, 0x34, 0x67, 0x20, 0x63, 0x34, 0x64, 0x20, 0x63, 0x34, 0x66, 0x20, 0x63, 0x34, 0x70, 0x20, 0x63, 0x34, 0x75, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6c, 0x75, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x61, 0x72, 0x74, 0x6f, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x09, 0x09, 0x63, 0x31, 0x31, 0x61, 0x6d, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6c, 0x75, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x61, 0x72, 0x74, 0x6f, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x70, 0x6b, 0x67, 0x09, 0x63, 0x31, 0x31, 0x61, 0x6d, 0x7a, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2b, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x65, 0x2d, 0x62, 0x61, 0x74, 0x74, 0x65, 0x6c, 0x6c, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x09, 0x09, 0x09, 0x63, 0x73, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x63, 0x6d, 0x73, 0x67, 0x09, 0x09, 0x09, 0x63, 0x64, 0x62, 0x63, 0x6d, 0x73, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x09, 0x09, 0x09, 0x63, 0x6d, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x72, 0x69, 0x63, 0x6b, 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x09, 0x09, 0x09, 0x63, 0x6c, 0x6b, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x72, 0x69, 0x63, 0x6b, 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x09, 0x09, 0x63, 0x6c, 0x6b, 0x6b, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x72, 0x69, 0x63, 0x6b, 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x61, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x09, 0x09, 0x63, 0x6c, 0x6b, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x72, 0x69, 0x63, 0x6b, 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x09, 0x63, 0x6c, 0x6b, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x72, 0x69, 0x63, 0x6b, 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x62, 0x61, 0x6e, 0x6b, 0x09, 0x09, 0x63, 0x6c, 0x6b, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x77, 0x62, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x77, 0x62, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x74, 0x63, 0x2d, 0x70, 0x6f, 0x73, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x70, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x74, 0x63, 0x74, 0x2e, 0x77, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x70, 0x73, 0x2d, 0x70, 0x64, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x70, 0x73, 0x2d, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x70, 0x73, 0x2d, 0x70, 0x70, 0x64, 0x09, 0x09, 0x09, 0x70, 0x70, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x70, 0x73, 0x2d, 0x72, 0x61, 0x73, 0x74, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x70, 0x73, 0x2d, 0x72, 0x61, 0x77, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x72, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x72, 0x6c, 0x2e, 0x63, 0x61, 0x72, 0x09, 0x09, 0x09, 0x63, 0x61, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x72, 0x6c, 0x2e, 0x70, 0x63, 0x75, 0x72, 0x6c, 0x09, 0x09, 0x09, 0x70, 0x63, 0x75, 0x72, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x79, 0x62, 0x61, 0x6e, 0x6b, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x61, 0x72, 0x74, 0x09, 0x09, 0x09, 0x09, 0x64, 0x61, 0x72, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x72, 0x64, 0x7a, 0x09, 0x09, 0x09, 0x72, 0x64, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x09, 0x09, 0x09, 0x75, 0x76, 0x66, 0x20, 0x75, 0x76, 0x76, 0x66, 0x20, 0x75, 0x76, 0x64, 0x20, 0x75, 0x76, 0x76, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x74, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x75, 0x76, 0x74, 0x20, 0x75, 0x76, 0x76, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x75, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x09, 0x09, 0x75, 0x76, 0x78, 0x20, 0x75, 0x76, 0x76, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x7a, 0x69, 0x70, 0x09, 0x09, 0x09, 0x75, 0x76, 0x7a, 0x20, 0x75, 0x76, 0x76, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x6e, 0x6f, 0x76, 0x6f, 0x2e, 0x66, 0x63, 0x73, 0x65, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2d, 0x6c, 0x69, 0x6e, 0x6b, 0x09, 0x09, 0x66, 0x65, 0x5f, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x69, 0x72, 0x2d, 0x62, 0x69, 0x2e, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2d, 0x64, 0x6c, 0x2d, 0x6e, 0x6f, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6e, 0x61, 0x09, 0x09, 0x09, 0x09, 0x64, 0x6e, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x6d, 0x6c, 0x70, 0x09, 0x09, 0x09, 0x6d, 0x6c, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x2e, 0x31, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x2e, 0x32, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x70, 0x67, 0x72, 0x61, 0x70, 0x68, 0x09, 0x09, 0x09, 0x09, 0x64, 0x70, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x72, 0x65, 0x61, 0x6d, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x09, 0x09, 0x09, 0x64, 0x66, 0x61, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x73, 0x2d, 0x6b, 0x65, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x09, 0x09, 0x09, 0x6b, 0x70, 0x78, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x61, 0x69, 0x74, 0x09, 0x09, 0x09, 0x09, 0x61, 0x69, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x64, 0x76, 0x62, 0x6a, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x65, 0x73, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x69, 0x70, 0x64, 0x63, 0x64, 0x66, 0x74, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x69, 0x70, 0x64, 0x63, 0x65, 0x73, 0x67, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x69, 0x70, 0x64, 0x63, 0x65, 0x73, 0x67, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x69, 0x70, 0x64, 0x63, 0x65, 0x73, 0x67, 0x70, 0x64, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x69, 0x70, 0x64, 0x63, 0x72, 0x6f, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x2e, 0x61, 0x6c, 0x66, 0x65, 0x63, 0x2d, 0x62, 0x61, 0x73, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x2e, 0x61, 0x6c, 0x66, 0x65, 0x63, 0x2d, 0x65, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x2d, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x2d, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x2d, 0x69, 0x61, 0x2d, 0x6d, 0x73, 0x67, 0x6c, 0x69, 0x73, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x2d, 0x69, 0x61, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x2d, 0x69, 0x61, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x2d, 0x69, 0x6e, 0x69, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x70, 0x66, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x09, 0x09, 0x09, 0x73, 0x76, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x78, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x67, 0x65, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x67, 0x65, 0x6f, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x61, 0x73, 0x79, 0x6b, 0x61, 0x72, 0x61, 0x6f, 0x6b, 0x65, 0x2e, 0x63, 0x64, 0x67, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x63, 0x64, 0x69, 0x73, 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x2e, 0x63, 0x68, 0x61, 0x72, 0x74, 0x09, 0x09, 0x09, 0x6d, 0x61, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x6d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x6e, 0x6c, 0x69, 0x76, 0x65, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x6e, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x70, 0x73, 0x6f, 0x6e, 0x2e, 0x65, 0x73, 0x66, 0x09, 0x09, 0x09, 0x65, 0x73, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x70, 0x73, 0x6f, 0x6e, 0x2e, 0x6d, 0x73, 0x66, 0x09, 0x09, 0x09, 0x6d, 0x73, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x70, 0x73, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x61, 0x6e, 0x69, 0x6d, 0x65, 0x09, 0x09, 0x71, 0x61, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x70, 0x73, 0x6f, 0x6e, 0x2e, 0x73, 0x61, 0x6c, 0x74, 0x09, 0x09, 0x09, 0x73, 0x6c, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x70, 0x73, 0x6f, 0x6e, 0x2e, 0x73, 0x73, 0x66, 0x09, 0x09, 0x09, 0x73, 0x73, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x72, 0x69, 0x63, 0x73, 0x73, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x63, 0x61, 0x6c, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x73, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x33, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x65, 0x73, 0x33, 0x20, 0x65, 0x74, 0x33, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x61, 0x6f, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x63, 0x75, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x73, 0x61, 0x64, 0x2d, 0x62, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x73, 0x61, 0x64, 0x2d, 0x63, 0x6f, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x73, 0x61, 0x64, 0x2d, 0x6e, 0x70, 0x76, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x73, 0x79, 0x6e, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x75, 0x65, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x6d, 0x63, 0x69, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x61, 0x64, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x73, 0x63, 0x69, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x73, 0x69, 0x6d, 0x73, 0x65, 0x72, 0x76, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x74, 0x73, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x74, 0x73, 0x6c, 0x2e, 0x64, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x7a, 0x70, 0x69, 0x78, 0x2d, 0x61, 0x6c, 0x62, 0x75, 0x6d, 0x09, 0x09, 0x09, 0x65, 0x7a, 0x32, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x7a, 0x70, 0x69, 0x78, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x09, 0x09, 0x09, 0x65, 0x7a, 0x33, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x2d, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x64, 0x66, 0x09, 0x09, 0x09, 0x09, 0x66, 0x64, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x64, 0x73, 0x6e, 0x2e, 0x6d, 0x73, 0x65, 0x65, 0x64, 0x09, 0x09, 0x09, 0x6d, 0x73, 0x65, 0x65, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x64, 0x73, 0x6e, 0x2e, 0x73, 0x65, 0x65, 0x64, 0x09, 0x09, 0x09, 0x73, 0x65, 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x6c, 0x65, 0x73, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x66, 0x73, 0x6e, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x74, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x6c, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x74, 0x09, 0x09, 0x09, 0x67, 0x70, 0x68, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x6c, 0x75, 0x78, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x63, 0x6c, 0x69, 0x70, 0x09, 0x09, 0x09, 0x66, 0x74, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x66, 0x6f, 0x72, 0x67, 0x65, 0x2d, 0x73, 0x66, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x6d, 0x61, 0x6b, 0x65, 0x72, 0x09, 0x09, 0x09, 0x66, 0x6d, 0x20, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x72, 0x20, 0x62, 0x6f, 0x6f, 0x6b, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x72, 0x6f, 0x67, 0x61, 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x63, 0x09, 0x09, 0x09, 0x66, 0x6e, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x72, 0x6f, 0x67, 0x61, 0x6e, 0x73, 0x2e, 0x6c, 0x74, 0x66, 0x09, 0x09, 0x09, 0x6c, 0x74, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x73, 0x63, 0x2e, 0x77, 0x65, 0x62, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x09, 0x09, 0x09, 0x66, 0x73, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x74, 0x73, 0x75, 0x2e, 0x6f, 0x61, 0x73, 0x79, 0x73, 0x09, 0x09, 0x09, 0x6f, 0x61, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x74, 0x73, 0x75, 0x2e, 0x6f, 0x61, 0x73, 0x79, 0x73, 0x32, 0x09, 0x09, 0x09, 0x6f, 0x61, 0x32, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x74, 0x73, 0x75, 0x2e, 0x6f, 0x61, 0x73, 0x79, 0x73, 0x33, 0x09, 0x09, 0x09, 0x6f, 0x61, 0x33, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x74, 0x73, 0x75, 0x2e, 0x6f, 0x61, 0x73, 0x79, 0x73, 0x67, 0x70, 0x09, 0x09, 0x09, 0x66, 0x67, 0x35, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x74, 0x73, 0x75, 0x2e, 0x6f, 0x61, 0x73, 0x79, 0x73, 0x70, 0x72, 0x73, 0x09, 0x09, 0x62, 0x68, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x78, 0x65, 0x72, 0x6f, 0x78, 0x2e, 0x61, 0x72, 0x74, 0x2d, 0x65, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x78, 0x65, 0x72, 0x6f, 0x78, 0x2e, 0x61, 0x72, 0x74, 0x34, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x78, 0x65, 0x72, 0x6f, 0x78, 0x2e, 0x68, 0x62, 0x70, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x78, 0x65, 0x72, 0x6f, 0x78, 0x2e, 0x64, 0x64, 0x64, 0x09, 0x09, 0x09, 0x64, 0x64, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x78, 0x65, 0x72, 0x6f, 0x78, 0x2e, 0x64, 0x6f, 0x63, 0x75, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x09, 0x09, 0x78, 0x64, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x78, 0x65, 0x72, 0x6f, 0x78, 0x2e, 0x64, 0x6f, 0x63, 0x75, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x09, 0x78, 0x62, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x74, 0x2d, 0x6d, 0x69, 0x73, 0x6e, 0x65, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x7a, 0x7a, 0x79, 0x73, 0x68, 0x65, 0x65, 0x74, 0x09, 0x09, 0x09, 0x66, 0x7a, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x65, 0x6e, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x78, 0x2e, 0x74, 0x75, 0x78, 0x65, 0x64, 0x6f, 0x09, 0x09, 0x74, 0x78, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x65, 0x6f, 0x63, 0x75, 0x62, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x65, 0x6f, 0x67, 0x65, 0x62, 0x72, 0x61, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x67, 0x67, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x65, 0x6f, 0x67, 0x65, 0x62, 0x72, 0x61, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x09, 0x09, 0x09, 0x67, 0x67, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2d, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x72, 0x09, 0x09, 0x67, 0x65, 0x78, 0x20, 0x67, 0x72, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x65, 0x6f, 0x6e, 0x65, 0x78, 0x74, 0x09, 0x09, 0x09, 0x09, 0x67, 0x78, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x65, 0x6f, 0x70, 0x6c, 0x61, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x67, 0x32, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x65, 0x6f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x09, 0x09, 0x09, 0x67, 0x33, 0x77, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x63, 0x61, 0x72, 0x64, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6d, 0x67, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x63, 0x61, 0x72, 0x64, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6d, 0x67, 0x74, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x6d, 0x78, 0x09, 0x09, 0x09, 0x09, 0x67, 0x6d, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2d, 0x65, 0x61, 0x72, 0x74, 0x68, 0x2e, 0x6b, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x6b, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2d, 0x65, 0x61, 0x72, 0x74, 0x68, 0x2e, 0x6b, 0x6d, 0x7a, 0x09, 0x09, 0x6b, 0x6d, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x61, 0x66, 0x65, 0x71, 0x09, 0x09, 0x09, 0x09, 0x67, 0x71, 0x66, 0x20, 0x67, 0x71, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x69, 0x64, 0x6d, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x6f, 0x6f, 0x76, 0x65, 0x2d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x09, 0x09, 0x09, 0x67, 0x61, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x6f, 0x6f, 0x76, 0x65, 0x2d, 0x68, 0x65, 0x6c, 0x70, 0x09, 0x09, 0x09, 0x67, 0x68, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x6f, 0x6f, 0x76, 0x65, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x09, 0x09, 0x67, 0x69, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x6f, 0x6f, 0x76, 0x65, 0x2d, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x09, 0x09, 0x09, 0x67, 0x72, 0x76, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x6f, 0x6f, 0x76, 0x65, 0x2d, 0x74, 0x6f, 0x6f, 0x6c, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x09, 0x09, 0x67, 0x74, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x6f, 0x6f, 0x76, 0x65, 0x2d, 0x74, 0x6f, 0x6f, 0x6c, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x09, 0x74, 0x70, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x6f, 0x6f, 0x76, 0x65, 0x2d, 0x76, 0x63, 0x61, 0x72, 0x64, 0x09, 0x09, 0x09, 0x76, 0x63, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x61, 0x6c, 0x2b, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x61, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x68, 0x61, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x68, 0x65, 0x6c, 0x64, 0x2d, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x7a, 0x6d, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x62, 0x63, 0x69, 0x09, 0x09, 0x09, 0x09, 0x68, 0x62, 0x63, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x63, 0x6c, 0x2d, 0x62, 0x69, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x68, 0x65, 0x2e, 0x6c, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x2d, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x09, 0x09, 0x6c, 0x65, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x70, 0x2d, 0x68, 0x70, 0x67, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x68, 0x70, 0x67, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x70, 0x2d, 0x68, 0x70, 0x69, 0x64, 0x09, 0x09, 0x09, 0x09, 0x68, 0x70, 0x69, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x70, 0x2d, 0x68, 0x70, 0x73, 0x09, 0x09, 0x09, 0x09, 0x68, 0x70, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x70, 0x2d, 0x6a, 0x6c, 0x79, 0x74, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x6c, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x70, 0x2d, 0x70, 0x63, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x70, 0x63, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x70, 0x2d, 0x70, 0x63, 0x6c, 0x78, 0x6c, 0x09, 0x09, 0x09, 0x70, 0x63, 0x6c, 0x78, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x79, 0x64, 0x72, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x78, 0x2e, 0x73, 0x6f, 0x66, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x09, 0x09, 0x73, 0x66, 0x64, 0x2d, 0x68, 0x64, 0x73, 0x74, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x7a, 0x6e, 0x2d, 0x33, 0x64, 0x2d, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x62, 0x6d, 0x2e, 0x61, 0x66, 0x70, 0x6c, 0x69, 0x6e, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x62, 0x6d, 0x2e, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x2d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x62, 0x6d, 0x2e, 0x6d, 0x69, 0x6e, 0x69, 0x70, 0x61, 0x79, 0x09, 0x09, 0x09, 0x6d, 0x70, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x62, 0x6d, 0x2e, 0x6d, 0x6f, 0x64, 0x63, 0x61, 0x70, 0x09, 0x09, 0x09, 0x61, 0x66, 0x70, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x61, 0x66, 0x70, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x33, 0x38, 0x32, 0x30, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x62, 0x6d, 0x2e, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x09, 0x09, 0x69, 0x72, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x62, 0x6d, 0x2e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x09, 0x09, 0x73, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x63, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x69, 0x63, 0x63, 0x20, 0x69, 0x63, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x67, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x09, 0x09, 0x09, 0x69, 0x67, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6d, 0x6d, 0x65, 0x72, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2d, 0x69, 0x76, 0x70, 0x09, 0x09, 0x09, 0x69, 0x76, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6d, 0x6d, 0x65, 0x72, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2d, 0x69, 0x76, 0x75, 0x09, 0x09, 0x09, 0x69, 0x76, 0x75, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x72, 0x6d, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x69, 0x78, 0x2d, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x61, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x74, 0x65, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x74, 0x65, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x6e, 0x6f, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x77, 0x61, 0x6d, 0x70, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x6f, 0x72, 0x73, 0x2e, 0x69, 0x67, 0x6d, 0x09, 0x09, 0x09, 0x69, 0x67, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x6e, 0x65, 0x74, 0x09, 0x09, 0x78, 0x70, 0x77, 0x20, 0x78, 0x70, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x67, 0x65, 0x6f, 0x09, 0x09, 0x09, 0x69, 0x32, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x62, 0x6f, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x6e, 0x63, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x74, 0x75, 0x2e, 0x71, 0x62, 0x6f, 0x09, 0x09, 0x09, 0x71, 0x62, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x74, 0x75, 0x2e, 0x71, 0x66, 0x78, 0x09, 0x09, 0x09, 0x71, 0x66, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x63, 0x2e, 0x67, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x65, 0x70, 0x74, 0x69, 0x74, 0x65, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x63, 0x2e, 0x67, 0x32, 0x2e, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x69, 0x74, 0x65, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x63, 0x2e, 0x67, 0x32, 0x2e, 0x6e, 0x65, 0x77, 0x73, 0x69, 0x74, 0x65, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x63, 0x2e, 0x67, 0x32, 0x2e, 0x6e, 0x65, 0x77, 0x73, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x63, 0x2e, 0x67, 0x32, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x69, 0x74, 0x65, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x63, 0x2e, 0x67, 0x32, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x69, 0x74, 0x65, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x75, 0x6e, 0x70, 0x6c, 0x75, 0x67, 0x67, 0x65, 0x64, 0x2e, 0x72, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x09, 0x72, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x69, 0x72, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x73, 0x2d, 0x78, 0x70, 0x72, 0x09, 0x09, 0x09, 0x09, 0x78, 0x70, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x73, 0x61, 0x63, 0x2e, 0x66, 0x63, 0x73, 0x09, 0x09, 0x09, 0x66, 0x63, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x61, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x61, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x61, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x74, 0x2d, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x61, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x74, 0x2d, 0x6a, 0x70, 0x6e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x77, 0x61, 0x6b, 0x65, 0x75, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x61, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x74, 0x2d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x77, 0x61, 0x6b, 0x65, 0x75, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x61, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x74, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x61, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x74, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x77, 0x61, 0x6b, 0x65, 0x75, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x61, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x74, 0x2d, 0x73, 0x65, 0x74, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x77, 0x61, 0x6b, 0x65, 0x75, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x61, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x74, 0x2d, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x61, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x74, 0x2d, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x77, 0x61, 0x6b, 0x65, 0x75, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x63, 0x70, 0x2e, 0x6a, 0x61, 0x76, 0x61, 0x6d, 0x65, 0x2e, 0x6d, 0x69, 0x64, 0x6c, 0x65, 0x74, 0x2d, 0x72, 0x6d, 0x73, 0x09, 0x09, 0x72, 0x6d, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x69, 0x73, 0x70, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x69, 0x73, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6a, 0x6f, 0x6f, 0x73, 0x74, 0x2e, 0x6a, 0x6f, 0x64, 0x61, 0x2d, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x09, 0x09, 0x6a, 0x6f, 0x64, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x61, 0x68, 0x6f, 0x6f, 0x74, 0x7a, 0x09, 0x09, 0x09, 0x09, 0x6b, 0x74, 0x7a, 0x20, 0x6b, 0x74, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x64, 0x65, 0x2e, 0x6b, 0x61, 0x72, 0x62, 0x6f, 0x6e, 0x09, 0x09, 0x09, 0x6b, 0x61, 0x72, 0x62, 0x6f, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x64, 0x65, 0x2e, 0x6b, 0x63, 0x68, 0x61, 0x72, 0x74, 0x09, 0x09, 0x09, 0x63, 0x68, 0x72, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x64, 0x65, 0x2e, 0x6b, 0x66, 0x6f, 0x72, 0x6d, 0x75, 0x6c, 0x61, 0x09, 0x09, 0x09, 0x6b, 0x66, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x64, 0x65, 0x2e, 0x6b, 0x69, 0x76, 0x69, 0x6f, 0x09, 0x09, 0x09, 0x66, 0x6c, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x64, 0x65, 0x2e, 0x6b, 0x6f, 0x6e, 0x74, 0x6f, 0x75, 0x72, 0x09, 0x09, 0x09, 0x6b, 0x6f, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x64, 0x65, 0x2e, 0x6b, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x09, 0x09, 0x09, 0x6b, 0x70, 0x72, 0x20, 0x6b, 0x70, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x64, 0x65, 0x2e, 0x6b, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x09, 0x09, 0x09, 0x6b, 0x73, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x64, 0x65, 0x2e, 0x6b, 0x77, 0x6f, 0x72, 0x64, 0x09, 0x09, 0x09, 0x6b, 0x77, 0x64, 0x20, 0x6b, 0x77, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x61, 0x61, 0x70, 0x70, 0x09, 0x09, 0x09, 0x68, 0x74, 0x6b, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x69, 0x64, 0x73, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x09, 0x09, 0x09, 0x6b, 0x69, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x69, 0x6e, 0x61, 0x72, 0x09, 0x09, 0x09, 0x09, 0x6b, 0x6e, 0x65, 0x20, 0x6b, 0x6e, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x6f, 0x61, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x73, 0x6b, 0x70, 0x20, 0x73, 0x6b, 0x64, 0x20, 0x73, 0x6b, 0x74, 0x20, 0x73, 0x6b, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6b, 0x6f, 0x64, 0x61, 0x6b, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x09, 0x09, 0x73, 0x73, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x61, 0x73, 0x2e, 0x6c, 0x61, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x6c, 0x61, 0x73, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x69, 0x62, 0x65, 0x72, 0x74, 0x79, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x6c, 0x61, 0x6d, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6c, 0x69, 0x66, 0x65, 0x2d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x09, 0x6c, 0x62, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x6c, 0x61, 0x6d, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6c, 0x69, 0x66, 0x65, 0x2d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x6c, 0x62, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x6f, 0x74, 0x75, 0x73, 0x2d, 0x31, 0x2d, 0x32, 0x2d, 0x33, 0x09, 0x09, 0x09, 0x31, 0x32, 0x33, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x6f, 0x74, 0x75, 0x73, 0x2d, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x61, 0x63, 0x68, 0x09, 0x09, 0x09, 0x61, 0x70, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x6f, 0x74, 0x75, 0x73, 0x2d, 0x66, 0x72, 0x65, 0x65, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x09, 0x09, 0x09, 0x70, 0x72, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x6f, 0x74, 0x75, 0x73, 0x2d, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x09, 0x09, 0x09, 0x6e, 0x73, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x6f, 0x74, 0x75, 0x73, 0x2d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x65, 0x72, 0x09, 0x09, 0x09, 0x6f, 0x72, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x6f, 0x74, 0x75, 0x73, 0x2d, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x63, 0x61, 0x6d, 0x09, 0x09, 0x09, 0x73, 0x63, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x6f, 0x74, 0x75, 0x73, 0x2d, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x09, 0x09, 0x09, 0x6c, 0x77, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x61, 0x63, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x70, 0x6b, 0x67, 0x09, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x70, 0x6b, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x61, 0x72, 0x6c, 0x69, 0x6e, 0x2e, 0x64, 0x72, 0x6d, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x61, 0x72, 0x6c, 0x69, 0x6e, 0x2e, 0x64, 0x72, 0x6d, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x61, 0x72, 0x6c, 0x69, 0x6e, 0x2e, 0x64, 0x72, 0x6d, 0x2e, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x61, 0x72, 0x6c, 0x69, 0x6e, 0x2e, 0x64, 0x72, 0x6d, 0x2e, 0x6d, 0x64, 0x63, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x63, 0x64, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x63, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x65, 0x64, 0x63, 0x61, 0x6c, 0x63, 0x64, 0x61, 0x74, 0x61, 0x09, 0x09, 0x09, 0x6d, 0x63, 0x31, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x64, 0x6b, 0x65, 0x79, 0x09, 0x09, 0x63, 0x64, 0x6b, 0x65, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x65, 0x72, 0x69, 0x64, 0x69, 0x61, 0x6e, 0x2d, 0x73, 0x6c, 0x69, 0x6e, 0x67, 0x73, 0x68, 0x6f, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x66, 0x65, 0x72, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x77, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x66, 0x6d, 0x70, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x66, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x66, 0x78, 0x2e, 0x66, 0x6c, 0x6f, 0x09, 0x09, 0x09, 0x66, 0x6c, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x66, 0x78, 0x2e, 0x69, 0x67, 0x78, 0x09, 0x09, 0x09, 0x69, 0x67, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x69, 0x66, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x69, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x69, 0x6e, 0x69, 0x73, 0x6f, 0x66, 0x74, 0x2d, 0x68, 0x70, 0x33, 0x30, 0x30, 0x30, 0x2d, 0x73, 0x61, 0x76, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x69, 0x74, 0x73, 0x75, 0x62, 0x69, 0x73, 0x68, 0x69, 0x2e, 0x6d, 0x69, 0x73, 0x74, 0x79, 0x2d, 0x67, 0x75, 0x61, 0x72, 0x64, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x77, 0x65, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x66, 0x09, 0x09, 0x09, 0x64, 0x61, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x09, 0x09, 0x09, 0x64, 0x69, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x75, 0x73, 0x2e, 0x6d, 0x62, 0x6b, 0x09, 0x09, 0x09, 0x6d, 0x62, 0x6b, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x75, 0x73, 0x2e, 0x6d, 0x71, 0x79, 0x09, 0x09, 0x09, 0x6d, 0x71, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x75, 0x73, 0x2e, 0x6d, 0x73, 0x6c, 0x09, 0x09, 0x09, 0x6d, 0x73, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x75, 0x73, 0x2e, 0x70, 0x6c, 0x63, 0x09, 0x09, 0x09, 0x70, 0x6c, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x75, 0x73, 0x2e, 0x74, 0x78, 0x66, 0x09, 0x09, 0x09, 0x74, 0x78, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x70, 0x68, 0x75, 0x6e, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x09, 0x09, 0x6d, 0x70, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x70, 0x68, 0x75, 0x6e, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x09, 0x09, 0x6d, 0x70, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x75, 0x69, 0x74, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x75, 0x69, 0x74, 0x65, 0x2e, 0x61, 0x64, 0x73, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x75, 0x69, 0x74, 0x65, 0x2e, 0x66, 0x69, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x75, 0x69, 0x74, 0x65, 0x2e, 0x67, 0x6f, 0x74, 0x61, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x75, 0x69, 0x74, 0x65, 0x2e, 0x6b, 0x6d, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x75, 0x69, 0x74, 0x65, 0x2e, 0x74, 0x74, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x75, 0x69, 0x74, 0x65, 0x2e, 0x77, 0x65, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x69, 0x70, 0x72, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0x2e, 0x78, 0x75, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x78, 0x75, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x61, 0x72, 0x74, 0x67, 0x61, 0x6c, 0x72, 0x79, 0x09, 0x09, 0x09, 0x63, 0x69, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x61, 0x73, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x63, 0x61, 0x62, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x09, 0x09, 0x63, 0x61, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x2e, 0x69, 0x63, 0x63, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, 0x63, 0x65, 0x6c, 0x09, 0x09, 0x09, 0x78, 0x6c, 0x73, 0x20, 0x78, 0x6c, 0x6d, 0x20, 0x78, 0x6c, 0x61, 0x20, 0x78, 0x6c, 0x63, 0x20, 0x78, 0x6c, 0x74, 0x20, 0x78, 0x6c, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, 0x63, 0x65, 0x6c, 0x2e, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x09, 0x78, 0x6c, 0x61, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, 0x63, 0x65, 0x6c, 0x2e, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2e, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x78, 0x6c, 0x73, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, 0x63, 0x65, 0x6c, 0x2e, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x09, 0x78, 0x6c, 0x73, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, 0x63, 0x65, 0x6c, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x78, 0x6c, 0x74, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x09, 0x09, 0x09, 0x65, 0x6f, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x68, 0x74, 0x6d, 0x6c, 0x68, 0x65, 0x6c, 0x70, 0x09, 0x09, 0x09, 0x63, 0x68, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x69, 0x6d, 0x73, 0x09, 0x09, 0x09, 0x09, 0x69, 0x6d, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x6c, 0x72, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x6c, 0x72, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x78, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x09, 0x09, 0x09, 0x74, 0x68, 0x6d, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6f, 0x62, 0x66, 0x75, 0x73, 0x63, 0x61, 0x74, 0x65, 0x64, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6b, 0x69, 0x2e, 0x73, 0x65, 0x63, 0x63, 0x61, 0x74, 0x09, 0x09, 0x09, 0x63, 0x61, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6b, 0x69, 0x2e, 0x73, 0x74, 0x6c, 0x09, 0x09, 0x09, 0x73, 0x74, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6c, 0x61, 0x79, 0x72, 0x65, 0x61, 0x64, 0x79, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x09, 0x09, 0x09, 0x70, 0x70, 0x74, 0x20, 0x70, 0x70, 0x73, 0x20, 0x70, 0x6f, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x09, 0x70, 0x70, 0x61, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x70, 0x70, 0x74, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x09, 0x73, 0x6c, 0x64, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x73, 0x68, 0x6f, 0x77, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x09, 0x70, 0x70, 0x73, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x09, 0x70, 0x6f, 0x74, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x09, 0x09, 0x09, 0x6d, 0x70, 0x70, 0x20, 0x6d, 0x70, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x74, 0x6e, 0x65, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x64, 0x72, 0x6d, 0x2e, 0x6c, 0x69, 0x63, 0x2d, 0x63, 0x68, 0x6c, 0x67, 0x2d, 0x72, 0x65, 0x71, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x64, 0x72, 0x6d, 0x2e, 0x6c, 0x69, 0x63, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x64, 0x72, 0x6d, 0x2e, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x2d, 0x63, 0x68, 0x6c, 0x67, 0x2d, 0x72, 0x65, 0x71, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x64, 0x72, 0x6d, 0x2e, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x77, 0x6f, 0x72, 0x64, 0x2e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x64, 0x6f, 0x63, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x77, 0x6f, 0x72, 0x64, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x31, 0x32, 0x09, 0x64, 0x6f, 0x74, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x09, 0x09, 0x09, 0x77, 0x70, 0x73, 0x20, 0x77, 0x6b, 0x73, 0x20, 0x77, 0x63, 0x6d, 0x20, 0x77, 0x64, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x77, 0x70, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x77, 0x70, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x09, 0x09, 0x09, 0x78, 0x70, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x65, 0x71, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x73, 0x65, 0x71, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x69, 0x67, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x61, 0x64, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x61, 0x64, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x63, 0x69, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x75, 0x73, 0x69, 0x63, 0x2d, 0x6e, 0x69, 0x66, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x75, 0x73, 0x69, 0x63, 0x69, 0x61, 0x6e, 0x09, 0x09, 0x09, 0x6d, 0x75, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x75, 0x76, 0x65, 0x65, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x6d, 0x73, 0x74, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x79, 0x6e, 0x66, 0x63, 0x09, 0x09, 0x09, 0x09, 0x74, 0x61, 0x67, 0x6c, 0x65, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x63, 0x64, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x65, 0x72, 0x76, 0x61, 0x6e, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x65, 0x74, 0x66, 0x70, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x65, 0x75, 0x72, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x2e, 0x6e, 0x6c, 0x75, 0x09, 0x09, 0x6e, 0x6c, 0x75, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x69, 0x74, 0x66, 0x09, 0x09, 0x09, 0x09, 0x6e, 0x74, 0x66, 0x20, 0x6e, 0x69, 0x74, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x62, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x2d, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x09, 0x09, 0x6e, 0x6e, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x62, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x2d, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x72, 0x09, 0x09, 0x09, 0x6e, 0x6e, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x62, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x2d, 0x77, 0x65, 0x62, 0x09, 0x09, 0x09, 0x6e, 0x6e, 0x77, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6e, 0x6d, 0x6c, 0x2b, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6e, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x69, 0x73, 0x64, 0x73, 0x2d, 0x72, 0x61, 0x64, 0x69, 0x6f, 0x2d, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x6c, 0x61, 0x6e, 0x64, 0x6d, 0x61, 0x72, 0x6b, 0x2b, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x6c, 0x61, 0x6e, 0x64, 0x6d, 0x61, 0x72, 0x6b, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x6c, 0x61, 0x6e, 0x64, 0x6d, 0x61, 0x72, 0x6b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x6e, 0x2d, 0x67, 0x61, 0x67, 0x65, 0x2e, 0x61, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x6e, 0x2d, 0x67, 0x61, 0x67, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x09, 0x09, 0x6e, 0x67, 0x64, 0x61, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x6e, 0x2d, 0x67, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x79, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x2e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x09, 0x6e, 0x2d, 0x67, 0x61, 0x67, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x6e, 0x63, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x70, 0x63, 0x64, 0x2b, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x70, 0x63, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x6f, 0x2d, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x09, 0x09, 0x72, 0x70, 0x73, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x6f, 0x2d, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x09, 0x09, 0x72, 0x70, 0x73, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x76, 0x61, 0x64, 0x69, 0x67, 0x6d, 0x2e, 0x65, 0x64, 0x6d, 0x09, 0x09, 0x09, 0x65, 0x64, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x76, 0x61, 0x64, 0x69, 0x67, 0x6d, 0x2e, 0x65, 0x64, 0x78, 0x09, 0x09, 0x09, 0x65, 0x64, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x76, 0x61, 0x64, 0x69, 0x67, 0x6d, 0x2e, 0x65, 0x78, 0x74, 0x09, 0x09, 0x09, 0x65, 0x78, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x74, 0x74, 0x2d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x74, 0x74, 0x2d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2e, 0x73, 0x69, 0x70, 0x2d, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x74, 0x74, 0x2d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2e, 0x73, 0x69, 0x70, 0x2d, 0x74, 0x61, 0x5f, 0x74, 0x63, 0x70, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x68, 0x61, 0x72, 0x74, 0x09, 0x09, 0x6f, 0x64, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x68, 0x61, 0x72, 0x74, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x6f, 0x74, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x09, 0x09, 0x6f, 0x64, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x75, 0x6c, 0x61, 0x09, 0x09, 0x6f, 0x64, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x75, 0x6c, 0x61, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x6f, 0x64, 0x66, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x09, 0x09, 0x6f, 0x64, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x6f, 0x74, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x09, 0x09, 0x6f, 0x64, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x6f, 0x74, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x09, 0x09, 0x6f, 0x64, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x6f, 0x74, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x09, 0x09, 0x6f, 0x64, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x6f, 0x74, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x09, 0x09, 0x09, 0x6f, 0x64, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x09, 0x09, 0x6f, 0x64, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x6f, 0x74, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x61, 0x73, 0x69, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x77, 0x65, 0x62, 0x09, 0x09, 0x6f, 0x74, 0x68, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x62, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x66, 0x74, 0x6e, 0x2e, 0x6c, 0x31, 0x30, 0x6e, 0x2b, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x63, 0x73, 0x70, 0x67, 0x2d, 0x68, 0x65, 0x78, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x64, 0x61, 0x65, 0x2e, 0x73, 0x76, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x64, 0x61, 0x65, 0x2e, 0x78, 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x6d, 0x69, 0x70, 0x70, 0x76, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x70, 0x61, 0x65, 0x2e, 0x67, 0x65, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x73, 0x70, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x73, 0x70, 0x64, 0x6c, 0x69, 0x73, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x75, 0x65, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x69, 0x70, 0x66, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6c, 0x70, 0x63, 0x2d, 0x73, 0x75, 0x67, 0x61, 0x72, 0x09, 0x09, 0x09, 0x78, 0x6f, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2d, 0x73, 0x63, 0x77, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2d, 0x73, 0x63, 0x77, 0x73, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2d, 0x73, 0x63, 0x77, 0x73, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x2d, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x75, 0x72, 0x65, 0x2d, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x64, 0x72, 0x6d, 0x2d, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x69, 0x6d, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x6c, 0x74, 0x6b, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x73, 0x67, 0x62, 0x6f, 0x6f, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x73, 0x67, 0x64, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x73, 0x67, 0x64, 0x75, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x61, 0x72, 0x64, 0x2d, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x6f, 0x76, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x62, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x6b, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x63, 0x61, 0x62, 0x2d, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2d, 0x62, 0x6f, 0x6f, 0x6b, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x63, 0x61, 0x62, 0x2d, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2d, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x63, 0x61, 0x62, 0x2d, 0x70, 0x63, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x63, 0x61, 0x62, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x70, 0x72, 0x65, 0x66, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x64, 0x63, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x64, 0x63, 0x64, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x64, 0x64, 0x32, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x64, 0x64, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x64, 0x72, 0x6d, 0x2e, 0x72, 0x69, 0x73, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2d, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x70, 0x61, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x70, 0x6f, 0x63, 0x2e, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x2d, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x70, 0x6f, 0x63, 0x2e, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x2d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x70, 0x6f, 0x63, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x70, 0x6f, 0x63, 0x2e, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x70, 0x6f, 0x63, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x2d, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x73, 0x63, 0x69, 0x64, 0x6d, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x2e, 0x78, 0x63, 0x61, 0x70, 0x2d, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x64, 0x73, 0x2d, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x64, 0x73, 0x2d, 0x66, 0x69, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x64, 0x73, 0x2d, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x6d, 0x61, 0x6c, 0x6f, 0x63, 0x2d, 0x73, 0x75, 0x70, 0x6c, 0x2d, 0x69, 0x6e, 0x69, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x09, 0x09, 0x6f, 0x78, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x78, 0x6d, 0x6c, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x69, 0x6e, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x63, 0x68, 0x61, 0x72, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x63, 0x68, 0x61, 0x72, 0x74, 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x64, 0x69, 0x61, 0x67, 0x72, 0x61, 0x6d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x64, 0x69, 0x61, 0x67, 0x72, 0x61, 0x6d, 0x64, 0x61, 0x74, 0x61, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x64, 0x69, 0x61, 0x67, 0x72, 0x61, 0x6d, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x64, 0x69, 0x61, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x2d, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6f, 0x75, 0x74, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x09, 0x70, 0x70, 0x74, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x09, 0x73, 0x6c, 0x64, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x73, 0x68, 0x6f, 0x77, 0x09, 0x70, 0x70, 0x73, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x73, 0x68, 0x6f, 0x77, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x73, 0x6c, 0x69, 0x64, 0x65, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x69, 0x6e, 0x66, 0x6f, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x74, 0x61, 0x67, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x70, 0x6f, 0x74, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x6c, 0x2e, 0x76, 0x69, 0x65, 0x77, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x63, 0x61, 0x6c, 0x63, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x63, 0x68, 0x61, 0x72, 0x74, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x6c, 0x69, 0x6e, 0x6b, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x63, 0x61, 0x63, 0x68, 0x65, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x6c, 0x6f, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x73, 0x68, 0x65, 0x65, 0x74, 0x09, 0x78, 0x6c, 0x73, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x78, 0x6c, 0x74, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x76, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6c, 0x65, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x6d, 0x6c, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x68, 0x65, 0x65, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x6d, 0x6c, 0x64, 0x72, 0x61, 0x77, 0x69, 0x6e, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x09, 0x64, 0x6f, 0x63, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x73, 0x73, 0x61, 0x72, 0x79, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x65, 0x6e, 0x64, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x66, 0x6f, 0x6e, 0x74, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x66, 0x6f, 0x6f, 0x74, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x64, 0x6f, 0x74, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x6d, 0x6c, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2d, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x2d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2d, 0x78, 0x6d, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x78, 0x6d, 0x6c, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x71, 0x75, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2d, 0x71, 0x75, 0x6f, 0x78, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x73, 0x61, 0x2e, 0x6e, 0x65, 0x74, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x73, 0x67, 0x65, 0x6f, 0x2e, 0x6d, 0x61, 0x70, 0x67, 0x75, 0x69, 0x64, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x09, 0x09, 0x6d, 0x67, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x73, 0x67, 0x69, 0x2e, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x73, 0x67, 0x69, 0x2e, 0x64, 0x70, 0x09, 0x09, 0x09, 0x09, 0x64, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x73, 0x67, 0x69, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x09, 0x09, 0x09, 0x65, 0x73, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x74, 0x70, 0x73, 0x2e, 0x63, 0x74, 0x2d, 0x6b, 0x69, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x61, 0x6c, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x70, 0x64, 0x62, 0x20, 0x70, 0x71, 0x61, 0x20, 0x6f, 0x70, 0x72, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x61, 0x6f, 0x73, 0x2e, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x61, 0x77, 0x61, 0x61, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x70, 0x61, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x67, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x09, 0x09, 0x09, 0x73, 0x74, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x67, 0x2e, 0x6f, 0x73, 0x61, 0x73, 0x6c, 0x69, 0x09, 0x09, 0x09, 0x65, 0x69, 0x36, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x69, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x63, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x69, 0x63, 0x73, 0x65, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x65, 0x66, 0x69, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x6d, 0x69, 0x2e, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x09, 0x09, 0x09, 0x77, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x6f, 0x63, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2d, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x6c, 0x65, 0x61, 0x72, 0x6e, 0x09, 0x09, 0x09, 0x70, 0x6c, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x36, 0x09, 0x09, 0x09, 0x70, 0x62, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x36, 0x2d, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x37, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x37, 0x2d, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x37, 0x35, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x37, 0x35, 0x2d, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x6e, 0x65, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x62, 0x6f, 0x78, 0x09, 0x09, 0x62, 0x6f, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x75, 0x73, 0x2e, 0x6d, 0x61, 0x67, 0x61, 0x7a, 0x69, 0x6e, 0x65, 0x09, 0x09, 0x6d, 0x67, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x2d, 0x74, 0x72, 0x65, 0x65, 0x09, 0x09, 0x71, 0x70, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x76, 0x69, 0x2e, 0x70, 0x74, 0x69, 0x64, 0x31, 0x09, 0x09, 0x09, 0x70, 0x74, 0x69, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x77, 0x67, 0x2d, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x77, 0x67, 0x2d, 0x78, 0x68, 0x74, 0x6d, 0x6c, 0x2d, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x71, 0x75, 0x61, 0x6c, 0x63, 0x6f, 0x6d, 0x6d, 0x2e, 0x62, 0x72, 0x65, 0x77, 0x2d, 0x61, 0x70, 0x70, 0x2d, 0x72, 0x65, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x71, 0x75, 0x61, 0x72, 0x6b, 0x2e, 0x71, 0x75, 0x61, 0x72, 0x6b, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x09, 0x09, 0x71, 0x78, 0x64, 0x20, 0x71, 0x78, 0x74, 0x20, 0x71, 0x77, 0x64, 0x20, 0x71, 0x77, 0x74, 0x20, 0x71, 0x78, 0x6c, 0x20, 0x71, 0x78, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x6f, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2d, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2d, 0x62, 0x61, 0x73, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2d, 0x66, 0x61, 0x78, 0x2d, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2d, 0x66, 0x61, 0x78, 0x2d, 0x73, 0x65, 0x6e, 0x64, 0x72, 0x65, 0x63, 0x76, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2d, 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x64, 0x69, 0x61, 0x6c, 0x6f, 0x67, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x69, 0x6e, 0x73, 0x74, 0x6f, 0x72, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x70, 0x69, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x65, 0x61, 0x6c, 0x76, 0x6e, 0x63, 0x2e, 0x62, 0x65, 0x64, 0x09, 0x09, 0x09, 0x62, 0x65, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x61, 0x72, 0x65, 0x2e, 0x6d, 0x75, 0x73, 0x69, 0x63, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x6d, 0x78, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x61, 0x72, 0x65, 0x2e, 0x6d, 0x75, 0x73, 0x69, 0x63, 0x78, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x6d, 0x75, 0x73, 0x69, 0x63, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x65, 0x6e, 0x6c, 0x65, 0x61, 0x72, 0x6e, 0x2e, 0x72, 0x6c, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x69, 0x67, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x6e, 0x6f, 0x74, 0x65, 0x09, 0x09, 0x09, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x6e, 0x6f, 0x74, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x69, 0x6d, 0x2e, 0x63, 0x6f, 0x64, 0x09, 0x09, 0x09, 0x09, 0x63, 0x6f, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x6e, 0x2d, 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x09, 0x09, 0x09, 0x72, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x6e, 0x2d, 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2d, 0x76, 0x62, 0x72, 0x09, 0x09, 0x72, 0x6d, 0x76, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x36, 0x36, 0x2e, 0x6c, 0x69, 0x6e, 0x6b, 0x36, 0x36, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x36, 0x36, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x73, 0x2d, 0x32, 0x37, 0x34, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x75, 0x63, 0x6b, 0x75, 0x73, 0x2e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x33, 0x73, 0x6d, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x61, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x09, 0x09, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x62, 0x6d, 0x2e, 0x63, 0x69, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x62, 0x6d, 0x2e, 0x6d, 0x69, 0x64, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x63, 0x72, 0x69, 0x62, 0x75, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x33, 0x64, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x63, 0x73, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x64, 0x6f, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x65, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x6d, 0x68, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x6e, 0x65, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x70, 0x70, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x74, 0x69, 0x66, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x78, 0x6c, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x73, 0x6f, 0x66, 0x74, 0x73, 0x65, 0x61, 0x6c, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x73, 0x6f, 0x66, 0x74, 0x73, 0x65, 0x61, 0x6c, 0x2e, 0x70, 0x64, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x73, 0x65, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x6d, 0x61, 0x09, 0x09, 0x09, 0x09, 0x73, 0x65, 0x6d, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x6d, 0x64, 0x09, 0x09, 0x09, 0x09, 0x73, 0x65, 0x6d, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x6d, 0x66, 0x09, 0x09, 0x09, 0x09, 0x73, 0x65, 0x6d, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x68, 0x61, 0x6e, 0x61, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x64, 0x61, 0x74, 0x61, 0x09, 0x09, 0x69, 0x66, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x68, 0x61, 0x6e, 0x61, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x69, 0x74, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x68, 0x61, 0x6e, 0x61, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x09, 0x69, 0x69, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x68, 0x61, 0x6e, 0x61, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x09, 0x09, 0x69, 0x70, 0x6b, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x69, 0x6d, 0x74, 0x65, 0x63, 0x68, 0x2d, 0x6d, 0x69, 0x6e, 0x64, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x72, 0x09, 0x09, 0x74, 0x77, 0x64, 0x20, 0x74, 0x77, 0x64, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x6d, 0x61, 0x66, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x6d, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x2e, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x09, 0x09, 0x09, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x36, 0x30, 0x32, 0x2e, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x36, 0x30, 0x32, 0x2e, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x78, 0x6d, 0x6c, 0x2d, 0x7a, 0x69, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x6f, 0x6c, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x73, 0x64, 0x6b, 0x6d, 0x20, 0x73, 0x64, 0x6b, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x70, 0x6f, 0x74, 0x66, 0x69, 0x72, 0x65, 0x2e, 0x64, 0x78, 0x70, 0x09, 0x09, 0x09, 0x64, 0x78, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x70, 0x6f, 0x74, 0x66, 0x69, 0x72, 0x65, 0x2e, 0x73, 0x66, 0x73, 0x09, 0x09, 0x09, 0x73, 0x66, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x73, 0x73, 0x2d, 0x63, 0x6f, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x73, 0x73, 0x2d, 0x64, 0x74, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x73, 0x73, 0x2d, 0x6e, 0x74, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x61, 0x6c, 0x63, 0x09, 0x09, 0x73, 0x64, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x09, 0x09, 0x73, 0x64, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x69, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x09, 0x09, 0x73, 0x64, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x09, 0x09, 0x73, 0x6d, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x72, 0x09, 0x09, 0x73, 0x64, 0x77, 0x20, 0x76, 0x6f, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x72, 0x2d, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x09, 0x73, 0x67, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x6d, 0x61, 0x6e, 0x69, 0x61, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x09, 0x09, 0x73, 0x6d, 0x7a, 0x69, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x6d, 0x61, 0x6e, 0x69, 0x61, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x63, 0x68, 0x61, 0x72, 0x74, 0x09, 0x09, 0x73, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x63, 0x61, 0x6c, 0x63, 0x09, 0x09, 0x09, 0x73, 0x78, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x63, 0x61, 0x6c, 0x63, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x09, 0x73, 0x74, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x09, 0x09, 0x09, 0x73, 0x78, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x09, 0x73, 0x74, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x69, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x09, 0x09, 0x09, 0x73, 0x78, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x69, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x73, 0x74, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x09, 0x09, 0x09, 0x73, 0x78, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x72, 0x09, 0x09, 0x09, 0x73, 0x78, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x72, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x09, 0x09, 0x73, 0x78, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x72, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x09, 0x09, 0x73, 0x74, 0x77, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x77, 0x61, 0x64, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x73, 0x2d, 0x63, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x61, 0x72, 0x09, 0x09, 0x09, 0x73, 0x75, 0x73, 0x20, 0x73, 0x75, 0x73, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x76, 0x64, 0x09, 0x09, 0x09, 0x09, 0x73, 0x76, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x77, 0x69, 0x66, 0x74, 0x76, 0x69, 0x65, 0x77, 0x2d, 0x69, 0x63, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x79, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x2e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x09, 0x09, 0x09, 0x73, 0x69, 0x73, 0x20, 0x73, 0x69, 0x73, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x78, 0x73, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x6d, 0x6c, 0x2e, 0x64, 0x6d, 0x2b, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x62, 0x64, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x6d, 0x6c, 0x2e, 0x64, 0x6d, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x78, 0x64, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x6d, 0x6c, 0x2e, 0x64, 0x6d, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x79, 0x6e, 0x63, 0x6d, 0x6c, 0x2e, 0x64, 0x73, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x74, 0x61, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2d, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x09, 0x74, 0x61, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x74, 0x63, 0x70, 0x64, 0x75, 0x6d, 0x70, 0x2e, 0x70, 0x63, 0x61, 0x70, 0x09, 0x09, 0x09, 0x70, 0x63, 0x61, 0x70, 0x20, 0x63, 0x61, 0x70, 0x20, 0x64, 0x6d, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x74, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x2d, 0x6c, 0x69, 0x76, 0x65, 0x74, 0x76, 0x09, 0x09, 0x09, 0x74, 0x6d, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x74, 0x72, 0x69, 0x64, 0x2e, 0x74, 0x70, 0x74, 0x09, 0x09, 0x09, 0x74, 0x70, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x74, 0x72, 0x69, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6d, 0x78, 0x73, 0x09, 0x09, 0x09, 0x6d, 0x78, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x74, 0x72, 0x75, 0x65, 0x61, 0x70, 0x70, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x74, 0x72, 0x75, 0x65, 0x64, 0x6f, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x62, 0x69, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x77, 0x65, 0x62, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x66, 0x64, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x75, 0x66, 0x64, 0x20, 0x75, 0x66, 0x64, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x69, 0x71, 0x2e, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x09, 0x09, 0x09, 0x75, 0x74, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x6d, 0x61, 0x6a, 0x69, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x75, 0x6d, 0x6a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x09, 0x09, 0x09, 0x09, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x77, 0x65, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x6f, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x75, 0x6f, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x2d, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x2d, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x2d, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x2d, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x6f, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x6f, 0x70, 0x2d, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2d, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x2d, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x63, 0x6d, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x63, 0x6d, 0x64, 0x2d, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x63, 0x78, 0x09, 0x09, 0x09, 0x09, 0x76, 0x63, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x64, 0x2d, 0x73, 0x74, 0x75, 0x64, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x2e, 0x76, 0x63, 0x61, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x69, 0x64, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x76, 0x69, 0x64, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x76, 0x73, 0x64, 0x20, 0x76, 0x73, 0x74, 0x20, 0x76, 0x73, 0x73, 0x20, 0x76, 0x73, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x61, 0x72, 0x79, 0x09, 0x09, 0x09, 0x76, 0x69, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x69, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x73, 0x66, 0x09, 0x09, 0x09, 0x09, 0x76, 0x73, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x73, 0x69, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x73, 0x6c, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x77, 0x6d, 0x6c, 0x63, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x6c, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x77, 0x6d, 0x6c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x63, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x6c, 0x73, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x65, 0x62, 0x74, 0x75, 0x72, 0x62, 0x6f, 0x09, 0x09, 0x09, 0x77, 0x74, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x66, 0x61, 0x2e, 0x77, 0x73, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x6d, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x6d, 0x66, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x72, 0x61, 0x6d, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x72, 0x61, 0x6d, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x72, 0x61, 0x6d, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x09, 0x09, 0x09, 0x6e, 0x62, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x65, 0x72, 0x66, 0x65, 0x63, 0x74, 0x09, 0x09, 0x09, 0x77, 0x70, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x71, 0x64, 0x09, 0x09, 0x09, 0x09, 0x77, 0x71, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x72, 0x71, 0x2d, 0x68, 0x70, 0x33, 0x30, 0x30, 0x30, 0x2d, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x74, 0x2e, 0x73, 0x74, 0x66, 0x09, 0x09, 0x09, 0x09, 0x73, 0x74, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x76, 0x2e, 0x63, 0x73, 0x70, 0x2b, 0x77, 0x62, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x76, 0x2e, 0x63, 0x73, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x76, 0x2e, 0x73, 0x73, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x61, 0x72, 0x61, 0x09, 0x09, 0x09, 0x09, 0x78, 0x61, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x66, 0x64, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x66, 0x64, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x66, 0x64, 0x6c, 0x2e, 0x77, 0x65, 0x62, 0x66, 0x6f, 0x72, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x6d, 0x69, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x6d, 0x70, 0x69, 0x65, 0x2e, 0x63, 0x70, 0x6b, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x6d, 0x70, 0x69, 0x65, 0x2e, 0x64, 0x70, 0x6b, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x6d, 0x70, 0x69, 0x65, 0x2e, 0x70, 0x6c, 0x61, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x6d, 0x70, 0x69, 0x65, 0x2e, 0x70, 0x70, 0x6b, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x6d, 0x70, 0x69, 0x65, 0x2e, 0x78, 0x6c, 0x69, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x68, 0x76, 0x2d, 0x64, 0x69, 0x63, 0x09, 0x09, 0x09, 0x68, 0x76, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x68, 0x76, 0x2d, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x09, 0x09, 0x68, 0x76, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x68, 0x76, 0x2d, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x09, 0x09, 0x09, 0x68, 0x76, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x09, 0x09, 0x09, 0x6f, 0x73, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x6f, 0x73, 0x66, 0x70, 0x76, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x6f, 0x73, 0x66, 0x70, 0x76, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2d, 0x73, 0x65, 0x74, 0x75, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x73, 0x6d, 0x61, 0x66, 0x2d, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x09, 0x09, 0x73, 0x61, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x73, 0x6d, 0x61, 0x66, 0x2d, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x09, 0x09, 0x73, 0x70, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x2d, 0x6e, 0x67, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x68, 0x61, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2d, 0x75, 0x64, 0x70, 0x65, 0x6e, 0x63, 0x61, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x79, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6d, 0x65, 0x6e, 0x75, 0x09, 0x09, 0x63, 0x6d, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x7a, 0x75, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x7a, 0x69, 0x72, 0x20, 0x7a, 0x69, 0x72, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x7a, 0x7a, 0x61, 0x7a, 0x7a, 0x2e, 0x64, 0x65, 0x63, 0x6b, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x7a, 0x61, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x78, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x76, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x71, 0x2d, 0x72, 0x74, 0x63, 0x70, 0x78, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x77, 0x68, 0x6f, 0x69, 0x73, 0x70, 0x70, 0x2d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x77, 0x68, 0x6f, 0x69, 0x73, 0x70, 0x70, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x77, 0x69, 0x64, 0x67, 0x65, 0x74, 0x09, 0x09, 0x09, 0x09, 0x77, 0x67, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x77, 0x69, 0x6e, 0x68, 0x6c, 0x70, 0x09, 0x09, 0x09, 0x09, 0x68, 0x6c, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x77, 0x69, 0x74, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x77, 0x6f, 0x72, 0x64, 0x70, 0x65, 0x72, 0x66, 0x65, 0x63, 0x74, 0x35, 0x2e, 0x31, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x77, 0x73, 0x64, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x77, 0x73, 0x64, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x77, 0x73, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x77, 0x73, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x37, 0x7a, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x09, 0x09, 0x09, 0x37, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x61, 0x62, 0x69, 0x77, 0x6f, 0x72, 0x64, 0x09, 0x09, 0x09, 0x09, 0x61, 0x62, 0x77, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x61, 0x63, 0x65, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x09, 0x09, 0x09, 0x61, 0x63, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x61, 0x6d, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2d, 0x64, 0x69, 0x73, 0x6b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x09, 0x09, 0x09, 0x64, 0x6d, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x62, 0x69, 0x6e, 0x09, 0x09, 0x09, 0x61, 0x61, 0x62, 0x20, 0x78, 0x33, 0x32, 0x20, 0x75, 0x33, 0x32, 0x20, 0x76, 0x6f, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x6d, 0x61, 0x70, 0x09, 0x09, 0x09, 0x61, 0x61, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x73, 0x65, 0x67, 0x09, 0x09, 0x09, 0x61, 0x61, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x62, 0x63, 0x70, 0x69, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x62, 0x63, 0x70, 0x69, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x62, 0x69, 0x74, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x09, 0x09, 0x09, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x62, 0x6c, 0x6f, 0x72, 0x62, 0x09, 0x09, 0x09, 0x09, 0x62, 0x6c, 0x62, 0x20, 0x62, 0x6c, 0x6f, 0x72, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x62, 0x7a, 0x69, 0x70, 0x09, 0x09, 0x09, 0x09, 0x62, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x62, 0x7a, 0x69, 0x70, 0x32, 0x09, 0x09, 0x09, 0x09, 0x62, 0x7a, 0x32, 0x20, 0x62, 0x6f, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x63, 0x62, 0x72, 0x09, 0x09, 0x09, 0x09, 0x63, 0x62, 0x72, 0x20, 0x63, 0x62, 0x61, 0x20, 0x63, 0x62, 0x74, 0x20, 0x63, 0x62, 0x7a, 0x20, 0x63, 0x62, 0x37, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x63, 0x64, 0x6c, 0x69, 0x6e, 0x6b, 0x09, 0x09, 0x09, 0x09, 0x76, 0x63, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x63, 0x66, 0x73, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x09, 0x09, 0x09, 0x63, 0x66, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x63, 0x68, 0x61, 0x74, 0x09, 0x09, 0x09, 0x09, 0x63, 0x68, 0x61, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x63, 0x68, 0x65, 0x73, 0x73, 0x2d, 0x70, 0x67, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x70, 0x67, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x09, 0x09, 0x09, 0x6e, 0x73, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x63, 0x70, 0x69, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x63, 0x70, 0x69, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x63, 0x73, 0x68, 0x09, 0x09, 0x09, 0x09, 0x63, 0x73, 0x68, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x64, 0x65, 0x62, 0x69, 0x61, 0x6e, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x09, 0x09, 0x09, 0x64, 0x65, 0x62, 0x20, 0x75, 0x64, 0x65, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x64, 0x67, 0x63, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x09, 0x09, 0x09, 0x64, 0x67, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x09, 0x09, 0x09, 0x64, 0x69, 0x72, 0x20, 0x64, 0x63, 0x72, 0x20, 0x64, 0x78, 0x72, 0x20, 0x63, 0x73, 0x74, 0x20, 0x63, 0x63, 0x74, 0x20, 0x63, 0x78, 0x74, 0x20, 0x77, 0x33, 0x64, 0x20, 0x66, 0x67, 0x64, 0x20, 0x73, 0x77, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x64, 0x6f, 0x6f, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x77, 0x61, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x64, 0x74, 0x62, 0x6e, 0x63, 0x78, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x6e, 0x63, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x64, 0x74, 0x62, 0x6f, 0x6f, 0x6b, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x64, 0x74, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x64, 0x74, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x72, 0x65, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x64, 0x76, 0x69, 0x09, 0x09, 0x09, 0x09, 0x64, 0x76, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x09, 0x09, 0x09, 0x09, 0x65, 0x76, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x65, 0x76, 0x61, 0x09, 0x09, 0x09, 0x09, 0x65, 0x76, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x62, 0x64, 0x66, 0x09, 0x09, 0x09, 0x09, 0x62, 0x64, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x64, 0x6f, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x6d, 0x61, 0x6b, 0x65, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x67, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x09, 0x09, 0x09, 0x67, 0x73, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x6c, 0x69, 0x62, 0x67, 0x72, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2d, 0x70, 0x73, 0x66, 0x09, 0x09, 0x09, 0x70, 0x73, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x6f, 0x74, 0x66, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x74, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x70, 0x63, 0x66, 0x09, 0x09, 0x09, 0x09, 0x70, 0x63, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x6e, 0x66, 0x09, 0x09, 0x09, 0x09, 0x73, 0x6e, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x70, 0x65, 0x65, 0x64, 0x6f, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x75, 0x6e, 0x6f, 0x73, 0x2d, 0x6e, 0x65, 0x77, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x74, 0x74, 0x66, 0x09, 0x09, 0x09, 0x09, 0x74, 0x74, 0x66, 0x20, 0x74, 0x74, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x31, 0x09, 0x09, 0x09, 0x70, 0x66, 0x61, 0x20, 0x70, 0x66, 0x62, 0x20, 0x70, 0x66, 0x6d, 0x20, 0x61, 0x66, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x6f, 0x66, 0x66, 0x09, 0x09, 0x09, 0x09, 0x77, 0x6f, 0x66, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x76, 0x66, 0x6f, 0x6e, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x72, 0x65, 0x65, 0x61, 0x72, 0x63, 0x09, 0x09, 0x09, 0x09, 0x61, 0x72, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x73, 0x70, 0x6c, 0x61, 0x73, 0x68, 0x09, 0x09, 0x09, 0x73, 0x70, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x67, 0x63, 0x61, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x09, 0x09, 0x09, 0x67, 0x63, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x67, 0x6c, 0x75, 0x6c, 0x78, 0x09, 0x09, 0x09, 0x09, 0x75, 0x6c, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x67, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x09, 0x09, 0x09, 0x09, 0x67, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x67, 0x72, 0x61, 0x6d, 0x70, 0x73, 0x2d, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x67, 0x72, 0x61, 0x6d, 0x70, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x67, 0x74, 0x61, 0x72, 0x09, 0x09, 0x09, 0x09, 0x67, 0x74, 0x61, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x67, 0x7a, 0x69, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x68, 0x64, 0x66, 0x09, 0x09, 0x09, 0x09, 0x68, 0x64, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x09, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x69, 0x73, 0x6f, 0x39, 0x36, 0x36, 0x30, 0x2d, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x09, 0x09, 0x09, 0x69, 0x73, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6a, 0x61, 0x76, 0x61, 0x2d, 0x6a, 0x6e, 0x6c, 0x70, 0x2d, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x6a, 0x6e, 0x6c, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6c, 0x61, 0x74, 0x65, 0x78, 0x09, 0x09, 0x09, 0x09, 0x6c, 0x61, 0x74, 0x65, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6c, 0x7a, 0x68, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x09, 0x09, 0x09, 0x6c, 0x7a, 0x68, 0x20, 0x6c, 0x68, 0x61, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x69, 0x65, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x69, 0x65, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x6f, 0x62, 0x69, 0x70, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x09, 0x09, 0x09, 0x70, 0x72, 0x63, 0x20, 0x6d, 0x6f, 0x62, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x09, 0x09, 0x09, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x09, 0x09, 0x09, 0x6c, 0x6e, 0x6b, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x64, 0x09, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x7a, 0x09, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, 0x62, 0x61, 0x70, 0x09, 0x09, 0x09, 0x09, 0x78, 0x62, 0x61, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x64, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x62, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x62, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x63, 0x61, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x63, 0x72, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x63, 0x6c, 0x69, 0x70, 0x09, 0x09, 0x09, 0x09, 0x63, 0x6c, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x09, 0x09, 0x09, 0x65, 0x78, 0x65, 0x20, 0x64, 0x6c, 0x6c, 0x20, 0x63, 0x6f, 0x6d, 0x20, 0x62, 0x61, 0x74, 0x20, 0x6d, 0x73, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x76, 0x69, 0x65, 0x77, 0x09, 0x09, 0x09, 0x6d, 0x76, 0x62, 0x20, 0x6d, 0x31, 0x33, 0x20, 0x6d, 0x31, 0x34, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x6d, 0x65, 0x74, 0x61, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x66, 0x20, 0x77, 0x6d, 0x7a, 0x20, 0x65, 0x6d, 0x66, 0x20, 0x65, 0x6d, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x6e, 0x79, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x09, 0x09, 0x09, 0x70, 0x75, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x73, 0x63, 0x64, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x09, 0x09, 0x09, 0x74, 0x72, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x77, 0x72, 0x69, 0x74, 0x65, 0x09, 0x09, 0x09, 0x09, 0x77, 0x72, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6e, 0x65, 0x74, 0x63, 0x64, 0x66, 0x09, 0x09, 0x09, 0x09, 0x6e, 0x63, 0x20, 0x63, 0x64, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6e, 0x7a, 0x62, 0x09, 0x09, 0x09, 0x09, 0x6e, 0x7a, 0x62, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x70, 0x6b, 0x63, 0x73, 0x31, 0x32, 0x09, 0x09, 0x09, 0x09, 0x70, 0x31, 0x32, 0x20, 0x70, 0x66, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x70, 0x6b, 0x63, 0x73, 0x37, 0x2d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x09, 0x09, 0x70, 0x37, 0x62, 0x20, 0x73, 0x70, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x70, 0x6b, 0x63, 0x73, 0x37, 0x2d, 0x63, 0x65, 0x72, 0x74, 0x72, 0x65, 0x71, 0x72, 0x65, 0x73, 0x70, 0x09, 0x09, 0x09, 0x70, 0x37, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x72, 0x61, 0x72, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x09, 0x09, 0x09, 0x72, 0x61, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x72, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x09, 0x09, 0x72, 0x69, 0x73, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x68, 0x09, 0x09, 0x09, 0x09, 0x73, 0x68, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x68, 0x61, 0x72, 0x09, 0x09, 0x09, 0x09, 0x73, 0x68, 0x61, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x68, 0x6f, 0x63, 0x6b, 0x77, 0x61, 0x76, 0x65, 0x2d, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x09, 0x09, 0x09, 0x73, 0x77, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x69, 0x6c, 0x76, 0x65, 0x72, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x2d, 0x61, 0x70, 0x70, 0x09, 0x09, 0x09, 0x78, 0x61, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x71, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x73, 0x71, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x74, 0x75, 0x66, 0x66, 0x69, 0x74, 0x09, 0x09, 0x09, 0x09, 0x73, 0x69, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x74, 0x75, 0x66, 0x66, 0x69, 0x74, 0x78, 0x09, 0x09, 0x09, 0x09, 0x73, 0x69, 0x74, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x75, 0x62, 0x72, 0x69, 0x70, 0x09, 0x09, 0x09, 0x09, 0x73, 0x72, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x76, 0x34, 0x63, 0x70, 0x69, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x73, 0x76, 0x34, 0x63, 0x70, 0x69, 0x6f, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x73, 0x76, 0x34, 0x63, 0x72, 0x63, 0x09, 0x09, 0x09, 0x09, 0x73, 0x76, 0x34, 0x63, 0x72, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x74, 0x33, 0x76, 0x6d, 0x2d, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x09, 0x09, 0x09, 0x74, 0x33, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x74, 0x61, 0x64, 0x73, 0x09, 0x09, 0x09, 0x09, 0x67, 0x61, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x74, 0x61, 0x72, 0x09, 0x09, 0x09, 0x09, 0x74, 0x61, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x74, 0x63, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x74, 0x63, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x74, 0x65, 0x78, 0x09, 0x09, 0x09, 0x09, 0x74, 0x65, 0x78, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x74, 0x65, 0x78, 0x2d, 0x74, 0x66, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x74, 0x66, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x74, 0x65, 0x78, 0x69, 0x6e, 0x66, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x74, 0x65, 0x78, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x74, 0x65, 0x78, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x74, 0x67, 0x69, 0x66, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x62, 0x6a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x75, 0x73, 0x74, 0x61, 0x72, 0x09, 0x09, 0x09, 0x09, 0x75, 0x73, 0x74, 0x61, 0x72, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x77, 0x61, 0x69, 0x73, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x09, 0x09, 0x09, 0x73, 0x72, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x78, 0x35, 0x30, 0x39, 0x2d, 0x63, 0x61, 0x2d, 0x63, 0x65, 0x72, 0x74, 0x09, 0x09, 0x09, 0x64, 0x65, 0x72, 0x20, 0x63, 0x72, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x78, 0x66, 0x69, 0x67, 0x09, 0x09, 0x09, 0x09, 0x66, 0x69, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x78, 0x6c, 0x69, 0x66, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x6c, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x78, 0x70, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x70, 0x69, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x78, 0x7a, 0x09, 0x09, 0x09, 0x09, 0x78, 0x7a, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x7a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x09, 0x09, 0x09, 0x09, 0x7a, 0x31, 0x20, 0x7a, 0x32, 0x20, 0x7a, 0x33, 0x20, 0x7a, 0x34, 0x20, 0x7a, 0x35, 0x20, 0x7a, 0x36, 0x20, 0x7a, 0x37, 0x20, 0x7a, 0x38, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x34, 0x30, 0x30, 0x2d, 0x62, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x61, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x63, 0x61, 0x70, 0x2d, 0x61, 0x74, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x63, 0x61, 0x70, 0x2d, 0x63, 0x61, 0x70, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x63, 0x61, 0x70, 0x2d, 0x64, 0x69, 0x66, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x78, 0x64, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x63, 0x61, 0x70, 0x2d, 0x65, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x63, 0x61, 0x70, 0x2d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x63, 0x61, 0x70, 0x2d, 0x6e, 0x73, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x63, 0x6f, 0x6e, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x2d, 0x64, 0x69, 0x66, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x63, 0x6f, 0x6e, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x65, 0x6e, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x65, 0x6e, 0x63, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x78, 0x68, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x68, 0x74, 0x6d, 0x6c, 0x2d, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x6d, 0x6c, 0x20, 0x78, 0x73, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6d, 0x6c, 0x2d, 0x64, 0x74, 0x64, 0x09, 0x09, 0x09, 0x09, 0x64, 0x74, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6d, 0x6c, 0x2d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2d, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2d, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6d, 0x70, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6f, 0x70, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x6f, 0x70, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x70, 0x72, 0x6f, 0x63, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x70, 0x6c, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x73, 0x6c, 0x74, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x73, 0x6c, 0x74, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x73, 0x70, 0x66, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x78, 0x73, 0x70, 0x66, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x76, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x78, 0x6d, 0x6c, 0x20, 0x78, 0x68, 0x76, 0x6d, 0x6c, 0x20, 0x78, 0x76, 0x6d, 0x6c, 0x20, 0x78, 0x76, 0x6d, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x79, 0x61, 0x6e, 0x67, 0x09, 0x09, 0x09, 0x09, 0x79, 0x61, 0x6e, 0x67, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x79, 0x69, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x79, 0x69, 0x6e, 0x0a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x7a, 0x69, 0x70, 0x09, 0x09, 0x09, 0x09, 0x09, 0x7a, 0x69, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x31, 0x64, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x64, 0x2d, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x33, 0x32, 0x6b, 0x61, 0x64, 0x70, 0x63, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x33, 0x67, 0x70, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x33, 0x67, 0x70, 0x70, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x63, 0x33, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x64, 0x70, 0x63, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x09, 0x61, 0x64, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x6d, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x6d, 0x72, 0x2d, 0x77, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x6d, 0x72, 0x2d, 0x77, 0x62, 0x2b, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x73, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x74, 0x72, 0x61, 0x63, 0x2d, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x2d, 0x6c, 0x6f, 0x73, 0x73, 0x6c, 0x65, 0x73, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x74, 0x72, 0x61, 0x63, 0x2d, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x74, 0x72, 0x61, 0x63, 0x33, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x09, 0x09, 0x09, 0x09, 0x09, 0x61, 0x75, 0x20, 0x73, 0x6e, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x62, 0x76, 0x31, 0x36, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x62, 0x76, 0x33, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x6d, 0x6f, 0x64, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x63, 0x6e, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x64, 0x61, 0x74, 0x31, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x64, 0x6c, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x64, 0x73, 0x72, 0x2d, 0x65, 0x73, 0x32, 0x30, 0x31, 0x31, 0x30, 0x38, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x64, 0x73, 0x72, 0x2d, 0x65, 0x73, 0x32, 0x30, 0x32, 0x30, 0x35, 0x30, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x64, 0x73, 0x72, 0x2d, 0x65, 0x73, 0x32, 0x30, 0x32, 0x32, 0x31, 0x31, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x64, 0x73, 0x72, 0x2d, 0x65, 0x73, 0x32, 0x30, 0x32, 0x32, 0x31, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x64, 0x76, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x64, 0x76, 0x69, 0x34, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x61, 0x63, 0x33, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x2d, 0x71, 0x63, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x30, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x31, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x62, 0x30, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x62, 0x31, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x77, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x77, 0x62, 0x30, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x76, 0x72, 0x63, 0x77, 0x62, 0x31, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x66, 0x77, 0x64, 0x72, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x31, 0x39, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x32, 0x31, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x33, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x36, 0x2d, 0x31, 0x36, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x36, 0x2d, 0x32, 0x34, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x36, 0x2d, 0x33, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x36, 0x2d, 0x34, 0x30, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x38, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x39, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x39, 0x31, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x39, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x37, 0x32, 0x39, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x73, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x73, 0x6d, 0x2d, 0x65, 0x66, 0x72, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x67, 0x73, 0x6d, 0x2d, 0x68, 0x72, 0x2d, 0x30, 0x38, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x69, 0x6c, 0x62, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x69, 0x70, 0x2d, 0x6d, 0x72, 0x5f, 0x76, 0x32, 0x2e, 0x35, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x69, 0x73, 0x61, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6c, 0x31, 0x36, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6c, 0x32, 0x30, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6c, 0x32, 0x34, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6c, 0x38, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6c, 0x70, 0x63, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x64, 0x69, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x69, 0x64, 0x20, 0x6d, 0x69, 0x64, 0x69, 0x20, 0x6b, 0x61, 0x72, 0x20, 0x72, 0x6d, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x2d, 0x78, 0x6d, 0x66, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6d, 0x70, 0x34, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x70, 0x34, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6d, 0x70, 0x34, 0x61, 0x2d, 0x6c, 0x61, 0x74, 0x6d, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6d, 0x70, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6d, 0x70, 0x61, 0x2d, 0x72, 0x6f, 0x62, 0x75, 0x73, 0x74, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6d, 0x70, 0x65, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x70, 0x67, 0x61, 0x20, 0x6d, 0x70, 0x32, 0x20, 0x6d, 0x70, 0x32, 0x61, 0x20, 0x6d, 0x70, 0x33, 0x20, 0x6d, 0x32, 0x61, 0x20, 0x6d, 0x33, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6d, 0x70, 0x65, 0x67, 0x34, 0x2d, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6d, 0x75, 0x73, 0x65, 0x70, 0x61, 0x63, 0x6b, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6f, 0x67, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x67, 0x61, 0x20, 0x6f, 0x67, 0x67, 0x20, 0x73, 0x70, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x6f, 0x70, 0x75, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x70, 0x63, 0x6d, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x70, 0x63, 0x6d, 0x61, 0x2d, 0x77, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x70, 0x63, 0x6d, 0x75, 0x2d, 0x77, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x70, 0x63, 0x6d, 0x75, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x73, 0x69, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x71, 0x63, 0x65, 0x6c, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x72, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x65, 0x6e, 0x63, 0x2d, 0x61, 0x65, 0x73, 0x63, 0x6d, 0x31, 0x32, 0x38, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x6d, 0x69, 0x64, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x72, 0x74, 0x78, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x33, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x09, 0x73, 0x33, 0x6d, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x69, 0x6c, 0x6b, 0x09, 0x09, 0x09, 0x09, 0x09, 0x73, 0x69, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x6d, 0x76, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x6d, 0x76, 0x30, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x6d, 0x76, 0x2d, 0x71, 0x63, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x70, 0x2d, 0x6d, 0x69, 0x64, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x73, 0x70, 0x65, 0x65, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x74, 0x31, 0x34, 0x30, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x74, 0x33, 0x38, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x74, 0x6f, 0x6e, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x75, 0x65, 0x6d, 0x63, 0x6c, 0x69, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x75, 0x6c, 0x70, 0x66, 0x65, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x64, 0x76, 0x69, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6d, 0x72, 0x2d, 0x77, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x33, 0x67, 0x70, 0x70, 0x2e, 0x69, 0x75, 0x66, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x34, 0x73, 0x62, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x6b, 0x6f, 0x7a, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x65, 0x6c, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2e, 0x6e, 0x73, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6d, 0x6c, 0x65, 0x73, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6e, 0x73, 0x2e, 0x61, 0x6e, 0x70, 0x31, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6e, 0x73, 0x2e, 0x69, 0x6e, 0x66, 0x31, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x75, 0x76, 0x61, 0x20, 0x75, 0x76, 0x76, 0x61, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x2d, 0x77, 0x69, 0x6e, 0x64, 0x73, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6f, 0x6c, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6c, 0x6e, 0x61, 0x2e, 0x61, 0x64, 0x74, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x68, 0x65, 0x61, 0x61, 0x63, 0x2e, 0x31, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x68, 0x65, 0x61, 0x61, 0x63, 0x2e, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x6d, 0x6c, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x6d, 0x70, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x70, 0x6c, 0x32, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x70, 0x6c, 0x32, 0x78, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x70, 0x6c, 0x32, 0x7a, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6f, 0x6c, 0x62, 0x79, 0x2e, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x2e, 0x31, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x72, 0x61, 0x09, 0x09, 0x09, 0x09, 0x09, 0x64, 0x72, 0x61, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x74, 0x73, 0x09, 0x09, 0x09, 0x09, 0x09, 0x64, 0x74, 0x73, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x74, 0x73, 0x2e, 0x68, 0x64, 0x09, 0x09, 0x09, 0x09, 0x64, 0x74, 0x73, 0x68, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x72, 0x61, 0x64, 0x2e, 0x70, 0x6c, 0x6a, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x6e, 0x73, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x75, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x09, 0x09, 0x09, 0x09, 0x6c, 0x76, 0x70, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6c, 0x61, 0x79, 0x72, 0x65, 0x61, 0x64, 0x79, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x70, 0x79, 0x61, 0x09, 0x09, 0x70, 0x79, 0x61, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x2d, 0x78, 0x6d, 0x66, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x72, 0x74, 0x65, 0x6c, 0x2e, 0x76, 0x62, 0x6b, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x75, 0x65, 0x72, 0x61, 0x2e, 0x65, 0x63, 0x65, 0x6c, 0x70, 0x34, 0x38, 0x30, 0x30, 0x09, 0x09, 0x09, 0x65, 0x63, 0x65, 0x6c, 0x70, 0x34, 0x38, 0x30, 0x30, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x75, 0x65, 0x72, 0x61, 0x2e, 0x65, 0x63, 0x65, 0x6c, 0x70, 0x37, 0x34, 0x37, 0x30, 0x09, 0x09, 0x09, 0x65, 0x63, 0x65, 0x6c, 0x70, 0x37, 0x34, 0x37, 0x30, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x75, 0x65, 0x72, 0x61, 0x2e, 0x65, 0x63, 0x65, 0x6c, 0x70, 0x39, 0x36, 0x30, 0x30, 0x09, 0x09, 0x09, 0x65, 0x63, 0x65, 0x6c, 0x70, 0x39, 0x36, 0x30, 0x30, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x63, 0x74, 0x65, 0x6c, 0x2e, 0x73, 0x62, 0x63, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x71, 0x63, 0x65, 0x6c, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x68, 0x65, 0x74, 0x6f, 0x72, 0x65, 0x78, 0x2e, 0x33, 0x32, 0x6b, 0x61, 0x64, 0x70, 0x63, 0x6d, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x69, 0x70, 0x09, 0x09, 0x09, 0x09, 0x09, 0x72, 0x69, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x73, 0x6f, 0x66, 0x74, 0x73, 0x65, 0x61, 0x6c, 0x2e, 0x6d, 0x70, 0x65, 0x67, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x6d, 0x78, 0x2e, 0x63, 0x76, 0x73, 0x64, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6f, 0x72, 0x62, 0x69, 0x73, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x76, 0x6f, 0x72, 0x62, 0x69, 0x73, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x77, 0x65, 0x62, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x65, 0x62, 0x61, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x61, 0x61, 0x63, 0x09, 0x09, 0x09, 0x09, 0x09, 0x61, 0x61, 0x63, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x61, 0x69, 0x66, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x61, 0x69, 0x66, 0x20, 0x61, 0x69, 0x66, 0x66, 0x20, 0x61, 0x69, 0x66, 0x63, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x63, 0x61, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x61, 0x66, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x66, 0x6c, 0x61, 0x63, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x6c, 0x61, 0x63, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x61, 0x74, 0x72, 0x6f, 0x73, 0x6b, 0x61, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x6b, 0x61, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x70, 0x65, 0x67, 0x75, 0x72, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x33, 0x75, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x77, 0x61, 0x78, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x61, 0x78, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x61, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x61, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x70, 0x6e, 0x2d, 0x72, 0x65, 0x61, 0x6c, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x72, 0x61, 0x6d, 0x20, 0x72, 0x61, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x70, 0x6e, 0x2d, 0x72, 0x65, 0x61, 0x6c, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2d, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x09, 0x09, 0x09, 0x72, 0x6d, 0x70, 0x0a, 0x23, 0x20, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x74, 0x74, 0x61, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x2d, 0x77, 0x61, 0x76, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x61, 0x76, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x78, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x6d, 0x0a, 0x63, 0x68, 0x65, 0x6d, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x78, 0x2d, 0x63, 0x64, 0x78, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x64, 0x78, 0x0a, 0x63, 0x68, 0x65, 0x6d, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x78, 0x2d, 0x63, 0x69, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x69, 0x66, 0x0a, 0x63, 0x68, 0x65, 0x6d, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x78, 0x2d, 0x63, 0x6d, 0x64, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x6d, 0x64, 0x66, 0x0a, 0x63, 0x68, 0x65, 0x6d, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x78, 0x2d, 0x63, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x6d, 0x6c, 0x0a, 0x63, 0x68, 0x65, 0x6d, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x78, 0x2d, 0x63, 0x73, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x73, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x63, 0x68, 0x65, 0x6d, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x78, 0x2d, 0x70, 0x64, 0x62, 0x0a, 0x63, 0x68, 0x65, 0x6d, 0x69, 0x63, 0x61, 0x6c, 0x2f, 0x78, 0x2d, 0x78, 0x79, 0x7a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x79, 0x7a, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x62, 0x6d, 0x70, 0x09, 0x09, 0x09, 0x09, 0x09, 0x62, 0x6d, 0x70, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x63, 0x67, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x67, 0x6d, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x66, 0x69, 0x74, 0x73, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x33, 0x66, 0x61, 0x78, 0x09, 0x09, 0x09, 0x09, 0x09, 0x67, 0x33, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x67, 0x69, 0x66, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x69, 0x65, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x65, 0x66, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x32, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x65, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x70, 0x65, 0x67, 0x20, 0x6a, 0x70, 0x67, 0x20, 0x6a, 0x70, 0x65, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x6d, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x78, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6b, 0x74, 0x78, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6b, 0x74, 0x78, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6e, 0x61, 0x70, 0x6c, 0x70, 0x73, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x70, 0x6e, 0x67, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x62, 0x74, 0x69, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x62, 0x74, 0x69, 0x66, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x70, 0x74, 0x69, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x73, 0x67, 0x69, 0x09, 0x09, 0x09, 0x09, 0x09, 0x73, 0x67, 0x69, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x73, 0x76, 0x67, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x73, 0x76, 0x67, 0x20, 0x73, 0x76, 0x67, 0x7a, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x33, 0x38, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x69, 0x66, 0x66, 0x20, 0x74, 0x69, 0x66, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x2d, 0x66, 0x78, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x09, 0x09, 0x09, 0x70, 0x73, 0x64, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6e, 0x73, 0x2e, 0x69, 0x6e, 0x66, 0x32, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x09, 0x09, 0x09, 0x09, 0x75, 0x76, 0x69, 0x20, 0x75, 0x76, 0x76, 0x69, 0x20, 0x75, 0x76, 0x67, 0x20, 0x75, 0x76, 0x76, 0x67, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x73, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x09, 0x73, 0x75, 0x62, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6a, 0x76, 0x75, 0x09, 0x09, 0x09, 0x09, 0x09, 0x64, 0x6a, 0x76, 0x75, 0x20, 0x64, 0x6a, 0x76, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x77, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x64, 0x77, 0x67, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x78, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x64, 0x78, 0x66, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x61, 0x73, 0x74, 0x62, 0x69, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74, 0x09, 0x09, 0x09, 0x09, 0x66, 0x62, 0x73, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x70, 0x78, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x70, 0x78, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x73, 0x74, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x73, 0x74, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x78, 0x65, 0x72, 0x6f, 0x78, 0x2e, 0x65, 0x64, 0x6d, 0x69, 0x63, 0x73, 0x2d, 0x6d, 0x6d, 0x72, 0x09, 0x09, 0x09, 0x6d, 0x6d, 0x72, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x75, 0x6a, 0x69, 0x78, 0x65, 0x72, 0x6f, 0x78, 0x2e, 0x65, 0x64, 0x6d, 0x69, 0x63, 0x73, 0x2d, 0x72, 0x6c, 0x63, 0x09, 0x09, 0x09, 0x72, 0x6c, 0x63, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x67, 0x62, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x69, 0x63, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x69, 0x78, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x64, 0x69, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x77, 0x64, 0x70, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x65, 0x74, 0x2d, 0x66, 0x70, 0x78, 0x09, 0x09, 0x09, 0x09, 0x6e, 0x70, 0x78, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x70, 0x6e, 0x67, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x73, 0x6f, 0x66, 0x74, 0x73, 0x65, 0x61, 0x6c, 0x2e, 0x67, 0x69, 0x66, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x73, 0x6f, 0x66, 0x74, 0x73, 0x65, 0x61, 0x6c, 0x2e, 0x6a, 0x70, 0x67, 0x0a, 0x23, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x76, 0x66, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x77, 0x62, 0x6d, 0x70, 0x09, 0x09, 0x09, 0x09, 0x77, 0x62, 0x6d, 0x70, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x78, 0x69, 0x66, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x69, 0x66, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x77, 0x65, 0x62, 0x70, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x65, 0x62, 0x70, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x33, 0x64, 0x73, 0x09, 0x09, 0x09, 0x09, 0x09, 0x33, 0x64, 0x73, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x63, 0x6d, 0x75, 0x2d, 0x72, 0x61, 0x73, 0x74, 0x65, 0x72, 0x09, 0x09, 0x09, 0x09, 0x72, 0x61, 0x73, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x63, 0x6d, 0x78, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x6d, 0x78, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x66, 0x72, 0x65, 0x65, 0x68, 0x61, 0x6e, 0x64, 0x09, 0x09, 0x09, 0x09, 0x66, 0x68, 0x20, 0x66, 0x68, 0x63, 0x20, 0x66, 0x68, 0x34, 0x20, 0x66, 0x68, 0x35, 0x20, 0x66, 0x68, 0x37, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x69, 0x63, 0x6f, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x63, 0x6f, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x6d, 0x72, 0x73, 0x69, 0x64, 0x2d, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x09, 0x09, 0x09, 0x09, 0x73, 0x69, 0x64, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x70, 0x63, 0x78, 0x09, 0x09, 0x09, 0x09, 0x09, 0x70, 0x63, 0x78, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x70, 0x69, 0x63, 0x74, 0x09, 0x09, 0x09, 0x09, 0x09, 0x70, 0x69, 0x63, 0x20, 0x70, 0x63, 0x74, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x61, 0x6e, 0x79, 0x6d, 0x61, 0x70, 0x09, 0x09, 0x09, 0x09, 0x70, 0x6e, 0x6d, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x09, 0x09, 0x09, 0x09, 0x70, 0x62, 0x6d, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x67, 0x72, 0x61, 0x79, 0x6d, 0x61, 0x70, 0x09, 0x09, 0x09, 0x70, 0x67, 0x6d, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x70, 0x69, 0x78, 0x6d, 0x61, 0x70, 0x09, 0x09, 0x09, 0x09, 0x70, 0x70, 0x6d, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x72, 0x67, 0x62, 0x09, 0x09, 0x09, 0x09, 0x09, 0x72, 0x67, 0x62, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x74, 0x67, 0x61, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x67, 0x61, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x62, 0x6d, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x78, 0x70, 0x69, 0x78, 0x6d, 0x61, 0x70, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x70, 0x6d, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, 0x2d, 0x78, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x64, 0x75, 0x6d, 0x70, 0x09, 0x09, 0x09, 0x09, 0x78, 0x77, 0x64, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x63, 0x70, 0x69, 0x6d, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2d, 0x62, 0x6f, 0x64, 0x79, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x66, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x2d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2d, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2d, 0x64, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x69, 0x6d, 0x64, 0x6e, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x6e, 0x65, 0x77, 0x73, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x72, 0x66, 0x63, 0x38, 0x32, 0x32, 0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6d, 0x6c, 0x20, 0x6d, 0x69, 0x6d, 0x65, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x73, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x73, 0x69, 0x70, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x73, 0x69, 0x70, 0x66, 0x72, 0x61, 0x67, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x0a, 0x23, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x69, 0x2e, 0x73, 0x69, 0x6d, 0x70, 0x0a, 0x23, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x69, 0x67, 0x65, 0x73, 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x67, 0x73, 0x20, 0x69, 0x67, 0x65, 0x73, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x6d, 0x65, 0x73, 0x68, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x73, 0x68, 0x20, 0x6d, 0x65, 0x73, 0x68, 0x20, 0x73, 0x69, 0x6c, 0x6f, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x64, 0x61, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x64, 0x61, 0x65, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x77, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x64, 0x77, 0x66, 0x0a, 0x23, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x6c, 0x61, 0x74, 0x6c, 0x61, 0x6e, 0x64, 0x2e, 0x33, 0x64, 0x6d, 0x6c, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x64, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x67, 0x64, 0x6c, 0x0a, 0x23, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x73, 0x2d, 0x67, 0x64, 0x6c, 0x0a, 0x23, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x73, 0x2e, 0x67, 0x64, 0x6c, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x74, 0x77, 0x09, 0x09, 0x09, 0x09, 0x09, 0x67, 0x74, 0x77, 0x0a, 0x23, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x74, 0x73, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x74, 0x73, 0x0a, 0x23, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x2e, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x74, 0x75, 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x74, 0x75, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x76, 0x72, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x72, 0x6c, 0x20, 0x76, 0x72, 0x6d, 0x6c, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x78, 0x33, 0x64, 0x2b, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x09, 0x09, 0x09, 0x09, 0x78, 0x33, 0x64, 0x62, 0x20, 0x78, 0x33, 0x64, 0x62, 0x7a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x78, 0x33, 0x64, 0x2b, 0x76, 0x72, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x33, 0x64, 0x76, 0x20, 0x78, 0x33, 0x64, 0x76, 0x7a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x78, 0x33, 0x64, 0x2b, 0x78, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x78, 0x33, 0x64, 0x20, 0x78, 0x33, 0x64, 0x7a, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x62, 0x79, 0x74, 0x65, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2d, 0x73, 0x65, 0x74, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x31, 0x64, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x64, 0x2d, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x09, 0x09, 0x09, 0x09, 0x61, 0x70, 0x70, 0x63, 0x61, 0x63, 0x68, 0x65, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x61, 0x72, 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x63, 0x73, 0x20, 0x69, 0x66, 0x62, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x73, 0x73, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x76, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x73, 0x76, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x64, 0x6e, 0x73, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x65, 0x63, 0x6d, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x65, 0x6e, 0x72, 0x69, 0x63, 0x68, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x66, 0x77, 0x64, 0x72, 0x65, 0x64, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x68, 0x74, 0x6d, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x6e, 0x33, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6e, 0x33, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x78, 0x74, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x20, 0x64, 0x65, 0x66, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x69, 0x6e, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x66, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x73, 0x74, 0x65, 0x69, 0x6e, 0x2e, 0x72, 0x73, 0x74, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x72, 0x73, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x2e, 0x74, 0x61, 0x67, 0x09, 0x09, 0x09, 0x09, 0x64, 0x73, 0x63, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x73, 0x79, 0x73, 0x2e, 0x6d, 0x73, 0x6d, 0x6c, 0x2d, 0x62, 0x61, 0x73, 0x69, 0x63, 0x2d, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x72, 0x65, 0x64, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x72, 0x66, 0x63, 0x38, 0x32, 0x32, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x72, 0x69, 0x63, 0x68, 0x74, 0x65, 0x78, 0x74, 0x09, 0x09, 0x09, 0x09, 0x09, 0x72, 0x74, 0x78, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x72, 0x74, 0x66, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x65, 0x6e, 0x63, 0x2d, 0x61, 0x65, 0x73, 0x63, 0x6d, 0x31, 0x32, 0x38, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x72, 0x74, 0x78, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x73, 0x67, 0x6d, 0x6c, 0x20, 0x73, 0x67, 0x6d, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x74, 0x31, 0x34, 0x30, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x74, 0x61, 0x62, 0x2d, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x09, 0x09, 0x09, 0x74, 0x73, 0x76, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x74, 0x72, 0x6f, 0x66, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x20, 0x74, 0x72, 0x20, 0x72, 0x6f, 0x66, 0x66, 0x20, 0x6d, 0x61, 0x6e, 0x20, 0x6d, 0x65, 0x20, 0x6d, 0x73, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x74, 0x75, 0x72, 0x74, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x74, 0x6c, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x75, 0x6c, 0x70, 0x66, 0x65, 0x63, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x75, 0x72, 0x69, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x09, 0x09, 0x09, 0x09, 0x09, 0x75, 0x72, 0x69, 0x20, 0x75, 0x72, 0x69, 0x73, 0x20, 0x75, 0x72, 0x6c, 0x73, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x63, 0x61, 0x72, 0x64, 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x63, 0x61, 0x72, 0x64, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x61, 0x62, 0x63, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x72, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x75, 0x72, 0x6c, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x72, 0x6c, 0x2e, 0x64, 0x63, 0x75, 0x72, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x64, 0x63, 0x75, 0x72, 0x6c, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x72, 0x6c, 0x2e, 0x73, 0x63, 0x75, 0x72, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x73, 0x63, 0x75, 0x72, 0x6c, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x75, 0x72, 0x6c, 0x2e, 0x6d, 0x63, 0x75, 0x72, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x63, 0x75, 0x72, 0x6c, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x73, 0x75, 0x62, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x09, 0x73, 0x75, 0x62, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x65, 0x73, 0x6d, 0x65, 0x72, 0x74, 0x65, 0x63, 0x2e, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x6c, 0x79, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x6c, 0x79, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x6d, 0x69, 0x2e, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x74, 0x6f, 0x72, 0x09, 0x09, 0x09, 0x09, 0x66, 0x6c, 0x78, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x76, 0x69, 0x7a, 0x09, 0x09, 0x09, 0x09, 0x67, 0x76, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x33, 0x64, 0x2e, 0x33, 0x64, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x33, 0x64, 0x6d, 0x6c, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x6e, 0x33, 0x64, 0x2e, 0x73, 0x70, 0x6f, 0x74, 0x09, 0x09, 0x09, 0x09, 0x73, 0x70, 0x6f, 0x74, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x63, 0x2e, 0x6e, 0x65, 0x77, 0x73, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x63, 0x2e, 0x6e, 0x69, 0x74, 0x66, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6c, 0x61, 0x74, 0x65, 0x78, 0x2d, 0x7a, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x78, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x65, 0x74, 0x32, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x69, 0x2e, 0x75, 0x72, 0x69, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x75, 0x65, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x75, 0x6e, 0x2e, 0x6a, 0x32, 0x6d, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x09, 0x09, 0x6a, 0x61, 0x64, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x74, 0x65, 0x63, 0x68, 0x2e, 0x6c, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x74, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x73, 0x69, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x73, 0x6c, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x77, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x6c, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x77, 0x61, 0x70, 0x2e, 0x77, 0x6d, 0x6c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x09, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x6c, 0x73, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x61, 0x73, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x09, 0x73, 0x20, 0x61, 0x73, 0x6d, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x63, 0x09, 0x09, 0x09, 0x09, 0x09, 0x63, 0x20, 0x63, 0x63, 0x20, 0x63, 0x78, 0x78, 0x20, 0x63, 0x70, 0x70, 0x20, 0x68, 0x20, 0x68, 0x68, 0x20, 0x64, 0x69, 0x63, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x66, 0x6f, 0x72, 0x74, 0x72, 0x61, 0x6e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x66, 0x37, 0x37, 0x20, 0x66, 0x39, 0x30, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x6a, 0x61, 0x76, 0x61, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x61, 0x76, 0x61, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x6f, 0x70, 0x6d, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x70, 0x6d, 0x6c, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x70, 0x61, 0x73, 0x63, 0x61, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x70, 0x20, 0x70, 0x61, 0x73, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x6e, 0x66, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6e, 0x66, 0x6f, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x73, 0x65, 0x74, 0x65, 0x78, 0x74, 0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x74, 0x78, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x73, 0x66, 0x76, 0x09, 0x09, 0x09, 0x09, 0x09, 0x73, 0x66, 0x76, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x75, 0x75, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x09, 0x09, 0x09, 0x09, 0x09, 0x75, 0x75, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x76, 0x63, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x61, 0x72, 0x09, 0x09, 0x09, 0x09, 0x76, 0x63, 0x73, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x2d, 0x76, 0x63, 0x61, 0x72, 0x64, 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x63, 0x66, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x6d, 0x6c, 0x0a, 0x23, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x6d, 0x6c, 0x2d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2d, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2d, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x31, 0x64, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x64, 0x2d, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x33, 0x67, 0x70, 0x70, 0x09, 0x09, 0x09, 0x09, 0x09, 0x33, 0x67, 0x70, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x33, 0x67, 0x70, 0x70, 0x2d, 0x74, 0x74, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x33, 0x67, 0x70, 0x70, 0x32, 0x09, 0x09, 0x09, 0x09, 0x09, 0x33, 0x67, 0x32, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x62, 0x6d, 0x70, 0x65, 0x67, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x62, 0x74, 0x36, 0x35, 0x36, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x63, 0x65, 0x6c, 0x62, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x64, 0x76, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x68, 0x32, 0x36, 0x31, 0x09, 0x09, 0x09, 0x09, 0x09, 0x68, 0x32, 0x36, 0x31, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x68, 0x32, 0x36, 0x33, 0x09, 0x09, 0x09, 0x09, 0x09, 0x68, 0x32, 0x36, 0x33, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x68, 0x32, 0x36, 0x33, 0x2d, 0x31, 0x39, 0x39, 0x38, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x68, 0x32, 0x36, 0x33, 0x2d, 0x32, 0x30, 0x30, 0x30, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x68, 0x32, 0x36, 0x34, 0x09, 0x09, 0x09, 0x09, 0x09, 0x68, 0x32, 0x36, 0x34, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x68, 0x32, 0x36, 0x34, 0x2d, 0x72, 0x63, 0x64, 0x6f, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x68, 0x32, 0x36, 0x34, 0x2d, 0x73, 0x76, 0x63, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6a, 0x70, 0x65, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x70, 0x67, 0x76, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6a, 0x70, 0x65, 0x67, 0x32, 0x30, 0x30, 0x30, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6a, 0x70, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6a, 0x70, 0x6d, 0x20, 0x6a, 0x70, 0x67, 0x6d, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6d, 0x6a, 0x32, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x6a, 0x32, 0x20, 0x6d, 0x6a, 0x70, 0x32, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6d, 0x70, 0x31, 0x73, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6d, 0x70, 0x32, 0x70, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6d, 0x70, 0x32, 0x74, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6d, 0x70, 0x34, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x70, 0x34, 0x20, 0x6d, 0x70, 0x34, 0x76, 0x20, 0x6d, 0x70, 0x67, 0x34, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6d, 0x70, 0x34, 0x76, 0x2d, 0x65, 0x73, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6d, 0x70, 0x65, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x70, 0x65, 0x67, 0x20, 0x6d, 0x70, 0x67, 0x20, 0x6d, 0x70, 0x65, 0x20, 0x6d, 0x31, 0x76, 0x20, 0x6d, 0x32, 0x76, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6d, 0x70, 0x65, 0x67, 0x34, 0x2d, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6d, 0x70, 0x76, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6e, 0x76, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x6f, 0x67, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6f, 0x67, 0x76, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x74, 0x69, 0x6d, 0x65, 0x09, 0x09, 0x09, 0x09, 0x09, 0x71, 0x74, 0x20, 0x6d, 0x6f, 0x76, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x72, 0x61, 0x77, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x72, 0x74, 0x70, 0x2d, 0x65, 0x6e, 0x63, 0x2d, 0x61, 0x65, 0x73, 0x63, 0x6d, 0x31, 0x32, 0x38, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x72, 0x74, 0x78, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x73, 0x6d, 0x70, 0x74, 0x65, 0x32, 0x39, 0x32, 0x6d, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x75, 0x6c, 0x70, 0x66, 0x65, 0x63, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x63, 0x31, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x63, 0x63, 0x74, 0x76, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x68, 0x64, 0x09, 0x09, 0x09, 0x09, 0x75, 0x76, 0x68, 0x20, 0x75, 0x76, 0x76, 0x68, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x09, 0x75, 0x76, 0x6d, 0x20, 0x75, 0x76, 0x76, 0x6d, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x6d, 0x70, 0x34, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x70, 0x64, 0x09, 0x09, 0x09, 0x09, 0x75, 0x76, 0x70, 0x20, 0x75, 0x76, 0x76, 0x70, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x73, 0x64, 0x09, 0x09, 0x09, 0x09, 0x75, 0x76, 0x73, 0x20, 0x75, 0x76, 0x76, 0x73, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x65, 0x63, 0x65, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x75, 0x76, 0x76, 0x20, 0x75, 0x76, 0x76, 0x76, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x76, 0x2e, 0x6d, 0x70, 0x65, 0x67, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x76, 0x2e, 0x6d, 0x70, 0x65, 0x67, 0x2d, 0x74, 0x74, 0x73, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x6c, 0x6e, 0x61, 0x2e, 0x6d, 0x70, 0x65, 0x67, 0x2d, 0x74, 0x74, 0x73, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x64, 0x76, 0x62, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x09, 0x09, 0x09, 0x09, 0x64, 0x76, 0x62, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x66, 0x76, 0x74, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x76, 0x74, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x68, 0x6e, 0x73, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x66, 0x6f, 0x72, 0x75, 0x6d, 0x2e, 0x31, 0x64, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x2d, 0x31, 0x30, 0x31, 0x30, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x66, 0x6f, 0x72, 0x75, 0x6d, 0x2e, 0x31, 0x64, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x2d, 0x32, 0x30, 0x30, 0x35, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x66, 0x6f, 0x72, 0x75, 0x6d, 0x2e, 0x32, 0x64, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x2d, 0x31, 0x30, 0x31, 0x30, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x66, 0x6f, 0x72, 0x75, 0x6d, 0x2e, 0x32, 0x64, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79, 0x66, 0x65, 0x63, 0x2d, 0x32, 0x30, 0x30, 0x35, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x66, 0x6f, 0x72, 0x75, 0x6d, 0x2e, 0x74, 0x74, 0x73, 0x61, 0x76, 0x63, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x69, 0x70, 0x74, 0x76, 0x66, 0x6f, 0x72, 0x75, 0x6d, 0x2e, 0x74, 0x74, 0x73, 0x6d, 0x70, 0x65, 0x67, 0x32, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6c, 0x61, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x70, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x70, 0x65, 0x67, 0x75, 0x72, 0x6c, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x78, 0x75, 0x20, 0x6d, 0x34, 0x75, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6c, 0x61, 0x79, 0x72, 0x65, 0x61, 0x64, 0x79, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x70, 0x79, 0x76, 0x09, 0x09, 0x70, 0x79, 0x76, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x64, 0x2d, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6e, 0x6f, 0x6b, 0x69, 0x61, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x76, 0x6f, 0x69, 0x70, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x6d, 0x70, 0x65, 0x67, 0x31, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x6d, 0x70, 0x65, 0x67, 0x34, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0x73, 0x77, 0x66, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x73, 0x6f, 0x66, 0x74, 0x73, 0x65, 0x61, 0x6c, 0x2e, 0x6d, 0x6f, 0x76, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x75, 0x76, 0x76, 0x75, 0x2e, 0x6d, 0x70, 0x34, 0x09, 0x09, 0x09, 0x09, 0x75, 0x76, 0x75, 0x20, 0x75, 0x76, 0x76, 0x75, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x76, 0x69, 0x76, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x69, 0x76, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x77, 0x65, 0x62, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x65, 0x62, 0x6d, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x66, 0x34, 0x76, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x34, 0x76, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x66, 0x6c, 0x69, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x6c, 0x69, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x66, 0x6c, 0x76, 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x6c, 0x76, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x34, 0x76, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x34, 0x76, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x61, 0x74, 0x72, 0x6f, 0x73, 0x6b, 0x61, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x6b, 0x76, 0x20, 0x6d, 0x6b, 0x33, 0x64, 0x20, 0x6d, 0x6b, 0x73, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x6e, 0x67, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x6e, 0x67, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x61, 0x73, 0x66, 0x09, 0x09, 0x09, 0x09, 0x09, 0x61, 0x73, 0x66, 0x20, 0x61, 0x73, 0x78, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x76, 0x6f, 0x62, 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x6f, 0x62, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x76, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x76, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x77, 0x6d, 0x78, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x6d, 0x78, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x77, 0x76, 0x78, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x76, 0x78, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x09, 0x09, 0x09, 0x09, 0x09, 0x61, 0x76, 0x69, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x73, 0x67, 0x69, 0x2d, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x6f, 0x76, 0x69, 0x65, 0x0a, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x2f, 0x78, 0x2d, 0x73, 0x6d, 0x76, 0x09, 0x09, 0x09, 0x09, 0x09, 0x73, 0x6d, 0x76, 0x0a, 0x78, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2f, 0x78, 0x2d, 0x63, 0x6f, 0x6f, 0x6c, 0x74, 0x61, 0x6c, 0x6b, 0x09, 0x09, 0x09, 0x09, 0x69, 0x63, 0x65, 0x0a }; unsigned int mime_types_len = 53051; telegram-purple/tgl/mime.types000066400000000000000000001474731357227200100170050ustar00rootroot00000000000000# This file maps Internet media types to unique file extension(s). # Although created for httpd, this file is used by many software systems # and has been placed in the public domain for unlimited redisribution. # # The table below contains both registered and (common) unregistered types. # A type that has no unique extension can be ignored -- they are listed # here to guide configurations toward known types and to make it easier to # identify "new" types. File extensions are also commonly used to indicate # content languages and encodings, so choose them carefully. # # Internet media types should be registered as described in RFC 4288. # The registry is at . # # MIME type (lowercased) Extensions # ============================================ ========== # application/1d-interleaved-parityfec # application/3gpp-ims+xml # application/activemessage application/andrew-inset ez # application/applefile application/applixware aw application/atom+xml atom application/atomcat+xml atomcat # application/atomicmail application/atomsvc+xml atomsvc # application/auth-policy+xml # application/batch-smtp # application/beep+xml # application/calendar+xml # application/cals-1840 # application/ccmp+xml application/ccxml+xml ccxml application/cdmi-capability cdmia application/cdmi-container cdmic application/cdmi-domain cdmid application/cdmi-object cdmio application/cdmi-queue cdmiq # application/cea-2018+xml # application/cellml+xml # application/cfw # application/cnrp+xml # application/commonground # application/conference-info+xml # application/cpl+xml # application/csta+xml # application/cstadata+xml application/cu-seeme cu # application/cybercash application/davmount+xml davmount # application/dca-rft # application/dec-dx # application/dialog-info+xml # application/dicom # application/dns application/docbook+xml dbk # application/dskpp+xml application/dssc+der dssc application/dssc+xml xdssc # application/dvcs application/ecmascript ecma # application/edi-consent # application/edi-x12 # application/edifact application/emma+xml emma # application/epp+xml application/epub+zip epub # application/eshop # application/example application/exi exi # application/fastinfoset # application/fastsoap application/fb2 fb2 # application/fits application/font-tdpfr pfr # application/framework-attributes+xml application/gml+xml gml application/gpx+xml gpx application/gxf gxf # application/h224 # application/held+xml # application/http application/hyperstudio stk # application/ibe-key-request+xml # application/ibe-pkg-reply+xml # application/ibe-pp-data # application/iges # application/im-iscomposing+xml # application/index # application/index.cmd # application/index.obj # application/index.response # application/index.vnd application/inkml+xml ink inkml # application/iotp application/ipfix ipfix # application/ipp # application/isup application/java-archive jar application/java-serialized-object ser application/java-vm class application/javascript js application/json json application/jsonml+json jsonml # application/kpml-request+xml # application/kpml-response+xml application/lost+xml lostxml application/mac-binhex40 hqx application/mac-compactpro cpt # application/macwriteii application/mads+xml mads application/marc mrc application/marcxml+xml mrcx application/mathematica ma nb mb # application/mathml-content+xml # application/mathml-presentation+xml application/mathml+xml mathml # application/mbms-associated-procedure-description+xml # application/mbms-deregister+xml # application/mbms-envelope+xml # application/mbms-msk+xml # application/mbms-msk-response+xml # application/mbms-protection-description+xml # application/mbms-reception-report+xml # application/mbms-register+xml # application/mbms-register-response+xml # application/mbms-user-service-description+xml application/mbox mbox # application/media_control+xml application/mediaservercontrol+xml mscml application/metalink+xml metalink application/metalink4+xml meta4 application/mets+xml mets # application/mikey application/mods+xml mods # application/moss-keys # application/moss-signature # application/mosskey-data # application/mosskey-request application/mp21 m21 mp21 application/mp4 mp4s # application/mpeg4-generic # application/mpeg4-iod # application/mpeg4-iod-xmt # application/msc-ivr+xml # application/msc-mixer+xml application/msword doc dot application/mxf mxf # application/nasdata # application/news-checkgroups # application/news-groupinfo # application/news-transmission # application/nss # application/ocsp-request # application/ocsp-response application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy application/oda oda application/oebps-package+xml opf application/ogg ogx application/omdoc+xml omdoc application/onenote onetoc onetoc2 onetmp onepkg application/oxps oxps # application/parityfec application/patch-ops-error+xml xer application/pdf pdf application/pgp-encrypted pgp # application/pgp-keys application/pgp-signature asc sig application/pics-rules prf # application/pidf+xml # application/pidf-diff+xml application/pkcs10 p10 application/pkcs7-mime p7m p7c application/pkcs7-signature p7s application/pkcs8 p8 application/pkix-attr-cert ac application/pkix-cert cer application/pkix-crl crl application/pkix-pkipath pkipath application/pkixcmp pki application/pls+xml pls # application/poc-settings+xml application/postscript ai eps ps # application/prs.alvestrand.titrax-sheet application/prs.cww cww # application/prs.nprend # application/prs.plucker # application/prs.rdf-xml-crypt # application/prs.xsf+xml application/pskc+xml pskcxml # application/qsig application/rdf+xml rdf application/reginfo+xml rif application/relax-ng-compact-syntax rnc # application/remote-printing application/resource-lists+xml rl application/resource-lists-diff+xml rld # application/riscos # application/rlmi+xml application/rls-services+xml rs application/rpki-ghostbusters gbr application/rpki-manifest mft application/rpki-roa roa # application/rpki-updown application/rsd+xml rsd application/rss+xml rss application/rtf rtf # application/rtx # application/samlassertion+xml # application/samlmetadata+xml application/sbml+xml sbml application/scvp-cv-request scq application/scvp-cv-response scs application/scvp-vp-request spq application/scvp-vp-response spp application/sdp sdp # application/set-payment application/set-payment-initiation setpay # application/set-registration application/set-registration-initiation setreg # application/sgml # application/sgml-open-catalog application/shf+xml shf # application/sieve # application/simple-filter+xml # application/simple-message-summary # application/simplesymbolcontainer # application/slate # application/smil application/smil+xml smi smil # application/soap+fastinfoset # application/soap+xml application/sparql-query rq application/sparql-results+xml srx # application/spirits-event+xml application/srgs gram application/srgs+xml grxml application/sru+xml sru application/ssdl+xml ssdl application/ssml+xml ssml # application/tamp-apex-update # application/tamp-apex-update-confirm # application/tamp-community-update # application/tamp-community-update-confirm # application/tamp-error # application/tamp-sequence-adjust # application/tamp-sequence-adjust-confirm # application/tamp-status-query # application/tamp-status-response # application/tamp-update # application/tamp-update-confirm application/tei+xml tei teicorpus application/thraud+xml tfi # application/timestamp-query # application/timestamp-reply application/timestamped-data tsd # application/tve-trigger # application/ulpfec # application/vcard+xml # application/vemmi # application/vividence.scriptfile # application/vnd.3gpp.bsf+xml application/vnd.3gpp.pic-bw-large plb application/vnd.3gpp.pic-bw-small psb application/vnd.3gpp.pic-bw-var pvb # application/vnd.3gpp.sms # application/vnd.3gpp2.bcmcsinfo+xml # application/vnd.3gpp2.sms application/vnd.3gpp2.tcap tcap application/vnd.3m.post-it-notes pwn application/vnd.accpac.simply.aso aso application/vnd.accpac.simply.imp imp application/vnd.acucobol acu application/vnd.acucorp atc acutc application/vnd.adobe.air-application-installer-package+zip air application/vnd.adobe.formscentral.fcdt fcdt application/vnd.adobe.fxp fxp fxpl # application/vnd.adobe.partial-upload application/vnd.adobe.xdp+xml xdp application/vnd.adobe.xfdf xfdf # application/vnd.aether.imp # application/vnd.ah-barcode application/vnd.ahead.space ahead application/vnd.airzip.filesecure.azf azf application/vnd.airzip.filesecure.azs azs application/vnd.amazon.ebook azw application/vnd.americandynamics.acc acc application/vnd.amiga.ami ami # application/vnd.amundsen.maze+xml application/vnd.android.package-archive apk application/vnd.anser-web-certificate-issue-initiation cii application/vnd.anser-web-funds-transfer-initiation fti application/vnd.antix.game-component atx application/vnd.apple.installer+xml mpkg application/vnd.apple.mpegurl m3u8 # application/vnd.arastra.swi application/vnd.aristanetworks.swi swi application/vnd.astraea-software.iota iota application/vnd.audiograph aep # application/vnd.autopackage # application/vnd.avistar+xml application/vnd.blueice.multipass mpm # application/vnd.bluetooth.ep.oob application/vnd.bmi bmi application/vnd.businessobjects rep # application/vnd.cab-jscript # application/vnd.canon-cpdl # application/vnd.canon-lips # application/vnd.cendio.thinlinc.clientconf application/vnd.chemdraw+xml cdxml application/vnd.chipnuts.karaoke-mmd mmd application/vnd.cinderella cdy # application/vnd.cirpack.isdn-ext application/vnd.claymore cla application/vnd.cloanto.rp9 rp9 application/vnd.clonk.c4group c4g c4d c4f c4p c4u application/vnd.cluetrust.cartomobile-config c11amc application/vnd.cluetrust.cartomobile-config-pkg c11amz # application/vnd.collection+json # application/vnd.commerce-battelle application/vnd.commonspace csp application/vnd.contact.cmsg cdbcmsg application/vnd.cosmocaller cmc application/vnd.crick.clicker clkx application/vnd.crick.clicker.keyboard clkk application/vnd.crick.clicker.palette clkp application/vnd.crick.clicker.template clkt application/vnd.crick.clicker.wordbank clkw application/vnd.criticaltools.wbs+xml wbs application/vnd.ctc-posml pml # application/vnd.ctct.ws+xml # application/vnd.cups-pdf # application/vnd.cups-postscript application/vnd.cups-ppd ppd # application/vnd.cups-raster # application/vnd.cups-raw # application/vnd.curl application/vnd.curl.car car application/vnd.curl.pcurl pcurl # application/vnd.cybank application/vnd.dart dart application/vnd.data-vision.rdz rdz application/vnd.dece.data uvf uvvf uvd uvvd application/vnd.dece.ttml+xml uvt uvvt application/vnd.dece.unspecified uvx uvvx application/vnd.dece.zip uvz uvvz application/vnd.denovo.fcselayout-link fe_launch # application/vnd.dir-bi.plate-dl-nosuffix application/vnd.dna dna application/vnd.dolby.mlp mlp # application/vnd.dolby.mobile.1 # application/vnd.dolby.mobile.2 application/vnd.dpgraph dpg application/vnd.dreamfactory dfac application/vnd.ds-keypoint kpxx application/vnd.dvb.ait ait # application/vnd.dvb.dvbj # application/vnd.dvb.esgcontainer # application/vnd.dvb.ipdcdftnotifaccess # application/vnd.dvb.ipdcesgaccess # application/vnd.dvb.ipdcesgaccess2 # application/vnd.dvb.ipdcesgpdd # application/vnd.dvb.ipdcroaming # application/vnd.dvb.iptv.alfec-base # application/vnd.dvb.iptv.alfec-enhancement # application/vnd.dvb.notif-aggregate-root+xml # application/vnd.dvb.notif-container+xml # application/vnd.dvb.notif-generic+xml # application/vnd.dvb.notif-ia-msglist+xml # application/vnd.dvb.notif-ia-registration-request+xml # application/vnd.dvb.notif-ia-registration-response+xml # application/vnd.dvb.notif-init+xml # application/vnd.dvb.pfr application/vnd.dvb.service svc # application/vnd.dxr application/vnd.dynageo geo # application/vnd.easykaraoke.cdgdownload # application/vnd.ecdis-update application/vnd.ecowin.chart mag # application/vnd.ecowin.filerequest # application/vnd.ecowin.fileupdate # application/vnd.ecowin.series # application/vnd.ecowin.seriesrequest # application/vnd.ecowin.seriesupdate # application/vnd.emclient.accessrequest+xml application/vnd.enliven nml # application/vnd.eprints.data+xml application/vnd.epson.esf esf application/vnd.epson.msf msf application/vnd.epson.quickanime qam application/vnd.epson.salt slt application/vnd.epson.ssf ssf # application/vnd.ericsson.quickcall application/vnd.eszigno3+xml es3 et3 # application/vnd.etsi.aoc+xml # application/vnd.etsi.cug+xml # application/vnd.etsi.iptvcommand+xml # application/vnd.etsi.iptvdiscovery+xml # application/vnd.etsi.iptvprofile+xml # application/vnd.etsi.iptvsad-bc+xml # application/vnd.etsi.iptvsad-cod+xml # application/vnd.etsi.iptvsad-npvr+xml # application/vnd.etsi.iptvservice+xml # application/vnd.etsi.iptvsync+xml # application/vnd.etsi.iptvueprofile+xml # application/vnd.etsi.mcid+xml # application/vnd.etsi.overload-control-policy-dataset+xml # application/vnd.etsi.sci+xml # application/vnd.etsi.simservs+xml # application/vnd.etsi.tsl+xml # application/vnd.etsi.tsl.der # application/vnd.eudora.data application/vnd.ezpix-album ez2 application/vnd.ezpix-package ez3 # application/vnd.f-secure.mobile application/vnd.fdf fdf application/vnd.fdsn.mseed mseed application/vnd.fdsn.seed seed dataless # application/vnd.ffsns # application/vnd.fints application/vnd.flographit gph application/vnd.fluxtime.clip ftc # application/vnd.font-fontforge-sfd application/vnd.framemaker fm frame maker book application/vnd.frogans.fnc fnc application/vnd.frogans.ltf ltf application/vnd.fsc.weblaunch fsc application/vnd.fujitsu.oasys oas application/vnd.fujitsu.oasys2 oa2 application/vnd.fujitsu.oasys3 oa3 application/vnd.fujitsu.oasysgp fg5 application/vnd.fujitsu.oasysprs bh2 # application/vnd.fujixerox.art-ex # application/vnd.fujixerox.art4 # application/vnd.fujixerox.hbpl application/vnd.fujixerox.ddd ddd application/vnd.fujixerox.docuworks xdw application/vnd.fujixerox.docuworks.binder xbd # application/vnd.fut-misnet application/vnd.fuzzysheet fzs application/vnd.genomatix.tuxedo txd # application/vnd.geocube+xml application/vnd.geogebra.file ggb application/vnd.geogebra.tool ggt application/vnd.geometry-explorer gex gre application/vnd.geonext gxt application/vnd.geoplan g2w application/vnd.geospace g3w # application/vnd.globalplatform.card-content-mgt # application/vnd.globalplatform.card-content-mgt-response application/vnd.gmx gmx application/vnd.google-earth.kml+xml kml application/vnd.google-earth.kmz kmz application/vnd.grafeq gqf gqs # application/vnd.gridmp application/vnd.groove-account gac application/vnd.groove-help ghf application/vnd.groove-identity-message gim application/vnd.groove-injector grv application/vnd.groove-tool-message gtm application/vnd.groove-tool-template tpl application/vnd.groove-vcard vcg # application/vnd.hal+json application/vnd.hal+xml hal application/vnd.handheld-entertainment+xml zmm application/vnd.hbci hbci # application/vnd.hcl-bireports application/vnd.hhe.lesson-player les application/vnd.hp-hpgl hpgl application/vnd.hp-hpid hpid application/vnd.hp-hps hps application/vnd.hp-jlyt jlt application/vnd.hp-pcl pcl application/vnd.hp-pclxl pclxl # application/vnd.httphone application/vnd.hydrostatix.sof-data sfd-hdstx # application/vnd.hzn-3d-crossword # application/vnd.ibm.afplinedata # application/vnd.ibm.electronic-media application/vnd.ibm.minipay mpy application/vnd.ibm.modcap afp listafp list3820 application/vnd.ibm.rights-management irm application/vnd.ibm.secure-container sc application/vnd.iccprofile icc icm application/vnd.igloader igl application/vnd.immervision-ivp ivp application/vnd.immervision-ivu ivu # application/vnd.informedcontrol.rms+xml # application/vnd.informix-visionary # application/vnd.infotech.project # application/vnd.infotech.project+xml # application/vnd.innopath.wamp.notification application/vnd.insors.igm igm application/vnd.intercon.formnet xpw xpx application/vnd.intergeo i2g # application/vnd.intertrust.digibox # application/vnd.intertrust.nncp application/vnd.intu.qbo qbo application/vnd.intu.qfx qfx # application/vnd.iptc.g2.conceptitem+xml # application/vnd.iptc.g2.knowledgeitem+xml # application/vnd.iptc.g2.newsitem+xml # application/vnd.iptc.g2.newsmessage+xml # application/vnd.iptc.g2.packageitem+xml # application/vnd.iptc.g2.planningitem+xml application/vnd.ipunplugged.rcprofile rcprofile application/vnd.irepository.package+xml irp application/vnd.is-xpr xpr application/vnd.isac.fcs fcs application/vnd.jam jam # application/vnd.japannet-directory-service # application/vnd.japannet-jpnstore-wakeup # application/vnd.japannet-payment-wakeup # application/vnd.japannet-registration # application/vnd.japannet-registration-wakeup # application/vnd.japannet-setstore-wakeup # application/vnd.japannet-verification # application/vnd.japannet-verification-wakeup application/vnd.jcp.javame.midlet-rms rms application/vnd.jisp jisp application/vnd.joost.joda-archive joda application/vnd.kahootz ktz ktr application/vnd.kde.karbon karbon application/vnd.kde.kchart chrt application/vnd.kde.kformula kfo application/vnd.kde.kivio flw application/vnd.kde.kontour kon application/vnd.kde.kpresenter kpr kpt application/vnd.kde.kspread ksp application/vnd.kde.kword kwd kwt application/vnd.kenameaapp htke application/vnd.kidspiration kia application/vnd.kinar kne knp application/vnd.koan skp skd skt skm application/vnd.kodak-descriptor sse application/vnd.las.las+xml lasxml # application/vnd.liberty-request+xml application/vnd.llamagraphics.life-balance.desktop lbd application/vnd.llamagraphics.life-balance.exchange+xml lbe application/vnd.lotus-1-2-3 123 application/vnd.lotus-approach apr application/vnd.lotus-freelance pre application/vnd.lotus-notes nsf application/vnd.lotus-organizer org application/vnd.lotus-screencam scm application/vnd.lotus-wordpro lwp application/vnd.macports.portpkg portpkg # application/vnd.marlin.drm.actiontoken+xml # application/vnd.marlin.drm.conftoken+xml # application/vnd.marlin.drm.license+xml # application/vnd.marlin.drm.mdcf application/vnd.mcd mcd application/vnd.medcalcdata mc1 application/vnd.mediastation.cdkey cdkey # application/vnd.meridian-slingshot application/vnd.mfer mwf application/vnd.mfmp mfm application/vnd.micrografx.flo flo application/vnd.micrografx.igx igx application/vnd.mif mif # application/vnd.minisoft-hp3000-save # application/vnd.mitsubishi.misty-guard.trustweb application/vnd.mobius.daf daf application/vnd.mobius.dis dis application/vnd.mobius.mbk mbk application/vnd.mobius.mqy mqy application/vnd.mobius.msl msl application/vnd.mobius.plc plc application/vnd.mobius.txf txf application/vnd.mophun.application mpn application/vnd.mophun.certificate mpc # application/vnd.motorola.flexsuite # application/vnd.motorola.flexsuite.adsi # application/vnd.motorola.flexsuite.fis # application/vnd.motorola.flexsuite.gotap # application/vnd.motorola.flexsuite.kmr # application/vnd.motorola.flexsuite.ttc # application/vnd.motorola.flexsuite.wem # application/vnd.motorola.iprm application/vnd.mozilla.xul+xml xul application/vnd.ms-artgalry cil # application/vnd.ms-asf application/vnd.ms-cab-compressed cab # application/vnd.ms-color.iccprofile application/vnd.ms-excel xls xlm xla xlc xlt xlw application/vnd.ms-excel.addin.macroenabled.12 xlam application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb application/vnd.ms-excel.sheet.macroenabled.12 xlsm application/vnd.ms-excel.template.macroenabled.12 xltm application/vnd.ms-fontobject eot application/vnd.ms-htmlhelp chm application/vnd.ms-ims ims application/vnd.ms-lrm lrm # application/vnd.ms-office.activex+xml application/vnd.ms-officetheme thmx # application/vnd.ms-opentype # application/vnd.ms-package.obfuscated-opentype application/vnd.ms-pki.seccat cat application/vnd.ms-pki.stl stl # application/vnd.ms-playready.initiator+xml application/vnd.ms-powerpoint ppt pps pot application/vnd.ms-powerpoint.addin.macroenabled.12 ppam application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm application/vnd.ms-powerpoint.slide.macroenabled.12 sldm application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm application/vnd.ms-powerpoint.template.macroenabled.12 potm # application/vnd.ms-printing.printticket+xml application/vnd.ms-project mpp mpt # application/vnd.ms-tnef # application/vnd.ms-wmdrm.lic-chlg-req # application/vnd.ms-wmdrm.lic-resp # application/vnd.ms-wmdrm.meter-chlg-req # application/vnd.ms-wmdrm.meter-resp application/vnd.ms-word.document.macroenabled.12 docm application/vnd.ms-word.template.macroenabled.12 dotm application/vnd.ms-works wps wks wcm wdb application/vnd.ms-wpl wpl application/vnd.ms-xpsdocument xps application/vnd.mseq mseq # application/vnd.msign # application/vnd.multiad.creator # application/vnd.multiad.creator.cif # application/vnd.music-niff application/vnd.musician mus application/vnd.muvee.style msty application/vnd.mynfc taglet # application/vnd.ncd.control # application/vnd.ncd.reference # application/vnd.nervana # application/vnd.netfpx application/vnd.neurolanguage.nlu nlu application/vnd.nitf ntf nitf application/vnd.noblenet-directory nnd application/vnd.noblenet-sealer nns application/vnd.noblenet-web nnw # application/vnd.nokia.catalogs # application/vnd.nokia.conml+wbxml # application/vnd.nokia.conml+xml # application/vnd.nokia.isds-radio-presets # application/vnd.nokia.iptv.config+xml # application/vnd.nokia.landmark+wbxml # application/vnd.nokia.landmark+xml # application/vnd.nokia.landmarkcollection+xml # application/vnd.nokia.n-gage.ac+xml application/vnd.nokia.n-gage.data ngdat application/vnd.nokia.n-gage.symbian.install n-gage # application/vnd.nokia.ncd # application/vnd.nokia.pcd+wbxml # application/vnd.nokia.pcd+xml application/vnd.nokia.radio-preset rpst application/vnd.nokia.radio-presets rpss application/vnd.novadigm.edm edm application/vnd.novadigm.edx edx application/vnd.novadigm.ext ext # application/vnd.ntt-local.file-transfer # application/vnd.ntt-local.sip-ta_remote # application/vnd.ntt-local.sip-ta_tcp_stream application/vnd.oasis.opendocument.chart odc application/vnd.oasis.opendocument.chart-template otc application/vnd.oasis.opendocument.database odb application/vnd.oasis.opendocument.formula odf application/vnd.oasis.opendocument.formula-template odft application/vnd.oasis.opendocument.graphics odg application/vnd.oasis.opendocument.graphics-template otg application/vnd.oasis.opendocument.image odi application/vnd.oasis.opendocument.image-template oti application/vnd.oasis.opendocument.presentation odp application/vnd.oasis.opendocument.presentation-template otp application/vnd.oasis.opendocument.spreadsheet ods application/vnd.oasis.opendocument.spreadsheet-template ots application/vnd.oasis.opendocument.text odt application/vnd.oasis.opendocument.text-master odm application/vnd.oasis.opendocument.text-template ott application/vnd.oasis.opendocument.text-web oth # application/vnd.obn # application/vnd.oftn.l10n+json # application/vnd.oipf.contentaccessdownload+xml # application/vnd.oipf.contentaccessstreaming+xml # application/vnd.oipf.cspg-hexbinary # application/vnd.oipf.dae.svg+xml # application/vnd.oipf.dae.xhtml+xml # application/vnd.oipf.mippvcontrolmessage+xml # application/vnd.oipf.pae.gem # application/vnd.oipf.spdiscovery+xml # application/vnd.oipf.spdlist+xml # application/vnd.oipf.ueprofile+xml # application/vnd.oipf.userprofile+xml application/vnd.olpc-sugar xo # application/vnd.oma-scws-config # application/vnd.oma-scws-http-request # application/vnd.oma-scws-http-response # application/vnd.oma.bcast.associated-procedure-parameter+xml # application/vnd.oma.bcast.drm-trigger+xml # application/vnd.oma.bcast.imd+xml # application/vnd.oma.bcast.ltkm # application/vnd.oma.bcast.notification+xml # application/vnd.oma.bcast.provisioningtrigger # application/vnd.oma.bcast.sgboot # application/vnd.oma.bcast.sgdd+xml # application/vnd.oma.bcast.sgdu # application/vnd.oma.bcast.simple-symbol-container # application/vnd.oma.bcast.smartcard-trigger+xml # application/vnd.oma.bcast.sprov+xml # application/vnd.oma.bcast.stkm # application/vnd.oma.cab-address-book+xml # application/vnd.oma.cab-feature-handler+xml # application/vnd.oma.cab-pcc+xml # application/vnd.oma.cab-user-prefs+xml # application/vnd.oma.dcd # application/vnd.oma.dcdc application/vnd.oma.dd2+xml dd2 # application/vnd.oma.drm.risd+xml # application/vnd.oma.group-usage-list+xml # application/vnd.oma.pal+xml # application/vnd.oma.poc.detailed-progress-report+xml # application/vnd.oma.poc.final-report+xml # application/vnd.oma.poc.groups+xml # application/vnd.oma.poc.invocation-descriptor+xml # application/vnd.oma.poc.optimized-progress-report+xml # application/vnd.oma.push # application/vnd.oma.scidm.messages+xml # application/vnd.oma.xcap-directory+xml # application/vnd.omads-email+xml # application/vnd.omads-file+xml # application/vnd.omads-folder+xml # application/vnd.omaloc-supl-init application/vnd.openofficeorg.extension oxt # application/vnd.openxmlformats-officedocument.custom-properties+xml # application/vnd.openxmlformats-officedocument.customxmlproperties+xml # application/vnd.openxmlformats-officedocument.drawing+xml # application/vnd.openxmlformats-officedocument.drawingml.chart+xml # application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml # application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml # application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml # application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml # application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml # application/vnd.openxmlformats-officedocument.extended-properties+xml # application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml # application/vnd.openxmlformats-officedocument.presentationml.comments+xml # application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml # application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml # application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml application/vnd.openxmlformats-officedocument.presentationml.presentation pptx # application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml # application/vnd.openxmlformats-officedocument.presentationml.presprops+xml application/vnd.openxmlformats-officedocument.presentationml.slide sldx # application/vnd.openxmlformats-officedocument.presentationml.slide+xml # application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml # application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx # application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml # application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml # application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml # application/vnd.openxmlformats-officedocument.presentationml.tags+xml application/vnd.openxmlformats-officedocument.presentationml.template potx # application/vnd.openxmlformats-officedocument.presentationml.template.main+xml # application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx # application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx # application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml # application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml # application/vnd.openxmlformats-officedocument.theme+xml # application/vnd.openxmlformats-officedocument.themeoverride+xml # application/vnd.openxmlformats-officedocument.vmldrawing # application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml application/vnd.openxmlformats-officedocument.wordprocessingml.document docx # application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml # application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml # application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml # application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml # application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml # application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml # application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml # application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml # application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx # application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml # application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml # application/vnd.openxmlformats-package.core-properties+xml # application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml # application/vnd.openxmlformats-package.relationships+xml # application/vnd.quobject-quoxdocument # application/vnd.osa.netdeploy application/vnd.osgeo.mapguide.package mgp # application/vnd.osgi.bundle application/vnd.osgi.dp dp application/vnd.osgi.subsystem esa # application/vnd.otps.ct-kip+xml application/vnd.palm pdb pqa oprc # application/vnd.paos.xml application/vnd.pawaafile paw application/vnd.pg.format str application/vnd.pg.osasli ei6 # application/vnd.piaccess.application-licence application/vnd.picsel efif application/vnd.pmi.widget wg # application/vnd.poc.group-advertisement+xml application/vnd.pocketlearn plf application/vnd.powerbuilder6 pbd # application/vnd.powerbuilder6-s # application/vnd.powerbuilder7 # application/vnd.powerbuilder7-s # application/vnd.powerbuilder75 # application/vnd.powerbuilder75-s # application/vnd.preminet application/vnd.previewsystems.box box application/vnd.proteus.magazine mgz application/vnd.publishare-delta-tree qps application/vnd.pvi.ptid1 ptid # application/vnd.pwg-multiplexed # application/vnd.pwg-xhtml-print+xml # application/vnd.qualcomm.brew-app-res application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb # application/vnd.radisys.moml+xml # application/vnd.radisys.msml+xml # application/vnd.radisys.msml-audit+xml # application/vnd.radisys.msml-audit-conf+xml # application/vnd.radisys.msml-audit-conn+xml # application/vnd.radisys.msml-audit-dialog+xml # application/vnd.radisys.msml-audit-stream+xml # application/vnd.radisys.msml-conf+xml # application/vnd.radisys.msml-dialog+xml # application/vnd.radisys.msml-dialog-base+xml # application/vnd.radisys.msml-dialog-fax-detect+xml # application/vnd.radisys.msml-dialog-fax-sendrecv+xml # application/vnd.radisys.msml-dialog-group+xml # application/vnd.radisys.msml-dialog-speech+xml # application/vnd.radisys.msml-dialog-transform+xml # application/vnd.rainstor.data # application/vnd.rapid application/vnd.realvnc.bed bed application/vnd.recordare.musicxml mxl application/vnd.recordare.musicxml+xml musicxml # application/vnd.renlearn.rlprint application/vnd.rig.cryptonote cryptonote application/vnd.rim.cod cod application/vnd.rn-realmedia rm application/vnd.rn-realmedia-vbr rmvb application/vnd.route66.link66+xml link66 # application/vnd.rs-274x # application/vnd.ruckus.download # application/vnd.s3sms application/vnd.sailingtracker.track st # application/vnd.sbm.cid # application/vnd.sbm.mid2 # application/vnd.scribus # application/vnd.sealed.3df # application/vnd.sealed.csf # application/vnd.sealed.doc # application/vnd.sealed.eml # application/vnd.sealed.mht # application/vnd.sealed.net # application/vnd.sealed.ppt # application/vnd.sealed.tiff # application/vnd.sealed.xls # application/vnd.sealedmedia.softseal.html # application/vnd.sealedmedia.softseal.pdf application/vnd.seemail see application/vnd.sema sema application/vnd.semd semd application/vnd.semf semf application/vnd.shana.informed.formdata ifm application/vnd.shana.informed.formtemplate itp application/vnd.shana.informed.interchange iif application/vnd.shana.informed.package ipk application/vnd.simtech-mindmapper twd twds application/vnd.smaf mmf # application/vnd.smart.notebook application/vnd.smart.teacher teacher # application/vnd.software602.filler.form+xml # application/vnd.software602.filler.form-xml-zip application/vnd.solent.sdkm+xml sdkm sdkd application/vnd.spotfire.dxp dxp application/vnd.spotfire.sfs sfs # application/vnd.sss-cod # application/vnd.sss-dtf # application/vnd.sss-ntf application/vnd.stardivision.calc sdc application/vnd.stardivision.draw sda application/vnd.stardivision.impress sdd application/vnd.stardivision.math smf application/vnd.stardivision.writer sdw vor application/vnd.stardivision.writer-global sgl application/vnd.stepmania.package smzip application/vnd.stepmania.stepchart sm # application/vnd.street-stream application/vnd.sun.xml.calc sxc application/vnd.sun.xml.calc.template stc application/vnd.sun.xml.draw sxd application/vnd.sun.xml.draw.template std application/vnd.sun.xml.impress sxi application/vnd.sun.xml.impress.template sti application/vnd.sun.xml.math sxm application/vnd.sun.xml.writer sxw application/vnd.sun.xml.writer.global sxg application/vnd.sun.xml.writer.template stw # application/vnd.sun.wadl+xml application/vnd.sus-calendar sus susp application/vnd.svd svd # application/vnd.swiftview-ics application/vnd.symbian.install sis sisx application/vnd.syncml+xml xsm application/vnd.syncml.dm+wbxml bdm application/vnd.syncml.dm+xml xdm # application/vnd.syncml.dm.notification # application/vnd.syncml.ds.notification application/vnd.tao.intent-module-archive tao application/vnd.tcpdump.pcap pcap cap dmp application/vnd.tmobile-livetv tmo application/vnd.trid.tpt tpt application/vnd.triscape.mxs mxs application/vnd.trueapp tra # application/vnd.truedoc # application/vnd.ubisoft.webplayer application/vnd.ufdl ufd ufdl application/vnd.uiq.theme utz application/vnd.umajin umj application/vnd.unity unityweb application/vnd.uoml+xml uoml # application/vnd.uplanet.alert # application/vnd.uplanet.alert-wbxml # application/vnd.uplanet.bearer-choice # application/vnd.uplanet.bearer-choice-wbxml # application/vnd.uplanet.cacheop # application/vnd.uplanet.cacheop-wbxml # application/vnd.uplanet.channel # application/vnd.uplanet.channel-wbxml # application/vnd.uplanet.list # application/vnd.uplanet.list-wbxml # application/vnd.uplanet.listcmd # application/vnd.uplanet.listcmd-wbxml # application/vnd.uplanet.signal application/vnd.vcx vcx # application/vnd.vd-study # application/vnd.vectorworks # application/vnd.verimatrix.vcas # application/vnd.vidsoft.vidconference application/vnd.visio vsd vst vss vsw application/vnd.visionary vis # application/vnd.vividence.scriptfile application/vnd.vsf vsf # application/vnd.wap.sic # application/vnd.wap.slc application/vnd.wap.wbxml wbxml application/vnd.wap.wmlc wmlc application/vnd.wap.wmlscriptc wmlsc application/vnd.webturbo wtb # application/vnd.wfa.wsc # application/vnd.wmc # application/vnd.wmf.bootstrap # application/vnd.wolfram.mathematica # application/vnd.wolfram.mathematica.package application/vnd.wolfram.player nbp application/vnd.wordperfect wpd application/vnd.wqd wqd # application/vnd.wrq-hp3000-labelled application/vnd.wt.stf stf # application/vnd.wv.csp+wbxml # application/vnd.wv.csp+xml # application/vnd.wv.ssp+xml application/vnd.xara xar application/vnd.xfdl xfdl # application/vnd.xfdl.webform # application/vnd.xmi+xml # application/vnd.xmpie.cpkg # application/vnd.xmpie.dpkg # application/vnd.xmpie.plan # application/vnd.xmpie.ppkg # application/vnd.xmpie.xlim application/vnd.yamaha.hv-dic hvd application/vnd.yamaha.hv-script hvs application/vnd.yamaha.hv-voice hvp application/vnd.yamaha.openscoreformat osf application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg # application/vnd.yamaha.remote-setup application/vnd.yamaha.smaf-audio saf application/vnd.yamaha.smaf-phrase spf # application/vnd.yamaha.through-ngn # application/vnd.yamaha.tunnel-udpencap application/vnd.yellowriver-custom-menu cmp application/vnd.zul zir zirz application/vnd.zzazz.deck+xml zaz application/voicexml+xml vxml # application/vq-rtcpxr # application/watcherinfo+xml # application/whoispp-query # application/whoispp-response application/widget wgt application/winhlp hlp # application/wita # application/wordperfect5.1 application/wsdl+xml wsdl application/wspolicy+xml wspolicy application/x-7z-compressed 7z application/x-abiword abw application/x-ace-compressed ace # application/x-amf application/x-apple-diskimage dmg application/x-authorware-bin aab x32 u32 vox application/x-authorware-map aam application/x-authorware-seg aas application/x-bcpio bcpio application/x-bittorrent torrent application/x-blorb blb blorb application/x-bzip bz application/x-bzip2 bz2 boz application/x-cbr cbr cba cbt cbz cb7 application/x-cdlink vcd application/x-cfs-compressed cfs application/x-chat chat application/x-chess-pgn pgn application/x-conference nsc # application/x-compress application/x-cpio cpio application/x-csh csh application/x-debian-package deb udeb application/x-dgc-compressed dgc application/x-director dir dcr dxr cst cct cxt w3d fgd swa application/x-doom wad application/x-dtbncx+xml ncx application/x-dtbook+xml dtb application/x-dtbresource+xml res application/x-dvi dvi application/x-envoy evy application/x-eva eva application/x-font-bdf bdf # application/x-font-dos # application/x-font-framemaker application/x-font-ghostscript gsf # application/x-font-libgrx application/x-font-linux-psf psf application/x-font-otf otf application/x-font-pcf pcf application/x-font-snf snf # application/x-font-speedo # application/x-font-sunos-news application/x-font-ttf ttf ttc application/x-font-type1 pfa pfb pfm afm application/font-woff woff # application/x-font-vfont application/x-freearc arc application/x-futuresplash spl application/x-gca-compressed gca application/x-glulx ulx application/x-gnumeric gnumeric application/x-gramps-xml gramps application/x-gtar gtar # application/x-gzip application/x-hdf hdf application/x-install-instructions install application/x-iso9660-image iso application/x-java-jnlp-file jnlp application/x-latex latex application/x-lzh-compressed lzh lha application/x-mie mie application/x-mobipocket-ebook prc mobi application/x-ms-application application application/x-ms-shortcut lnk application/x-ms-wmd wmd application/x-ms-wmz wmz application/x-ms-xbap xbap application/x-msaccess mdb application/x-msbinder obd application/x-mscardfile crd application/x-msclip clp application/x-msdownload exe dll com bat msi application/x-msmediaview mvb m13 m14 application/x-msmetafile wmf wmz emf emz application/x-msmoney mny application/x-mspublisher pub application/x-msschedule scd application/x-msterminal trm application/x-mswrite wri application/x-netcdf nc cdf application/x-nzb nzb application/x-pkcs12 p12 pfx application/x-pkcs7-certificates p7b spc application/x-pkcs7-certreqresp p7r application/x-rar-compressed rar application/x-research-info-systems ris application/x-sh sh application/x-shar shar application/x-shockwave-flash swf application/x-silverlight-app xap application/x-sql sql application/x-stuffit sit application/x-stuffitx sitx application/x-subrip srt application/x-sv4cpio sv4cpio application/x-sv4crc sv4crc application/x-t3vm-image t3 application/x-tads gam application/x-tar tar application/x-tcl tcl application/x-tex tex application/x-tex-tfm tfm application/x-texinfo texinfo texi application/x-tgif obj application/x-ustar ustar application/x-wais-source src application/x-x509-ca-cert der crt application/x-xfig fig application/x-xliff+xml xlf application/x-xpinstall xpi application/x-xz xz application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 # application/x400-bp application/xaml+xml xaml # application/xcap-att+xml # application/xcap-caps+xml application/xcap-diff+xml xdf # application/xcap-el+xml # application/xcap-error+xml # application/xcap-ns+xml # application/xcon-conference-info-diff+xml # application/xcon-conference-info+xml application/xenc+xml xenc application/xhtml+xml xhtml xht # application/xhtml-voice+xml application/xml xml xsl application/xml-dtd dtd # application/xml-external-parsed-entity # application/xmpp+xml application/xop+xml xop application/xproc+xml xpl application/xslt+xml xslt application/xspf+xml xspf application/xv+xml mxml xhvml xvml xvm application/yang yang application/yin+xml yin application/zip zip # audio/1d-interleaved-parityfec # audio/32kadpcm # audio/3gpp # audio/3gpp2 # audio/ac3 audio/adpcm adp # audio/amr # audio/amr-wb # audio/amr-wb+ # audio/asc # audio/atrac-advanced-lossless # audio/atrac-x # audio/atrac3 audio/basic au snd # audio/bv16 # audio/bv32 # audio/clearmode # audio/cn # audio/dat12 # audio/dls # audio/dsr-es201108 # audio/dsr-es202050 # audio/dsr-es202211 # audio/dsr-es202212 # audio/dv # audio/dvi4 # audio/eac3 # audio/evrc # audio/evrc-qcp # audio/evrc0 # audio/evrc1 # audio/evrcb # audio/evrcb0 # audio/evrcb1 # audio/evrcwb # audio/evrcwb0 # audio/evrcwb1 # audio/example # audio/fwdred # audio/g719 # audio/g722 # audio/g7221 # audio/g723 # audio/g726-16 # audio/g726-24 # audio/g726-32 # audio/g726-40 # audio/g728 # audio/g729 # audio/g7291 # audio/g729d # audio/g729e # audio/gsm # audio/gsm-efr # audio/gsm-hr-08 # audio/ilbc # audio/ip-mr_v2.5 # audio/isac # audio/l16 # audio/l20 # audio/l24 # audio/l8 # audio/lpc audio/midi mid midi kar rmi # audio/mobile-xmf audio/mp4 mp4a # audio/mp4a-latm # audio/mpa # audio/mpa-robust audio/mpeg mpga mp2 mp2a mp3 m2a m3a # audio/mpeg4-generic # audio/musepack audio/ogg oga ogg spx # audio/opus # audio/parityfec # audio/pcma # audio/pcma-wb # audio/pcmu-wb # audio/pcmu # audio/prs.sid # audio/qcelp # audio/red # audio/rtp-enc-aescm128 # audio/rtp-midi # audio/rtx audio/s3m s3m audio/silk sil # audio/smv # audio/smv0 # audio/smv-qcp # audio/sp-midi # audio/speex # audio/t140c # audio/t38 # audio/telephone-event # audio/tone # audio/uemclip # audio/ulpfec # audio/vdvi # audio/vmr-wb # audio/vnd.3gpp.iufp # audio/vnd.4sb # audio/vnd.audiokoz # audio/vnd.celp # audio/vnd.cisco.nse # audio/vnd.cmles.radio-events # audio/vnd.cns.anp1 # audio/vnd.cns.inf1 audio/vnd.dece.audio uva uvva audio/vnd.digital-winds eol # audio/vnd.dlna.adts # audio/vnd.dolby.heaac.1 # audio/vnd.dolby.heaac.2 # audio/vnd.dolby.mlp # audio/vnd.dolby.mps # audio/vnd.dolby.pl2 # audio/vnd.dolby.pl2x # audio/vnd.dolby.pl2z # audio/vnd.dolby.pulse.1 audio/vnd.dra dra audio/vnd.dts dts audio/vnd.dts.hd dtshd # audio/vnd.dvb.file # audio/vnd.everad.plj # audio/vnd.hns.audio audio/vnd.lucent.voice lvp audio/vnd.ms-playready.media.pya pya # audio/vnd.nokia.mobile-xmf # audio/vnd.nortel.vbk audio/vnd.nuera.ecelp4800 ecelp4800 audio/vnd.nuera.ecelp7470 ecelp7470 audio/vnd.nuera.ecelp9600 ecelp9600 # audio/vnd.octel.sbc # audio/vnd.qcelp # audio/vnd.rhetorex.32kadpcm audio/vnd.rip rip # audio/vnd.sealedmedia.softseal.mpeg # audio/vnd.vmx.cvsd # audio/vorbis # audio/vorbis-config audio/webm weba audio/x-aac aac audio/x-aiff aif aiff aifc audio/x-caf caf audio/x-flac flac audio/x-matroska mka audio/x-mpegurl m3u audio/x-ms-wax wax audio/x-ms-wma wma audio/x-pn-realaudio ram ra audio/x-pn-realaudio-plugin rmp # audio/x-tta audio/x-wav wav audio/xm xm chemical/x-cdx cdx chemical/x-cif cif chemical/x-cmdf cmdf chemical/x-cml cml chemical/x-csml csml # chemical/x-pdb chemical/x-xyz xyz image/bmp bmp image/cgm cgm # image/example # image/fits image/g3fax g3 image/gif gif image/ief ief # image/jp2 image/jpeg jpeg jpg jpe # image/jpm # image/jpx image/ktx ktx # image/naplps image/png png image/prs.btif btif # image/prs.pti image/sgi sgi image/svg+xml svg svgz # image/t38 image/tiff tiff tif # image/tiff-fx image/vnd.adobe.photoshop psd # image/vnd.cns.inf2 image/vnd.dece.graphic uvi uvvi uvg uvvg image/vnd.dvb.subtitle sub image/vnd.djvu djvu djv image/vnd.dwg dwg image/vnd.dxf dxf image/vnd.fastbidsheet fbs image/vnd.fpx fpx image/vnd.fst fst image/vnd.fujixerox.edmics-mmr mmr image/vnd.fujixerox.edmics-rlc rlc # image/vnd.globalgraphics.pgb # image/vnd.microsoft.icon # image/vnd.mix image/vnd.ms-modi mdi image/vnd.ms-photo wdp image/vnd.net-fpx npx # image/vnd.radiance # image/vnd.sealed.png # image/vnd.sealedmedia.softseal.gif # image/vnd.sealedmedia.softseal.jpg # image/vnd.svf image/vnd.wap.wbmp wbmp image/vnd.xiff xif image/webp webp image/x-3ds 3ds image/x-cmu-raster ras image/x-cmx cmx image/x-freehand fh fhc fh4 fh5 fh7 image/x-icon ico image/x-mrsid-image sid image/x-pcx pcx image/x-pict pic pct image/x-portable-anymap pnm image/x-portable-bitmap pbm image/x-portable-graymap pgm image/x-portable-pixmap ppm image/x-rgb rgb image/x-tga tga image/x-xbitmap xbm image/x-xpixmap xpm image/x-xwindowdump xwd # message/cpim # message/delivery-status # message/disposition-notification # message/example # message/external-body # message/feedback-report # message/global # message/global-delivery-status # message/global-disposition-notification # message/global-headers # message/http # message/imdn+xml # message/news # message/partial message/rfc822 eml mime # message/s-http # message/sip # message/sipfrag # message/tracking-status # message/vnd.si.simp # model/example model/iges igs iges model/mesh msh mesh silo model/vnd.collada+xml dae model/vnd.dwf dwf # model/vnd.flatland.3dml model/vnd.gdl gdl # model/vnd.gs-gdl # model/vnd.gs.gdl model/vnd.gtw gtw # model/vnd.moml+xml model/vnd.mts mts # model/vnd.parasolid.transmit.binary # model/vnd.parasolid.transmit.text model/vnd.vtu vtu model/vrml wrl vrml model/x3d+binary x3db x3dbz model/x3d+vrml x3dv x3dvz model/x3d+xml x3d x3dz # multipart/alternative # multipart/appledouble # multipart/byteranges # multipart/digest # multipart/encrypted # multipart/example # multipart/form-data # multipart/header-set # multipart/mixed # multipart/parallel # multipart/related # multipart/report # multipart/signed # multipart/voice-message # text/1d-interleaved-parityfec text/cache-manifest appcache text/calendar ics ifb text/css css text/csv csv # text/directory # text/dns # text/ecmascript # text/enriched # text/example # text/fwdred text/html html htm # text/javascript text/n3 n3 # text/parityfec text/plain txt text conf def list log in # text/prs.fallenstein.rst text/prs.lines.tag dsc # text/vnd.radisys.msml-basic-layout # text/red # text/rfc822-headers text/richtext rtx # text/rtf # text/rtp-enc-aescm128 # text/rtx text/sgml sgml sgm # text/t140 text/tab-separated-values tsv text/troff t tr roff man me ms text/turtle ttl # text/ulpfec text/uri-list uri uris urls text/vcard vcard # text/vnd.abc text/vnd.curl curl text/vnd.curl.dcurl dcurl text/vnd.curl.scurl scurl text/vnd.curl.mcurl mcurl # text/vnd.dmclientscript text/vnd.dvb.subtitle sub # text/vnd.esmertec.theme-descriptor text/vnd.fly fly text/vnd.fmi.flexstor flx text/vnd.graphviz gv text/vnd.in3d.3dml 3dml text/vnd.in3d.spot spot # text/vnd.iptc.newsml # text/vnd.iptc.nitf # text/vnd.latex-z # text/vnd.motorola.reflex # text/vnd.ms-mediapackage # text/vnd.net2phone.commcenter.command # text/vnd.si.uricatalogue text/vnd.sun.j2me.app-descriptor jad # text/vnd.trolltech.linguist # text/vnd.wap.si # text/vnd.wap.sl text/vnd.wap.wml wml text/vnd.wap.wmlscript wmls text/x-asm s asm text/x-c c cc cxx cpp h hh dic text/x-fortran f for f77 f90 text/x-java-source java text/x-opml opml text/x-pascal p pas text/x-nfo nfo text/x-setext etx text/x-sfv sfv text/x-uuencode uu text/x-vcalendar vcs text/x-vcard vcf # text/xml # text/xml-external-parsed-entity # video/1d-interleaved-parityfec video/3gpp 3gp # video/3gpp-tt video/3gpp2 3g2 # video/bmpeg # video/bt656 # video/celb # video/dv # video/example video/h261 h261 video/h263 h263 # video/h263-1998 # video/h263-2000 video/h264 h264 # video/h264-rcdo # video/h264-svc video/jpeg jpgv # video/jpeg2000 video/jpm jpm jpgm video/mj2 mj2 mjp2 # video/mp1s # video/mp2p # video/mp2t video/mp4 mp4 mp4v mpg4 # video/mp4v-es video/mpeg mpeg mpg mpe m1v m2v # video/mpeg4-generic # video/mpv # video/nv video/ogg ogv # video/parityfec # video/pointer video/quicktime qt mov # video/raw # video/rtp-enc-aescm128 # video/rtx # video/smpte292m # video/ulpfec # video/vc1 # video/vnd.cctv video/vnd.dece.hd uvh uvvh video/vnd.dece.mobile uvm uvvm # video/vnd.dece.mp4 video/vnd.dece.pd uvp uvvp video/vnd.dece.sd uvs uvvs video/vnd.dece.video uvv uvvv # video/vnd.directv.mpeg # video/vnd.directv.mpeg-tts # video/vnd.dlna.mpeg-tts video/vnd.dvb.file dvb video/vnd.fvt fvt # video/vnd.hns.video # video/vnd.iptvforum.1dparityfec-1010 # video/vnd.iptvforum.1dparityfec-2005 # video/vnd.iptvforum.2dparityfec-1010 # video/vnd.iptvforum.2dparityfec-2005 # video/vnd.iptvforum.ttsavc # video/vnd.iptvforum.ttsmpeg2 # video/vnd.motorola.video # video/vnd.motorola.videop video/vnd.mpegurl mxu m4u video/vnd.ms-playready.media.pyv pyv # video/vnd.nokia.interleaved-multimedia # video/vnd.nokia.videovoip # video/vnd.objectvideo # video/vnd.sealed.mpeg1 # video/vnd.sealed.mpeg4 # video/vnd.sealed.swf # video/vnd.sealedmedia.softseal.mov video/vnd.uvvu.mp4 uvu uvvu video/vnd.vivo viv video/webm webm video/x-f4v f4v video/x-fli fli video/x-flv flv video/x-m4v m4v video/x-matroska mkv mk3d mks video/x-mng mng video/x-ms-asf asf asx video/x-ms-vob vob video/x-ms-wm wm video/x-ms-wmv wmv video/x-ms-wmx wmx video/x-ms-wvx wvx video/x-msvideo avi video/x-sgi-movie movie video/x-smv smv x-conference/x-cooltalk ice telegram-purple/tgl/mtproto-client.c000066400000000000000000001336401357227200100201030ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Nikolay Durov, Andrey Lopatin 2012-2013 Vitaly Valtman 2013-2015 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #else #include #include #include #include #include #endif #include "crypto/rand.h" #include "crypto/rsa_pem.h" #include "crypto/sha.h" //#include "telegram.h" #include "queries.h" //#include "loop.h" #include "tgl-structures.h" #include "tgl-binlog.h" #include "auto.h" #include "auto/auto-types.h" #include "auto/auto-skip.h" #include "tgl.h" #include "mtproto-client.h" #include "tools.h" #include "tree.h" #include "updates.h" #include "mtproto-utils.h" #include "auto.h" #include "tgl-methods-in.h" #include "mtproto-common.h" #define MAX_NET_RES (1L << 16) //extern int log_level; static long long generate_next_msg_id (struct tgl_state *TLS, struct tgl_dc *DC, struct tgl_session *S); static double get_server_time (struct tgl_dc *DC); // for statistic only static int total_packets_sent; static long long total_data_sent; static int rpc_execute (struct tgl_state *TLS, struct connection *c, int op, int len); static int rpc_becomes_ready (struct tgl_state *TLS, struct connection *c); static int rpc_close (struct tgl_state *TLS, struct connection *c); static double get_utime (int clock_id) { struct timespec T; tgl_my_clock_gettime (clock_id, &T); return T.tv_sec + (double) T.tv_nsec * 1e-9; } #define MAX_RESPONSE_SIZE (1L << 24) static TGLC_rsa *rsa_load_public_key (struct tgl_state *TLS, const char *public_key_name) { FILE *f = fopen (public_key_name, "r"); if (f == NULL) { vlogprintf (E_WARNING, "Couldn't open public key file: %s\n", public_key_name); return NULL; } TGLC_rsa *res = TGLC_pem_read_RSAPublicKey (f); fclose (f); if (res == NULL) { vlogprintf (E_WARNING, "TGLC_pem_read_RSAPublicKey returns NULL.\n"); return NULL; } vlogprintf (E_NOTICE, "public key '%s' loaded successfully\n", public_key_name); return res; } /* * * UNAUTHORIZED (DH KEY EXCHANGE) PROTOCOL PART * */ #define ENCRYPT_BUFFER_INTS 16384 static int encrypt_buffer[ENCRYPT_BUFFER_INTS]; #define DECRYPT_BUFFER_INTS 16384 static int decrypt_buffer[ENCRYPT_BUFFER_INTS]; static int encrypt_packet_buffer (struct tgl_state *TLS, struct tgl_dc *DC) { TGLC_rsa *key = TLS->rsa_key_loaded[DC->rsa_key_idx]; return tgl_pad_rsa_encrypt (TLS, (char *) packet_buffer, (packet_ptr - packet_buffer) * 4, (char *) encrypt_buffer, ENCRYPT_BUFFER_INTS * 4, TGLC_rsa_n (key), TGLC_rsa_e (key)); } static int encrypt_packet_buffer_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32]) { tgl_init_aes_unauth (server_nonce, hidden_client_nonce, 1); return tgl_pad_aes_encrypt ((char *) packet_buffer, (packet_ptr - packet_buffer) * 4, (char *) encrypt_buffer, ENCRYPT_BUFFER_INTS * 4); } // // Used in unauthorized part of protocol // static int rpc_send_packet (struct tgl_state *TLS, struct connection *c) { static struct { long long auth_key_id; long long out_msg_id; int msg_len; } unenc_msg_header; int len = (packet_ptr - packet_buffer) * 4; TLS->net_methods->incr_out_packet_num (c); struct tgl_dc *DC = TLS->net_methods->get_dc (c); struct tgl_session *S = TLS->net_methods->get_session (c); unenc_msg_header.out_msg_id = generate_next_msg_id (TLS, DC, S); unenc_msg_header.msg_len = len; int total_len = len + 20; assert (total_len > 0 && !(total_len & 0xfc000003)); total_len >>= 2; vlogprintf (E_DEBUG, "writing packet: total_len = %d, len = %d\n", total_len, len); if (total_len < 0x7f) { assert (TLS->net_methods->write_out (c, &total_len, 1) == 1); } else { total_len = (total_len << 8) | 0x7f; assert (TLS->net_methods->write_out (c, &total_len, 4) == 4); } TLS->net_methods->write_out (c, &unenc_msg_header, 20); TLS->net_methods->write_out (c, packet_buffer, len); TLS->net_methods->flush_out (c); total_packets_sent ++; total_data_sent += total_len; return 1; } static int rpc_send_message (struct tgl_state *TLS, struct connection *c, void *data, int len) { assert (len > 0 && !(len & 0xfc000003)); int total_len = len >> 2; if (total_len < 0x7f) { assert (TLS->net_methods->write_out (c, &total_len, 1) == 1); } else { total_len = (total_len << 8) | 0x7f; assert (TLS->net_methods->write_out (c, &total_len, 4) == 4); } TLS->net_methods->incr_out_packet_num (c); assert (TLS->net_methods->write_out (c, data, len) == len); TLS->net_methods->flush_out (c); total_packets_sent ++; total_data_sent += total_len; return 1; } // // State machine. See description at // https://core.telegram.org/mtproto/auth_key // static int check_unauthorized_header (struct tgl_state *TLS) { long long auth_key_id = fetch_long (); if (auth_key_id) { vlogprintf (E_ERROR, "ERROR: auth_key_id should be NULL\n"); return -1; } fetch_long (); // msg_id int len = fetch_int (); if (len != 4 * (in_end - in_ptr)) { vlogprintf (E_ERROR, "ERROR: length mismatch\n"); return -1; } return 0; } /* {{{ REQ_PQ */ // req_pq#60469778 nonce:int128 = ResPQ static int send_req_pq_packet (struct tgl_state *TLS, struct connection *c) { struct tgl_dc *DC = TLS->net_methods->get_dc (c); assert (DC->state == st_init); tglt_secure_random (DC->nonce, 16); clear_packet (); out_int (CODE_req_pq); out_ints ((int *)DC->nonce, 4); rpc_send_packet (TLS, c); DC->state = st_reqpq_sent; return 1; } // req_pq#60469778 nonce:int128 = ResPQ static int send_req_pq_temp_packet (struct tgl_state *TLS, struct connection *c) { struct tgl_dc *DC = TLS->net_methods->get_dc (c); assert (DC->state == st_authorized); tglt_secure_random (DC->nonce, 16); clear_packet (); out_int (CODE_req_pq); out_ints ((int *)DC->nonce, 4); rpc_send_packet (TLS, c); DC->state = st_reqpq_sent_temp; return 1; } /* }}} */ /* {{{ REQ DH */ // req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; // p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; // p_q_inner_data_temp#3c6a84d4 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data; static void send_req_dh_packet (struct tgl_state *TLS, struct connection *c, TGLC_bn *pq, int temp_key) { struct tgl_dc *DC = TLS->net_methods->get_dc (c); TGLC_bn *p = TGLC_bn_new (); TGLC_bn *q = TGLC_bn_new (); assert (bn_factorize (pq, p, q) >= 0); clear_packet (); packet_ptr += 5; out_int (temp_key ? CODE_p_q_inner_data_temp : CODE_p_q_inner_data); out_bignum (pq); out_bignum (p); out_bignum (q); out_ints ((int *) DC->nonce, 4); out_ints ((int *) DC->server_nonce, 4); tglt_secure_random (DC->new_nonce, 32); out_ints ((int *) DC->new_nonce, 8); if (temp_key) { out_int (TLS->temp_key_expire_time); } TGLC_sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); int l = encrypt_packet_buffer (TLS, DC); clear_packet (); out_int (CODE_req_DH_params); out_ints ((int *) DC->nonce, 4); out_ints ((int *) DC->server_nonce, 4); out_bignum (p); out_bignum (q); out_long (TLS->rsa_key_fingerprint[DC->rsa_key_idx]); out_cstring ((char *) encrypt_buffer, l); TGLC_bn_free (p); TGLC_bn_free (q); DC->state = temp_key ? st_reqdh_sent_temp : st_reqdh_sent; rpc_send_packet (TLS, c); } /* }}} */ /* {{{ SEND DH PARAMS */ // set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; // client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data static void send_dh_params (struct tgl_state *TLS, struct connection *c, TGLC_bn *dh_prime, TGLC_bn *g_a, int g, int temp_key) { struct tgl_dc *DC = TLS->net_methods->get_dc (c); clear_packet (); packet_ptr += 5; out_int (CODE_client_DH_inner_data); out_ints ((int *) DC->nonce, 4); out_ints ((int *) DC->server_nonce, 4); out_long (0); TGLC_bn *dh_g = TGLC_bn_new (); ensure (TGLC_bn_set_word (dh_g, g)); static unsigned char s_power[256]; tglt_secure_random (s_power, 256); TGLC_bn *dh_power = TGLC_bn_bin2bn ((unsigned char *)s_power, 256, 0); ensure_ptr (dh_power); TGLC_bn *y = TGLC_bn_new (); ensure_ptr (y); ensure (TGLC_bn_mod_exp (y, dh_g, dh_power, dh_prime, TLS->TGLC_bn_ctx)); out_bignum (y); TGLC_bn_free (y); TGLC_bn *auth_key_num = TGLC_bn_new (); ensure (TGLC_bn_mod_exp (auth_key_num, g_a, dh_power, dh_prime, TLS->TGLC_bn_ctx)); int l = TGLC_bn_num_bytes (auth_key_num); assert (l >= 250 && l <= 256); assert (TGLC_bn_bn2bin (auth_key_num, (unsigned char *)(temp_key ? DC->temp_auth_key : DC->auth_key))); if (l < 256) { char *key = temp_key ? DC->temp_auth_key : DC->auth_key; memmove (key + 256 - l, key, l); memset (key, 0, 256 - l); } TGLC_bn_free (dh_power); TGLC_bn_free (auth_key_num); TGLC_bn_free (dh_g); TGLC_sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); l = encrypt_packet_buffer_aes_unauth (DC->server_nonce, DC->new_nonce); clear_packet (); out_int (CODE_set_client_DH_params); out_ints ((int *) DC->nonce, 4); out_ints ((int *) DC->server_nonce, 4); out_cstring ((char *) encrypt_buffer, l); DC->state = temp_key ? st_client_dh_sent_temp : st_client_dh_sent;; rpc_send_packet (TLS, c); } /* }}} */ /* {{{ RECV RESPQ */ // resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector long = ResPQ static int process_respq_answer (struct tgl_state *TLS, struct connection *c, char *packet, int len, int temp_key) { assert (!(len & 3)); in_ptr = (int *)packet; in_end = in_ptr + (len / 4); if (check_unauthorized_header (TLS) < 0) { return -1; } int *in_save = in_ptr; if (skip_type_any (TYPE_TO_PARAM (res_p_q)) < 0 || in_ptr != in_end) { vlogprintf (E_ERROR, "can not parse req_p_q answer\n"); return -1; } in_ptr = in_save; struct tgl_dc *DC = TLS->net_methods->get_dc (c); assert (fetch_int() == CODE_res_p_q); static int tmp[4]; fetch_ints (tmp, 4); if (memcmp (tmp, DC->nonce, 16)) { vlogprintf (E_ERROR, "nonce mismatch\n"); return -1; } fetch_ints (DC->server_nonce, 4); TGLC_bn *pq = TGLC_bn_new (); assert (fetch_bignum (pq) >= 0); assert (fetch_int () == CODE_vector); int fingerprints_num = fetch_int (); assert (fingerprints_num >= 0); DC->rsa_key_idx = -1; int i; for (i = 0; i < fingerprints_num; i++) { int j; long long fprint = fetch_long (); for (j = 0; j < TLS->rsa_key_num; j++) { if (TLS->rsa_key_loaded[j]) { if (fprint == TLS->rsa_key_fingerprint[j]) { DC->rsa_key_idx = j; break; } } } } assert (in_ptr == in_end); if (DC->rsa_key_idx == -1) { vlogprintf (E_ERROR, "fatal: don't have any matching keys\n"); return -1; } send_req_dh_packet (TLS, c, pq, temp_key); TGLC_bn_free (pq); return 1; } /* }}} */ /* {{{ RECV DH */ // server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; // server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; // server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; static int process_dh_answer (struct tgl_state *TLS, struct connection *c, char *packet, int len, int temp_key) { assert (!(len & 3)); in_ptr = (int *)packet; in_end = in_ptr + (len / 4); if (check_unauthorized_header (TLS) < 0) { return -1; } int *in_save = in_ptr; if (skip_type_any (TYPE_TO_PARAM (server_d_h_params)) < 0 || in_ptr != in_end) { vlogprintf (E_ERROR, "can not parse server_DH_params answer\n"); return -1; } in_ptr = in_save; struct tgl_dc *DC = TLS->net_methods->get_dc (c); unsigned op = fetch_int (); assert (op == CODE_server__d_h_params_ok || op == CODE_server__d_h_params_fail); int tmp[4]; fetch_ints (tmp, 4); if (memcmp (tmp, DC->nonce, 16)) { vlogprintf (E_ERROR, "nonce mismatch\n"); return -1; } assert (!memcmp (tmp, DC->nonce, 16)); fetch_ints (tmp, 4); if (memcmp (tmp, DC->server_nonce, 16)) { vlogprintf (E_ERROR, "nonce mismatch\n"); return -1; } assert (!memcmp (tmp, DC->server_nonce, 16)); if (op == CODE_server__d_h_params_fail) { vlogprintf (E_ERROR, "DH params fail\n"); return -1; } tgl_init_aes_unauth (DC->server_nonce, DC->new_nonce, 0); int l = prefetch_strlen (); assert (l >= 0); if (!l) { vlogprintf (E_ERROR, "non-empty encrypted part expected\n"); return -1; } l = tgl_pad_aes_decrypt (fetch_str (l), l, (char *) decrypt_buffer, DECRYPT_BUFFER_INTS * 4 - 16); assert (in_ptr == in_end); in_ptr = decrypt_buffer + 5; in_end = decrypt_buffer + (l >> 2); if (skip_type_any (TYPE_TO_PARAM (server_d_h_inner_data)) < 0) { vlogprintf (E_ERROR, "can not parse server_DH_inner_data answer\n"); return -1; } in_ptr = decrypt_buffer + 5; assert (fetch_int () == (int)CODE_server_DH_inner_data); fetch_ints (tmp, 4); if (memcmp (tmp, DC->nonce, 16)) { vlogprintf (E_ERROR, "nonce mismatch\n"); return -1; } assert (!memcmp (tmp, DC->nonce, 16)); fetch_ints (tmp, 4); if (memcmp (tmp, DC->server_nonce, 16)) { vlogprintf (E_ERROR, "nonce mismatch\n"); return -1; } assert (!memcmp (tmp, DC->server_nonce, 16)); int g = fetch_int (); TGLC_bn *dh_prime = TGLC_bn_new (); TGLC_bn *g_a = TGLC_bn_new (); assert (fetch_bignum (dh_prime) > 0); assert (fetch_bignum (g_a) > 0); if (tglmp_check_DH_params (TLS, dh_prime, g) < 0) { vlogprintf (E_ERROR, "bad DH params\n"); return -1; } if (tglmp_check_g_a (TLS, dh_prime, g_a) < 0) { vlogprintf (E_ERROR, "bad dh_prime\n"); return -1; } int server_time = fetch_int (); assert (in_ptr <= in_end); static char sha1_buffer[20]; TGLC_sha1 ((unsigned char *) decrypt_buffer + 20, (in_ptr - decrypt_buffer - 5) * 4, (unsigned char *) sha1_buffer); if (memcmp (decrypt_buffer, sha1_buffer, 20)) { vlogprintf (E_ERROR, "bad encrypted message SHA1\n"); return -1; } if ((char *) in_end - (char *) in_ptr >= 16) { vlogprintf (E_ERROR, "too much padding\n"); return -1; } DC->server_time_delta = server_time - get_utime (CLOCK_REALTIME); DC->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); send_dh_params (TLS, c, dh_prime, g_a, g, temp_key); TGLC_bn_free (dh_prime); TGLC_bn_free (g_a); return 1; } /* }}} */ static void create_temp_auth_key (struct tgl_state *TLS, struct connection *c) { assert (TLS->enable_pfs); send_req_pq_temp_packet (TLS, c); } int tglmp_encrypt_inner_temp (struct tgl_state *TLS, struct connection *c, int *msg, int msg_ints, int useful, void *data, long long msg_id); static long long msg_id_override; static void mpc_on_get_config (struct tgl_state *TLS, void *extra, int success); static void bind_temp_auth_key (struct tgl_state *TLS, struct connection *c); /* {{{ RECV AUTH COMPLETE */ // dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; // dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; // dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; static int process_auth_complete (struct tgl_state *TLS, struct connection *c, char *packet, int len, int temp_key) { struct tgl_dc *DC = TLS->net_methods->get_dc (c); assert (!(len & 3)); in_ptr = (int *)packet; in_end = in_ptr + (len / 4); if (check_unauthorized_header (TLS) < 0) { return -1; } int *in_save = in_ptr; if (skip_type_any (TYPE_TO_PARAM (set_client_d_h_params_answer)) < 0 || in_ptr != in_end) { vlogprintf (E_ERROR, "can not parse server_DH_params answer\n"); return -1; } in_ptr = in_save; unsigned op = fetch_int (); assert (op == CODE_dh_gen_ok || op == CODE_dh_gen_retry || op == CODE_dh_gen_fail); int tmp[4]; fetch_ints (tmp, 4); if (memcmp (DC->nonce, tmp, 16)) { vlogprintf (E_ERROR, "nonce mismatch\n"); return -1; } fetch_ints (tmp, 4); if (memcmp (DC->server_nonce, tmp, 16)) { vlogprintf (E_ERROR, "nonce mismatch\n"); return -1; } if (op != CODE_dh_gen_ok) { vlogprintf (E_ERROR, "something bad. Retry regen\n"); return -1; } fetch_ints (tmp, 4); static unsigned char th[44], sha1_buffer[20]; memcpy (th, DC->new_nonce, 32); th[32] = 1; if (!temp_key) { TGLC_sha1 ((unsigned char *)DC->auth_key, 256, sha1_buffer); } else { TGLC_sha1 ((unsigned char *)DC->temp_auth_key, 256, sha1_buffer); } memcpy (th + 33, sha1_buffer, 8); TGLC_sha1 (th, 41, sha1_buffer); if (memcmp (tmp, sha1_buffer + 4, 16)) { vlogprintf (E_ERROR, "hash mismatch\n"); return -1; } if (!temp_key) { bl_do_set_auth_key (TLS, DC->id, (unsigned char *)DC->auth_key); TGLC_sha1 ((unsigned char *)DC->auth_key, 256, sha1_buffer); } else { TGLC_sha1 ((unsigned char *)DC->temp_auth_key, 256, sha1_buffer); DC->temp_auth_key_id = *(long long *)(sha1_buffer + 12); } DC->server_salt = *(long long *)DC->server_nonce ^ *(long long *)DC->new_nonce; DC->state = st_authorized; vlogprintf (E_DEBUG, "Auth success\n"); if (temp_key) { bind_temp_auth_key (TLS, c); } else { DC->flags |= 1; if (TLS->enable_pfs) { assert (TLS->enable_pfs); create_temp_auth_key (TLS, c); } else { DC->temp_auth_key_id = DC->auth_key_id; memcpy (DC->temp_auth_key, DC->auth_key, 256); DC->flags |= 2; if (!(DC->flags & 4)) { tgl_do_help_get_config_dc (TLS, DC, mpc_on_get_config, DC); } } } return 1; } /* }}} */ static void bind_temp_auth_key (struct tgl_state *TLS, struct connection *c) { struct tgl_dc *DC = TLS->net_methods->get_dc (c); if (DC->temp_auth_key_bind_query_id) { tglq_query_delete (TLS, DC->temp_auth_key_bind_query_id); } struct tgl_session *S = TLS->net_methods->get_session (c); long long msg_id = generate_next_msg_id (TLS, DC, S); clear_packet (); out_int (CODE_bind_auth_key_inner); long long rand; tglt_secure_random (&rand, 8); out_long (rand); out_long (DC->temp_auth_key_id); out_long (DC->auth_key_id); if (!S->session_id) { tglt_secure_random (&S->session_id, 8); } out_long (S->session_id); int expires = time (0) + DC->server_time_delta + TLS->temp_key_expire_time; out_int (expires); static int data[1000]; int len = tglmp_encrypt_inner_temp (TLS, c, packet_buffer, packet_ptr - packet_buffer, 0, data, msg_id); msg_id_override = msg_id; DC->temp_auth_key_bind_query_id = msg_id; tgl_do_send_bind_temp_key (TLS, DC, rand, expires, (void *)data, len, msg_id); msg_id_override = 0; } /* * * AUTHORIZED (MAIN) PROTOCOL PART * */ static struct encrypted_message enc_msg; static double get_server_time (struct tgl_dc *DC) { //if (!DC->server_time_udelta) { // DC->server_time_udelta = get_utime (CLOCK_REALTIME) - get_utime (CLOCK_MONOTONIC); //} return get_utime (CLOCK_MONOTONIC) + DC->server_time_udelta; } static long long generate_next_msg_id (struct tgl_state *TLS, struct tgl_dc *DC, struct tgl_session *S) { long long next_id = (long long) (get_server_time (DC) * (1LL << 32)) & -4; if (next_id <= TLS->last_msg_id) { next_id = TLS->last_msg_id += 4; } else { TLS->last_msg_id = next_id; } S->last_msg_id = next_id; // See tglmp_encrypt_send_message return next_id; } static void init_enc_msg (struct tgl_state *TLS, struct tgl_session *S, int useful) { struct tgl_dc *DC = S->dc; assert (DC->state == st_authorized); assert (DC->temp_auth_key_id); vlogprintf (E_DEBUG, "temp_auth_key_id = 0x%016" INT64_PRINTF_MODIFIER "x, auth_key_id = 0x%016" INT64_PRINTF_MODIFIER "x\n", DC->temp_auth_key_id, DC->auth_key_id); enc_msg.auth_key_id = DC->temp_auth_key_id; enc_msg.server_salt = DC->server_salt; if (!S->session_id) { tglt_secure_random (&S->session_id, 8); } enc_msg.session_id = S->session_id; enc_msg.msg_id = msg_id_override ? msg_id_override : generate_next_msg_id (TLS, DC, S); enc_msg.seq_no = S->seq_no; if (useful) { enc_msg.seq_no |= 1; } S->seq_no += 2; }; static void init_enc_msg_inner_temp (struct tgl_dc *DC, long long msg_id) { enc_msg.auth_key_id = DC->auth_key_id; tglt_secure_random (&enc_msg.server_salt, 8); tglt_secure_random (&enc_msg.session_id, 8); enc_msg.msg_id = msg_id; enc_msg.seq_no = 0; }; static int aes_encrypt_message (struct tgl_state *TLS, char *key, struct encrypted_message *enc) { unsigned char sha1_buffer[20]; const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); int enc_len = (MINSZ - UNENCSZ) + enc->msg_len; assert (enc->msg_len >= 0 && enc->msg_len <= MAX_MESSAGE_INTS * 4 - 16 && !(enc->msg_len & 3)); TGLC_sha1 ((unsigned char *) &enc->server_salt, enc_len, sha1_buffer); vlogprintf (E_DEBUG, "sending message with sha1 %08x\n", *(int *)sha1_buffer); memcpy (enc->msg_key, sha1_buffer + 4, 16); tgl_init_aes_auth (key, enc->msg_key, 1); return tgl_pad_aes_encrypt ((char *) &enc->server_salt, enc_len, (char *) &enc->server_salt, MAX_MESSAGE_INTS * 4 + (MINSZ - UNENCSZ)); } long long tglmp_encrypt_send_message (struct tgl_state *TLS, struct connection *c, int *msg, int msg_ints, int flags) { struct tgl_dc *DC = TLS->net_methods->get_dc (c); struct tgl_session *S = TLS->net_methods->get_session (c); assert (S); if (!(DC->flags & 4) && !(flags & 2)) { return generate_next_msg_id (TLS, DC, S); } const int UNENCSZ = offsetof (struct encrypted_message, server_salt); if (msg_ints <= 0 || msg_ints > MAX_MESSAGE_INTS - 4) { return -1; } if (msg) { memcpy (enc_msg.message, msg, msg_ints * 4); enc_msg.msg_len = msg_ints * 4; } else { if ((enc_msg.msg_len & 0x80000003) || enc_msg.msg_len > MAX_MESSAGE_INTS * 4 - 16) { return -1; } } init_enc_msg (TLS, S, flags & 1); int l = aes_encrypt_message (TLS, DC->temp_auth_key, &enc_msg); assert (l > 0); rpc_send_message (TLS, c, &enc_msg, l + UNENCSZ); return S->last_msg_id; // Pray that this was set by generate_next_msg_id somehow } int tglmp_encrypt_inner_temp (struct tgl_state *TLS, struct connection *c, int *msg, int msg_ints, int useful, void *data, long long msg_id) { struct tgl_dc *DC = TLS->net_methods->get_dc (c); struct tgl_session *S = TLS->net_methods->get_session (c); assert (S); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); if (msg_ints <= 0 || msg_ints > MAX_MESSAGE_INTS - 4) { return -1; } memcpy (enc_msg.message, msg, msg_ints * 4); enc_msg.msg_len = msg_ints * 4; init_enc_msg_inner_temp (DC, msg_id); int l = aes_encrypt_message (TLS, DC->auth_key, &enc_msg); assert (l > 0); //rpc_send_message (c, &enc_msg, l + UNENCSZ); memcpy (data, &enc_msg, l + UNENCSZ); return l + UNENCSZ; } static int rpc_execute_answer (struct tgl_state *TLS, struct connection *c, long long msg_id); static int work_container (struct tgl_state *TLS, struct connection *c, long long msg_id) { vlogprintf (E_DEBUG, "work_container: msg_id = %" INT64_PRINTF_MODIFIER "d\n", msg_id); assert (fetch_int () == CODE_msg_container); int n = fetch_int (); int i; for (i = 0; i < n; i++) { long long id = fetch_long (); //int seqno = fetch_int (); fetch_int (); // seq_no if (id & 1) { tgln_insert_msg_id (TLS, TLS->net_methods->get_session (c), id); } int bytes = fetch_int (); int *t = in_end; in_end = in_ptr + (bytes / 4); int r = rpc_execute_answer (TLS, c, id); if (r < 0) { return -1; } assert (in_ptr == in_end); in_end = t; } return 0; } static int work_new_session_created (struct tgl_state *TLS, struct connection *c, long long msg_id) { struct tgl_session *S = TLS->net_methods->get_session (c); struct tgl_dc *DC = TLS->net_methods->get_dc (c); vlogprintf (E_NOTICE, "work_new_session_created: msg_id = %" INT64_PRINTF_MODIFIER "d, dc = %d\n", msg_id, DC->id); assert (fetch_int () == (int)CODE_new_session_created); fetch_long (); // first message id fetch_long (); // unique_id TLS->net_methods->get_dc (c)->server_salt = fetch_long (); tglq_regen_queries_from_old_session (TLS, DC, S); if (TLS->started && !(TLS->locks & TGL_LOCK_DIFF) && (TLS->DC_working->flags & TGLDCF_LOGGED_IN)) { tgl_do_get_difference (TLS, 0, 0, 0); } return 0; } static int work_msgs_ack (struct tgl_state *TLS, struct connection *c, long long msg_id) { vlogprintf (E_DEBUG, "work_msgs_ack: msg_id = %" INT64_PRINTF_MODIFIER "d\n", msg_id); assert (fetch_int () == CODE_msgs_ack); assert (fetch_int () == CODE_vector); int n = fetch_int (); int i; for (i = 0; i < n; i++) { long long id = fetch_long (); vlogprintf (E_DEBUG + 1, "ack for %" INT64_PRINTF_MODIFIER "d\n", id); tglq_query_ack (TLS, id); } return 0; } static int work_rpc_result (struct tgl_state *TLS, struct connection *c, long long msg_id) { vlogprintf (E_DEBUG, "work_rpc_result: msg_id = %" INT64_PRINTF_MODIFIER "d\n", msg_id); assert (fetch_int () == (int)CODE_rpc_result); long long id = fetch_long (); int op = prefetch_int (); if (op == CODE_rpc_error) { return tglq_query_error (TLS, id); } else { return tglq_query_result (TLS, id); } } #define MAX_PACKED_SIZE (1 << 24) static int work_packed (struct tgl_state *TLS, struct connection *c, long long msg_id) { assert (fetch_int () == CODE_gzip_packed); static int in_gzip; static int buf[MAX_PACKED_SIZE >> 2]; assert (!in_gzip); in_gzip = 1; int l = prefetch_strlen (); char *s = fetch_str (l); int total_out = tgl_inflate (s, l, buf, MAX_PACKED_SIZE); int *end = in_ptr; int *eend = in_end; //assert (total_out % 4 == 0); in_ptr = buf; in_end = in_ptr + total_out / 4; int r = rpc_execute_answer (TLS, c, msg_id); in_ptr = end; in_end = eend; in_gzip = 0; return r; } static int work_bad_server_salt (struct tgl_state *TLS, struct connection *c, long long msg_id) { assert (fetch_int () == (int)CODE_bad_server_salt); long long id = fetch_long (); fetch_int (); // seq_no fetch_int (); // error_code long long new_server_salt = fetch_long (); TLS->net_methods->get_dc (c)->server_salt = new_server_salt; tglq_query_restart (TLS, id); return 0; } static int work_pong (struct tgl_state *TLS, struct connection *c, long long msg_id) { assert (fetch_int () == CODE_pong); fetch_long (); // msg_id fetch_long (); // ping_id return 0; } static int work_detailed_info (struct tgl_state *TLS, struct connection *c, long long msg_id) { assert (fetch_int () == CODE_msg_detailed_info); fetch_long (); // msg_id fetch_long (); // answer_msg_id fetch_int (); // bytes fetch_int (); // status return 0; } static int work_new_detailed_info (struct tgl_state *TLS, struct connection *c, long long msg_id) { assert (fetch_int () == (int)CODE_msg_new_detailed_info); fetch_long (); // answer_msg_id fetch_int (); // bytes fetch_int (); // status return 0; } static int work_bad_msg_notification (struct tgl_state *TLS, struct connection *c, long long msg_id) { assert (fetch_int () == (int)CODE_bad_msg_notification); long long m1 = fetch_long (); int s = fetch_int (); int e = fetch_int (); vlogprintf (E_NOTICE, "bad_msg_notification: msg_id = %" INT64_PRINTF_MODIFIER "d, seq = %d, error = %d\n", m1, s, e); switch (e) { // Too low msg id case 16: tglq_regen_query (TLS, m1); break; // Too high msg id case 17: tglq_regen_query (TLS, m1); break; // Bad container case 64: vlogprintf (E_NOTICE, "bad_msg_notification: msg_id = %" INT64_PRINTF_MODIFIER "d, seq = %d, error = %d\n", m1, s, e); tglq_regen_query (TLS, m1); break; default: vlogprintf (E_NOTICE, "bad_msg_notification: msg_id = %" INT64_PRINTF_MODIFIER "d, seq = %d, error = %d\n", m1, s, e); break; } return -1; } static int rpc_execute_answer (struct tgl_state *TLS, struct connection *c, long long msg_id) { int op = prefetch_int (); switch (op) { case CODE_msg_container: return work_container (TLS, c, msg_id); case CODE_new_session_created: return work_new_session_created (TLS, c, msg_id); case CODE_msgs_ack: return work_msgs_ack (TLS, c, msg_id); case CODE_rpc_result: return work_rpc_result (TLS, c, msg_id); case CODE_update_short: case CODE_updates: case CODE_update_short_message: case CODE_update_short_chat_message: case CODE_updates_too_long: tglu_work_any_updates_buf (TLS); return 0; case CODE_gzip_packed: return work_packed (TLS, c, msg_id); case CODE_bad_server_salt: return work_bad_server_salt (TLS, c, msg_id); case CODE_pong: return work_pong (TLS, c, msg_id); case CODE_msg_detailed_info: return work_detailed_info (TLS, c, msg_id); case CODE_msg_new_detailed_info: return work_new_detailed_info (TLS, c, msg_id); case CODE_bad_msg_notification: return work_bad_msg_notification (TLS, c, msg_id); } vlogprintf (E_WARNING, "Unknown message: %08x\n", op); in_ptr = in_end; // Will not fail due to assertion in_ptr == in_end return 0; } static struct mtproto_methods mtproto_methods; void tgls_free_session (struct tgl_state *TLS, struct tgl_session *S); /* static char *get_ipv6 (struct tgl_state *TLS, int num) { static char res[1<< 10]; if (TLS->test_mode) { switch (num) { case 1: strcpy (res, TG_SERVER_TEST_IPV6_1); break; case 2: strcpy (res, TG_SERVER_TEST_IPV6_2); break; case 3: strcpy (res, TG_SERVER_TEST_IPV6_3); break; default: assert (0); } } else { switch (num) { case 1: strcpy (res, TG_SERVER_IPV6_1); break; case 2: strcpy (res, TG_SERVER_IPV6_2); break; case 3: strcpy (res, TG_SERVER_IPV6_3); break; case 4: strcpy (res, TG_SERVER_IPV6_4); break; case 5: strcpy (res, TG_SERVER_IPV6_5); break; default: assert (0); } } return res; } */ static void create_session_connect (struct tgl_state *TLS, struct tgl_session *S) { struct tgl_dc *DC = S->dc; if (TLS->ipv6_enabled) { S->c = TLS->net_methods->create_connection (TLS, DC->options[1]->ip, DC->options[1]->port, S, DC, &mtproto_methods); } else { S->c = TLS->net_methods->create_connection (TLS, DC->options[0]->ip, DC->options[0]->port, S, DC, &mtproto_methods); } } static void fail_connection (struct tgl_state *TLS, struct connection *c) { struct tgl_session *S = TLS->net_methods->get_session (c); TLS->net_methods->free (c); create_session_connect (TLS, S); } static void fail_session (struct tgl_state *TLS, struct tgl_session *S) { vlogprintf (E_NOTICE, "failing session %" INT64_PRINTF_MODIFIER "d\n", S->session_id); struct tgl_dc *DC = S->dc; tgls_free_session (TLS, S); DC->sessions[0] = NULL; tglmp_dc_create_session (TLS, DC); } static int process_rpc_message (struct tgl_state *TLS, struct connection *c, struct encrypted_message *enc, int len) { const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); vlogprintf (E_DEBUG, "process_rpc_message(), len=%d\n", len); if (len < MINSZ || (len & 15) != (UNENCSZ & 15)) { vlogprintf (E_WARNING, "Incorrect packet from server. Closing connection\n"); fail_connection (TLS, c); return -1; } assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); struct tgl_dc *DC = TLS->net_methods->get_dc (c); if (enc->auth_key_id != DC->temp_auth_key_id && enc->auth_key_id != DC->auth_key_id) { vlogprintf (E_WARNING, "received msg from dc %d with auth_key_id %" INT64_PRINTF_MODIFIER "d (perm_auth_key_id %" INT64_PRINTF_MODIFIER "d temp_auth_key_id %" INT64_PRINTF_MODIFIER "d). Dropping\n", DC->id, enc->auth_key_id, DC->auth_key_id, DC->temp_auth_key_id); return 0; } if (enc->auth_key_id == DC->temp_auth_key_id) { assert (enc->auth_key_id == DC->temp_auth_key_id); assert (DC->temp_auth_key_id); tgl_init_aes_auth (DC->temp_auth_key + 8, enc->msg_key, 0); } else { assert (enc->auth_key_id == DC->auth_key_id); assert (DC->auth_key_id); tgl_init_aes_auth (DC->auth_key + 8, enc->msg_key, 0); } int l = tgl_pad_aes_decrypt ((char *)&enc->server_salt, len - UNENCSZ, (char *)&enc->server_salt, len - UNENCSZ); assert (l == len - UNENCSZ); if (!(!(enc->msg_len & 3) && enc->msg_len > 0 && enc->msg_len <= len - MINSZ && len - MINSZ - enc->msg_len <= 12)) { vlogprintf (E_WARNING, "Incorrect packet from server. Closing connection\n"); fail_connection (TLS, c); return -1; } assert (!(enc->msg_len & 3) && enc->msg_len > 0 && enc->msg_len <= len - MINSZ && len - MINSZ - enc->msg_len <= 12); struct tgl_session *S = TLS->net_methods->get_session (c); if (!S || S->session_id != enc->session_id) { vlogprintf (E_WARNING, "Message to bad session. Drop.\n"); return 0; } static unsigned char sha1_buffer[20]; TGLC_sha1 ((void *)&enc->server_salt, enc->msg_len + (MINSZ - UNENCSZ), sha1_buffer); if (memcmp (&enc->msg_key, sha1_buffer + 4, 16)) { vlogprintf (E_WARNING, "Incorrect packet from server. Closing connection\n"); fail_connection (TLS, c); return -1; } assert (!memcmp (&enc->msg_key, sha1_buffer + 4, 16)); int this_server_time = enc->msg_id >> 32LL; if (!S->received_messages) { DC->server_time_delta = this_server_time - get_utime (CLOCK_REALTIME); if (DC->server_time_udelta) { vlogprintf (E_WARNING, "adjusting CLOCK_MONOTONIC delta to %lf\n", DC->server_time_udelta - this_server_time + get_utime (CLOCK_MONOTONIC)); } DC->server_time_udelta = this_server_time - get_utime (CLOCK_MONOTONIC); } double st = get_server_time (DC); if (this_server_time < st - 300 || this_server_time > st + 30) { vlogprintf (E_WARNING, "bad msg time: salt = %" INT64_PRINTF_MODIFIER "d, session_id = %" INT64_PRINTF_MODIFIER "d, msg_id = %" INT64_PRINTF_MODIFIER "d, seq_no = %d, st = %lf, now = %lf\n", enc->server_salt, enc->session_id, enc->msg_id, enc->seq_no, st, get_utime (CLOCK_REALTIME)); fail_session (TLS, S); return -1; } S->received_messages ++; if (DC->server_salt != enc->server_salt) { DC->server_salt = enc->server_salt; } assert (this_server_time >= st - 300 && this_server_time <= st + 30); //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); vlogprintf (E_DEBUG, "received mesage id %016" INT64_PRINTF_MODIFIER "x\n", enc->msg_id); //server_last_msg_id = enc->msg_id; //*(long long *)(longpoll_query + 3) = *(long long *)((char *)(&enc->msg_id) + 0x3c); //*(long long *)(longpoll_query + 5) = *(long long *)((char *)(&enc->msg_id) + 0x3c); assert (l >= (MINSZ - UNENCSZ) + 8); //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); in_ptr = enc->message; in_end = in_ptr + (enc->msg_len / 4); if (enc->msg_id & 1) { tgln_insert_msg_id (TLS, S, enc->msg_id); } assert (S->session_id == enc->session_id); if (rpc_execute_answer (TLS, c, enc->msg_id) < 0) { fail_session (TLS, S); return -1; } assert (in_ptr == in_end); return 0; } static int rpc_execute (struct tgl_state *TLS, struct connection *c, int op, int len) { struct tgl_dc *DC = TLS->net_methods->get_dc (c); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { vlogprintf (E_WARNING, "answer too long (%d bytes), skipping\n", len); return 0; } int Response_len = len; static char Response[MAX_RESPONSE_SIZE]; vlogprintf (E_DEBUG, "Response_len = %d\n", Response_len); assert (TLS->net_methods->read_in (c, Response, Response_len) == Response_len); #if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) // setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif int o = DC->state; //if (DC->flags & 1) { o = st_authorized;} if (o != st_authorized) { vlogprintf (E_DEBUG, "%s: state = %d\n", __func__, o); } switch (o) { case st_reqpq_sent: process_respq_answer (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 0); return 0; case st_reqdh_sent: process_dh_answer (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 0); return 0; case st_client_dh_sent: process_auth_complete (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 0); return 0; case st_reqpq_sent_temp: process_respq_answer (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 1); return 0; case st_reqdh_sent_temp: process_dh_answer (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 1); return 0; case st_client_dh_sent_temp: process_auth_complete (TLS, c, Response/* + 8*/, Response_len/* - 12*/, 1); return 0; case st_authorized: if (op < 0 && op >= -999) { vlogprintf (E_WARNING, "Server error %d\n", op); } else { return process_rpc_message (TLS, c, (void *)(Response/* + 8*/), Response_len/* - 12*/); } return 0; default: vlogprintf (E_ERROR, "fatal: cannot receive answer in state %d\n", DC->state); exit (2); } return 0; } static int tc_close (struct tgl_state *TLS, struct connection *c, int who) { vlogprintf (E_DEBUG, "outbound rpc connection from dc #%d : closing by %d\n", TLS->net_methods->get_dc(c)->id, who); return 0; } static void mpc_on_get_config (struct tgl_state *TLS, void *extra, int success) { assert (success); struct tgl_dc *DC = extra; DC->flags |= 4; } static int tc_becomes_ready (struct tgl_state *TLS, struct connection *c) { vlogprintf (E_NOTICE, "outbound rpc connection from dc #%d becomed ready\n", TLS->net_methods->get_dc(c)->id); //char byte = 0xef; //assert (TLS->net_methods->write_out (c, &byte, 1) == 1); //TLS->net_methods->flush_out (c); struct tgl_dc *DC = TLS->net_methods->get_dc (c); if (DC->flags & 1) { DC->state = st_authorized; } int o = DC->state; if (o == st_authorized && !TLS->enable_pfs) { DC->temp_auth_key_id = DC->auth_key_id; memcpy (DC->temp_auth_key, DC->auth_key, 256); DC->flags |= 2; } switch (o) { case st_init: send_req_pq_packet (TLS, c); break; case st_authorized: if (!(DC->flags & 2)) { assert (TLS->enable_pfs); if (!DC->temp_auth_key_id) { assert (!DC->temp_auth_key_id); assert (TLS->enable_pfs); create_temp_auth_key (TLS, c); } else { bind_temp_auth_key (TLS, c); } } else if (!(DC->flags & 4)) { tgl_do_help_get_config_dc (TLS, DC, mpc_on_get_config, DC); } break; default: vlogprintf (E_DEBUG, "c_state = %d\n", DC->state); DC->state = st_init; // previous connection was reset send_req_pq_packet (TLS, c); break; } return 0; } static int rpc_becomes_ready (struct tgl_state *TLS, struct connection *c) { return tc_becomes_ready (TLS, c); } static int rpc_close (struct tgl_state *TLS, struct connection *c) { return tc_close (TLS, c, 0); } #define RANDSEED_PASSWORD_FILENAME NULL #define RANDSEED_PASSWORD_LENGTH 0 int tglmp_on_start (struct tgl_state *TLS) { tgl_prng_seed (TLS, RANDSEED_PASSWORD_FILENAME, RANDSEED_PASSWORD_LENGTH); int i; int ok = 0; for (i = 0; i < TLS->rsa_key_num; i++) { char *key = TLS->rsa_key_list[i]; if (!key) { /* This key was provided using 'tgl_set_rsa_key_direct'. */ TGLC_rsa *rsa = TLS->rsa_key_loaded[i]; assert (rsa); TLS->rsa_key_fingerprint[i] = tgl_do_compute_rsa_key_fingerprint (rsa); vlogprintf (E_NOTICE, "'direct' public key loaded successfully\n"); ok = 1; } else { TGLC_rsa *res = rsa_load_public_key (TLS, key); if (!res) { vlogprintf (E_WARNING, "Can not load key %s\n", key); TLS->rsa_key_loaded[i] = NULL; } else { ok = 1; TLS->rsa_key_loaded[i] = res; TLS->rsa_key_fingerprint[i] = tgl_do_compute_rsa_key_fingerprint (res); } } } if (!ok) { vlogprintf (E_ERROR, "No public keys found\n"); TLS->error = tstrdup ("No public keys found"); TLS->error_code = ENOTCONN; return -1; } return 0; } void tgl_dc_authorize (struct tgl_state *TLS, struct tgl_dc *DC) { //c_state = 0; if (!DC->sessions[0]) { tglmp_dc_create_session (TLS, DC); } vlogprintf (E_DEBUG, "Starting authorization for DC #%d\n", DC->id); //net_loop (0, auth_ok); } #define long_cmp(a,b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1) DEFINE_TREE(long,long long,long_cmp,0) static int send_all_acks (struct tgl_state *TLS, struct tgl_session *S) { clear_packet (); out_int (CODE_msgs_ack); out_int (CODE_vector); out_int (tree_count_long (S->ack_tree)); while (S->ack_tree) { long long x = tree_get_min_long (S->ack_tree); out_long (x); S->ack_tree = tree_delete_long (S->ack_tree, x); } tglmp_encrypt_send_message (TLS, S->c, packet_buffer, packet_ptr - packet_buffer, 0); return 0; } static void send_all_acks_gateway (struct tgl_state *TLS, void *arg) { send_all_acks (TLS, arg); } void tgln_insert_msg_id (struct tgl_state *TLS, struct tgl_session *S, long long id) { if (!S->ack_tree) { TLS->timer_methods->insert (S->ev, ACK_TIMEOUT); } if (!tree_lookup_long (S->ack_tree, id)) { S->ack_tree = tree_insert_long (S->ack_tree, id, rand ()); } } //extern struct tgl_dc *DC_list[]; static void regen_temp_key_gw (struct tgl_state *TLS, void *arg) { tglmp_regenerate_temp_auth_key (TLS, arg); } struct tgl_dc *tglmp_alloc_dc (struct tgl_state *TLS, int flags, int id, char *ip, int port) { //assert (!TLS->DC_list[id]); if (!TLS->DC_list[id]) { struct tgl_dc *DC = talloc0 (sizeof (*DC)); DC->id = id; TLS->DC_list[id] = DC; if (id > TLS->max_dc_num) { TLS->max_dc_num = id; } if (TLS->enable_pfs) { DC->ev = TLS->timer_methods->alloc (TLS, regen_temp_key_gw, DC); TLS->timer_methods->insert (DC->ev, 0); } } struct tgl_dc *DC = TLS->DC_list[id]; struct tgl_dc_option *O = DC->options[flags & 3]; struct tgl_dc_option *O2 = O; while (O2) { if (!strcmp (O2->ip, ip)) { tfree_str (ip); return DC; } O2 = O2->next; } struct tgl_dc_option *T = talloc (sizeof (*T)); T->ip = ip; T->port = port; T->next = O; DC->options[flags & 3] = T; return DC; } static struct mtproto_methods mtproto_methods = { .execute = rpc_execute, .ready = rpc_becomes_ready, .close = rpc_close }; void tglmp_dc_create_session (struct tgl_state *TLS, struct tgl_dc *DC) { struct tgl_session *S = talloc0 (sizeof (*S)); assert (TGLC_rand_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); S->dc = DC; //S->c = TLS->net_methods->create_connection (TLS, DC->ip, DC->port, S, DC, &mtproto_methods); create_session_connect (TLS, S); S->ev = TLS->timer_methods->alloc (TLS, send_all_acks_gateway, S); assert (!DC->sessions[0]); DC->sessions[0] = S; } void tgl_do_send_ping (struct tgl_state *TLS, struct connection *c) { int x[3]; x[0] = CODE_ping; *(long long *)(x + 1) = rand () * (1ll << 32) + rand (); tglmp_encrypt_send_message (TLS, c, x, 3, 0); } void tgl_dc_iterator (struct tgl_state *TLS, void (*iterator)(struct tgl_dc *DC)) { int i; for (i = 0; i <= TLS->max_dc_num; i++) { iterator (TLS->DC_list[i]); } } void tgl_dc_iterator_ex (struct tgl_state *TLS, void (*iterator)(struct tgl_dc *DC, void *extra), void *extra) { int i; for (i = 0; i <= TLS->max_dc_num; i++) { iterator (TLS->DC_list[i], extra); } } void tglmp_regenerate_temp_auth_key (struct tgl_state *TLS, struct tgl_dc *DC) { DC->flags &= ~6; DC->temp_auth_key_id = 0; memset (DC->temp_auth_key, 0, 256); if (!DC->sessions[0]) { tgl_dc_authorize (TLS, DC); return; } struct tgl_session *S = DC->sessions[0]; tglt_secure_random (&S->session_id, 8); S->seq_no = 0; TLS->timer_methods->remove (S->ev); S->ack_tree = tree_clear_long (S->ack_tree); if (DC->state != st_authorized) { return; } if (!TLS->enable_pfs) { return; } if (S->c) { assert (TLS->enable_pfs); create_temp_auth_key (TLS, S->c); } } void tgls_free_session (struct tgl_state *TLS, struct tgl_session *S) { S->ack_tree = tree_clear_long (S->ack_tree); if (S->ev) { TLS->timer_methods->free (S->ev); } if (S->c) { TLS->net_methods->free (S->c); } tfree (S, sizeof (*S)); } void tgls_free_dc (struct tgl_state *TLS, struct tgl_dc *DC) { //if (DC->ip) { tfree_str (DC->ip); } struct tgl_session *S = DC->sessions[0]; if (S) { tgls_free_session (TLS, S); } int i; for (i = 0; i < 4; i++) { struct tgl_dc_option *O = DC->options[i]; while (O) { struct tgl_dc_option *N = O->next; tfree_str (O->ip); tfree (O, sizeof (*O)); O = N; } } if (DC->ev) { TLS->timer_methods->free (DC->ev); } tfree (DC, sizeof (*DC)); } void tgls_free_pubkey (struct tgl_state *TLS) { int i; for (i = 0; i < TLS->rsa_key_num; i++) { if (TLS->rsa_key_loaded[i]) { TGLC_rsa_free (TLS->rsa_key_loaded[i]); TLS->rsa_key_loaded[i] = NULL; } } } telegram-purple/tgl/mtproto-client.h000066400000000000000000000047411357227200100201070ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Nikolay Durov, Andrey Lopatin 2012-2013 Vitaly Valtman 2013-2015 */ #ifndef __MTPROTO_CLIENT_H__ #define __MTPROTO_CLIENT_H__ //#include "net.h" #include "crypto/bn.h" //void on_start (void); //..long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful); //void dc_authorize (struct tgl_dc *DC); //void work_update (struct connection *c, long long msg_id); //void work_update_binlog (void); //int check_g (unsigned char p[256], BIGNUM *g); //int check_g_bn (BIGNUM *p, BIGNUM *g); //int check_DH_params (BIGNUM *p, int g); //void secure_random (void *s, int l); #include "tgl.h" struct connection; struct tgl_dc; //#include "queries.h" #define TG_APP_HASH "844584f2b1fd2daecee726166dcc1ef8" #define TG_APP_ID 10534 #define ACK_TIMEOUT 1 #define MAX_DC_ID 10 struct connection; long long tglmp_encrypt_send_message (struct tgl_state *TLS, struct connection *c, int *msg, int msg_ints, int flags); void tglmp_dc_create_session (struct tgl_state *TLS, struct tgl_dc *DC); //int tglmp_check_g (struct tgl_state *TLS, unsigned char p[256], BIGNUM *g); //int tglmp_check_DH_params (struct tgl_state *TLS, BIGNUM *p, int g); struct tgl_dc *tglmp_alloc_dc (struct tgl_state *TLS, int flags, int id, char *ip, int port); void tglmp_regenerate_temp_auth_key (struct tgl_state *TLS, struct tgl_dc *D); void tgln_insert_msg_id (struct tgl_state *TLS, struct tgl_session *S, long long id); int tglmp_on_start (struct tgl_state *TLS); void tgl_dc_authorize (struct tgl_state *TLS, struct tgl_dc *DC); void tgls_free_dc (struct tgl_state *TLS, struct tgl_dc *DC); void tgls_free_pubkey (struct tgl_state *TLS); void tgl_do_send_ping (struct tgl_state *TLS, struct connection *c); #endif telegram-purple/tgl/mtproto-common.c000066400000000000000000000275021357227200100201140ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Nikolay Durov, Andrey Lopatin 2012-2013 Vitaly Valtman 2013-2015 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #ifdef WIN32 #include #else #include #endif #include "crypto/aes.h" #include "crypto/rand.h" #include "crypto/sha.h" #include "mtproto-common.h" #include "tools.h" #ifdef __MACH__ #include #include #endif #include #ifndef O_BINARY #define O_BINARY 0 #endif static int __packet_buffer[PACKET_BUFFER_SIZE + 16]; int *tgl_packet_ptr; int *tgl_packet_buffer = __packet_buffer + 16; static long long rsa_encrypted_chunks, rsa_decrypted_chunks; //int verbosity; #ifndef WIN32 static int get_random_bytes (struct tgl_state *TLS, unsigned char *buf, int n) { int r = 0, h = open ("/dev/random", O_RDONLY | O_NONBLOCK); if (h >= 0) { r = read (h, buf, n); if (r > 0) { vlogprintf (E_DEBUG, "added %d bytes of real entropy to secure random numbers seed\n", r); } else { r = 0; } close (h); } if (r < n) { h = open ("/dev/urandom", O_RDONLY); if (h < 0) { return r; } int s = read (h, buf + r, n - r); close (h); if (s > 0) { r += s; } } if (r >= (int) sizeof (long)) { *(long *)buf ^= lrand48 (); srand48 (*(long *)buf); } return r; } #else static HCRYPTPROV hCryptoServiceProvider = 0; static int get_random_bytes (struct tgl_state *TLS, unsigned char *buf, int n) { if (hCryptoServiceProvider == 0) { /* Crypto init */ CryptAcquireContextA(&hCryptoServiceProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); } if (!CryptGenRandom(hCryptoServiceProvider, n, buf)) { return -1; } return n; } #endif /* RDTSC */ #if defined(__i386__) #define HAVE_RDTSC static __inline__ unsigned long long rdtsc (void) { unsigned long long int x; __asm__ volatile ("rdtsc" : "=A" (x)); return x; } #elif defined(__x86_64__) #define HAVE_RDTSC static __inline__ unsigned long long rdtsc (void) { unsigned hi, lo; __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); return ((unsigned long long) lo) | (((unsigned long long) hi) << 32); } #endif void tgl_prng_seed (struct tgl_state *TLS, const char *password_filename, int password_length) { struct timespec T; tgl_my_clock_gettime (CLOCK_REALTIME, &T); TGLC_rand_add (&T, sizeof (T), 4.0); #ifdef HAVE_RDTSC unsigned long long r = rdtsc (); TGLC_rand_add (&r, 8, 4.0); #endif unsigned short p = getpid (); TGLC_rand_add (&p, sizeof (p), 0.0); #ifndef WIN32 p = getppid (); TGLC_rand_add (&p, sizeof (p), 0.0); #endif unsigned char rb[32]; int s = get_random_bytes (TLS, rb, 32); if (s > 0) { TGLC_rand_add (rb, s, s); } memset (rb, 0, sizeof (rb)); if (password_filename && password_length > 0) { int fd = open (password_filename, O_RDONLY | O_BINARY); if (fd < 0) { vlogprintf (E_WARNING, "Warning: fail to open password file - \"%s\", %s.\n", password_filename, strerror(errno)); } else { unsigned char *a = talloc0 (password_length); int l = read (fd, a, password_length); if (l < 0) { vlogprintf (E_WARNING, "Warning: fail to read password file - \"%s\", %s.\n", password_filename, strerror(errno)); } else { vlogprintf (E_DEBUG, "read %d bytes from password file.\n", l); TGLC_rand_add (a, l, l); } close (fd); tfree_secure (a, password_length); } } TLS->TGLC_bn_ctx = TGLC_bn_ctx_new (); ensure_ptr (TLS->TGLC_bn_ctx); } int tgl_serialize_bignum (TGLC_bn *b, char *buffer, int maxlen) { int itslen = TGLC_bn_num_bytes (b); int reqlen; if (itslen < 254) { reqlen = itslen + 1; } else { reqlen = itslen + 4; } int newlen = (reqlen + 3) & -4; int pad = newlen - reqlen; reqlen = newlen; if (reqlen > maxlen) { return -reqlen; } if (itslen < 254) { *buffer++ = itslen; } else { *(int *)buffer = (itslen << 8) + 0xfe; buffer += 4; } int l = TGLC_bn_bn2bin (b, (unsigned char *)buffer); assert (l == itslen); buffer += l; while (pad --> 0) { *buffer++ = 0; } return reqlen; } long long tgl_do_compute_rsa_key_fingerprint (TGLC_rsa *key) { static char tempbuff[4096]; static unsigned char sha[20]; assert (TGLC_rsa_n (key) && TGLC_rsa_e (key)); int l1 = tgl_serialize_bignum (TGLC_rsa_n (key), tempbuff, 4096); assert (l1 > 0); int l2 = tgl_serialize_bignum (TGLC_rsa_e (key), tempbuff + l1, 4096 - l1); assert (l2 > 0 && l1 + l2 <= 4096); TGLC_sha1 ((unsigned char *)tempbuff, l1 + l2, sha); return *(long long *)(sha + 12); } void tgl_out_cstring (const char *str, long len) { assert (len >= 0 && len < (1 << 24)); assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE)); char *dest = (char *) packet_ptr; if (len < 254) { *dest++ = len; } else { *packet_ptr = (len << 8) + 0xfe; dest += 4; } memcpy (dest, str, len); dest += len; while ((long) dest & 3) { *dest++ = 0; } packet_ptr = (int *) dest; } void tgl_out_cstring_careful (const char *str, long len) { assert (len >= 0 && len < (1 << 24)); assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE)); char *dest = (char *) packet_ptr; if (len < 254) { dest++; if (dest != str) { memmove (dest, str, len); } dest[-1] = len; } else { dest += 4; if (dest != str) { memmove (dest, str, len); } *packet_ptr = (len << 8) + 0xfe; } dest += len; while ((long) dest & 3) { *dest++ = 0; } packet_ptr = (int *) dest; } void tgl_out_data (const void *data, long len) { assert (len >= 0 && len < (1 << 24) && !(len & 3)); assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE)); memcpy (packet_ptr, data, len); packet_ptr += len >> 2; } int *tgl_in_ptr, *tgl_in_end; int tgl_fetch_bignum (TGLC_bn *x) { int l = prefetch_strlen (); if (l < 0) { return l; } char *str = fetch_str (l); assert (TGLC_bn_bin2bn ((unsigned char *) str, l, x) == x); return l; } int tgl_pad_rsa_encrypt (struct tgl_state *TLS, char *from, int from_len, char *to, int size, TGLC_bn *N, TGLC_bn *E) { int pad = (255000 - from_len - 32) % 255 + 32; int chunks = (from_len + pad) / 255; int bits = TGLC_bn_num_bits (N); assert (bits >= 2041 && bits <= 2048); assert (from_len > 0 && from_len <= 2550); assert (size >= chunks * 256); assert (TGLC_rand_pseudo_bytes ((unsigned char *) from + from_len, pad) >= 0); int i; TGLC_bn *x = TGLC_bn_new (); TGLC_bn *y = TGLC_bn_new (); assert(x); assert(y); rsa_encrypted_chunks += chunks; for (i = 0; i < chunks; i++) { TGLC_bn_bin2bn ((unsigned char *) from, 255, x); assert (TGLC_bn_mod_exp (y, x, E, N, TLS->TGLC_bn_ctx) == 1); unsigned l = 256 - TGLC_bn_num_bytes (y); assert (l <= 256); memset (to, 0, l); TGLC_bn_bn2bin (y, (unsigned char *) to + l); to += 256; } TGLC_bn_free (x); TGLC_bn_free (y); return chunks * 256; } int tgl_pad_rsa_decrypt (struct tgl_state *TLS, char *from, int from_len, char *to, int size, TGLC_bn *N, TGLC_bn *D) { if (from_len < 0 || from_len > 0x1000 || (from_len & 0xff)) { return -1; } int chunks = (from_len >> 8); int bits = TGLC_bn_num_bits (N); assert (bits >= 2041 && bits <= 2048); assert (size >= chunks * 255); int i; TGLC_bn *x = TGLC_bn_new (); TGLC_bn *y = TGLC_bn_new (); assert(x); assert(y); for (i = 0; i < chunks; i++) { ++rsa_decrypted_chunks; TGLC_bn_bin2bn ((unsigned char *) from, 256, x); assert (TGLC_bn_mod_exp (y, x, D, N, TLS->TGLC_bn_ctx) == 1); int l = TGLC_bn_num_bytes (y); if (l > 255) { TGLC_bn_free (x); TGLC_bn_free (y); return -1; } assert (l >= 0 && l <= 255); memset (to, 0, 255 - l); TGLC_bn_bn2bin (y, (unsigned char *) to + 255 - l); to += 255; } TGLC_bn_free (x); TGLC_bn_free (y); return chunks * 255; } static unsigned char aes_key_raw[32], aes_iv[32]; static TGLC_aes_key aes_key; void tgl_init_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32], int encrypt) { static unsigned char buffer[64], hash[20]; memcpy (buffer, hidden_client_nonce, 32); memcpy (buffer + 32, server_nonce, 16); TGLC_sha1 (buffer, 48, aes_key_raw); memcpy (buffer + 32, hidden_client_nonce, 32); TGLC_sha1 (buffer, 64, aes_iv + 8); memcpy (buffer, server_nonce, 16); memcpy (buffer + 16, hidden_client_nonce, 32); TGLC_sha1 (buffer, 48, hash); memcpy (aes_key_raw + 20, hash, 12); memcpy (aes_iv, hash + 12, 8); memcpy (aes_iv + 28, hidden_client_nonce, 4); if (encrypt) { TGLC_aes_set_encrypt_key (aes_key_raw, 32*8, &aes_key); } else { TGLC_aes_set_decrypt_key (aes_key_raw, 32*8, &aes_key); } memset (aes_key_raw, 0, sizeof (aes_key_raw)); } void tgl_init_aes_auth (char auth_key[192], char msg_key[16], int encrypt) { static unsigned char buffer[48], hash[20]; // sha1_a = SHA1 (msg_key + substr (auth_key, 0, 32)); // sha1_b = SHA1 (substr (auth_key, 32, 16) + msg_key + substr (auth_key, 48, 16)); // sha1_с = SHA1 (substr (auth_key, 64, 32) + msg_key); // sha1_d = SHA1 (msg_key + substr (auth_key, 96, 32)); // aes_key = substr (sha1_a, 0, 8) + substr (sha1_b, 8, 12) + substr (sha1_c, 4, 12); // aes_iv = substr (sha1_a, 8, 12) + substr (sha1_b, 0, 8) + substr (sha1_c, 16, 4) + substr (sha1_d, 0, 8); memcpy (buffer, msg_key, 16); memcpy (buffer + 16, auth_key, 32); TGLC_sha1 (buffer, 48, hash); memcpy (aes_key_raw, hash, 8); memcpy (aes_iv, hash + 8, 12); memcpy (buffer, auth_key + 32, 16); memcpy (buffer + 16, msg_key, 16); memcpy (buffer + 32, auth_key + 48, 16); TGLC_sha1 (buffer, 48, hash); memcpy (aes_key_raw + 8, hash + 8, 12); memcpy (aes_iv + 12, hash, 8); memcpy (buffer, auth_key + 64, 32); memcpy (buffer + 32, msg_key, 16); TGLC_sha1 (buffer, 48, hash); memcpy (aes_key_raw + 20, hash + 4, 12); memcpy (aes_iv + 20, hash + 16, 4); memcpy (buffer, msg_key, 16); memcpy (buffer + 16, auth_key + 96, 32); TGLC_sha1 (buffer, 48, hash); memcpy (aes_iv + 24, hash, 8); if (encrypt) { TGLC_aes_set_encrypt_key (aes_key_raw, 32*8, &aes_key); } else { TGLC_aes_set_decrypt_key (aes_key_raw, 32*8, &aes_key); } memset (aes_key_raw, 0, sizeof (aes_key_raw)); } int tgl_pad_aes_encrypt (char *from, int from_len, char *to, int size) { int padded_size = (from_len + 15) & -16; assert (from_len > 0 && padded_size <= size); if (from_len < padded_size) { assert (TGLC_rand_pseudo_bytes ((unsigned char *) from + from_len, padded_size - from_len) >= 0); } TGLC_aes_ige_encrypt ((unsigned char *) from, (unsigned char *) to, padded_size, &aes_key, aes_iv, 1); return padded_size; } int tgl_pad_aes_decrypt (char *from, int from_len, char *to, int size) { if (from_len <= 0 || from_len > size || (from_len & 15)) { return -1; } TGLC_aes_ige_encrypt ((unsigned char *) from, (unsigned char *) to, from_len, &aes_key, aes_iv, 0); return from_len; } telegram-purple/tgl/mtproto-common.h000066400000000000000000000244331357227200100201210ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Nikolay Durov, Andrey Lopatin 2012-2013 Vitaly Valtman 2013-2015 */ #ifndef __MTPROTO_COMMON_H__ #define __MTPROTO_COMMON_H__ #include #include "crypto/rsa_pem.h" #include "crypto/bn.h" #include #include #if defined(_MSC_VER) || defined(__MINGW32__) #define INT64_PRINTF_MODIFIER "I64" #else #define INT64_PRINTF_MODIFIER "ll" #endif //#include "interface.h" #include "tools.h" #include "auto/constants.h" #include "tgl.h" #include "tgl-inner.h" /* DH key exchange protocol data structures */ #define CODE_req_pq 0x60469778 #define CODE_resPQ 0x05162463 #define CODE_req_DH_params 0xd712e4be #define CODE_p_q_inner_data 0x83c95aec #define CODE_p_q_inner_data_temp 0x3c6a84d4 #define CODE_server_DH_inner_data 0xb5890dba #define CODE_server_DH_params_fail 0x79cb045d #define CODE_server_DH_params_ok 0xd0e8075c #define CODE_set_client_DH_params 0xf5045f1f #define CODE_client_DH_inner_data 0x6643b654 #define CODE_dh_gen_ok 0x3bcbf734 #define CODE_dh_gen_retry 0x46dc1fb9 #define CODE_dh_gen_fail 0xa69dae02 #define CODE_bind_auth_key_inner 0x75a3f765 /* service messages */ #define CODE_rpc_result 0xf35c6d01 #define CODE_rpc_error 0x2144ca19 #define CODE_msg_container 0x73f1f8dc #define CODE_msg_copy 0xe06046b2 #define CODE_msgs_ack 0x62d6b459 #define CODE_bad_msg_notification 0xa7eff811 #define CODE_bad_server_salt 0xedab447b #define CODE_msgs_state_req 0xda69fb52 #define CODE_msgs_state_info 0x04deb57d #define CODE_msgs_all_info 0x8cc0d131 #define CODE_new_session_created 0x9ec20908 #define CODE_msg_resend_req 0x7d861a08 #define CODE_ping 0x7abe77ec #define CODE_pong 0x347773c5 #define CODE_destroy_session 0xe7512126 #define CODE_destroy_session_ok 0xe22045fc #define CODE_destroy_session_none 0x62d350c9 #define CODE_destroy_sessions 0x9a6face8 #define CODE_destroy_sessions_res 0xa8164668 #define CODE_get_future_salts 0xb921bd04 #define CODE_future_salt 0x0949d9dc #define CODE_future_salts 0xae500895 #define CODE_rpc_drop_answer 0x58e4a740 #define CODE_rpc_answer_unknown 0x5e2ad36e #define CODE_rpc_answer_dropped_running 0xcd78e586 #define CODE_rpc_answer_dropped 0xa43ad8b7 #define CODE_msg_detailed_info 0x276d3ec6 #define CODE_msg_new_detailed_info 0x809db6df #define CODE_ping_delay_disconnect 0xf3427b8c #define CODE_gzip_packed 0x3072cfa1 #define CODE_input_peer_notify_settings_old 0x3cf4b1be #define CODE_peer_notify_settings_old 0xddbcd4a5 #define CODE_user_profile_photo_old 0x990d1493 #define CODE_config_old 0x232d5905 #define CODE_msg_new_detailed_info 0x809db6df #define CODE_msg_detailed_info 0x276d3ec6 /* not really a limit, for struct encrypted_message only */ // #define MAX_MESSAGE_INTS 16384 #define MAX_MESSAGE_INTS 1048576 #define MAX_PROTO_MESSAGE_INTS 1048576 #define PACKET_BUFFER_SIZE (16384 * 100 + 16) // temp fix #pragma pack(push,4) struct encrypted_message { // unencrypted header long long auth_key_id; char msg_key[16]; // encrypted part, starts with encrypted header long long server_salt; long long session_id; // long long auth_key_id2; // removed // first message follows long long msg_id; int seq_no; int msg_len; // divisible by 4 int message[MAX_MESSAGE_INTS]; }; #pragma pack(pop) //TGLC_bn_ctx *bn_ctx; void tgl_prng_seed (struct tgl_state *TLS, const char *password_filename, int password_length); int tgl_serialize_bignum (TGLC_bn *b, char *buffer, int maxlen); long long tgl_do_compute_rsa_key_fingerprint (TGLC_rsa *key); #define packet_buffer tgl_packet_buffer #define packet_ptr tgl_packet_ptr extern int *tgl_packet_buffer; extern int *tgl_packet_ptr; static inline void out_ints (const int *what, int len) { assert (packet_ptr + len <= packet_buffer + PACKET_BUFFER_SIZE); memcpy (packet_ptr, what, len * 4); packet_ptr += len; } static inline void out_int (int x) { assert (packet_ptr + 1 <= packet_buffer + PACKET_BUFFER_SIZE); *packet_ptr++ = x; } static inline void out_long (long long x) { assert (packet_ptr + 2 <= packet_buffer + PACKET_BUFFER_SIZE); *(long long *)packet_ptr = x; packet_ptr += 2; } static inline void out_double (double x) { assert (packet_ptr + 2 <= packet_buffer + PACKET_BUFFER_SIZE); *(double *)packet_ptr = x; packet_ptr += 2; } static inline void clear_packet (void) { packet_ptr = packet_buffer; } void tgl_out_cstring (const char *str, long len); void tgl_out_cstring_careful (const char *str, long len); void tgl_out_data (const void *data, long len); #define out_cstring tgl_out_cstring #define out_cstring_careful tgl_out_cstring_careful #define out_data tgl_out_data static inline void out_string (const char *str) { out_cstring (str, strlen (str)); } static inline void out_bignum (TGLC_bn *n) { int l = tgl_serialize_bignum (n, (char *)packet_ptr, (PACKET_BUFFER_SIZE - (packet_ptr - packet_buffer)) * 4); assert (l > 0); packet_ptr += l >> 2; } #define in_ptr tgl_in_ptr #define in_end tgl_in_end extern int *tgl_in_ptr, *tgl_in_end; //void fetch_pts (void); //void fetch_qts (void); //void fetch_date (void); //void fetch_seq (void); static inline int prefetch_strlen (void) { if (in_ptr >= in_end) { return -1; } unsigned l = *in_ptr; if ((l & 0xff) < 0xfe) { l &= 0xff; return (in_end >= in_ptr + (l >> 2) + 1) ? (int)l : -1; } else if ((l & 0xff) == 0xfe) { l >>= 8; return (l >= 254 && in_end >= in_ptr + ((l + 7) >> 2)) ? (int)l : -1; } else { return -1; } } static inline char *fetch_str (int len) { assert (len >= 0); if (len < 254) { char *str = (char *) in_ptr + 1; in_ptr += 1 + (len >> 2); return str; } else { char *str = (char *) in_ptr + 4; in_ptr += (len + 7) >> 2; return str; } } static inline char *fetch_str_dup (void) { int l = prefetch_strlen (); assert (l >= 0); int i; char *s = fetch_str (l); for (i = 0; i < l; i++) { if (!s[i]) { break; } } char *r = talloc (i + 1); memcpy (r, s, i); r[i] = 0; return r; } static inline int fetch_update_str (char **s) { if (!*s) { *s = fetch_str_dup (); return 1; } int l = prefetch_strlen (); char *r = fetch_str (l); if (memcmp (*s, r, l) || (*s)[l]) { tfree_str (*s); *s = talloc (l + 1); memcpy (*s, r, l); (*s)[l] = 0; return 1; } return 0; } static inline int fetch_update_int (int *value) { if (*value == *in_ptr) { in_ptr ++; return 0; } else { *value = *(in_ptr ++); return 1; } } static inline int fetch_update_long (long long *value) { if (*value == *(long long *)in_ptr) { in_ptr += 2; return 0; } else { *value = *(long long *)(in_ptr); in_ptr += 2; return 1; } } static inline int set_update_int (int *value, int new_value) { if (*value == new_value) { return 0; } else { *value = new_value; return 1; } } static inline void fetch_skip (int n) { in_ptr += n; assert (in_ptr <= in_end); } static inline void fetch_skip_str (void) { int l = prefetch_strlen (); assert (l >= 0); fetch_str (l); } static inline long have_prefetch_ints (void) { return in_end - in_ptr; } int tgl_fetch_bignum (TGLC_bn *x); #define fetch_bignum tgl_fetch_bignum static inline int fetch_int (void) { assert (in_ptr + 1 <= in_end); return *(in_ptr ++); } static inline int fetch_bool (void) { assert (in_ptr + 1 <= in_end); assert (*(in_ptr) == (int)CODE_bool_true || *(in_ptr) == (int)CODE_bool_false); return *(in_ptr ++) == (int)CODE_bool_true; } static inline int prefetch_int (void) { assert (in_ptr < in_end); return *(in_ptr); } static inline void prefetch_data (void *data, int size) { assert (in_ptr + (size >> 2) <= in_end); memcpy (data, in_ptr, size); } static inline void fetch_data (void *data, int size) { assert (in_ptr + (size >> 2) <= in_end); memcpy (data, in_ptr, size); assert (!(size & 3)); in_ptr += (size >> 2); } static inline long long fetch_long (void) { assert (in_ptr + 2 <= in_end); long long r = *(long long *)in_ptr; in_ptr += 2; return r; } static inline double fetch_double (void) { assert (in_ptr + 2 <= in_end); double r = *(double *)in_ptr; in_ptr += 2; return r; } static inline void fetch_ints (void *data, int count) { assert (in_ptr + count <= in_end); memcpy (data, in_ptr, 4 * count); in_ptr += count; } static inline void fetch256 (void *buf) { int l = prefetch_strlen (); assert (l >= 0); char *s = fetch_str (l); if (l < 256) { memcpy (buf + 256 - l, s, l); memset (buf, 0, 256 - l); } else { memcpy (buf, s + (l - 256), 256); } } static inline int in_remaining (void) { return 4 * (in_end - in_ptr); } //int get_random_bytes (unsigned char *buf, int n); int tgl_pad_rsa_encrypt (struct tgl_state *TLS, char *from, int from_len, char *to, int size, TGLC_bn *N, TGLC_bn *E); int tgl_pad_rsa_decrypt (struct tgl_state *TLS, char *from, int from_len, char *to, int size, TGLC_bn *N, TGLC_bn *D); //extern long long rsa_encrypted_chunks, rsa_decrypted_chunks; //extern unsigned char aes_key_raw[32], aes_iv[32]; //extern TGLC_aes_key aes_key; void tgl_init_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32], int encrypt); void tgl_init_aes_auth (char auth_key[192], char msg_key[16], int encrypt); int tgl_pad_aes_encrypt (char *from, int from_len, char *to, int size); int tgl_pad_aes_decrypt (char *from, int from_len, char *to, int size); /* static inline void hexdump_in (void) { hexdump (in_ptr, in_end); } static inline void hexdump_out (void) { hexdump (packet_buffer, packet_ptr); }*/ #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 1 #endif #endif telegram-purple/tgl/mtproto-key.c000066400000000000000000000053511357227200100174120ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2015 */ const unsigned char _mtproto_default_key[] = { 0xc1, 0x50, 0x02, 0x3e, 0x2f, 0x70, 0xdb, 0x79, 0x85, 0xde, 0xd0, 0x64, 0x75, 0x9c, 0xfe, 0xcf, 0x0a, 0xf3, 0x28, 0xe6, 0x9a, 0x41, 0xda, 0xf4, 0xd6, 0xf0, 0x1b, 0x53, 0x81, 0x35, 0xa6, 0xf9, 0x1f, 0x8f, 0x8b, 0x2a, 0x0e, 0xc9, 0xba, 0x97, 0x20, 0xce, 0x35, 0x2e, 0xfc, 0xf6, 0xc5, 0x68, 0x0f, 0xfc, 0x42, 0x4b, 0xd6, 0x34, 0x86, 0x49, 0x02, 0xde, 0x0b, 0x4b, 0xd6, 0xd4, 0x9f, 0x4e, 0x58, 0x02, 0x30, 0xe3, 0xae, 0x97, 0xd9, 0x5c, 0x8b, 0x19, 0x44, 0x2b, 0x3c, 0x0a, 0x10, 0xd8, 0xf5, 0x63, 0x3f, 0xec, 0xed, 0xd6, 0x92, 0x6a, 0x7f, 0x6d, 0xab, 0x0d, 0xdb, 0x7d, 0x45, 0x7f, 0x9e, 0xa8, 0x1b, 0x84, 0x65, 0xfc, 0xd6, 0xff, 0xfe, 0xed, 0x11, 0x40, 0x11, 0xdf, 0x91, 0xc0, 0x59, 0xca, 0xed, 0xaf, 0x97, 0x62, 0x5f, 0x6c, 0x96, 0xec, 0xc7, 0x47, 0x25, 0x55, 0x69, 0x34, 0xef, 0x78, 0x1d, 0x86, 0x6b, 0x34, 0xf0, 0x11, 0xfc, 0xe4, 0xd8, 0x35, 0xa0, 0x90, 0x19, 0x6e, 0x9a, 0x5f, 0x0e, 0x44, 0x49, 0xaf, 0x7e, 0xb6, 0x97, 0xdd, 0xb9, 0x07, 0x64, 0x94, 0xca, 0x5f, 0x81, 0x10, 0x4a, 0x30, 0x5b, 0x6d, 0xd2, 0x76, 0x65, 0x72, 0x2c, 0x46, 0xb6, 0x0e, 0x5d, 0xf6, 0x80, 0xfb, 0x16, 0xb2, 0x10, 0x60, 0x7e, 0xf2, 0x17, 0x65, 0x2e, 0x60, 0x23, 0x6c, 0x25, 0x5f, 0x6a, 0x28, 0x31, 0x5f, 0x40, 0x83, 0xa9, 0x67, 0x91, 0xd7, 0x21, 0x4b, 0xf6, 0x4c, 0x1d, 0xf4, 0xfd, 0x0d, 0xb1, 0x94, 0x4f, 0xb2, 0x6a, 0x2a, 0x57, 0x03, 0x1b, 0x32, 0xee, 0xe6, 0x4a, 0xd1, 0x5a, 0x8b, 0xa6, 0x88, 0x85, 0xcd, 0xe7, 0x4a, 0x5b, 0xfc, 0x92, 0x0f, 0x6a, 0xbf, 0x59, 0xba, 0x5c, 0x75, 0x50, 0x63, 0x73, 0xe7, 0x13, 0x0f, 0x90, 0x42, 0xda, 0x92, 0x21, 0x79, 0x25, 0x1f }; const unsigned int _mtproto_default_key_len = 256; const long long _mtproto_default_e = 65537; const unsigned char *tglmp_get_default_key (void) { return _mtproto_default_key; } unsigned int tglmp_get_default_key_len (void) { return _mtproto_default_key_len; } long long tglmp_get_default_e (void) { return _mtproto_default_e; } telegram-purple/tgl/mtproto-key.h000066400000000000000000000020011357227200100174040ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2015 */ #ifndef __MTPROTO_KEY_H__ #define __MTPROTO_KEY_H__ const unsigned char *tglmp_get_default_key (void); unsigned int tglmp_get_default_key_len (void); long long tglmp_get_default_e (void); #endif telegram-purple/tgl/mtproto-utils.c000066400000000000000000000075321357227200100177650ustar00rootroot00000000000000#include "config.h" #include "crypto/bn.h" #include "tl-parser/portable_endian.h" #include "tgl.h" #include "tools.h" #include "mtproto-utils.h" static unsigned long long gcd (unsigned long long a, unsigned long long b) { return b ? gcd (b, a % b) : a; } static int check_prime (struct tgl_state *TLS, TGLC_bn *p) { int r = TGLC_bn_is_prime (p, /* "use default" */ 0, 0, TLS->TGLC_bn_ctx, 0); ensure (r >= 0); return r; } // Complete set of checks see at https://core.telegram.org/mtproto/security_guidelines // Checks that (p,g) is acceptable pair for DH int tglmp_check_DH_params (struct tgl_state *TLS, TGLC_bn *p, int g) { if (g < 2 || g > 7) { return -1; } if (TGLC_bn_num_bits (p) != 2048) { return -1; } TGLC_bn *t = TGLC_bn_new (); TGLC_bn *dh_g = TGLC_bn_new (); ensure (TGLC_bn_set_word (dh_g, 4 * g)); ensure (TGLC_bn_mod (t, p, dh_g, TLS->TGLC_bn_ctx)); int x = TGLC_bn_get_word (t); assert (x >= 0 && x < 4 * g); TGLC_bn_free (dh_g); int res = 0; switch (g) { case 2: if (x != 7) { res = -1; } break; case 3: if (x % 3 != 2) { res = -1; } break; case 4: break; case 5: if (x % 5 != 1 && x % 5 != 4) { res = -1; } break; case 6: if (x != 19 && x != 23) { res = -1; } break; case 7: if (x % 7 != 3 && x % 7 != 5 && x % 7 != 6) { res = -1; } break; } if (res < 0 || !check_prime (TLS, p)) { TGLC_bn_free (t); return -1; } TGLC_bn *b = TGLC_bn_new (); ensure (TGLC_bn_set_word (b, 2)); ensure (TGLC_bn_div (t, 0, p, b, TLS->TGLC_bn_ctx)); if (!check_prime (TLS, t)) { res = -1; } TGLC_bn_free (b); TGLC_bn_free (t); return res; } // checks that g_a is acceptable for DH int tglmp_check_g_a (struct tgl_state *TLS, TGLC_bn *p, TGLC_bn *g_a) { if (TGLC_bn_num_bytes (g_a) > 256) { return -1; } if (TGLC_bn_num_bits (g_a) < 2048 - 64) { return -1; } if (TGLC_bn_cmp (p, g_a) <= 0) { return -1; } TGLC_bn *dif = TGLC_bn_new (); TGLC_bn_sub (dif, p, g_a); if (TGLC_bn_num_bits (dif) < 2048 - 64) { TGLC_bn_free (dif); return -1; } TGLC_bn_free (dif); return 0; } static unsigned long long BN2ull (TGLC_bn *b) { if (sizeof (unsigned long) == 8) { return TGLC_bn_get_word (b); } else if (sizeof (unsigned long long) == 8) { unsigned long long tmp; TGLC_bn_bn2bin (b, (unsigned char *) &tmp); return be64toh (tmp); } else { assert (0); } } static void ull2BN (TGLC_bn *b, unsigned long long val) { if (sizeof (unsigned long) == 8 || val < (1ll << 32)) { TGLC_bn_set_word (b, val); } else if (sizeof (unsigned long long) == 8) { val = htobe64(val); TGLC_bn_bin2bn ((unsigned char *) &val, 8, b); } else { assert (0); } } int bn_factorize (TGLC_bn *pq, TGLC_bn *p, TGLC_bn *q) { // Should work in any case // Rewrite this code unsigned long long what = BN2ull (pq); int it = 0; unsigned long long g = 0; int i; for (i = 0; i < 3 || it < 1000; i++) { int q = ((rand() & 15) + 17) % what; unsigned long long x = (long long)rand () % (what - 1) + 1, y = x; int lim = 1 << (i + 18); int j; for (j = 1; j < lim; j++) { ++it; unsigned long long a = x, b = x, c = q; while (b) { if (b & 1) { c += a; if (c >= what) { c -= what; } } a += a; if (a >= what) { a -= what; } b >>= 1; } x = c; unsigned long long z = x < y ? what + x - y : x - y; g = gcd (z, what); if (g != 1) { break; } if (!(j & (j - 1))) { y = x; } } if (g > 1 && g < what) break; } assert (g > 1 && g < what); unsigned long long p1 = g; unsigned long long p2 = what / g; if (p1 > p2) { unsigned long long t = p1; p1 = p2; p2 = t; } ull2BN (p, p1); ull2BN (q, p2); return 0; } telegram-purple/tgl/mtproto-utils.h000066400000000000000000000004331357227200100177630ustar00rootroot00000000000000#ifndef __MTPROTO_UTILS_H__ #define __MTPROTO_UTILS_H__ #include "crypto/bn.h" int tglmp_check_DH_params (struct tgl_state *TLS, TGLC_bn *p, int g); int tglmp_check_g_a (struct tgl_state *TLS, TGLC_bn *p, TGLC_bn *g_a); int bn_factorize (TGLC_bn *pq, TGLC_bn *p, TGLC_bn *q); #endif telegram-purple/tgl/mtproto.tl000066400000000000000000000027151357227200100170220ustar00rootroot00000000000000---types--- resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:(Vector long) = ResPQ; server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params; p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; p_q_inner_data_temp#3c6a84d4 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data; client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data; dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; ---functions--- req_pq#60469778 nonce:int128 = ResPQ; req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params; set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer; telegram-purple/tgl/no-preview.h000066400000000000000000000152301357227200100172150ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ // Just sample jpg file 90x90 int thumb_file_size = (82 * 6 - 2) * 4; int thumb_file [] = { 0xe0ffd8ff, 0x464a1000, 0x01004649, 0x64000101, 0x00006400, 0xa002e2ff, 0x5f434349, 0x464f5250, 0x00454c49, 0x00000101, 0x636c9002, 0x3004736d, 0x6e6d0000, 0x47527274, 0x59582042, 0xdd07205a, 0x04000b00, 0x1b001600, 0x63612400, 0x50417073, 0x00004c50, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0100d6f6, 0x00000000, 0x636c2dd3, 0x0000736d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x65640b00, 0x00006373, 0x00000801, 0x70633800, 0x00007472, 0x00004001, 0x74774e00, 0x00007470, 0x00009001, 0x68631400, 0x00006461, 0x0000a401, 0x58722c00, 0x00005a59, 0x0000d001, 0x58621400, 0x00005a59, 0x0000e401, 0x58671400, 0x00005a59, 0x0000f801, 0x54721400, 0x00004352, 0x00000c02, 0x54672000, 0x00004352, 0x00002c02, 0x54622000, 0x00004352, 0x00004c02, 0x68632000, 0x00006d72, 0x00006c02, 0x6c6d2400, 0x00006375, 0x00000000, 0x00000100, 0x6e650c00, 0x00005355, 0x00001c00, 0x73001c00, 0x47005200, 0x20004200, 0x75006200, 0x6c006900, 0x2d007400, 0x6e006900, 0x6c6d0000, 0x00006375, 0x00000000, 0x00000100, 0x6e650c00, 0x00005355, 0x00003200, 0x4e001c00, 0x20006f00, 0x6f006300, 0x79007000, 0x69007200, 0x68006700, 0x2c007400, 0x75002000, 0x65007300, 0x66002000, 0x65007200, 0x6c006500, 0x00007900, 0x59580000, 0x0000205a, 0x00000000, 0x0100d6f6, 0x00000000, 0x66732dd3, 0x00003233, 0x01000000, 0x00004a0c, 0xffffe305, 0x00002af3, 0x00009b07, 0xffff87fd, 0xffffa2fb, 0x0000a3fd, 0x0000d803, 0x595894c0, 0x0000205a, 0x00000000, 0x0000946f, 0x0000ee38, 0x59589003, 0x0000205a, 0x00000000, 0x00009d24, 0x0000830f, 0x5958beb6, 0x0000205a, 0x00000000, 0x0000a562, 0x000090b7, 0x6170de18, 0x00006172, 0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, 0x61705b0a, 0x00006172, 0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, 0x61705b0a, 0x00006172, 0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, 0x68635b0a, 0x00006d72, 0x03000000, 0x00000000, 0x0000d7a3, 0x00007b54, 0x0000cd4c, 0x00009a99, 0x00006626, 0xdbff5c0f, 0x14004300, 0x0f120f0e, 0x1112140d, 0x14161712, 0x21331f18, 0x1f1c1c1f, 0x252f2d3f, 0x4e414a33, 0x4841494d, 0x765c5246, 0x6f575264, 0x66484658, 0x7a6f688c, 0x8485847d, 0x9b91634f, 0x769a808f, 0xff7f8481, 0x014300db, 0x1f171716, 0x213c1f1b, 0x547f3c21, 0x7f7f5448, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x1100c0ff, 0x005a0008, 0x2201035a, 0x01110200, 0xff011103, 0x001900c4, 0x01010101, 0x00000101, 0x00000000, 0x00000000, 0x02030400, 0xc4ff0605, 0x00103600, 0x02010401, 0x06050304, 0x00000306, 0x01000000, 0x11030200, 0x05211204, 0x13514131, 0x32146122, 0x23918171, 0x72423424, 0x432515a1, 0xa2827444, 0xc4fff0b3, 0x01011400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1400c4ff, 0x00000111, 0x00000000, 0x00000000, 0x00000000, 0xdaff0000, 0x01030c00, 0x03110200, 0x003f0011, 0x404434fb, 0xbcb4875c, 0x006b38b0, 0x03dcdb12, 0xf4637f74, 0xe519f153, 0x09d7c5c7, 0x47d29160, 0x20692f18, 0xd06d786a, 0x53f7f922, 0x17b3e260, 0x2fe8668c, 0x1786a473, 0x9775efbd, 0xe917e43a, 0x1d0a1bb0, 0x114d0f82, 0x14651110, 0x35f299ed, 0xe9b09680, 0xf5a4fc2f, 0xe975bd03, 0xb506737b, 0x04444440, 0x5c444044, 0x8e8dedbd, 0xc61adc7b, 0x689c738b, 0x92a0dc01, 0x58e2b77f, 0x7bfb37d1, 0xb5b5e79d, 0xdbf968cc, 0xead3f48d, 0x38ed1313, 0xdea77c86, 0xae089963, 0xc743435a, 0x403fe4ce, 0x392ee1b9, 0xed39e718, 0xd6517e2d, 0x7fc4aa03, 0xb7ad7590, 0x77e7e6ab, 0x34bf705d, 0x7c77ca53, 0x3dea1299, 0x7fb0bcf4, 0x241fadc5, 0x95a7a816, 0x13fbe6f3, 0x3182b135, 0xd1b4b224, 0x1b0d48a2, 0xbf9d26d8, 0x82dc3640, 0x63569a2a, 0xbbd224c3, 0xb9b4714c, 0x1680aec6, 0x3d311856, 0x9b59be91, 0x09876ca6, 0x61d86564, 0x5a9f06d2, 0x36f51b0d, 0x8682e476, 0xacb1b131, 0xd1584363, 0x00456b4d, 0x22d2053b, 0x22202202, 0xf3f30222, 0xe3e513e5, 0xf1e6e1f0, 0x2380496e, 0x5fdcdb68, 0x549b3a27, 0x825e6a6c, 0x6522028b, 0xaf91ccc8, 0x341cf26b, 0x58dbc4b5, 0xf2289add, 0x0854ddbd, 0x0b9247d5, 0xf02b5c54, 0x3f917f92, 0xaf56affd, 0xe3760637, 0x05cebde0, 0xed4c76ce, 0x3cef1b63, 0x7fd8aff8, 0xa0c902ea, 0x7e730d0a, 0x435834f3, 0x26edbb76, 0xd3ec00fd, 0x76d48efa, 0xa8560f2d, 0x0e766331, 0xd319993c, 0x20243209, 0x61b7e6c8, 0x998331d0, 0x640ee802, 0x47a3d493, 0xfab99413, 0x4fd871f1, 0xe9443792, 0x627e051c, 0xd8f3051c, 0x2f28f558, 0x64b51745, 0x1b2bfee3, 0xb8783953, 0x9900fff6, 0xd8176a65, 0x5a3bf56a, 0x1b331fdb, 0x64b3572f, 0xd59a3643, 0xaf3abce1, 0x11dd20bd, 0x01111110, 0x5c141011, 0xb3e3083f, 0xd9b19cc4, 0x17edb20e, 0xa78e9aa1, 0x4ef4de06, 0x00c0bfe7, 0x7e1e442d, 0x9221fe38, 0xedb5c7dc, 0x6338078a, 0x62495b8d, 0xc11d9b8c, 0x49e81b16, 0x51d02bea, 0x3eb86d70, 0xc8bc4f13, 0xa10ec758, 0xd40751c0, 0x5ac94710, 0xc4c8b080, 0x95492b83, 0x975ee696, 0xb7bd96b4, 0x17379cce, 0x82e856e8, 0xe4c2c82a, 0x398e935f, 0x632437ea, 0x7c9c87d2, 0xdc1ddb7c, 0x65a80a48, 0x2309f164, 0x51fab475, 0x081dc11d, 0xda45573b, 0x6622f3f3, 0x48f1b214, 0x676c4edb, 0x243468c7, 0x00ffde60, 0xf1630350, 0xa0076c1d, 0x8f2c0c8b, 0x2383c26b, 0x361a8f4e, 0xaceea6c9, 0x01dd5a5d, 0x11111011, 0xc3780c04, 0xbf093ee2, 0xc7972c0b, 0x00d99040, 0xc0c20eb7, 0x659d3bd4, 0x269ab85e, 0x468e114f, 0x11ad4fdb, 0x83d083d8, 0x8c52f4bd, 0x3c9664bf, 0xa4f9c77c, 0x22a68876, 0xadb18784, 0xf480be83, 0x885a00ea, 0x220e0a88, 0xc303e4f6, 0xc866e058, 0xdddbd661, 0xdf395db1, 0xbad64343, 0xe6e65b03, 0x668e81c3, 0xad619e98, 0xeeb94563, 0xd4d19a3c, 0x3316ce95, 0x9d65f1e1, 0x3bf324fe, 0x0e468f53, 0xc386068c, 0xa89e24f7, 0xf0c7c73b, 0xb60e391f, 0x1b8827cb, 0x58601954, 0xc54f90f9, 0x80886ec5, 0x88088888, 0x1b7bb980, 0xb4c71c23, 0xe6148e39, 0xb12358b8, 0xbd08225d, 0x0ffef085, 0x72b4f025, 0x635ce389, 0xb90277e4, 0x0d05e000, 0x9bf9dbb9, 0x8e749fbc, 0x7ee6abbf, 0x4ddbf4af, 0x728df7f3, 0x10b59adf, 0xe3c38f49, 0xb23c638a, 0xdb3d9349, 0x66899a64, 0x00004dd5, 0xf51b5adf, 0x2220a255, 0xd9ff0f22}; telegram-purple/tgl/queries-encrypted.c000066400000000000000000000646011357227200100205730ustar00rootroot00000000000000 /* {{{ Encrypt decrypted */ static int *encr_extra; static int *encr_ptr; static int *encr_end; static char *encrypt_decrypted_message (struct tgl_secret_chat *E) { static int msg_key[4]; static unsigned char sha1a_buffer[20]; static unsigned char sha1b_buffer[20]; static unsigned char sha1c_buffer[20]; static unsigned char sha1d_buffer[20]; int x = *(encr_ptr); assert (x >= 0 && !(x & 3)); TGLC_sha1 ((void *)encr_ptr, 4 + x, sha1a_buffer); memcpy (msg_key, sha1a_buffer + 4, 16); static unsigned char buf[64]; memcpy (buf, msg_key, 16); memcpy (buf + 16, E->key, 32); TGLC_sha1 (buf, 48, sha1a_buffer); memcpy (buf, E->key + 8, 16); memcpy (buf + 16, msg_key, 16); memcpy (buf + 32, E->key + 12, 16); TGLC_sha1 (buf, 48, sha1b_buffer); memcpy (buf, E->key + 16, 32); memcpy (buf + 32, msg_key, 16); TGLC_sha1 (buf, 48, sha1c_buffer); memcpy (buf, msg_key, 16); memcpy (buf + 16, E->key + 24, 32); TGLC_sha1 (buf, 48, sha1d_buffer); static unsigned char key[32]; memcpy (key, sha1a_buffer + 0, 8); memcpy (key + 8, sha1b_buffer + 8, 12); memcpy (key + 20, sha1c_buffer + 4, 12); static unsigned char iv[32]; memcpy (iv, sha1a_buffer + 8, 12); memcpy (iv + 12, sha1b_buffer + 0, 8); memcpy (iv + 20, sha1c_buffer + 16, 4); memcpy (iv + 24, sha1d_buffer + 0, 8); TGLC_aes_key aes_key; TGLC_aes_set_encrypt_key (key, 256, &aes_key); TGLC_aes_ige_encrypt ((void *)encr_ptr, (void *)encr_ptr, 4 * (encr_end - encr_ptr), &aes_key, iv, 1); memset (&aes_key, 0, sizeof (aes_key)); return (void *)msg_key; } static void encr_start (void) { encr_extra = packet_ptr; packet_ptr += 1; // str len packet_ptr += 2; // fingerprint packet_ptr += 4; // msg_key packet_ptr += 1; // len } static void encr_finish (struct tgl_secret_chat *E) { int l = packet_ptr - (encr_extra + 8); while (((packet_ptr - encr_extra) - 3) & 3) { int t; tglt_secure_random (&t, 4); out_int (t); } *encr_extra = ((packet_ptr - encr_extra) - 1) * 4 * 256 + 0xfe; encr_extra ++; *(long long *)encr_extra = E->key_fingerprint; encr_extra += 2; encr_extra[4] = l * 4; encr_ptr = encr_extra + 4; encr_end = packet_ptr; memcpy (encr_extra, encrypt_decrypted_message (E), 16); } /* }}} */ void tgl_do_send_encr_action (struct tgl_state *TLS, struct tgl_secret_chat *E, struct tl_ds_decrypted_message_action *A) { long long t; tglt_secure_random (&t, 8); int date = time (0); struct tgl_message_id id = tgl_peer_id_to_random_msg_id (E->id); tgl_peer_id_t from_id = TLS->our_id; bl_do_edit_message_encr (TLS, &id, &from_id, &E->id, &date, NULL, 0, NULL, A, NULL, TGLMF_PENDING | TGLMF_OUT | TGLMF_UNREAD | TGLMF_CREATE | TGLMF_CREATED | TGLMF_ENCRYPTED); struct tgl_message *M = tgl_message_get (TLS, &id); assert (M); tgl_do_send_msg (TLS, M, 0, 0); } void tgl_do_send_encr_chat_layer (struct tgl_state *TLS, struct tgl_secret_chat *E) { static struct tl_ds_decrypted_message_action A; A.magic = CODE_decrypted_message_action_notify_layer; int layer = TGL_ENCRYPTED_LAYER; A.layer = &layer; tgl_do_send_encr_action (TLS, E, &A); } void tgl_do_set_encr_chat_ttl (struct tgl_state *TLS, struct tgl_secret_chat *E, int ttl, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { static struct tl_ds_decrypted_message_action A; A.magic = CODE_decrypted_message_action_set_message_t_t_l; A.layer = &ttl; tgl_do_send_encr_action (TLS, E, &A); } /* {{{ Seng msg (plain text, encrypted) */ static int msg_send_encr_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tgl_message *M = q->extra; assert (M->flags & TGLMF_ENCRYPTED); if (M->flags & TGLMF_PENDING) { bl_do_edit_message_encr (TLS, &M->permanent_id, NULL, NULL, &M->date, NULL, 0, NULL, NULL, NULL, M->flags ^ TGLMF_PENDING); bl_do_msg_update (TLS, &M->permanent_id); } if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int, struct tgl_message *))q->callback) (TLS, q->callback_extra, 1, M); } return 0; } static int msg_send_encr_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { struct tgl_message *M = q->extra; tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); if (P && P->encr_chat.state != sc_deleted && error_code == 400) { if (strncmp (error, "ENCRYPTION_DECLINED", 19) == 0) { bl_do_peer_delete (TLS, P->id); } } if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int, struct tgl_message *))q->callback) (TLS, q->callback_extra, 0, M); } if (M) { bl_do_message_delete (TLS, &M->permanent_id); } return 0; } static struct query_methods msg_send_encr_methods = { .on_answer = msg_send_encr_on_answer, .on_error = msg_send_encr_on_error, .type = TYPE_TO_PARAM(messages_sent_encrypted_message), .name = "send encrypted (message)", .timeout = 0, }; /* }}} */ void tgl_do_send_encr_msg_action (struct tgl_state *TLS, struct tgl_message *M, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); if (!P || P->encr_chat.state != sc_ok) { vlogprintf (E_WARNING, "Unknown encrypted chat\n"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } assert (M->flags & TGLMF_ENCRYPTED); clear_packet (); out_int (CODE_messages_send_encrypted_service); out_int (CODE_input_encrypted_chat); out_int (M->permanent_id.peer_id); out_long (M->permanent_id.access_hash); out_long (M->permanent_id.id); encr_start (); out_int (CODE_decrypted_message_layer); out_random (15 + 4 * (rand () % 3)); out_int (TGL_ENCRYPTED_LAYER); out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != tgl_get_peer_id (TLS->our_id))); out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == tgl_get_peer_id (TLS->our_id)) - 2); out_int (CODE_decrypted_message_service); out_long (M->permanent_id.id); switch (M->action.type) { case tgl_message_action_notify_layer: out_int (CODE_decrypted_message_action_notify_layer); out_int (M->action.layer); break; case tgl_message_action_set_message_ttl: out_int (CODE_decrypted_message_action_set_message_t_t_l); out_int (M->action.ttl); break; case tgl_message_action_request_key: out_int (CODE_decrypted_message_action_request_key); out_long (M->action.exchange_id); out_cstring ((void *)M->action.g_a, 256); break; case tgl_message_action_accept_key: out_int (CODE_decrypted_message_action_accept_key); out_long (M->action.exchange_id); out_cstring ((void *)M->action.g_a, 256); out_long (M->action.key_fingerprint); break; case tgl_message_action_commit_key: out_int (CODE_decrypted_message_action_commit_key); out_long (M->action.exchange_id); out_long (M->action.key_fingerprint); break; case tgl_message_action_abort_key: out_int (CODE_decrypted_message_action_abort_key); out_long (M->action.exchange_id); break; case tgl_message_action_noop: out_int (CODE_decrypted_message_action_noop); break; default: assert (0); } encr_finish (&P->encr_chat); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M, callback, callback_extra); } void tgl_do_send_encr_msg (struct tgl_state *TLS, struct tgl_message *M, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { if (M->flags & TGLMF_SERVICE) { tgl_do_send_encr_msg_action (TLS, M, callback, callback_extra); return; } tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); if (!P || P->encr_chat.state != sc_ok) { vlogprintf (E_WARNING, "Unknown encrypted chat\n"); if (callback) { callback (TLS, callback_extra, 0, M); } return; } assert (M->flags & TGLMF_ENCRYPTED); clear_packet (); out_int (CODE_messages_send_encrypted); out_int (CODE_input_encrypted_chat); out_int (tgl_get_peer_id (M->to_id)); out_long (P->encr_chat.access_hash); out_long (M->permanent_id.id); encr_start (); out_int (CODE_decrypted_message_layer); out_random (15 + 4 * (rand () % 3)); out_int (TGL_ENCRYPTED_LAYER); out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != tgl_get_peer_id (TLS->our_id))); out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == tgl_get_peer_id (TLS->our_id)) - 2); out_int (CODE_decrypted_message); out_long (M->permanent_id.id); out_int (P->encr_chat.ttl); out_cstring ((void *)M->message, M->message_len); switch (M->media.type) { case tgl_message_media_none: out_int (CODE_decrypted_message_media_empty); break; case tgl_message_media_geo: out_int (CODE_decrypted_message_media_geo_point); out_double (M->media.geo.latitude); out_double (M->media.geo.longitude); break; default: assert (0); } encr_finish (&P->encr_chat); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M, callback, callback_extra); } static int mark_read_encr_on_receive (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 1); } return 0; } static int mark_read_encr_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_peer_t *P = q->extra; if (P && P->encr_chat.state != sc_deleted && error_code == 400) { if (strncmp (error, "ENCRYPTION_DECLINED", 19) == 0) { bl_do_peer_delete (TLS, P->id); } } return 0; } static struct query_methods mark_read_encr_methods = { .on_answer = mark_read_encr_on_receive, .on_error = mark_read_encr_on_error, .type = TYPE_TO_PARAM(bool), .name = "read encrypted", .timeout = 0, }; void tgl_do_messages_mark_read_encr (struct tgl_state *TLS, tgl_peer_id_t id, long long access_hash, int last_time, void (*callback)(struct tgl_state *TLS, void *callback_extra, int), void *callback_extra) { clear_packet (); out_int (CODE_messages_read_encrypted_history); out_int (CODE_input_encrypted_chat); out_int (tgl_get_peer_id (id)); out_long (access_hash); out_int (last_time); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_encr_methods, tgl_peer_get (TLS, id), callback, callback_extra); } static int send_encr_file_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_messages_sent_encrypted_message *DS_MSEM = D; struct tgl_message *M = q->extra; if (M->flags & TGLMF_PENDING) { bl_do_edit_message_encr (TLS, &M->permanent_id, NULL, NULL, DS_MSEM->date, NULL, 0, NULL, NULL, DS_MSEM->file, M->flags ^ TGLMF_PENDING); bl_do_msg_update (TLS, &M->permanent_id); } if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_message *))q->callback)(TLS, q->callback_extra, 1, M); } return 0; } static struct query_methods send_encr_file_methods = { .on_answer = send_encr_file_on_answer, .on_error = msg_send_encr_on_error, .type = TYPE_TO_PARAM(messages_sent_encrypted_message), .name = "send encrypted (file)", .timeout = 0, }; static void send_file_encrypted_end (struct tgl_state *TLS, struct send_file *f, void *callback, void *callback_extra) { out_int (CODE_messages_send_encrypted_file); out_int (CODE_input_encrypted_chat); out_int (tgl_get_peer_id (f->to_id)); tgl_peer_t *P = tgl_peer_get (TLS, f->to_id); assert (P); out_long (P->encr_chat.access_hash); long long r; tglt_secure_random (&r, 8); out_long (r); encr_start (); out_int (CODE_decrypted_message_layer); out_random (15 + 4 * (rand () % 3)); out_int (TGL_ENCRYPTED_LAYER); out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != tgl_get_peer_id (TLS->our_id))); out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == tgl_get_peer_id (TLS->our_id))); out_int (CODE_decrypted_message); out_long (r); out_int (P->encr_chat.ttl); out_string (""); int *save_ptr = packet_ptr; if (f->flags == -1) { out_int (CODE_decrypted_message_media_photo); } else if ((f->flags & TGLDF_VIDEO)) { out_int (CODE_decrypted_message_media_video); } else if ((f->flags & TGLDF_AUDIO)) { out_int (CODE_decrypted_message_media_audio); } else { out_int (CODE_decrypted_message_media_document); } if (f->flags == -1 || !(f->flags & TGLDF_AUDIO)) { out_cstring ("", 0); out_int (90); out_int (90); } if (f->flags == -1) { out_int (f->w); out_int (f->h); } else if (f->flags & TGLDF_VIDEO) { out_int (f->duration); out_string (tg_mime_by_filename (f->file_name)); out_int (f->w); out_int (f->h); } else if (f->flags & TGLDF_AUDIO) { out_int (f->duration); out_string (tg_mime_by_filename (f->file_name)); } else { out_string (""); out_string (tg_mime_by_filename (f->file_name)); // document } out_int (f->size); out_cstring ((void *)f->key, 32); out_cstring ((void *)f->init_iv, 32); int *save_in_ptr = in_ptr; int *save_in_end = in_end; in_ptr = save_ptr; in_end = packet_ptr; assert (skip_type_any (TYPE_TO_PARAM(decrypted_message_media)) >= 0); assert (in_ptr == in_end); in_ptr = save_ptr; in_end = packet_ptr; struct tl_ds_decrypted_message_media *DS_DMM = fetch_ds_type_decrypted_message_media (TYPE_TO_PARAM (decrypted_message_media)); in_end = save_in_ptr; in_ptr = save_in_end; int date = time (NULL); encr_finish (&P->encr_chat); if (f->size < (16 << 20)) { out_int (CODE_input_encrypted_file_uploaded); } else { out_int (CODE_input_encrypted_file_big_uploaded); } out_long (f->id); out_int (f->part_num); if (f->size < (16 << 20)) { out_string (""); } unsigned char md5[16]; unsigned char str[64]; memcpy (str, f->key, 32); memcpy (str + 32, f->init_iv, 32); TGLC_md5 (str, 64, md5); out_int ((*(int *)md5) ^ (*(int *)(md5 + 4))); tfree_secure (f->iv, 32); tgl_peer_id_t from_id = TLS->our_id; struct tgl_message_id id = tgl_peer_id_to_msg_id (P->id, r); bl_do_edit_message_encr (TLS, &id, &from_id, &f->to_id, &date, NULL, 0, DS_DMM, NULL, NULL, TGLMF_OUT | TGLMF_UNREAD | TGLMF_ENCRYPTED | TGLMF_CREATE | TGLMF_CREATED); free_ds_type_decrypted_message_media (DS_DMM, TYPE_TO_PARAM (decrypted_message_media)); struct tgl_message *M = tgl_message_get (TLS, &id); assert (M); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_file_methods, M, callback, callback_extra); tfree_str (f->file_name); tfree (f, sizeof (*f)); } void tgl_do_send_location_encr (struct tgl_state *TLS, tgl_peer_id_t peer_id, double latitude, double longitude, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { struct tl_ds_decrypted_message_media TDSM; TDSM.magic = CODE_decrypted_message_media_geo_point; TDSM.latitude = talloc (sizeof (double)); *TDSM.latitude = latitude; TDSM.longitude = talloc (sizeof (double)); *TDSM.longitude = longitude; int date = time (0); tgl_peer_id_t from_id = TLS->our_id; tgl_peer_t *P = tgl_peer_get (TLS, peer_id); struct tgl_message_id id = tgl_peer_id_to_random_msg_id (P->id);; bl_do_edit_message_encr (TLS, &id, &from_id, &peer_id, &date, NULL, 0, &TDSM, NULL, NULL, TGLMF_UNREAD | TGLMF_OUT | TGLMF_PENDING | TGLMF_CREATE | TGLMF_CREATED | TGLMF_ENCRYPTED); tfree (TDSM.latitude, sizeof (double)); tfree (TDSM.longitude, sizeof (double)); struct tgl_message *M = tgl_message_get (TLS, &id); tgl_do_send_encr_msg (TLS, M, callback, callback_extra); } /* {{{ Encr accept */ static int send_encr_accept_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tgl_secret_chat *E = tglf_fetch_alloc_encrypted_chat (TLS, D); if (E->state == sc_ok) { tgl_do_send_encr_chat_layer (TLS, E); } if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_secret_chat *))q->callback) (TLS, q->callback_extra, E->state == sc_ok, E); } return 0; } static int send_encr_request_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tgl_secret_chat *E = tglf_fetch_alloc_encrypted_chat (TLS, D); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_secret_chat *))q->callback) (TLS, q->callback_extra, E->state != sc_deleted, E); } return 0; } static int encr_accept_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_peer_t *P = q->extra; if (P && P->encr_chat.state != sc_deleted && error_code == 400) { if (strncmp (error, "ENCRYPTION_DECLINED", 19) == 0) { bl_do_peer_delete (TLS, P->id); } } if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_secret_chat *))q->callback) (TLS, q->callback_extra, 0, NULL); } return 0; } static struct query_methods send_encr_accept_methods = { .on_answer = send_encr_accept_on_answer, .on_error = encr_accept_on_error, .type = TYPE_TO_PARAM(encrypted_chat), .name = "send encrypted (chat accept)", .timeout = 0, }; static struct query_methods send_encr_request_methods = { .on_answer = send_encr_request_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM(encrypted_chat), .name = "send encrypted (chat request)", .timeout = 0, }; //int encr_root; //unsigned char *encr_prime; //int encr_param_version; //static TGLC_bn_ctx *ctx; void tgl_do_send_accept_encr_chat (struct tgl_state *TLS, struct tgl_secret_chat *E, unsigned char *random, void (*callback)(struct tgl_state *TLS,void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra) { int i; int ok = 0; for (i = 0; i < 64; i++) { if (E->key[i]) { ok = 1; break; } } if (ok) { if (callback) { callback (TLS, callback_extra, 1, E); } return; } // Already generated key for this chat assert (E->g_key); assert (TLS->TGLC_bn_ctx); unsigned char random_here[256]; tglt_secure_random (random_here, 256); for (i = 0; i < 256; i++) { random[i] ^= random_here[i]; } TGLC_bn *b = TGLC_bn_bin2bn (random, 256, 0); ensure_ptr (b); TGLC_bn *g_a = TGLC_bn_bin2bn (E->g_key, 256, 0); ensure_ptr (g_a); assert (tglmp_check_g_a (TLS, TLS->encr_prime_bn, g_a) >= 0); //if (!ctx) { // ctx = TGLC_bn_ctx_new (); // ensure_ptr (ctx); //} TGLC_bn *p = TLS->encr_prime_bn; TGLC_bn *r = TGLC_bn_new (); ensure_ptr (r); ensure (TGLC_bn_mod_exp (r, g_a, b, p, TLS->TGLC_bn_ctx)); static unsigned char kk[256]; memset (kk, 0, sizeof (kk)); TGLC_bn_bn2bin (r, kk + (256 - TGLC_bn_num_bytes (r))); static unsigned char sha_buffer[20]; TGLC_sha1 (kk, 256, sha_buffer); long long fingerprint = *(long long *)(sha_buffer + 12); //bl_do_encr_chat_set_key (TLS, E, kk, *(long long *)(sha_buffer + 12)); //bl_do_encr_chat_set_sha (TLS, E, sha_buffer); int state = sc_ok; bl_do_encr_chat (TLS, tgl_get_peer_id (E->id), NULL, NULL, NULL, NULL, kk, NULL, sha_buffer, &state, NULL, NULL, NULL, NULL, NULL, &fingerprint, TGL_FLAGS_UNCHANGED, NULL, 0 ); clear_packet (); out_int (CODE_messages_accept_encryption); out_int (CODE_input_encrypted_chat); out_int (tgl_get_peer_id (E->id)); out_long (E->access_hash); ensure (TGLC_bn_set_word (g_a, TLS->encr_root)); ensure (TGLC_bn_mod_exp (r, g_a, b, p, TLS->TGLC_bn_ctx)); static unsigned char buf[256]; memset (buf, 0, sizeof (buf)); TGLC_bn_bn2bin (r, buf + (256 - TGLC_bn_num_bytes (r))); out_cstring ((void *)buf, 256); out_long (E->key_fingerprint); TGLC_bn_clear_free (b); TGLC_bn_clear_free (g_a); TGLC_bn_clear_free (r); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E, callback, callback_extra); } void tgl_do_create_keys_end (struct tgl_state *TLS, struct tgl_secret_chat *U) { assert (TLS->encr_prime); TGLC_bn *g_b = TGLC_bn_bin2bn (U->g_key, 256, 0); ensure_ptr (g_b); assert (tglmp_check_g_a (TLS, TLS->encr_prime_bn, g_b) >= 0); TGLC_bn *p = TLS->encr_prime_bn; ensure_ptr (p); TGLC_bn *r = TGLC_bn_new (); ensure_ptr (r); TGLC_bn *a = TGLC_bn_bin2bn ((void *)U->key, 256, 0); ensure_ptr (a); ensure (TGLC_bn_mod_exp (r, g_b, a, p, TLS->TGLC_bn_ctx)); unsigned char *t = talloc (256); memcpy (t, U->key, 256); memset (U->key, 0, sizeof (U->key)); TGLC_bn_bn2bin (r, (void *)(((char *)(U->key)) + (256 - TGLC_bn_num_bytes (r)))); static unsigned char sha_buffer[20]; TGLC_sha1 ((void *)U->key, 256, sha_buffer); long long k = *(long long *)(sha_buffer + 12); if (k != U->key_fingerprint) { vlogprintf (E_WARNING, "Key fingerprint mismatch (my 0x%" INT64_PRINTF_MODIFIER "x 0x%" INT64_PRINTF_MODIFIER "x)\n", (unsigned long long)k, (unsigned long long)U->key_fingerprint); U->state = sc_deleted; } memcpy (U->first_key_sha, sha_buffer, 20); tfree_secure (t, 256); TGLC_bn_clear_free (g_b); TGLC_bn_clear_free (r); TGLC_bn_clear_free (a); } void tgl_do_send_create_encr_chat (struct tgl_state *TLS, void *x, unsigned char *random, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra) { int user_id = (long)x; int i; unsigned char random_here[256]; tglt_secure_random (random_here, 256); for (i = 0; i < 256; i++) { random[i] ^= random_here[i]; } TGLC_bn *a = TGLC_bn_bin2bn (random, 256, 0); ensure_ptr (a); TGLC_bn *p = TGLC_bn_bin2bn (TLS->encr_prime, 256, 0); ensure_ptr (p); TGLC_bn *g = TGLC_bn_new (); ensure_ptr (g); ensure (TGLC_bn_set_word (g, TLS->encr_root)); TGLC_bn *r = TGLC_bn_new (); ensure_ptr (r); ensure (TGLC_bn_mod_exp (r, g, a, p, TLS->TGLC_bn_ctx)); TGLC_bn_clear_free (a); static char g_a[256]; memset (g_a, 0, 256); TGLC_bn_bn2bin (r, (void *)(g_a + (256 - TGLC_bn_num_bytes (r)))); int t = rand (); while (tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (t))) { t = rand (); } //bl_do_encr_chat_init (TLS, t, user_id, (void *)random, (void *)g_a); int state = sc_waiting; int our_id = tgl_get_peer_id (TLS->our_id); bl_do_encr_chat (TLS, t, NULL, NULL, &our_id, &user_id, random, NULL, NULL, &state, NULL, NULL, NULL, NULL, NULL, NULL, TGLPF_CREATE | TGLPF_CREATED, NULL, 0); tgl_peer_t *_E = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (t)); assert (_E); struct tgl_secret_chat *E = &_E->encr_chat; clear_packet (); out_int (CODE_messages_request_encryption); tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER (E->user_id)); assert (U); out_int (CODE_input_user); out_int (E->user_id); out_long (U ? U->user.access_hash : 0); out_int (tgl_get_peer_id (E->id)); out_cstring (g_a, 256); //write_secret_chat_file (); TGLC_bn_clear_free (g); TGLC_bn_clear_free (p); TGLC_bn_clear_free (r); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E, callback, callback_extra); } static int send_encr_discard_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tgl_secret_chat *E = q->extra; bl_do_peer_delete (TLS, E->id); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_secret_chat *))q->callback) (TLS, q->callback_extra, 1, E); } return 0; } static struct query_methods send_encr_discard_methods = { .on_answer = send_encr_discard_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM(bool), .name = "send encrypted (chat discard)", .timeout = 0, }; void tgl_do_discard_secret_chat (struct tgl_state *TLS, struct tgl_secret_chat *E, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra) { assert (E); assert (tgl_get_peer_id (E->id) > 0); if (E->state == sc_deleted || E->state == sc_none) { if (callback) { callback (TLS, callback_extra, 0, E); } return; } clear_packet (); out_int (CODE_messages_discard_encryption); out_int (tgl_get_peer_id (E->id)); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_discard_methods, E, callback, callback_extra); } static int get_dh_config_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_messages_dh_config *DS_MDC = D; if (DS_MDC->magic == CODE_messages_dh_config) { assert (DS_MDC->p->len == 256); bl_do_set_dh_params (TLS, DS_LVAL (DS_MDC->g), (void *)DS_MDC->p->data, DS_LVAL (DS_MDC->version)); } else { assert (TLS->encr_param_version); } unsigned char *random = talloc (256); assert (DS_MDC->random->len == 256); memcpy (random, DS_MDC->random->data, 256); if (q->extra) { void **x = q->extra; ((void (*)(struct tgl_state *, void *, void *, void *, void *))(*x))(TLS, x[1], random, q->callback, q->callback_extra); tfree (x, 2 * sizeof (void *)); tfree_secure (random, 256); } else { tfree_secure (random, 256); } return 0; } static struct query_methods get_dh_config_methods = { .on_answer = get_dh_config_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(messages_dh_config), .name = "dh config", .timeout = 0, }; void tgl_do_accept_encr_chat_request (struct tgl_state *TLS, struct tgl_secret_chat *E, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra) { if (E->state != sc_request) { if (callback) { callback (TLS, callback_extra, 0, E); } return; } assert (E->state == sc_request); clear_packet (); out_int (CODE_messages_get_dh_config); out_int (TLS->encr_param_version); out_int (256); void **x = talloc (2 * sizeof (void *)); x[0] = tgl_do_send_accept_encr_chat; x[1] = E; tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x, callback, callback_extra); } void tgl_do_create_encr_chat_request (struct tgl_state *TLS, int user_id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra) { clear_packet (); out_int (CODE_messages_get_dh_config); out_int (TLS->encr_param_version); out_int (256); void **x = talloc (2 * sizeof (void *)); x[0] = tgl_do_send_create_encr_chat; x[1] = (void *)(long)(user_id); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x, callback, callback_extra); } /* }}} */ telegram-purple/tgl/queries.c000066400000000000000000005577471357227200100166220ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #ifndef WIN32 #include #endif #include "mtproto-client.h" #include "queries.h" #include "tree.h" #include "mtproto-common.h" //#include "telegram.h" #include "tgl-structures.h" //#include "interface.h" //#include "net.h" #include "crypto/bn.h" #include "crypto/rand.h" #include "crypto/aes.h" #include "crypto/sha.h" #include "crypto/md5.h" #include "no-preview.h" #include "tgl-binlog.h" #include "updates.h" #include "auto.h" #include "auto/auto-types.h" #include "auto/auto-skip.h" #include "auto/auto-free-ds.h" #include "auto/auto-fetch-ds.h" #include "auto/auto-print-ds.h" #include "tgl.h" #include "tg-mime-types.h" #include "mtproto-utils.h" #include "tgl-methods-in.h" #include "tgl-queries.h" #ifndef EPROTO // BSD doesn't define EPROTO, even though it is POSIX: // https://lists.freebsd.org/pipermail/freebsd-standards/2003-June/000124.html #define EPROTO EIO #endif #ifndef PATH_MAX #define PATH_MAX 4096 #endif #ifndef O_BINARY #define O_BINARY 0 #endif static void out_peer_id (struct tgl_state *TLS, tgl_peer_id_t id); static struct query_methods send_msgs_methods; struct messages_send_extra { int multi; int count; tgl_message_id_t id; tgl_message_id_t *list; }; #define QUERY_TIMEOUT 6.0 struct send_file { int fd; long long size; long long offset; int part_num; int part_size; long long id; long long thumb_id; tgl_peer_id_t to_id; int flags; char *file_name; int encr; //int avatar; tgl_peer_id_t avatar; int reply; unsigned char *iv; unsigned char *init_iv; unsigned char *key; int w; int h; int duration; char *caption; int channel; }; #define memcmp8(a,b) memcmp ((a), (b), 8) DEFINE_TREE (query, struct query *, memcmp8, 0) ; static int mystreq1 (const char *a, const char *b, int l) { if ((int)strlen (a) != l) { return 1; } return memcmp (a, b, l); } /* {{{ COMMON */ struct query *tglq_query_get (struct tgl_state *TLS, long long id) { return tree_lookup_query (TLS->queries_tree, (void *)&id); } static int alarm_query (struct tgl_state *TLS, struct query *q) { assert (q); vlogprintf (E_DEBUG - 2, "Alarm query %" INT64_PRINTF_MODIFIER "d (type '%s')\n", q->msg_id, q->methods->name); TLS->timer_methods->insert (q->ev, q->methods->timeout ? q->methods->timeout : QUERY_TIMEOUT); if (q->session && q->session_id && q->DC && q->DC->sessions[0] == q->session && q->session->session_id == q->session_id) { clear_packet (); out_int (CODE_msg_container); out_int (1); out_long (q->msg_id); out_int (q->seq_no); out_int (4 * q->data_len); out_ints (q->data, q->data_len); tglmp_encrypt_send_message (TLS, q->session->c, packet_buffer, packet_ptr - packet_buffer, q->flags & QUERY_FORCE_SEND); } else { q->flags &= ~QUERY_ACK_RECEIVED; if (tree_lookup_query (TLS->queries_tree, q)) { TLS->queries_tree = tree_delete_query (TLS->queries_tree, q); } q->session = q->DC->sessions[0]; long long old_id = q->msg_id; q->msg_id = tglmp_encrypt_send_message (TLS, q->session->c, q->data, q->data_len, (q->flags & QUERY_FORCE_SEND) | 1); vlogprintf (E_NOTICE, "Resent query #%" INT64_PRINTF_MODIFIER "d as #%" INT64_PRINTF_MODIFIER "d of size %d to DC %d\n", old_id, q->msg_id, 4 * q->data_len, q->DC->id); TLS->queries_tree = tree_insert_query (TLS->queries_tree, q, rand ()); q->session_id = q->session->session_id; if (!(q->session->dc->flags & 4) && !(q->flags & QUERY_FORCE_SEND)) { q->session_id = 0; } } return 0; } void tglq_regen_query (struct tgl_state *TLS, long long id) { struct query *q = tglq_query_get (TLS, id); if (!q) { return; } q->flags &= ~QUERY_ACK_RECEIVED; if (!(q->session && q->session_id && q->DC && q->DC->sessions[0] == q->session && q->session->session_id == q->session_id)) { q->session_id = 0; } else { if (!(q->session->dc->flags & 4) && !(q->flags & QUERY_FORCE_SEND)) { q->session_id = 0; } } vlogprintf (E_NOTICE, "regen query %" INT64_PRINTF_MODIFIER "d\n", id); TLS->timer_methods->insert (q->ev, 0.001); } struct regen_tmp_struct { struct tgl_state *TLS; struct tgl_dc *DC; struct tgl_session *S; }; void tglq_regen_query_from_old_session (struct query *q, void *ex) { struct regen_tmp_struct *T = ex; struct tgl_state *TLS = T->TLS; if (q->DC == T->DC) { if (!q->session || q->session_id != T->S->session_id || q->session != T->S) { q->session_id = 0; vlogprintf (E_NOTICE, "regen query from old session %" INT64_PRINTF_MODIFIER "d\n", q->msg_id); TLS->timer_methods->insert (q->ev, q->methods->timeout ? 0.001 : 0.1); } } } void tglq_regen_queries_from_old_session (struct tgl_state *TLS, struct tgl_dc *DC, struct tgl_session *S) { struct regen_tmp_struct T; T.TLS = TLS; T.DC = DC; T.S = S; tree_act_ex_query (TLS->queries_tree, tglq_regen_query_from_old_session, &T); } void tglq_query_restart (struct tgl_state *TLS, long long id) { struct query *q = tglq_query_get (TLS, id); if (q) { vlogprintf (E_NOTICE, "restarting query %" INT64_PRINTF_MODIFIER "d\n", id); TLS->timer_methods->remove (q->ev); alarm_query (TLS, q); } } static void alarm_query_gateway (struct tgl_state *TLS, void *arg) { alarm_query (TLS, arg); } struct query *tglq_send_query_ex (struct tgl_state *TLS, struct tgl_dc *DC, int ints, void *data, struct query_methods *methods, void *extra, void *callback, void *callback_extra, int flags) { assert (DC); assert (DC->auth_key_id); if (!DC->sessions[0]) { tglmp_dc_create_session (TLS, DC); } vlogprintf (E_DEBUG, "Sending query of size %d to DC %d\n", 4 * ints, DC->id); struct query *q = talloc0 (sizeof (*q)); q->data_len = ints; q->data = talloc (4 * ints); memcpy (q->data, data, 4 * ints); q->msg_id = tglmp_encrypt_send_message (TLS, DC->sessions[0]->c, data, ints, 1 | (flags & QUERY_FORCE_SEND)); q->session = DC->sessions[0]; q->seq_no = q->session->seq_no - 1; q->session_id = q->session->session_id; if (!(DC->flags & 4) && !(flags & QUERY_FORCE_SEND)) { q->session_id = 0; } vlogprintf (E_DEBUG, "Msg_id is %" INT64_PRINTF_MODIFIER "d %p\n", q->msg_id, q); vlogprintf (E_NOTICE, "Sent query #%" INT64_PRINTF_MODIFIER "d of size %d to DC %d\n", q->msg_id, 4 * ints, DC->id); q->methods = methods; q->type = methods->type; q->DC = DC; q->flags = flags & QUERY_FORCE_SEND; if (TLS->queries_tree) { vlogprintf (E_DEBUG + 2, "%" INT64_PRINTF_MODIFIER "d %" INT64_PRINTF_MODIFIER "d\n", q->msg_id, TLS->queries_tree->x->msg_id); } TLS->queries_tree = tree_insert_query (TLS->queries_tree, q, rand ()); q->ev = TLS->timer_methods->alloc (TLS, alarm_query_gateway, q); TLS->timer_methods->insert (q->ev, q->methods->timeout ? q->methods->timeout : QUERY_TIMEOUT); q->extra = extra; q->callback = callback; q->callback_extra = callback_extra; TLS->active_queries ++; return q; } struct query *tglq_send_query (struct tgl_state *TLS, struct tgl_dc *DC, int ints, void *data, struct query_methods *methods, void *extra, void *callback, void *callback_extra) { return tglq_send_query_ex (TLS, DC, ints, data, methods, extra, callback, callback_extra, 0); } static int fail_on_error (struct tgl_state *TLS, struct query *q, int error_code, int l, const char *error) { vlogprintf (E_ERROR, "error #%d: %.*s\n", error_code, l, error); assert (0); return 0; } void tglq_query_ack (struct tgl_state *TLS, long long id) { struct query *q = tglq_query_get (TLS, id); if (q && !(q->flags & QUERY_ACK_RECEIVED)) { assert (q->msg_id == id); q->flags |= QUERY_ACK_RECEIVED; TLS->timer_methods->remove (q->ev); } } void tglq_query_delete (struct tgl_state *TLS, long long id) { struct query *q = tglq_query_get (TLS, id); if (!q) { return; } if (!(q->flags & QUERY_ACK_RECEIVED)) { TLS->timer_methods->remove (q->ev); } TLS->queries_tree = tree_delete_query (TLS->queries_tree, q); tfree (q->data, q->data_len * 4); TLS->timer_methods->free (q->ev); TLS->active_queries --; } static void resend_query_cb (struct tgl_state *TLS, void *_q, int success); void tglq_free_query (struct query *q, void *extra) { struct tgl_state *TLS = extra; if (!(q->flags & QUERY_ACK_RECEIVED)) { TLS->timer_methods->remove (q->ev); } tfree (q->data, q->data_len * 4); TLS->timer_methods->free (q->ev); } void tglq_query_free_all (struct tgl_state *TLS) { tree_act_ex_query (TLS->queries_tree, tglq_free_query, TLS); TLS->queries_tree = tree_clear_query (TLS->queries_tree); } int tglq_query_error (struct tgl_state *TLS, long long id) { assert (fetch_int () == CODE_rpc_error); int error_code = fetch_int (); int error_len = prefetch_strlen (); char *error = fetch_str (error_len); struct query *q = tglq_query_get (TLS, id); if (!q) { vlogprintf (E_WARNING, "error for query ?! #%" INT64_PRINTF_MODIFIER "d: #%d :%.*s\n", id, error_code, error_len, error); vlogprintf (E_WARNING, "No such query\n"); } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { TLS->timer_methods->remove (q->ev); } int res = 0; int error_handled = 0; switch (error_code) { case 303: // migrate { int offset = -1; if (error_len >= 15 && !memcmp (error, "PHONE_MIGRATE_", 14)) { offset = 14; } if (error_len >= 17 && !memcmp (error, "NETWORK_MIGRATE_", 16)) { offset = 16; } if (error_len >= 14 && !memcmp (error, "USER_MIGRATE_", 13)) { offset = 13; } if (offset >= 0) { int i = 0; while (offset < error_len && error[offset] >= '0' && error[offset] <= '9') { i = i * 10 + error[offset] - '0'; offset ++; } if (i > 0 && i < TGL_MAX_DC_NUM) { bl_do_set_working_dc (TLS, i); q->flags &= ~QUERY_ACK_RECEIVED; //q->session_id = 0; //struct tgl_dc *DC = q->DC; //if (!(DC->flags & 4) && !(q->flags & QUERY_FORCE_SEND)) { q->session_id = 0; //} q->DC = TLS->DC_working; TLS->timer_methods->insert (q->ev, 0); error_handled = 1; res = 1; } } } break; case 400: // nothing to handle // bad user input probably break; case 401: if (!mystreq1 ("SESSION_PASSWORD_NEEDED", error, error_len)) { if (!(TLS->locks & TGL_LOCK_PASSWORD)) { TLS->locks |= TGL_LOCK_PASSWORD; tgl_do_check_password (TLS, resend_query_cb, q); } res = 1; error_handled = 1; } break; case 403: // privacy violation break; case 404: // not found break; case 420: // flood case 500: // internal error default: // anything else. Treated as internal error { // Do not auto-resend the same packet, it has already been answered. Retry at a higher level. // Most errors won't be fixed by endless repeats either. if (strncmp (error, "FLOOD_WAIT_", 11) == 0) { //wait = atoll (error + 11); } else if (error_code == 420) { vlogprintf (E_ERROR, "non-standard wait = '%s'\n", error); } else { //non-floodwait error } q->flags &= ~QUERY_ACK_RECEIVED; struct tgl_dc *DC = q->DC; if (!(DC->flags & 4) && !(q->flags & QUERY_FORCE_SEND)) { q->session_id = 0; } error_handled = 0; res = 0; } break; } if (error_handled) { vlogprintf (E_DEBUG - 2, "error for query #%" INT64_PRINTF_MODIFIER "d: #%d %.*s (HANDLED)\n", id, error_code, error_len, error); } else { vlogprintf (E_WARNING, "error for query '%s' #%" INT64_PRINTF_MODIFIER "d: #%d %.*s\n", q->methods->name, id, error_code, error_len, error); if (q->methods && q->methods->on_error) { res = q->methods->on_error (TLS, q, error_code, error_len, error); } } if (res <= 0) { TLS->queries_tree = tree_delete_query (TLS->queries_tree, q); tfree (q->data, q->data_len * 4); TLS->timer_methods->free (q->ev); } if (res == -11) { TLS->active_queries --; return -1; } } TLS->active_queries --; return 0; } #define MAX_PACKED_SIZE (1 << 24) static int packed_buffer[MAX_PACKED_SIZE / 4]; int tglq_query_result (struct tgl_state *TLS, long long id) { vlogprintf (E_DEBUG, "result for query #%" INT64_PRINTF_MODIFIER "d. Size %ld bytes\n", id, (long)4 * (in_end - in_ptr)); int op = prefetch_int (); int *end = 0; int *eend = 0; if (op == CODE_gzip_packed) { fetch_int (); int l = prefetch_strlen (); char *s = fetch_str (l); int total_out = tgl_inflate (s, l, packed_buffer, MAX_PACKED_SIZE); vlogprintf (E_DEBUG, "inflated %d bytes\n", total_out); end = in_ptr; eend = in_end; in_ptr = packed_buffer; in_end = in_ptr + total_out / 4; } struct query *q = tglq_query_get (TLS, id); if (!q) { vlogprintf (E_WARNING, "No such query\n"); in_ptr = in_end; } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { TLS->timer_methods->remove (q->ev); } TLS->queries_tree = tree_delete_query (TLS->queries_tree, q); if (q->methods && q->methods->on_answer) { assert (q->type); int *save = in_ptr; vlogprintf (E_DEBUG, "in_ptr = %p, end_ptr = %p\n", in_ptr, in_end); if (skip_type_any (q->type) < 0) { vlogprintf (E_ERROR, "Skipped %ld int out of %ld (type %s) (query type %s)\n", (long)(in_ptr - save), (long)(in_end - save), q->type->type->id, q->methods->name); vlogprintf (E_ERROR, "0x%08x 0x%08x 0x%08x 0x%08x\n", *(save - 1), *(save), *(save + 1), *(save + 2)); assert (0); } assert (in_ptr == in_end); in_ptr = save; void *DS = fetch_ds_type_any (q->type); assert (DS); q->methods->on_answer (TLS, q, DS); free_ds_type_any (DS, q->type); assert (in_ptr == in_end); } tfree (q->data, 4 * q->data_len); TLS->timer_methods->free (q->ev); tfree (q, sizeof (*q)); } if (end) { in_ptr = end; in_end = eend; } TLS->active_queries --; return 0; } static void out_random (int n) { assert (n <= 32); static char buf[32]; tglt_secure_random (buf, n); out_cstring (buf, n); } int allow_send_linux_version; void tgl_do_insert_header (struct tgl_state *TLS) { out_int (CODE_invoke_with_layer); out_int (TGL_SCHEME_LAYER); out_int (CODE_init_connection); out_int (TLS->app_id); #ifndef WIN32 if (allow_send_linux_version) { struct utsname st; uname (&st); out_string (st.machine); static char buf[4096]; tsnprintf (buf, sizeof (buf) - 1, "%.999s %.999s %.999s", st.sysname, st.release, st.version); out_string (buf); tsnprintf (buf, sizeof (buf) - 1, "%s (TGL %s)", TLS->app_version, TGL_VERSION); out_string (buf); out_string ("En"); } else { out_string ("x86"); out_string ("Linux"); static char buf[4096]; tsnprintf (buf, sizeof (buf) - 1, "%s (TGL %s)", TLS->app_version, TGL_VERSION); out_string (buf); out_string ("en"); } #else out_string ("x86"); out_string ("Windows"); static char buf[4096]; tsnprintf (buf, sizeof (buf) - 1, "%s (TGL %s)", TLS->app_version, TGL_VERSION); out_string (buf); out_string ("en"); #endif } void tgl_set_query_error (struct tgl_state *TLS, int error_code, const char *format, ...) __attribute__ ((format (printf, 3, 4))); void tgl_set_query_error (struct tgl_state *TLS, int error_code, const char *format, ...) { static char s[1001]; va_list ap; va_start (ap, format); vsnprintf (s, 1000, format, ap); va_end (ap); if (TLS->error) { tfree_str (TLS->error); } TLS->error = tstrdup (s); TLS->error_code = error_code; } /* }}} */ /* {{{ Default on error */ static int q_void_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); if (q->callback) { ((void (*)(struct tgl_state *,void *, int))(q->callback))(TLS, q->callback_extra, 0); } return 0; } static int q_ptr_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); if (q->callback) { ((void (*)(struct tgl_state *,void *, int, void *))(q->callback))(TLS, q->callback_extra, 0, NULL); } return 0; } static int q_list_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); if (q->callback) { ((void (*)(struct tgl_state *,void *, int, int, void *))(q->callback))(TLS, q->callback_extra, 0, 0, NULL); } return 0; } /* }}} */ #include "queries-encrypted.c" static void increase_ent (int *ent_size, int **ent, int s) { *ent = trealloc (*ent, (*ent_size) * 4, (*ent_size) * 4 + 4 * s); (*ent_size) +=s; } int utf8_len (const char *s, int len) { int i; int r = 0; for (i = 0; i < len; i++) { if ((s[i] & 0xc0) != 0x80) { r ++; } } return r; } static inline char ascii_char_norm (char c) { return (c >= 0x41 && c <= 0x5A) ? c + 32 : c; } static int ascii_cmp_nocase (const char *what, const char *with, size_t num) { size_t i; for (i = 0; i < num; i ++) { if (ascii_char_norm (what[i]) != ascii_char_norm (with[i])) { return 1; } } return 0; } static char *process_html_text (struct tgl_state *TLS, const char *text, int text_len, int *ent_size, int **ent) { char *new_text = talloc (2 * text_len + 1); int stpos[100]; int sttype[100]; int stp = 0; int p; int cur_p = 0; *ent = talloc (8); *ent_size = 2; (*ent)[0] = CODE_vector; (*ent)[1] = 0; int total = 0; for (p = 0; p < text_len; p++) { assert (cur_p <= 2 * text_len); if (text[p] == '<') { if (stp == 99) { tgl_set_query_error (TLS, EINVAL, "Too nested tags..."); tfree (new_text, 2 * text_len + 1); return NULL; } int old_p = *ent_size; if (text_len - p >= 3 && !ascii_cmp_nocase (text + p, "", 3)) { increase_ent (ent_size, ent, 3); total ++; (*ent)[old_p] = CODE_message_entity_bold; (*ent)[old_p + 1] = utf8_len (new_text, cur_p); stpos[stp] = old_p + 2; sttype[stp] = 0; stp ++; p += 2; continue; } if (text_len - p >= 4 && !ascii_cmp_nocase (text + p, "", 4)) { if (stp == 0 || sttype[stp - 1] != 0) { tgl_set_query_error (TLS, EINVAL, "Invalid tag nest"); tfree (new_text, 2 * text_len + 1); return NULL; } (*ent)[stpos[stp - 1]] = utf8_len (new_text, cur_p) - (*ent)[stpos[stp - 1] - 1]; stp --; p += 3; continue; } if (text_len - p >= 3 && !ascii_cmp_nocase (text + p, "", 3)) { increase_ent (ent_size, ent, 3); total ++; (*ent)[old_p] = CODE_message_entity_italic; (*ent)[old_p + 1] = utf8_len (new_text, cur_p); stpos[stp] = old_p + 2; sttype[stp] = 1; stp ++; p += 2; continue; } if (text_len - p >= 4 && !ascii_cmp_nocase (text + p, "", 4)) { if (stp == 0 || sttype[stp - 1] != 1) { tgl_set_query_error (TLS, EINVAL, "Invalid tag nest"); tfree (new_text, 2 * text_len + 1); return NULL; } (*ent)[stpos[stp - 1]] = utf8_len (new_text, cur_p) - (*ent)[stpos[stp - 1] - 1]; stp --; p += 3; continue; } if (text_len - p >= 6 && !ascii_cmp_nocase (text + p, "", 6)) { increase_ent (ent_size, ent, 3); total ++; (*ent)[old_p] = CODE_message_entity_code; (*ent)[old_p + 1] = utf8_len (new_text, cur_p); stpos[stp] = old_p + 2; sttype[stp] = 2; stp ++; p += 5; continue; } if (text_len - p >= 7 && !ascii_cmp_nocase (text + p, "", 7)) { if (stp == 0 || sttype[stp - 1] != 2) { tgl_set_query_error (TLS, EINVAL, "Invalid tag nest"); tfree (new_text, 2 * text_len + 1); return NULL; } (*ent)[stpos[stp - 1]] = utf8_len (new_text, cur_p) - (*ent)[stpos[stp - 1] - 1]; stp --; p += 6; continue; } if (text_len - p >= 9 && !ascii_cmp_nocase (text + p, " tag did not close"); tfree (new_text, 2 * text_len + 1); return NULL; } int len = pp - p - 9; assert (len >= 0); if (len >= 250) { tgl_set_query_error (TLS, EINVAL, "too long link"); tfree (new_text, 2 * text_len + 1); return NULL; } increase_ent (ent_size, ent, 3 + (len + 1 + ((-len-1) & 3)) / 4); total ++; (*ent)[old_p] = CODE_message_entity_text_url; (*ent)[old_p + 1] = utf8_len (new_text, cur_p); stpos[stp] = old_p + 2; sttype[stp] = 3; stp ++; unsigned char *r = (void *)((*ent) + old_p + 3); r[0] = len; memcpy (r + 1, text + p + 9, len); memset (r + 1 + len, 0, (-len-1) & 3); while (pp < text_len && text[pp] != '>') { pp ++; } p = pp; continue; } if (text_len - p >= 4 && !ascii_cmp_nocase (text + p, "", 4)) { if (stp == 0 || sttype[stp - 1] != 3) { tgl_set_query_error (TLS, EINVAL, "Invalid tag nest"); tfree (new_text, 2 * text_len + 1); return NULL; } (*ent)[stpos[stp - 1]] = utf8_len (new_text, cur_p) - (*ent)[stpos[stp - 1] - 1]; stp --; p += 3; continue; } if (text_len - p >= 4 && !ascii_cmp_nocase (text + p, "
", 4)) { new_text[cur_p ++] = '\n'; p += 3; continue; } tgl_set_query_error (TLS, EINVAL, "Unknown tag"); tfree (new_text, 2 * text_len + 1); return NULL; } else if (text_len - p >= 4 && !ascii_cmp_nocase (text + p, ">", 4)) { p += 3; new_text[cur_p ++] = '>'; } else if (text_len - p >= 4 && !ascii_cmp_nocase (text + p, "<", 4)) { p += 3; new_text[cur_p ++] = '<'; } else if (text_len - p >= 5 && !ascii_cmp_nocase (text + p, "&", 5)) { p += 4; new_text[cur_p ++] = '&'; } else if (text_len - p >= 6 && !ascii_cmp_nocase (text + p, """, 6)) { p += 5; new_text[cur_p ++] = '"'; } else if (text_len - p >= 6 && !ascii_cmp_nocase (text + p, " ", 6)) { p += 5; new_text[cur_p ++] = 0xc2; new_text[cur_p ++] = 0xa0; } else if (text_len - p >= 3 && text[p] == '&' && text[p + 1] == '#') { p += 2; int num = 0; int ok = 0; while (p < text_len) { if (text[p] >= '0' && text[p] <= '9') { num = num * 10 + text[p] - '0'; if (num >= 127) { tgl_set_query_error (TLS, EINVAL, "Too big number in &-sequence"); tfree (new_text, text_len + 1); return NULL; } p ++; } else if (text[p] == ';') { new_text[cur_p ++] = num; ok = 1; break; } else { tgl_set_query_error (TLS, EINVAL, "Bad &-sequence"); tfree (new_text, text_len + 1); return NULL; } } if (ok) { continue; } tgl_set_query_error (TLS, EINVAL, "Unterminated &-sequence"); tfree (new_text, text_len + 1); return NULL; } else { new_text[cur_p ++] = text[p]; } } if (stp != 0) { tgl_set_query_error (TLS, EINVAL, "Invalid tag nest"); tfree (new_text, text_len + 1); return NULL; } (*ent)[1] = total; char *n = talloc (cur_p + 1); memcpy (n, new_text, cur_p); n[cur_p] = 0; tfree (new_text, 2 * text_len + 1); return n; } /* {{{ Get config */ static void fetch_dc_option (struct tgl_state *TLS, struct tl_ds_dc_option *DS_DO) { bl_do_dc_option (TLS, DS_LVAL (DS_DO->flags), DS_LVAL (DS_DO->id), NULL, 0, DS_STR (DS_DO->ip_address), DS_LVAL (DS_DO->port)); } static int help_get_config_on_answer (struct tgl_state *TLS, struct query *q, void *DS) { struct tl_ds_config *DS_C = DS; int i; for (i = 0; i < DS_LVAL (DS_C->dc_options->cnt); i++) { fetch_dc_option (TLS, DS_C->dc_options->data[i]); } int max_chat_size = DS_LVAL (DS_C->chat_size_max); int max_bcast_size = 0;//DS_LVAL (DS_C->broadcast_size_max); vlogprintf (E_DEBUG, "chat_size = %d, bcast_size = %d\n", max_chat_size, max_bcast_size); if (q->callback) { ((void (*)(struct tgl_state *,void *, int))(q->callback))(TLS, q->callback_extra, 1); } return 0; } static struct query_methods help_get_config_methods = { .on_answer = help_get_config_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(config), .name = "get config", .timeout = 1 }; void tgl_do_help_get_config (struct tgl_state *TLS, void (*callback)(struct tgl_state *,void *, int), void *callback_extra) { clear_packet (); tgl_do_insert_header (TLS); out_int (CODE_help_get_config); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0, callback, callback_extra); } void tgl_do_help_get_config_dc (struct tgl_state *TLS, struct tgl_dc *D, void (*callback)(struct tgl_state *, void *, int), void *callback_extra) { clear_packet (); tgl_do_insert_header (TLS); out_int (CODE_help_get_config); tglq_send_query_ex (TLS, D, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0, callback, callback_extra, 2); } /* }}} */ /* {{{ Send code */ static int send_code_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_auth_sent_code *DS_ASC = D; char *phone_code_hash = DS_STR_DUP (DS_ASC->phone_code_hash); int registered = DS_BVAL (DS_ASC->phone_registered);; if (q->callback) { ((void (*)(struct tgl_state *, void *, int, int, const char *))(q->callback)) (TLS, q->callback_extra, 1, registered, phone_code_hash); } tfree_str (phone_code_hash); return 0; } static struct query_methods send_code_methods = { .on_answer = send_code_on_answer, .on_error = q_list_on_error, .type = TYPE_TO_PARAM(auth_sent_code), .name = "send code" }; void tgl_do_send_code (struct tgl_state *TLS, const char *phone, int phone_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int registered, const char *hash), void *callback_extra) { vlogprintf (E_DEBUG, "sending code to dc %d\n", TLS->dc_working_num); clear_packet (); tgl_do_insert_header (TLS); out_int (CODE_auth_send_code); out_cstring (phone, phone_len); out_int (0); out_int (TLS->app_id); out_string (TLS->app_hash); out_string ("en"); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, NULL, callback, callback_extra); } static int phone_call_on_answer (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int))(q->callback))(TLS, q->callback_extra, 1); } return 0; } static struct query_methods phone_call_methods = { .on_answer = phone_call_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(bool), .name = "phone call" }; void tgl_do_phone_call (struct tgl_state *TLS, const char *phone, int phone_len, const char *hash, int hash_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { vlogprintf (E_DEBUG, "calling user\n"); clear_packet (); tgl_do_insert_header (TLS); out_int (CODE_auth_send_call); out_cstring (phone, phone_len); out_cstring (hash, hash_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &phone_call_methods, NULL, callback, callback_extra); } /* }}} */ /* {{{ Sign in / Sign up */ static int sign_in_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_auth_authorization *DS_AA = D; //vlogprintf (E_DEBUG, "Expires in %d\n", DS_LVAL (DS_AA->expires)); struct tgl_user *U = tglf_fetch_alloc_user (TLS, DS_AA->user); bl_do_dc_signed (TLS, TLS->DC_working->id); if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int, struct tgl_user *))q->callback) (TLS, q->callback_extra, 1, U); } return 0; } static int sign_in_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_user *))q->callback) (TLS, q->callback_extra, 0, NULL); } return 0; } static struct query_methods sign_in_methods = { .on_answer = sign_in_on_answer, .on_error = sign_in_on_error, .type = TYPE_TO_PARAM(auth_authorization), .name = "sign in" }; int tgl_do_send_code_result (struct tgl_state *TLS, const char *phone, int phone_len, const char *hash, int hash_len, const char *code, int code_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *Self), void *callback_extra) { clear_packet (); out_int (CODE_auth_sign_in); out_cstring (phone, phone_len); out_cstring (hash, hash_len); out_cstring (code, code_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, 0, callback, callback_extra); return 0; } int tgl_do_send_code_result_auth (struct tgl_state *TLS, const char *phone, int phone_len, const char *hash, int hash_len, const char *code, int code_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *Self), void *callback_extra) { clear_packet (); out_int (CODE_auth_sign_up); out_cstring (phone, phone_len); out_cstring (hash, hash_len); out_cstring (code, code_len); out_cstring (first_name, first_name_len); out_cstring (last_name, last_name_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, 0, callback, callback_extra); return 0; } int tgl_do_send_bot_auth (struct tgl_state *TLS, const char *code, int code_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *Self), void *callback_extra) { clear_packet (); out_int (CODE_auth_import_bot_authorization); out_int (0); out_int (TLS->app_id); out_string (TLS->app_hash); out_cstring (code, code_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, 0, callback, callback_extra); return 0; } /* }}} */ /* {{{ Get contacts */ static int get_contacts_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_contacts_contacts *DS_CC = D; int n = DS_CC->users ? DS_LVAL (DS_CC->users->cnt) : 0; int i; struct tgl_user **list = talloc (sizeof (void *) * n); for (i = 0; i < n; i++) { list[i] = tglf_fetch_alloc_user (TLS, DS_CC->users->data[i]); } if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int, int, struct tgl_user **))q->callback) (TLS, q->callback_extra, 1, n, list); } tfree (list, sizeof (void *) * n); return 0; } static struct query_methods get_contacts_methods = { .on_answer = get_contacts_on_answer, .on_error = q_list_on_error, .type = TYPE_TO_PARAM(contacts_contacts), .name = "get contacts" }; void tgl_do_update_contact_list (struct tgl_state *TLS, void (*callback) (struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_user *contacts[]), void *callback_extra) { clear_packet (); out_int (CODE_contacts_get_contacts); out_string (""); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods, NULL, callback, callback_extra); } /* }}} */ /* {{{ Send msg (plain text) */ static int msg_send_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_updates *DS_U = D; tgl_message_id_t id; id.peer_type = TGL_PEER_RANDOM_ID; id.id = *(long long *)q->extra; tfree (q->extra, 8); struct tgl_message *M = tgl_message_get (TLS, &id); if (M && M->permanent_id.id == id.id) { tglu_work_any_updates (TLS, 1, DS_U, M); tglu_work_any_updates (TLS, 0, DS_U, M); } else { tglu_work_any_updates (TLS, 1, DS_U, NULL); tglu_work_any_updates (TLS, 0, DS_U, NULL); } M = tgl_message_get (TLS, &id); if (q->callback) { ((void (*)(struct tgl_state *,void *, int, struct tgl_message *))q->callback) (TLS, q->callback_extra, 1, M); } return 0; } static int msg_send_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); tgl_message_id_t id; id.peer_type = TGL_PEER_RANDOM_ID; id.id = *(long long *)q->extra; tfree (q->extra, 8); struct tgl_message *M = tgl_message_get (TLS, &id); if (q->callback) { ((void (*)(struct tgl_state *,void *, int, struct tgl_message *))q->callback) (TLS, q->callback_extra, 0, M); } if (M) { bl_do_message_delete (TLS, &M->permanent_id); } return 0; } static struct query_methods msg_send_methods = { .on_answer = msg_send_on_answer, .on_error = msg_send_on_error, .type = TYPE_TO_PARAM(updates), .name = "send message" }; void tgl_do_send_msg (struct tgl_state *TLS, struct tgl_message *M, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) { tgl_do_send_encr_msg (TLS, M, callback, callback_extra); return; } clear_packet (); out_int (CODE_messages_send_message); unsigned f = ((M->flags & TGLMF_DISABLE_PREVIEW) ? 2 : 0) | (M->reply_id ? 1 : 0) | (M->reply_markup ? 4 : 0) | (M->entities_num > 0 ? 8 : 0); if (tgl_get_peer_type (M->from_id) == TGL_PEER_CHANNEL) { f |= 16; } out_int (f); out_peer_id (TLS, M->to_id); if (M->reply_id) { out_int (M->reply_id); } out_cstring (M->message, M->message_len); out_long (M->permanent_id.id); long long *x = talloc (8); *x = M->permanent_id.id; if (M->reply_markup) { if (M->reply_markup->rows) { out_int (CODE_reply_keyboard_markup); out_int (M->reply_markup->flags); out_int (CODE_vector); out_int (M->reply_markup->rows); int i; for (i = 0; i < M->reply_markup->rows; i++) { out_int (CODE_keyboard_button_row); out_int (CODE_vector); out_int (M->reply_markup->row_start[i + 1] - M->reply_markup->row_start[i]); int j; for (j = 0; j < M->reply_markup->row_start[i + 1] - M->reply_markup->row_start[i]; j++) { out_int (CODE_keyboard_button); out_string (M->reply_markup->buttons[j + M->reply_markup->row_start[i]]); } } } else { out_int (CODE_reply_keyboard_hide); out_int (M->reply_markup->flags); } } if (M->entities_num > 0) { out_int (CODE_vector); out_int (M->entities_num); int i; for (i = 0; i < M->entities_num; i++) { struct tgl_message_entity *E = &M->entities[i]; switch (E->type) { case tgl_message_entity_bold: out_int (CODE_message_entity_bold); out_int (E->start); out_int (E->length); break; case tgl_message_entity_italic: out_int (CODE_message_entity_italic); out_int (E->start); out_int (E->length); break; case tgl_message_entity_code: out_int (CODE_message_entity_code); out_int (E->start); out_int (E->length); break; case tgl_message_entity_text_url: out_int (CODE_message_entity_text_url); out_int (E->start); out_int (E->length); out_string (E->extra); break; default: assert (0); } } } tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, x, callback, callback_extra); } void tgl_do_send_message (struct tgl_state *TLS, tgl_peer_id_t peer_id, const char *text, int text_len, unsigned long long flags, struct tl_ds_reply_markup *reply_markup, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { if (tgl_get_peer_type (peer_id) == TGL_PEER_ENCR_CHAT) { tgl_peer_t *P = tgl_peer_get (TLS, peer_id); if (!P) { tgl_set_query_error (TLS, EINVAL, "unknown secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (P->encr_chat.state != sc_ok) { tgl_set_query_error (TLS, EINVAL, "secret chat not in ok state"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } } int date = time (0); struct tgl_message_id id = tgl_peer_id_to_random_msg_id (peer_id); if (tgl_get_peer_type (peer_id) != TGL_PEER_ENCR_CHAT) { int reply = (flags >> 32); int disable_preview = flags & TGL_SEND_MSG_FLAG_DISABLE_PREVIEW; if (!(flags & TGL_SEND_MSG_FLAG_ENABLE_PREVIEW) && TLS->disable_link_preview) { disable_preview = 1; } if (disable_preview) { disable_preview = TGLMF_DISABLE_PREVIEW; } struct tl_ds_message_media TDSM; TDSM.magic = CODE_message_media_empty; tgl_peer_id_t from_id; if (flags & TGLMF_POST_AS_CHANNEL) { from_id = peer_id; } else { from_id = TLS->our_id; } struct tl_ds_vector *EN = NULL; char *new_text = NULL; if (flags & TGLMF_HTML) { int ent_size = 0; int *ent = NULL; text = new_text = process_html_text (TLS, text, text_len, &ent_size, &ent); if (!text) { tfree (ent, ent_size); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } text_len = strlen (new_text); int *save_ptr = in_ptr; int *save_end = in_end; in_ptr = ent; in_end = ent + ent_size; EN = fetch_ds_type_any (TYPE_TO_PARAM_1 (vector, TYPE_TO_PARAM (message_entity))); assert (EN); vlogprintf (E_DEBUG, "in_ptr = %p, in_end = %p\n", in_ptr, in_end); assert (in_ptr == in_end); in_ptr = save_ptr; in_end = save_end; tfree (ent, 4 * ent_size); } bl_do_edit_message (TLS, &id, &from_id, &peer_id, NULL, NULL, &date, text, text_len, &TDSM, NULL, reply ? &reply : NULL, reply_markup, EN, TGLMF_UNREAD | TGLMF_OUT | TGLMF_PENDING | TGLMF_CREATE | TGLMF_CREATED | TGLMF_SESSION_OUTBOUND | disable_preview); if (flags & TGLMF_HTML) { tfree_str (new_text); free_ds_type_any (EN, TYPE_TO_PARAM_1 (vector, TYPE_TO_PARAM (message_entity))); } } else { struct tl_ds_decrypted_message_media TDSM; TDSM.magic = CODE_decrypted_message_media_empty; tgl_peer_id_t from_id = TLS->our_id; bl_do_edit_message_encr (TLS, &id, &from_id, &peer_id, &date, text, text_len, &TDSM, NULL, NULL, TGLMF_UNREAD | TGLMF_OUT | TGLMF_PENDING | TGLMF_CREATE | TGLMF_CREATED | TGLMF_SESSION_OUTBOUND | TGLMF_ENCRYPTED); } struct tgl_message *M = tgl_message_get (TLS, &id); assert (M); tgl_do_send_msg (TLS, M, callback, callback_extra); } void tgl_do_reply_message (struct tgl_state *TLS, tgl_message_id_t *_reply_id, const char *text, int text_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { tgl_message_id_t reply_id = *_reply_id; if (reply_id.peer_type == TGL_PEER_TEMP_ID) { reply_id = tgl_convert_temp_msg_id (TLS, reply_id); } if (reply_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (reply_id.peer_type == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not reply on message from secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } tgl_peer_id_t peer_id = tgl_msg_id_to_peer_id (reply_id); tgl_do_send_message (TLS, peer_id, text, text_len, flags | TGL_SEND_MSG_FLAG_REPLY (reply_id.id), NULL, callback, callback_extra); } /* }}} */ /* {{{ Send text file */ void tgl_do_send_text (struct tgl_state *TLS, tgl_peer_id_t id, const char *file_name, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { int fd = open (file_name, O_RDONLY | O_BINARY); if (fd < 0) { tgl_set_query_error (TLS, EBADF, "Can not open file: %s", strerror(errno)); if (callback) { callback (TLS, callback_extra, 0, NULL); } return; } static char buf[(1 << 20) + 1]; int x = read (fd, buf, (1 << 20) + 1); if (x < 0) { tgl_set_query_error (TLS, EBADF, "Can not read from file: %s", strerror(errno)); close (fd); if (callback) { callback (TLS, callback_extra, 0, NULL); } return; } assert (x >= 0); close (fd); if (x == (1 << 20) + 1) { tgl_set_query_error (TLS, E2BIG, "text file is too big"); if (callback) { callback (TLS, callback_extra, 0, NULL); } } else { tgl_do_send_message (TLS, id, buf, x, flags, NULL, callback, callback_extra); } } void tgl_do_reply_text (struct tgl_state *TLS, tgl_message_id_t *_reply_id, const char *file_name, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { tgl_message_id_t reply_id = *_reply_id; if (reply_id.peer_type == TGL_PEER_TEMP_ID) { reply_id = tgl_convert_temp_msg_id (TLS, reply_id); } if (reply_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (reply_id.peer_type == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not reply on message from secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } tgl_peer_id_t peer_id = tgl_msg_id_to_peer_id (reply_id); tgl_do_send_text (TLS, peer_id, file_name, flags | TGL_SEND_MSG_FLAG_REPLY (reply_id.id), callback, callback_extra); } /* }}} */ /* {{{ Mark read */ struct mark_read_extra { tgl_peer_id_t id; int max_id; }; void tgl_do_messages_mark_read (struct tgl_state *TLS, tgl_peer_id_t id, int max_id, int offset, void (*callback)(struct tgl_state *TLS, void *callback_extra, int), void *callback_extra); static int mark_read_channels_on_receive (struct tgl_state *TLS, struct query *q, void *D) { struct mark_read_extra *E = q->extra; bl_do_channel (TLS, tgl_get_peer_id (E->id), NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, &E->max_id, TGL_FLAGS_UNCHANGED); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 1); } tfree (E, sizeof (*E)); return 0; } static int mark_read_on_receive (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_messages_affected_messages *DS_MAM = D; int r = tgl_check_pts_diff (TLS, DS_LVAL (DS_MAM->pts), DS_LVAL (DS_MAM->pts_count)); if (r > 0) { bl_do_set_pts (TLS, DS_LVAL (DS_MAM->pts)); } struct mark_read_extra *E = q->extra; if (tgl_get_peer_type (E->id) == TGL_PEER_USER) { bl_do_user (TLS, tgl_get_peer_id (E->id), NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, &E->max_id, NULL, NULL, TGL_FLAGS_UNCHANGED); } else { assert (tgl_get_peer_type (E->id) == TGL_PEER_CHAT); bl_do_chat (TLS, tgl_get_peer_id (E->id), NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &E->max_id, NULL, TGL_FLAGS_UNCHANGED); } if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 1); } tfree (E, sizeof (*E)); return 0; } static int mark_read_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); struct mark_read_extra *E = q->extra; tfree (E, sizeof (*E)); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 0); } return 0; } static struct query_methods mark_read_methods = { .on_answer = mark_read_on_receive, .on_error = mark_read_on_error, .type = TYPE_TO_PARAM(messages_affected_messages), .name = "mark read" }; static struct query_methods mark_read_channels_methods = { .on_answer = mark_read_channels_on_receive, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(bool), .name = "mark read (channels)" }; void tgl_do_messages_mark_read (struct tgl_state *TLS, tgl_peer_id_t id, int max_id, int offset, void (*callback)(struct tgl_state *TLS, void *callback_extra, int), void *callback_extra) { if (TLS->is_bot) { return; } if (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT) { tgl_do_mark_read (TLS, id, callback, callback_extra); return; } clear_packet (); if (tgl_get_peer_type (id) != TGL_PEER_CHANNEL) { out_int (CODE_messages_read_history); out_peer_id (TLS, id); out_int (max_id); //out_int (offset); struct mark_read_extra *E = talloc (sizeof (*E)); E->id = id; E->max_id = max_id; tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_methods, E, callback, callback_extra); } else { out_int (CODE_channels_read_history); out_int (CODE_input_channel); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); out_int (max_id); struct mark_read_extra *E = talloc (sizeof (*E)); E->id = id; E->max_id = max_id; tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_channels_methods, E, callback, callback_extra); } } void tgl_do_mark_read (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { if (tgl_get_peer_type (id) == TGL_PEER_USER || tgl_get_peer_type (id) == TGL_PEER_CHAT || tgl_get_peer_type (id) == TGL_PEER_CHANNEL) { tgl_do_messages_mark_read (TLS, id, 0, 0, callback, callback_extra); return; } assert (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT); tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P) { tgl_set_query_error (TLS, EINVAL, "unknown secret chat"); if (callback) { callback (TLS, callback_extra, 0); } return; } if (P->last) { tgl_do_messages_mark_read_encr (TLS, id, P->encr_chat.access_hash, P->last->date, callback, callback_extra); } else { tgl_do_messages_mark_read_encr (TLS, id, P->encr_chat.access_hash, time (0) - 10, callback, callback_extra); } } /* }}} */ /* {{{ Get history */ struct get_history_extra { struct tgl_message **ML; int list_offset; int list_size; tgl_peer_id_t id; int limit; int offset; int offset_id; int min_id; int is_range; }; static void _tgl_do_get_history (struct tgl_state *TLS, struct get_history_extra *E, void (*callback)(struct tgl_state *TLS,void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra); static int get_history_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_messages_messages *DS_MM = D; int i; for (i = 0; i < DS_LVAL (DS_MM->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_MM->chats->data[i]); } for (i = 0; i < DS_LVAL (DS_MM->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_MM->users->data[i]); } struct get_history_extra *E = q->extra; int n = DS_LVAL (DS_MM->messages->cnt); if (E->list_size - E->list_offset < n) { int new_list_size = 2 * E->list_size; if (new_list_size - E->list_offset < n) { new_list_size = n + E->list_offset; } E->ML = trealloc (E->ML, E->list_size * sizeof (void *), new_list_size * sizeof (void *)); assert (E->ML); E->list_size = new_list_size; } for (i = 0; i < n; i++) { E->ML[i + E->list_offset] = tglf_fetch_alloc_message (TLS, DS_MM->messages->data[i], NULL); } E->list_offset += n; E->offset += n; E->limit -= n; int count = DS_LVAL (DS_MM->count); if (count >= 0 && E->limit + E->offset >= count) { E->limit = count - E->offset; if (E->limit < 0) { E->limit = 0; } } if (E->is_range > 0) { if (n <= 0) { E->limit = 0; // no messages left in the range } else if (E->ML[E->list_offset - 1] && E->ML[E->list_offset - 1]->permanent_id.id <= E->min_id + 1) { E->limit = 0; // offset_id lower than min_id } } if (E->limit <= 0 || DS_MM->magic == CODE_messages_messages) { if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int, int, struct tgl_message **))q->callback) (TLS, q->callback_extra, 1, E->list_offset, E->ML); } /*if (E->list_offset > 0) { tgl_do_messages_mark_read (TLS, E->id, E->ML[0]->id, 0, 0, 0); }*/ tfree (E->ML, sizeof (void *) * E->list_size); tfree (E, sizeof (*E)); } else { assert (E->list_offset > 0); E->offset = 0; E->offset_id = E->ML[E->list_offset - 1]->permanent_id.id; _tgl_do_get_history (TLS, E, q->callback, q->callback_extra); } return 0; } static int get_history_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); struct get_history_extra *E = q->extra; tfree (E->ML, sizeof (void *) * E->list_size); tfree (E, sizeof (*E)); if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int, int, struct tgl_message **))q->callback) (TLS, q->callback_extra, 0, 0, NULL); } return 0; } static struct query_methods get_history_methods = { .on_answer = get_history_on_answer, .on_error = get_history_on_error, .type = TYPE_TO_PARAM(messages_messages), .name = "get history" }; void tgl_do_get_local_history (struct tgl_state *TLS, tgl_peer_id_t id, int offset, int limit, void (*callback)(struct tgl_state *TLS,void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra) { tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P || !P->last) { tgl_set_query_error (TLS, EINVAL, "unknown peer"); if (callback) { callback (TLS, callback_extra, 0, 0, 0); } return; } struct tgl_message *M = P->last; int count = 1; assert (!M->prev); while (count < limit + offset && M->next) { M = M->next; count ++; } if (count <= offset) { if (callback) { callback (TLS, callback_extra, 1, 0, 0); } return; } struct tgl_message **ML = talloc (sizeof (void *) * (count - offset)); M = P->last; ML[0] = M; count = 1; while (count < limit && M->next) { M = M->next; if (count >= offset) { ML[count - offset] = M; } count ++; } if (callback) { callback (TLS, callback_extra, 1, count - offset, ML); } tfree (ML, sizeof (void *) * (count) - offset); } static void _tgl_do_get_history (struct tgl_state *TLS, struct get_history_extra *E, void (*callback)(struct tgl_state *TLS,void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra) { clear_packet (); tgl_peer_t *C = tgl_peer_get (TLS, E->id); if (tgl_get_peer_type (E->id) != TGL_PEER_CHANNEL || (C && (C->flags & TGLCHF_MEGAGROUP))) { out_int (CODE_messages_get_history); out_peer_id (TLS, E->id); } else { out_int (CODE_channels_get_important_history); out_int (CODE_input_channel); out_int (tgl_get_peer_id (E->id)); out_long (E->id.access_hash); } out_int (E->offset_id); out_int (E->offset); out_int (E->limit); out_int (0); out_int (E->min_id); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, E, callback, callback_extra); } void tgl_do_get_history (struct tgl_state *TLS, tgl_peer_id_t id, int offset, int limit, int offline_mode, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra) { if (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT || offline_mode) { tgl_do_get_local_history (TLS, id, offset, limit, callback, callback_extra); //tgl_do_mark_read (TLS, id, 0, 0); return; } struct get_history_extra *E = talloc0 (sizeof (*E)); E->id = id; E->limit = limit; E->offset = offset; _tgl_do_get_history (TLS, E, callback, callback_extra); } void tgl_do_get_history_range (struct tgl_state *TLS, tgl_peer_id_t id, int min_id, int max_id, int limit, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra) { struct get_history_extra *E = talloc0 (sizeof (*E)); E->id = id; E->limit = limit; E->offset_id = max_id; E->min_id = min_id; E->is_range = 1; _tgl_do_get_history (TLS, E, callback, callback_extra); } /* }}} */ /* {{{ Get dialogs */ struct get_dialogs_extra { tgl_peer_id_t *PL; int *UC; tgl_message_id_t **LM; tgl_message_id_t *LMD; int *LRM; int list_offset; int list_size; int limit; int offset; int offset_date; int max_id; tgl_peer_id_t offset_peer; int channels; }; static void _tgl_do_get_dialog_list (struct tgl_state *TLS, struct get_dialogs_extra *E, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]), void *callback_extra); static int get_dialogs_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_messages_dialogs *DS_MD = D; struct get_dialogs_extra *E = q->extra; int dl_size = DS_LVAL (DS_MD->dialogs->cnt); int i; for (i = 0; i < DS_LVAL (DS_MD->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_MD->chats->data[i]); } for (i = 0; i < DS_LVAL (DS_MD->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_MD->users->data[i]); } if (E->list_offset + dl_size > E->list_size) { int new_list_size = E->list_size * 2; if (new_list_size < E->list_offset + dl_size) { new_list_size = E->list_offset + dl_size; } E->PL = trealloc (E->PL, E->list_size * sizeof (tgl_peer_id_t), new_list_size * sizeof (tgl_peer_id_t)); assert (E->PL); E->UC = trealloc (E->UC, E->list_size * sizeof (int), new_list_size * sizeof (int)); assert (E->UC); E->LM = trealloc (E->LM, E->list_size * sizeof (void *), new_list_size * sizeof (void *)); assert (E->LM); E->LMD = trealloc (E->LMD, E->list_size * sizeof (tgl_message_id_t), new_list_size * sizeof (tgl_message_id_t)); assert (E->LMD); E->LRM = trealloc (E->LRM, E->list_size * sizeof (int), new_list_size * sizeof (int)); assert (E->LRM); E->list_size = new_list_size; int i; for (i = 0; i < E->list_offset; i++) { E->LM[i] = &E->LMD[i]; } } for (i = 0; i < dl_size; i++) { struct tl_ds_dialog *DS_D = DS_MD->dialogs->data[i]; tgl_peer_t *P = tgl_peer_get (TLS, tglf_fetch_peer_id (TLS, DS_D->peer)); assert (P); E->PL[E->list_offset + i] = P->id; E->LMD[E->list_offset + i] = tgl_peer_id_to_msg_id (E->PL[E->list_offset + i], DS_LVAL (DS_D->top_message)); E->LM[E->list_offset + i] = &E->LMD[E->list_offset + i]; E->UC[E->list_offset + i] = DS_LVAL (DS_D->unread_count); E->LRM[E->list_offset + i] = DS_LVAL (DS_D->read_inbox_max_id); } E->list_offset += dl_size; for (i = 0; i < DS_LVAL (DS_MD->messages->cnt); i++) { tglf_fetch_alloc_message (TLS, DS_MD->messages->data[i], NULL); } vlogprintf (E_DEBUG, "dl_size = %d, total = %d\n", dl_size, E->list_offset); if (dl_size && E->list_offset < E->limit && DS_MD->magic == CODE_messages_dialogs_slice && E->list_offset < DS_LVAL (DS_MD->count)) { E->offset += dl_size; if (E->list_offset > 0) { E->offset_peer = E->PL[E->list_offset - 1]; int p = E->list_offset - 1; while (p >= 0) { struct tgl_message *M = tgl_message_get (TLS, E->LM[p]); if (M) { E->offset_date = M->date; break; } p --; } } _tgl_do_get_dialog_list (TLS, E, q->callback, q->callback_extra); } else { if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int, int, tgl_peer_id_t *, tgl_message_id_t **, int *))q->callback) (TLS, q->callback_extra, 1, E->list_offset, E->PL, E->LM, E->UC); } tfree (E->PL, sizeof (tgl_peer_id_t) * E->list_size); tfree (E->UC, 4 * E->list_size); tfree (E->LM, sizeof (void *) * E->list_size); tfree (E->LMD, sizeof (tgl_message_id_t) * E->list_size); tfree (E->LRM, 4 * E->list_size); tfree (E, sizeof (*E)); } return 0; } static int get_dialogs_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); struct get_dialogs_extra *E = q->extra; tfree (E->PL, sizeof (tgl_peer_id_t) * E->list_size); tfree (E->UC, 4 * E->list_size); tfree (E->LM, sizeof (void *) * E->list_size); tfree (E->LMD, sizeof (tgl_message_id_t) * E->list_size); tfree (E->LRM, 4 * E->list_size); tfree (E, sizeof (*E)); if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int, int, tgl_peer_id_t *, tgl_message_id_t **, int *))q->callback) (TLS, q->callback_extra, 0, 0, NULL, NULL, NULL); } return 0; } static struct query_methods get_dialogs_methods = { .on_answer = get_dialogs_on_answer, .on_error = get_dialogs_on_error, .type = TYPE_TO_PARAM(messages_dialogs), .name = "get dialogs" }; static void _tgl_do_get_dialog_list (struct tgl_state *TLS, struct get_dialogs_extra *E, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]), void *callback_extra) { clear_packet (); if (E->channels) { out_int (CODE_channels_get_dialogs); out_int (E->offset); out_int (E->limit - E->list_offset); } else { out_int (CODE_messages_get_dialogs); out_int (E->offset_date); out_int (E->offset); //out_int (0); if (E->offset_peer.peer_type) { out_peer_id (TLS, E->offset_peer); } else { out_int (CODE_input_peer_empty); } out_int (E->limit - E->list_offset); } tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, E, callback, callback_extra); } void tgl_do_get_dialog_list (struct tgl_state *TLS, int limit, int offset, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]), void *callback_extra) { struct get_dialogs_extra *E = talloc0 (sizeof (*E)); E->limit = limit; E->offset = offset; E->channels = 0; _tgl_do_get_dialog_list (TLS, E, callback, callback_extra); } void tgl_do_get_channels_dialog_list (struct tgl_state *TLS, int limit, int offset, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]), void *callback_extra) { struct get_dialogs_extra *E = talloc0 (sizeof (*E)); E->limit = limit; E->offset = offset; E->channels = 1; E->offset_date = 0; E->offset_peer.peer_type = 0; _tgl_do_get_dialog_list (TLS, E, callback, callback_extra); } /* }}} */ int allow_send_linux_version = 1; /* {{{ Send document file */ static void out_peer_id (struct tgl_state *TLS, tgl_peer_id_t id) { switch (tgl_get_peer_type (id)) { case TGL_PEER_CHAT: out_int (CODE_input_peer_chat); out_int (tgl_get_peer_id (id)); break; case TGL_PEER_USER: out_int (CODE_input_peer_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); break; case TGL_PEER_CHANNEL: out_int (CODE_input_peer_channel); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); break; default: assert (0); } } static void send_part (struct tgl_state *TLS, struct send_file *f, void *callback, void *callback_extra); static int send_file_part_on_answer (struct tgl_state *TLS, struct query *q, void *D) { send_part (TLS, q->extra, q->callback, q->callback_extra); return 0; } static int set_photo_on_answer (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 1); } return 0; } static int send_file_part_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); struct send_file *f = q->extra; tfree_str (f->file_name); tfree_str (f->caption); if (!f->avatar.peer_type) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_message *))q->callback) (TLS, q->callback_extra, 0, 0); } } else { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 0); } } tfree (f, sizeof (*f)); return 0; } static struct query_methods send_file_part_methods = { .on_answer = send_file_part_on_answer, .on_error = send_file_part_on_error, .type = TYPE_TO_PARAM(bool), .name = "send file part" }; static struct query_methods set_photo_methods = { .on_answer = set_photo_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(photos_photo), .name = "set photo" }; static void send_avatar_end (struct tgl_state *TLS, struct send_file *f, void *callback, void *callback_extra) { switch (tgl_get_peer_type (f->avatar)) { case TGL_PEER_CHAT: out_int (CODE_messages_edit_chat_photo); out_int (f->avatar.peer_id); out_int (CODE_input_chat_uploaded_photo); break; case TGL_PEER_USER: out_int (CODE_photos_upload_profile_photo); break; case TGL_PEER_CHANNEL: out_int (CODE_channels_edit_photo); out_int (CODE_input_channel); out_int (f->avatar.peer_id); out_long (f->avatar.access_hash); out_int (CODE_input_chat_uploaded_photo); break; default: assert (0); } if (f->size < (16 << 20)) { out_int (CODE_input_file); } else { out_int (CODE_input_file_big); } out_long (f->id); out_int (f->part_num); char *s = f->file_name + strlen (f->file_name); while (s >= f->file_name && *s != '/') { s --;} out_string (s + 1); if (f->size < (16 << 20)) { out_string (""); } if (f->avatar.peer_type != TGL_PEER_USER) { out_int (CODE_input_photo_crop_auto); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, NULL, callback, callback_extra); } else { out_string ("profile photo"); out_int (CODE_input_geo_point_empty); out_int (CODE_input_photo_crop_auto); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &set_photo_methods, 0, callback, callback_extra); } } static void send_file_unencrypted_end (struct tgl_state *TLS, struct send_file *f, void *callback, void *callback_extra) { out_int (CODE_messages_send_media); out_int ((f->reply ? 1 : 0) | f->channel); out_peer_id (TLS, f->to_id); if (f->reply) { out_int (f->reply); } if (f->flags & TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO) { out_int (CODE_input_media_uploaded_photo); } else { if (f->thumb_id > 0) { out_int (CODE_input_media_uploaded_thumb_document); } else { out_int (CODE_input_media_uploaded_document); } } if (f->size < (16 << 20)) { out_int (CODE_input_file); } else { out_int (CODE_input_file_big); } out_long (f->id); out_int (f->part_num); char *s = f->file_name + strlen (f->file_name); while (s >= f->file_name && *s != '/') { s --;} out_string (s + 1); if (f->size < (16 << 20)) { out_string (""); } if (!(f->flags & TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO)) { out_string (tg_mime_by_filename (f->file_name)); out_int (CODE_vector); if (f->flags & TGLDF_IMAGE) { if (f->flags & TGLDF_ANIMATED) { out_int (2); out_int (CODE_document_attribute_image_size); out_int (f->w); out_int (f->h); out_int (CODE_document_attribute_animated); } else { out_int (1); out_int (CODE_document_attribute_image_size); out_int (f->w); out_int (f->h); } } else if (f->flags & TGLDF_AUDIO) { out_int (2); out_int (CODE_document_attribute_audio); out_int (f->duration); out_string (""); out_string (""); out_int (CODE_document_attribute_filename); out_string (s + 1); } else if (f->flags & TGLDF_VIDEO) { out_int (2); out_int (CODE_document_attribute_video); out_int (f->duration); out_int (f->w); out_int (f->h); out_int (CODE_document_attribute_filename); out_string (s + 1); } else if (f->flags & TGLDF_STICKER) { out_int (1); out_int (CODE_document_attribute_sticker); } else { out_int (1); out_int (CODE_document_attribute_filename); out_string (s + 1); } if (f->thumb_id > 0) { out_int (CODE_input_file); out_long (f->thumb_id); out_int (1); out_string ("thumb.jpg"); out_string (""); } out_string (f->caption ? f->caption : ""); } else { out_string (f->caption ? f->caption : ""); } struct messages_send_extra *E = talloc0 (sizeof (*E)); E->id = tgl_peer_id_to_random_msg_id (f->to_id); out_long (E->id.id); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, E, callback, callback_extra); tfree_str (f->file_name); tfree_str (f->caption); tfree (f, sizeof (*f)); } static void send_file_end (struct tgl_state *TLS, struct send_file *f, void *callback, void *callback_extra) { TLS->cur_uploaded_bytes -= f->size; TLS->cur_uploading_bytes -= f->size; clear_packet (); if (f->avatar.peer_id) { send_avatar_end (TLS, f, callback, callback_extra); return; } if (!f->encr) { send_file_unencrypted_end (TLS, f, callback, callback_extra); return; } send_file_encrypted_end (TLS, f, callback, callback_extra); return; } static void send_part (struct tgl_state *TLS, struct send_file *f, void *callback, void *callback_extra) { if (f->fd >= 0) { if (!f->part_num) { TLS->cur_uploading_bytes += f->size; } clear_packet (); if (f->size < (16 << 20)) { out_int (CODE_upload_save_file_part); out_long (f->id); out_int (f->part_num ++); } else { out_int (CODE_upload_save_big_file_part); out_long (f->id); out_int (f->part_num ++); out_int ((f->size + f->part_size - 1) / f->part_size); } static char buf[512 << 10]; int x = read (f->fd, buf, f->part_size); assert (x > 0); f->offset += x; TLS->cur_uploaded_bytes += x; if (f->encr) { if (x & 15) { assert (f->offset == f->size); tglt_secure_random (buf + x, (-x) & 15); x = (x + 15) & ~15; } TGLC_aes_key aes_key; TGLC_aes_set_encrypt_key (f->key, 256, &aes_key); TGLC_aes_ige_encrypt ((void *)buf, (void *)buf, x, &aes_key, f->iv, 1); memset (&aes_key, 0, sizeof (aes_key)); } out_cstring (buf, x); vlogprintf (E_DEBUG, "offset=%" INT64_PRINTF_MODIFIER "d size=%" INT64_PRINTF_MODIFIER "d\n", f->offset, f->size); if (f->offset == f->size) { close (f->fd); f->fd = -1; } else { assert (f->part_size == x); } //update_prompt (); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f, callback, callback_extra); } else { send_file_end (TLS, f, callback, callback_extra); } } static void send_file_thumb (struct tgl_state *TLS, struct send_file *f, const void *thumb_data, int thumb_len, void *callback, void *callback_extra) { clear_packet (); tglt_secure_random (&f->thumb_id, 8); out_int (CODE_upload_save_file_part); out_long (f->thumb_id); out_int (0); out_cstring ((void *)thumb_data, thumb_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f, callback, callback_extra); } static void _tgl_do_send_photo (struct tgl_state *TLS, tgl_peer_id_t to_id, const char *file_name, tgl_peer_id_t avatar, int w, int h, int duration, const void *thumb_data, int thumb_len, const char *caption, int caption_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { int fd = open (file_name, O_RDONLY | O_BINARY); if (fd < 0) { tgl_set_query_error (TLS, EBADF, "Can not open file: %s", strerror(errno)); if (!avatar.peer_id) { if (callback) { callback (TLS, callback_extra, 0, 0); } } else { if (callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_message*))callback) (TLS, callback_extra, 0, NULL); } } return; } struct stat buf; fstat (fd, &buf); long long size = buf.st_size; if (size <= 0) { tgl_set_query_error (TLS, EBADF, "File is empty"); close (fd); if (!avatar.peer_id) { if (callback) { callback (TLS, callback_extra, 0, 0); } } else { if (callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_message*))callback) (TLS, callback_extra, 0, NULL); } } return; } struct send_file *f = talloc0 (sizeof (*f)); f->fd = fd; f->size = size; f->offset = 0; f->part_num = 0; f->avatar = avatar; f->reply = flags >> 32; int tmp = ((size + 2999) / 3000); f->part_size = (1 << 14); while (f->part_size < tmp) { f->part_size *= 2; } f->flags = flags; f->channel = 0; if (flags & TGLMF_POST_AS_CHANNEL) { f->channel = 16; } if (f->part_size > (512 << 10)) { close (fd); tgl_set_query_error (TLS, E2BIG, "File is too big"); tfree (f, sizeof (*f)); if (!avatar.peer_id) { if (callback) { callback (TLS, callback_extra, 0, 0); } } else { if (callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_message*))callback) (TLS, callback_extra, 0, NULL); } } return; } tglt_secure_random (&f->id, 8); f->to_id = to_id; f->flags = flags; f->file_name = tstrdup (file_name); f->w = w; f->h = h; f->duration = duration; f->caption = caption ? tstrdup (caption) : tstrdup (""); if (tgl_get_peer_type (f->to_id) == TGL_PEER_ENCR_CHAT) { f->encr = 1; f->iv = talloc (32); tglt_secure_random (f->iv, 32); f->init_iv = talloc (32); memcpy (f->init_iv, f->iv, 32); f->key = talloc (32); tglt_secure_random (f->key, 32); } if (!f->encr && f->flags != -1 && thumb_len > 0) { send_file_thumb (TLS, f, thumb_data, thumb_len, callback, callback_extra); } else { send_part (TLS, f, callback, callback_extra); } } void tgl_do_send_document (struct tgl_state *TLS, tgl_peer_id_t to_id, const char *file_name, const char *caption, int caption_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { if (flags & TGL_SEND_MSG_FLAG_DOCUMENT_AUTO) { char *mime_type = tg_mime_by_filename (file_name); if (strcmp (mime_type, "image/gif") == 0) { flags |= TGL_SEND_MSG_FLAG_DOCUMENT_ANIMATED; } else if (!memcmp (mime_type, "image/", 6)) { flags |= TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO; } else if (!memcmp (mime_type, "video/", 6)) { flags |= TGLDF_VIDEO; } else if (!memcmp (mime_type, "audio/", 6)) { flags |= TGLDF_AUDIO; } } tgl_peer_id_t x; x.peer_id = 0; _tgl_do_send_photo (TLS, to_id, file_name, x, 100, 100, 100, 0, 0, caption, caption_len, flags, callback, callback_extra); } void tgl_do_reply_document (struct tgl_state *TLS, tgl_message_id_t *_reply_id, const char *file_name, const char *caption, int caption_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { tgl_message_id_t reply_id = *_reply_id; if (reply_id.peer_type == TGL_PEER_TEMP_ID) { reply_id = tgl_convert_temp_msg_id (TLS, reply_id); } if (reply_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (reply_id.peer_type == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not reply on message from secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } tgl_peer_id_t peer_id = tgl_msg_id_to_peer_id (reply_id); tgl_do_send_document (TLS, peer_id, file_name, caption, caption_len, flags | TGL_SEND_MSG_FLAG_REPLY (reply_id.id), callback, callback_extra); } void tgl_do_set_chat_photo (struct tgl_state *TLS, tgl_peer_id_t chat_id, const char *file_name, void (*callback)(struct tgl_state *TLS,void *callback_extra, int success), void *callback_extra) { assert (tgl_get_peer_type (chat_id) == TGL_PEER_CHAT); _tgl_do_send_photo (TLS, chat_id, file_name, chat_id, 0, 0, 0, 0, 0, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, (void *)callback, callback_extra); } void tgl_do_set_channel_photo (struct tgl_state *TLS, tgl_peer_id_t chat_id, const char *file_name, void (*callback)(struct tgl_state *TLS,void *callback_extra, int success), void *callback_extra) { assert (tgl_get_peer_type (chat_id) == TGL_PEER_CHANNEL); _tgl_do_send_photo (TLS, chat_id, file_name, chat_id, 0, 0, 0, 0, 0, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, (void *)callback, callback_extra); } void tgl_do_set_profile_photo (struct tgl_state *TLS, const char *file_name, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { _tgl_do_send_photo (TLS, TLS->our_id, file_name, TLS->our_id, 0, 0, 0, 0, 0, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, (void *)callback, callback_extra); } /* }}} */ /* {{{ Profile name */ int set_profile_name_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_user *DS_U = D; struct tgl_user *U = tglf_fetch_alloc_user (TLS, DS_U); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_user *))q->callback) (TLS, q->callback_extra, 1, U); } return 0; } static struct query_methods set_profile_name_methods = { .on_answer = set_profile_name_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM(user), .name = "set profile name" }; void tgl_do_set_profile_name (struct tgl_state *TLS, const char *first_name, int first_name_len, const char *last_name, int last_name_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *U), void *callback_extra) { clear_packet (); out_int (CODE_account_update_profile); out_cstring (first_name, first_name_len); out_cstring (last_name, last_name_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &set_profile_name_methods, 0, callback, callback_extra); } void tgl_do_set_username (struct tgl_state *TLS, const char *username, int username_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *U), void *callback_extra) { clear_packet (); out_int (CODE_account_update_username); out_cstring (username, username_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &set_profile_name_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Contacts search */ int contact_search_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_contacts_resolved_peer *DS_CRU = D; tgl_peer_id_t peer_id = tglf_fetch_peer_id (TLS, DS_CRU->peer); int i; for (i = 0; i < DS_LVAL (DS_CRU->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_CRU->users->data[i]); } for (i = 0; i < DS_LVAL (DS_CRU->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_CRU->chats->data[i]); } tgl_peer_t *P = tgl_peer_get (TLS, peer_id); if (q->callback) { ((void (*)(struct tgl_state *,void *, int, tgl_peer_t *))q->callback) (TLS, q->callback_extra, 1, P); } return 0; } static struct query_methods contact_search_methods = { .on_answer = contact_search_on_answer, .on_error = q_list_on_error, .type = TYPE_TO_PARAM(contacts_resolved_peer), .name = "contacts search" }; void tgl_do_contact_search (struct tgl_state *TLS, const char *name, int name_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, tgl_peer_t *U), void *callback_extra) { clear_packet (); out_int (CODE_contacts_resolve_username); out_cstring (name, name_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &contact_search_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Forward */ static int send_msgs_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct messages_send_extra *E = q->extra; tglu_work_any_updates (TLS, 1, D, (!E || E->multi) ? NULL : tgl_message_get (TLS, &E->id)); tglu_work_any_updates (TLS, 0, D, (!E || E->multi) ? NULL : tgl_message_get (TLS, &E->id)); if (!E) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } } else if (E->multi) { struct tgl_message **ML = talloc (sizeof (void *) * E->count); int count = E->count; int i; for (i = 0; i < count; i++) { struct tgl_message_id id; id.peer_type = TGL_PEER_RANDOM_ID; id.id = E->list[i].id; ML[i] = tgl_message_get (TLS, &id); } tfree (E->list, sizeof (tgl_message_id_t) * count); tfree (E, sizeof (*E)); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, int, struct tgl_message **))q->callback) (TLS, q->callback_extra, 1, count, ML); } tfree (ML, sizeof (void *) * count); } else { struct tgl_message_id id; id.peer_type = TGL_PEER_RANDOM_ID; id.id = E->id.id; struct tgl_message *M = tgl_message_get (TLS, &id); tfree (E, sizeof (*E)); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_message *))q->callback) (TLS, q->callback_extra, 1, M); } } return 0; } static int send_msgs_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); struct messages_send_extra *E = q->extra; if (!E) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 0); } } else if (E->multi) { int count = E->count; tfree (E->list, sizeof (tgl_message_id_t) * count); tfree (E, sizeof (*E)); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, int, struct tgl_message **))q->callback) (TLS, q->callback_extra, 0, 0, NULL); } } else { tfree (E, sizeof (*E)); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_message *))q->callback) (TLS, q->callback_extra, 0, NULL); } } return 0; } static struct query_methods send_msgs_methods = { .on_answer = send_msgs_on_answer, .on_error = send_msgs_on_error, .type = TYPE_TO_PARAM(updates), .name = "forward messages" }; void tgl_do_forward_messages (struct tgl_state *TLS, tgl_peer_id_t id, int n, const tgl_message_id_t *_ids[], unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int count, struct tgl_message *ML[]), void *callback_extra) { if (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not forward messages to secret chats"); if (callback) { callback (TLS, callback_extra, 0, 0, 0); } return; } tgl_peer_id_t from_id = TGL_MK_USER (0); tgl_message_id_t *ids = talloc (sizeof (tgl_message_id_t) * n); int i; for (i = 0; i < n; i++) { tgl_message_id_t msg_id = *_ids[i]; if (msg_id.peer_type == TGL_PEER_TEMP_ID) { msg_id = tgl_convert_temp_msg_id (TLS, msg_id); } if (msg_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0, 0, NULL); } tfree (ids, n * sizeof (tgl_message_id_t)); return; } if (msg_id.peer_type == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not forward message from secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0, NULL); } tfree (ids, n * sizeof (tgl_message_id_t)); return; } ids[i] = msg_id; if (i == 0) { from_id = tgl_msg_id_to_peer_id (msg_id); } else { if (tgl_cmp_peer_id (from_id, tgl_msg_id_to_peer_id (msg_id))) { tgl_set_query_error (TLS, EINVAL, "can not forward messages from different dialogs"); if (callback) { callback (TLS, callback_extra, 0, 0, NULL); } tfree (ids, n * sizeof (tgl_message_id_t)); return; } } } clear_packet (); out_int (CODE_messages_forward_messages); unsigned f = 0; if (flags & TGLMF_POST_AS_CHANNEL) { f |= 16; } out_int (f); out_peer_id (TLS, from_id); out_int (CODE_vector); out_int (n); for (i = 0; i < n; i++) { out_int (ids[i].id); } struct messages_send_extra *E = talloc0 (sizeof (*E)); E->multi = 1; E->count = n; E->list = talloc (sizeof (tgl_message_id_t) * n); out_int (CODE_vector); out_int (n); for (i = 0; i < n; i++) { E->list[i] = tgl_peer_id_to_random_msg_id (id); assert (E->list[i].id); out_long (E->list[i].id); } out_peer_id (TLS, id); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, E, callback, callback_extra); tfree (ids, n * sizeof (tgl_message_id_t)); } void tgl_do_forward_message (struct tgl_state *TLS, tgl_peer_id_t peer_id, tgl_message_id_t *_msg_id, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { tgl_message_id_t msg_id = *_msg_id; if (msg_id.peer_type == TGL_PEER_TEMP_ID) { msg_id = tgl_convert_temp_msg_id (TLS, msg_id); } if (msg_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (msg_id.peer_type == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not forward messages from secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (peer_id.peer_type == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not forward messages to secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } clear_packet (); out_int (CODE_messages_forward_message); tgl_peer_id_t from_peer = tgl_msg_id_to_peer_id (msg_id); out_peer_id (TLS, from_peer); out_int (msg_id.id); struct messages_send_extra *E = talloc0 (sizeof (*E)); E->id = tgl_peer_id_to_random_msg_id (peer_id); out_long (E->id.id); out_peer_id (TLS, peer_id); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, E, callback, callback_extra); } void tgl_do_send_contact (struct tgl_state *TLS, tgl_peer_id_t id, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { if (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not send contact to secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } int reply_id = flags >> 32; clear_packet (); out_int (CODE_messages_send_media); out_int (reply_id ? 1 : 0); if (reply_id) { out_int (reply_id); } out_peer_id (TLS, id); out_int (CODE_input_media_contact); out_cstring (phone, phone_len); out_cstring (first_name, first_name_len); out_cstring (last_name, last_name_len); struct messages_send_extra *E = talloc0 (sizeof (*E)); E->id = tgl_peer_id_to_random_msg_id (id); out_long (E->id.id); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, E, callback, callback_extra); } void tgl_do_reply_contact (struct tgl_state *TLS, tgl_message_id_t *_reply_id, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { tgl_message_id_t reply_id = *_reply_id; if (reply_id.peer_type == TGL_PEER_TEMP_ID) { reply_id = tgl_convert_temp_msg_id (TLS, reply_id); } if (reply_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (reply_id.peer_type == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not reply on message from secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } tgl_peer_id_t peer_id = tgl_msg_id_to_peer_id (reply_id); tgl_do_send_contact (TLS, peer_id, phone, phone_len, first_name, first_name_len, last_name, last_name_len, flags | TGL_SEND_MSG_FLAG_REPLY (reply_id.id), callback, callback_extra); } void tgl_do_forward_media (struct tgl_state *TLS, tgl_peer_id_t peer_id, tgl_message_id_t *_msg_id, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { if (tgl_get_peer_type (peer_id) == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not forward messages to secret chats"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } tgl_message_id_t msg_id = *_msg_id; if (msg_id.peer_type == TGL_PEER_TEMP_ID) { msg_id = tgl_convert_temp_msg_id (TLS, msg_id); } if (msg_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (msg_id.peer_type == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not forward message from secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } struct tgl_message *M = tgl_message_get (TLS, &msg_id); if (!M || !(M->flags & TGLMF_CREATED) || (M->flags & TGLMF_ENCRYPTED)) { if (!M || !(M->flags & TGLMF_CREATED)) { tgl_set_query_error (TLS, EINVAL, "unknown message"); } else { tgl_set_query_error (TLS, EINVAL, "can not forward message from secret chat"); } if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (M->media.type != tgl_message_media_photo && M->media.type != tgl_message_media_document && M->media.type != tgl_message_media_audio && M->media.type != tgl_message_media_video) { tgl_set_query_error (TLS, EINVAL, "can only forward photo/document"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } clear_packet (); out_int (CODE_messages_send_media); int f = 0; if (flags & TGLMF_POST_AS_CHANNEL) { f |= 16; } out_int (f); out_peer_id (TLS, peer_id); switch (M->media.type) { case tgl_message_media_photo: assert (M->media.photo); out_int (CODE_input_media_photo); out_int (CODE_input_photo); out_long (M->media.photo->id); out_long (M->media.photo->access_hash); out_string (""); break; case tgl_message_media_document: case tgl_message_media_audio: case tgl_message_media_video: assert (M->media.document); out_int (CODE_input_media_document); out_int (CODE_input_document); out_long (M->media.document->id); out_long (M->media.document->access_hash); out_string (""); break; default: assert (0); } struct messages_send_extra *E = talloc0 (sizeof (*E)); E->id = tgl_peer_id_to_random_msg_id (peer_id); out_long (E->id.id); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, E, callback, callback_extra); } /* }}} */ /* {{{ Send location */ void tgl_do_send_location (struct tgl_state *TLS, tgl_peer_id_t peer_id, double latitude, double longitude, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { if (tgl_get_peer_type (peer_id) == TGL_PEER_ENCR_CHAT) { tgl_do_send_location_encr (TLS, peer_id, latitude, longitude, flags, callback, callback_extra); } else { int reply_id = flags >> 32; clear_packet (); out_int (CODE_messages_send_media); unsigned f = reply_id ? 1 : 0; if (flags & TGLMF_POST_AS_CHANNEL) { f |= 16; } out_int (f); if (reply_id) { out_int (reply_id); } out_peer_id (TLS, peer_id); out_int (CODE_input_media_geo_point); out_int (CODE_input_geo_point); out_double (latitude); out_double (longitude); struct messages_send_extra *E = talloc0 (sizeof (*E)); E->id = tgl_peer_id_to_random_msg_id (peer_id); out_long (E->id.id); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, E, callback, callback_extra); } } void tgl_do_reply_location (struct tgl_state *TLS, tgl_message_id_t *_reply_id, double latitude, double longitude, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { tgl_message_id_t reply_id = *_reply_id; if (reply_id.peer_type == TGL_PEER_TEMP_ID) { reply_id = tgl_convert_temp_msg_id (TLS, reply_id); } if (reply_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (reply_id.peer_type == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not reply on message from secret chat"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } tgl_peer_id_t peer_id = tgl_msg_id_to_peer_id (reply_id); tgl_do_send_location (TLS, peer_id, latitude, longitude, flags | TGL_SEND_MSG_FLAG_REPLY (reply_id.id), callback, callback_extra); } /* }}} */ /* {{{ Rename chat */ void tgl_do_rename_chat (struct tgl_state *TLS, tgl_peer_id_t id, const char *name, int name_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_messages_edit_chat_title); assert (tgl_get_peer_type (id) == TGL_PEER_CHAT); out_int (tgl_get_peer_id (id)); out_cstring (name, name_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Rename channel */ void tgl_do_rename_channel (struct tgl_state *TLS, tgl_peer_id_t id, const char *name, int name_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_channels_edit_title); assert (tgl_get_peer_type (id) == TGL_PEER_CHANNEL); out_int (CODE_input_channel); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); out_cstring (name, name_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Join channel */ void tgl_do_join_channel (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_channels_join_channel); assert (tgl_get_peer_type (id) == TGL_PEER_CHANNEL); out_int (CODE_input_channel); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Leave channel */ void tgl_do_leave_channel (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_channels_leave_channel); assert (tgl_get_peer_type (id) == TGL_PEER_CHANNEL); out_int (CODE_input_channel); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ channel change about */ static int channels_set_about_on_answer (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 1); } return 0; } static struct query_methods channels_set_about_methods = { .on_answer = channels_set_about_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(bool), .name = "channels set about" }; void tgl_do_channel_set_about (struct tgl_state *TLS, tgl_peer_id_t id, const char *about, int about_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_channels_edit_about); assert (tgl_get_peer_type (id) == TGL_PEER_CHANNEL); out_int (CODE_input_channel); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); out_cstring (about, about_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &channels_set_about_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Channel set username */ void tgl_do_channel_set_username (struct tgl_state *TLS, tgl_peer_id_t id, const char *username, int username_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_channels_update_username); assert (tgl_get_peer_type (id) == TGL_PEER_CHANNEL); out_int (CODE_input_channel); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); out_cstring (username, username_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &channels_set_about_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Channel set admin */ void tgl_do_channel_set_admin (struct tgl_state *TLS, tgl_peer_id_t channel_id, tgl_peer_id_t user_id, int type, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_channels_edit_admin); assert (tgl_get_peer_type (channel_id) == TGL_PEER_CHANNEL); assert (tgl_get_peer_type (user_id) == TGL_PEER_USER); out_int (CODE_input_channel); out_int (tgl_get_peer_id (channel_id)); out_long (channel_id.access_hash); out_int (CODE_input_user); out_int (tgl_get_peer_id (user_id)); out_long (user_id.access_hash); switch (type) { case 1: out_int (CODE_channel_role_moderator); break; case 2: out_int (CODE_channel_role_editor); break; default: out_int (CODE_channel_role_empty); break; } tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Channel members */ struct channel_get_members_extra { int size; int count; struct tgl_user **UL; int type; int offset; int limit; tgl_peer_id_t id; }; void _tgl_do_channel_get_members (struct tgl_state *TLS, struct channel_get_members_extra *E, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_user *UL[]), void *callback_extra); static int channels_get_members_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_channels_channel_participants *DS_CP = D; int count = DS_LVAL (DS_CP->participants->cnt); struct channel_get_members_extra *E = q->extra; if (E->count + count > E->size) { E->UL = trealloc (E->UL, E->size * sizeof (void *), (E->count + count) * sizeof (void *)); E->size = E->count + count; } int i; for (i = 0; i < DS_LVAL (DS_CP->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_CP->users->data[i]); } for (i = 0; i < count; i++) { E->UL[E->count ++] = (void *)tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_CP->participants->data[i]->user_id))); } E->offset += count; if (!count || E->count == E->limit) { ((void (*)(struct tgl_state *, void *, int, int, struct tgl_user **))q->callback)(TLS, q->callback_extra, 1, E->count, E->UL); tfree (E->UL, E->size * sizeof (void *)); tfree (E, sizeof (*E)); return 0; } _tgl_do_channel_get_members (TLS, E, q->callback, q->callback_extra); return 0; } static int channels_get_members_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); if (q->callback) { ((void (*)(struct tgl_state *,void *, int, int, void *))(q->callback))(TLS, q->callback_extra, 0, 0, NULL); } struct channel_get_members_extra *E = q->extra; tfree (E->UL, E->size * sizeof (void *)); tfree (E, sizeof (*E)); return 0; } static struct query_methods channels_get_members_methods = { .on_answer = channels_get_members_on_answer, .on_error = channels_get_members_on_error, .type = TYPE_TO_PARAM(channels_channel_participants), .name = "channels get members" }; void _tgl_do_channel_get_members (struct tgl_state *TLS, struct channel_get_members_extra *E, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_user *UL[]), void *callback_extra) { clear_packet (); out_int (CODE_channels_get_participants); assert (tgl_get_peer_type (E->id) == TGL_PEER_CHANNEL); out_int (CODE_input_channel); out_int (E->id.peer_id); out_long (E->id.access_hash); switch (E->type) { case 1: case 2: out_int (CODE_channel_participants_admins); break; case 3: out_int (CODE_channel_participants_kicked); break; case 4: out_int (CODE_channel_participants_bots); break; default: out_int (CODE_channel_participants_recent); break; } out_int (E->offset); out_int (E->limit); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &channels_get_members_methods, E, callback, callback_extra); } void tgl_do_channel_get_members (struct tgl_state *TLS, tgl_peer_id_t channel_id, int limit, int offset, int type, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_user *UL[]), void *callback_extra) { struct channel_get_members_extra *E = talloc0 (sizeof (*E)); E->type = type; E->id = channel_id; E->limit = limit; E->offset = offset; _tgl_do_channel_get_members (TLS, E, callback, callback_extra); } /* }}} */ /* {{{ Chat info */ static int chat_info_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tgl_chat *C = tglf_fetch_alloc_chat_full (TLS, D); //print_chat_info (C); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_chat *))q->callback) (TLS, q->callback_extra, 1, C); } return 0; } static struct query_methods chat_info_methods = { .on_answer = chat_info_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM(messages_chat_full), .name = "chat info" }; void tgl_do_get_chat_info (struct tgl_state *TLS, tgl_peer_id_t id, int offline_mode, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_chat *C), void *callback_extra) { if (offline_mode) { tgl_peer_t *C = tgl_peer_get (TLS, id); if (!C) { tgl_set_query_error (TLS, EINVAL, "unknown chat id"); if (callback) { callback (TLS, callback_extra, 0, 0); } } else { if (callback) { callback (TLS, callback_extra, 1, &C->chat); } } return; } clear_packet (); out_int (CODE_messages_get_full_chat); assert (tgl_get_peer_type (id) == TGL_PEER_CHAT); out_int (tgl_get_peer_id (id)); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &chat_info_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Channel info */ static int channel_info_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tgl_channel *C = tglf_fetch_alloc_channel_full (TLS, D); //print_chat_info (C); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_channel *))q->callback) (TLS, q->callback_extra, 1, C); } return 0; } static struct query_methods channel_info_methods = { .on_answer = channel_info_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM(messages_chat_full), .name = "channel info" }; void tgl_do_get_channel_info (struct tgl_state *TLS, tgl_peer_id_t id, int offline_mode, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_channel *C), void *callback_extra) { if (offline_mode) { tgl_peer_t *C = tgl_peer_get (TLS, id); if (!C) { tgl_set_query_error (TLS, EINVAL, "unknown chat id"); if (callback) { callback (TLS, callback_extra, 0, 0); } } else { if (callback) { callback (TLS, callback_extra, 1, &C->channel); } } return; } clear_packet (); out_int (CODE_channels_get_full_channel); assert (tgl_get_peer_type (id) == TGL_PEER_CHANNEL); out_int (CODE_input_channel); out_int (id.peer_id); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &channel_info_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ User info */ static int user_info_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tgl_user *U = tglf_fetch_alloc_user_full (TLS, D); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_user *))q->callback) (TLS, q->callback_extra, 1, U); } return 0; } static struct query_methods user_info_methods = { .on_answer = user_info_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM(user_full), .name = "user info" }; void tgl_do_get_user_info (struct tgl_state *TLS, tgl_peer_id_t id, int offline_mode, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *U), void *callback_extra) { if (tgl_get_peer_type (id) != TGL_PEER_USER) { tgl_set_query_error (TLS, EINVAL, "id should be user id"); if (callback) { callback (TLS, callback_extra, 0, NULL); } return; } if (offline_mode) { tgl_peer_t *C = tgl_peer_get (TLS, id); if (!C) { tgl_set_query_error (TLS, EINVAL, "unknown user id"); if (callback) { callback (TLS, callback_extra, 0, 0); } } else { if (callback) { callback (TLS, callback_extra, 1, &C->user); } } return; } clear_packet (); out_int (CODE_users_get_full_user); assert (tgl_get_peer_type (id) == TGL_PEER_USER); out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &user_info_methods, 0, callback, callback_extra); } static void resend_query_cb (struct tgl_state *TLS, void *_q, int success) { assert (success); bl_do_dc_signed (TLS, TLS->DC_working->id); struct query *q = _q; clear_packet (); out_int (CODE_users_get_full_user); out_int (CODE_input_user_self); tglq_send_query (TLS, q->DC, packet_ptr - packet_buffer, packet_buffer, &user_info_methods, 0, q->callback, q->callback_extra); tfree (q->data, 4 * q->data_len); TLS->timer_methods->free (q->ev); tfree (q, sizeof (*q)); } /* }}} */ /* {{{ Load photo/video */ struct download { int offset; //chosen automatically based on the partially downloaded file, incremented progressively int size; long long volume; long long secret; long long access_hash; int local_id; int dc; int next; int fd; //opened internally, closed on completion char *name; //allocated internally, freed on completion char *ext; //allocated by caller [optional], freed on completion long long id; unsigned char *iv; //allocated by caller [optional], freed on completion unsigned char *key; //provided by caller [optional], left alone int type; //request code, if provided by the caller - otherwise autoselected int refcnt; char* file_reference; //allocated by caller [optional], freed on completion. for inputPhotoFileLocation etc char* thumb_size; //allocated by caller [optional], freed on completion. for inputPhotoFileLocation etc }; //Frees temporary fields in the download structure and resets it to caller-provided state static void download_reset(struct download *D) { if (D->fd >= 0) { close (D->fd); D->fd = -1; } tfree_str (D->name); //since its auto-selected D->name = 0; D->offset = 0; //redetermine offset automatically } //Frees all fields in the download structure and the structure itself static void download_free(struct download *D) { download_reset(D); //Additionally, free any parts allocated by the caller if (D->iv) { tfree_secure (D->iv, 32); D->iv = 0; } if (D->ext) { tfree_str (D->ext); D->ext = 0; } if (D->file_reference) { tfree_str (D->file_reference); D->file_reference = 0; } if (D->thumb_size) { tfree_str (D->thumb_size); D->thumb_size = 0; } tfree (D, sizeof (*D)); } static void end_load (struct tgl_state *TLS, struct download *D, void *callback, void *callback_extra) { TLS->cur_downloading_bytes -= D->size; TLS->cur_downloaded_bytes -= D->size; if (callback) { ((void (*)(struct tgl_state *, void *, int, char *))callback) (TLS, callback_extra, 1, D->name); } download_free(D); } static void download_next_part (struct tgl_state *TLS, struct download *D, void *callback, void *callback_extra); static int download_on_answer (struct tgl_state *TLS, struct query *q, void *DD) { struct tl_ds_upload_file *DS_UF = DD; struct download *D = q->extra; if (D->fd == -1) { D->fd = open (D->name, O_CREAT | O_WRONLY | O_BINARY, 0640); if (D->fd < 0) { tgl_set_query_error (TLS, EBADF, "Can not open file for writing: %s", strerror(errno)); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, char *))q->callback) (TLS, q->callback_extra, 0, NULL); } if (D->iv) { tfree_secure (D->iv, 32); } tfree_str (D->name); if (D->ext) { tfree_str (D->ext); } tfree (D, sizeof (*D)); return 0; } } int len = DS_UF->bytes->len; TLS->cur_downloaded_bytes += len; //update_prompt (); if (D->iv) { assert (!(len & 15)); void *ptr = DS_UF->bytes->data; TGLC_aes_key aes_key; TGLC_aes_set_decrypt_key (D->key, 256, &aes_key); TGLC_aes_ige_encrypt (ptr, ptr, len, &aes_key, D->iv, 0); memset (&aes_key, 0, sizeof (aes_key)); if (len > D->size - D->offset) { len = D->size - D->offset; } assert (write (D->fd, ptr, len) == len); } else { assert (write (D->fd, DS_UF->bytes->data, len) == len); } D->offset += len; D->refcnt --; if (D->offset < D->size) { download_next_part (TLS, D, q->callback, q->callback_extra); return 0; } else { if (!D->refcnt) { end_load (TLS, D, q->callback, q->callback_extra); } return 0; } } struct download_retry_data { struct download *D; struct tgl_timer *ev; void *callback; void *callback_extra; }; static void download_retry_alarm(struct tgl_state *TLS, void *arg) { struct download_retry_data *ri = arg; assert (ri); vlogprintf (E_DEBUG, "download_retry_alarm(size=%d, offset=%d, dc=%d, local_id=%d, volume=%" INT64_PRINTF_MODIFIER "d, secret=%" INT64_PRINTF_MODIFIER "d)", ri->D->size, ri->D->offset, ri->D->dc, ri->D->local_id, ri->D->volume, ri->D->secret); //Remove and free our retry timer TLS->timer_methods->remove (ri->ev); TLS->timer_methods->free (ri->ev); //Run download_next_part (TLS, ri->D, ri->callback, ri->callback_extra); //Free redownload_info tfree (ri, sizeof(*ri)); } static int download_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { vlogprintf (E_ERROR, "download_on_error(): '%s'\n", error); tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); struct download *D = q->extra; int wait = -1; if (strncmp (error, "FLOOD_WAIT_", 11) == 0) { wait = atoll (error + 11); } else if (error_code == 420) { //non-standard floodwait: no repeat, better not guess } else { //non-floodwait error: no repeat } int redownload = (wait > 0) && (wait <= 10); //can't transparently wait more than just a bit, fail //If failing, run callback now while the data is not freed if (!redownload && q->callback) { vlogprintf (E_ERROR, "download_error: admitting failure\n"); ((void (*)(struct tgl_state *, void *, int, char *))q->callback) (TLS, q->callback_extra, 0, NULL); } D->refcnt--; //download_next_part() completed so deref if (redownload) { vlogprintf (E_ERROR, "download_error: scheduling retry\n"); download_reset(D); //query q will be destroyed by tglq_query_error when we return so copy everything struct download_retry_data *ri = talloc0 (sizeof (*ri)); ri->D = D; ri->callback = q->callback; ri->callback_extra = q->callback_extra; ri->ev = TLS->timer_methods->alloc (TLS, download_retry_alarm, ri); TLS->timer_methods->insert (ri->ev, wait); } else { //Only do this on no redownload: download_free(D); } return 0; } static struct query_methods download_methods = { .on_answer = download_on_answer, .on_error = download_on_error, .type = TYPE_TO_PARAM(upload_file), .name = "download part" }; static void download_next_part (struct tgl_state *TLS, struct download *D, void *callback, void *callback_extra) { if (!D->offset) { static char buf[PATH_MAX]; int l; if (!D->id) { l = tsnprintf (buf, sizeof (buf), "%s/download_%" INT64_PRINTF_MODIFIER "d_%d.jpg", TLS->downloads_directory, D->volume, D->local_id); } else { if (D->ext) { l = tsnprintf (buf, sizeof (buf), "%s/download_%" INT64_PRINTF_MODIFIER "d.%s", TLS->downloads_directory, D->id, D->ext); } else { l = tsnprintf (buf, sizeof (buf), "%s/download_%" INT64_PRINTF_MODIFIER "d", TLS->downloads_directory, D->id); } } if (l >= (int) sizeof (buf)) { vlogprintf (E_ERROR, "Download filename is too long"); assert (0); } D->name = tstrdup (buf); struct stat st; if (stat (buf, &st) >= 0) { D->offset = st.st_size; if (D->offset >= D->size) { TLS->cur_downloading_bytes += D->size; TLS->cur_downloaded_bytes += D->offset; vlogprintf (E_NOTICE, "Already downloaded\n"); end_load (TLS, D, callback, callback_extra); return; } } TLS->cur_downloading_bytes += D->size; TLS->cur_downloaded_bytes += D->offset; //update_prompt (); } D->refcnt ++; clear_packet (); out_int (CODE_upload_get_file); if (!D->id) { out_int (CODE_input_file_location); out_long (D->volume); out_int (D->local_id); out_long (D->secret); } else { if (D->iv) { out_int (CODE_input_encrypted_file_location); } else { out_int (D->type); //CODE_* set by the caller } out_long (D->id); out_long (D->access_hash); //Used by inputPhotoFileLocation: if (D->file_reference) out_string(D->file_reference); //I'm not sure but let's say it's a string for now if (D->thumb_size) out_string(D->thumb_size); //Definitely a string } out_int (D->offset); out_int (D->size ? (1 << 14) : (1 << 19)); tglq_send_query (TLS, TLS->DC_list[D->dc], packet_ptr - packet_buffer, packet_buffer, &download_methods, D, callback, callback_extra); //tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); } void tgl_do_load_photo_size (struct tgl_state *TLS, struct tgl_photo_size *P, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *filename), void *callback_extra) { if (!P->loc.dc) { vlogprintf (E_WARNING, "Bad video thumb\n"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } assert (P); struct download *D = talloc0 (sizeof (*D)); D->id = 0; D->offset = 0; D->size = P->size; D->volume = P->loc.volume; D->dc = P->loc.dc; D->local_id = P->loc.local_id; D->secret = P->loc.secret; D->name = 0; D->fd = -1; download_next_part (TLS, D, callback, callback_extra); } void tgl_do_load_file_location (struct tgl_state *TLS, struct tgl_file_location *P, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *filename), void *callback_extra) { if (!P->dc) { tgl_set_query_error (TLS, EINVAL, "Bad file location"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } assert (P); struct download *D = talloc0 (sizeof (*D)); D->id = 0; D->offset = 0; D->size = 0; D->volume = P->volume; D->dc = P->dc; D->local_id = P->local_id; D->secret = P->secret; D->name = 0; D->fd = -1; download_next_part (TLS, D, callback, callback_extra); } void tgl_do_load_photo (struct tgl_state *TLS, struct tgl_photo *photo, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *filename), void *callback_extra) { if (!photo) { tgl_set_query_error (TLS, EINVAL, "Bad photo (invalid)"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } if (!photo->sizes_num) { tgl_set_query_error (TLS, EINVAL, "Bad photo (no photo sizes"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } int max = -1; int maxi = 0; int i; for (i = 0; i < photo->sizes_num; i++) { if (photo->sizes[i].w + photo->sizes[i].h > max) { max = photo->sizes[i].w + photo->sizes[i].h; maxi = i; } } tgl_do_load_photo_size (TLS, &photo->sizes[maxi], callback, callback_extra); } void tgl_do_load_document_thumb (struct tgl_state *TLS, struct tgl_document *video, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *filename), void *callback_extra) { tgl_do_load_photo_size (TLS, &video->thumb, callback, callback_extra); } static void _tgl_do_load_document (struct tgl_state *TLS, struct tgl_document *V, struct download *D, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *filename), void *callback_extra) { assert (V); D->offset = 0; D->size = V->size; D->id = V->id; D->access_hash = V->access_hash; D->dc = V->dc_id; D->name = V->caption; D->fd = -1; if (V->mime_type) { char *r = tg_extension_by_mime (V->mime_type); if (r) { D->ext = tstrdup (r); } } download_next_part (TLS, D, callback, callback_extra); } void tgl_do_load_document (struct tgl_state *TLS, struct tgl_document *V, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *filename), void *callback_extra) { struct download *D = talloc0 (sizeof (*D)); D->type = CODE_input_document_file_location; _tgl_do_load_document (TLS, V, D, callback, callback_extra); } void tgl_do_load_video (struct tgl_state *TLS, struct tgl_document *V, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *filename), void *callback_extra) { struct download *D = talloc0 (sizeof (*D)); D->type = CODE_input_video_file_location; _tgl_do_load_document (TLS, V, D, callback, callback_extra); } void tgl_do_load_audio (struct tgl_state *TLS, struct tgl_document *V, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *filename), void *callback_extra) { struct download *D = talloc0 (sizeof (*D)); D->type = CODE_input_audio_file_location; _tgl_do_load_document (TLS, V, D, callback, callback_extra); } void tgl_do_load_encr_document (struct tgl_state *TLS, struct tgl_encr_document *V, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *filename), void *callback_extra) { assert (V); struct download *D = talloc0 (sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; D->access_hash = V->access_hash; D->dc = V->dc_id; D->name = 0; D->fd = -1; D->key = V->key; D->iv = talloc (32); memcpy (D->iv, V->iv, 32); if (V->mime_type) { char *r = tg_extension_by_mime (V->mime_type); if (r) { D->ext = tstrdup (r); } } download_next_part (TLS, D, callback, callback_extra); unsigned char md5[16]; unsigned char str[64]; memcpy (str, V->key, 32); memcpy (str + 32, V->iv, 32); TGLC_md5 (str, 64, md5); assert (V->key_fingerprint == ((*(int *)md5) ^ (*(int *)(md5 + 4)))); } /* }}} */ /* {{{ Export auth */ static int import_auth_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_auth_authorization *DS_U = D; tglf_fetch_alloc_user (TLS, DS_U->user); bl_do_dc_signed (TLS, ((struct tgl_dc *)q->extra)->id); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } return 0; } static struct query_methods import_auth_methods = { .on_answer = import_auth_on_answer, .on_error = fail_on_error, .type = TYPE_TO_PARAM(auth_authorization), .name = "import authorization" }; static int export_auth_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_auth_exported_authorization *DS_EA = D; bl_do_set_our_id (TLS, TGL_MK_USER (DS_LVAL (DS_EA->id))); clear_packet (); tgl_do_insert_header (TLS); out_int (CODE_auth_import_authorization); out_int (tgl_get_peer_id (TLS->our_id)); out_cstring (DS_STR (DS_EA->bytes)); tglq_send_query (TLS, q->extra, packet_ptr - packet_buffer, packet_buffer, &import_auth_methods, q->extra, q->callback, q->callback_extra); return 0; } static struct query_methods export_auth_methods = { .on_answer = export_auth_on_answer, .on_error = fail_on_error, .type = TYPE_TO_PARAM(auth_exported_authorization), .name = "export authorization" }; void tgl_do_export_auth (struct tgl_state *TLS, int num, void (*callback) (struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_auth_export_authorization); out_int (num); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &export_auth_methods, TLS->DC_list[num], callback, callback_extra); } /* }}} */ /* {{{ Add contact */ static int add_contact_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_contacts_imported_contacts *DS_CIC = D; if (DS_LVAL (DS_CIC->imported->cnt) > 0) { vlogprintf (E_DEBUG, "Added successfully"); } else { vlogprintf (E_DEBUG, "Not added"); } int n = DS_LVAL (DS_CIC->users->cnt); struct tgl_user **UL = talloc (n * sizeof (void *)); int i; for (i = 0; i < n; i++) { UL[i] = tglf_fetch_alloc_user (TLS, DS_CIC->users->data[i]); } if (q->callback) { ((void (*)(struct tgl_state *, void *, int, int, struct tgl_user **))q->callback) (TLS, q->callback_extra, 1, n, UL); } tfree (UL, n * sizeof (void *)); return 0; } static struct query_methods add_contact_methods = { .on_answer = add_contact_on_answer, .on_error = q_list_on_error, .type = TYPE_TO_PARAM(contacts_imported_contacts), .name = "add contact" }; void tgl_do_add_contact (struct tgl_state *TLS, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force, void (*callback)(struct tgl_state *TLS,void *callback_extra, int success, int size, struct tgl_user *users[]), void *callback_extra) { clear_packet (); out_int (CODE_contacts_import_contacts); out_int (CODE_vector); out_int (1); out_int (CODE_input_phone_contact); long long r; tglt_secure_random (&r, 8); out_long (r); out_cstring (phone, phone_len); out_cstring (first_name, first_name_len); out_cstring (last_name, last_name_len); out_int (force ? CODE_bool_true : CODE_bool_false); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &add_contact_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Del contact */ static int del_contact_on_answer (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } return 0; } static struct query_methods del_contact_methods = { .on_answer = del_contact_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(contacts_link), .name = "del contact" }; void tgl_do_del_contact (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { if (tgl_get_peer_type (id) != TGL_PEER_USER) { tgl_set_query_error (TLS, EINVAL, "id should be user id"); if (callback) { callback (TLS, callback_extra, 0); } return; } clear_packet (); out_int (CODE_contacts_delete_contact); out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &del_contact_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Msg search */ struct msg_search_extra { struct tgl_message **ML; int list_offset; int list_size; tgl_peer_id_t id; int limit; int offset; int from; int to; int max_id; char *query; }; static void _tgl_do_msg_search (struct tgl_state *TLS, struct msg_search_extra *E, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra); static int msg_search_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_messages_messages *DS_MM = D; int i; for (i = 0; i < DS_LVAL (DS_MM->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_MM->chats->data[i]); } for (i = 0; i < DS_LVAL (DS_MM->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_MM->users->data[i]); } struct msg_search_extra *E = q->extra; int n = DS_LVAL (DS_MM->messages->cnt); if (E->list_size - E->list_offset < n) { int new_list_size = 2 * E->list_size; if (new_list_size - E->list_offset < n) { new_list_size = n + E->list_offset; } E->ML = trealloc (E->ML, E->list_size * sizeof (void *), new_list_size * sizeof (void *)); assert (E->ML); E->list_size = new_list_size; } for (i = 0; i < n; i++) { E->ML[i + E->list_offset] = tglf_fetch_alloc_message (TLS, DS_MM->messages->data[i], NULL); } E->list_offset += n; E->offset += n; E->limit -= n; if (E->limit + E->offset >= DS_LVAL (DS_MM->count)) { E->limit = DS_LVAL (DS_MM->count) - E->offset; if (E->limit < 0) { E->limit = 0; } } assert (E->limit >= 0); if (E->limit <= 0 || DS_MM->magic == CODE_messages_messages) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int, int, struct tgl_message **))q->callback) (TLS, q->callback_extra, 1, E->list_offset, E->ML); } tfree_str (E->query); tfree (E->ML, sizeof (void *) * E->list_size); tfree (E, sizeof (*E)); } else { E->max_id = E->ML[E->list_offset - 1]->permanent_id.id; E->offset = 0; _tgl_do_msg_search (TLS, E, q->callback, q->callback_extra); } return 0; } static int msg_search_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); struct msg_search_extra *E = q->extra; tfree_str (E->query); tfree (E->ML, sizeof (void *) * E->list_size); tfree (E, sizeof (*E)); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, int, struct tgl_message **))q->callback) (TLS, q->callback_extra, 0, 0, NULL); } return 0; } static struct query_methods msg_search_methods = { .on_answer = msg_search_on_answer, .on_error = msg_search_on_error, .type = TYPE_TO_PARAM(messages_messages), .name = "messages search" }; static void _tgl_do_msg_search (struct tgl_state *TLS, struct msg_search_extra *E, void (*callback)(struct tgl_state *TLS,void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra) { clear_packet (); if (tgl_get_peer_type (E->id) == TGL_PEER_UNKNOWN) { out_int (CODE_messages_search_global); out_string (E->query); out_int (0); out_int (CODE_input_peer_empty); out_int (E->offset); out_int (E->limit); } else { out_int (CODE_messages_search); out_int (0); out_peer_id (TLS, E->id); out_string (E->query); out_int (CODE_input_messages_filter_empty); out_int (E->from); out_int (E->to); out_int (E->offset); // offset out_int (E->max_id); // max_id out_int (E->limit); } tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_search_methods, E, callback, callback_extra); } void tgl_do_msg_search (struct tgl_state *TLS, tgl_peer_id_t id, int from, int to, int limit, int offset, const char *pattern, int pattern_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra) { if (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT) { tgl_set_query_error (TLS, EINVAL, "can not search in secret chats"); if (callback) { callback (TLS, callback_extra, 0, 0, 0); } return; } struct msg_search_extra *E = talloc0 (sizeof (*E)); E->id = id; E->from = from; E->to = to; E->limit = limit; E->offset = offset; E->query = tstrndup (pattern, pattern_len); _tgl_do_msg_search (TLS, E, callback, callback_extra); } /* }}} */ /* {{{ Get difference */ static int get_state_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_updates_state *DS_US = D; assert (TLS->locks & TGL_LOCK_DIFF); TLS->locks ^= TGL_LOCK_DIFF; bl_do_set_pts (TLS, DS_LVAL (DS_US->pts)); bl_do_set_qts (TLS, DS_LVAL (DS_US->qts)); bl_do_set_date (TLS, DS_LVAL (DS_US->date)); bl_do_set_seq (TLS, DS_LVAL (DS_US->seq)); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } return 0; } static int lookup_state_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_updates_state *DS_US = D; int pts = DS_LVAL (DS_US->pts); int qts = DS_LVAL (DS_US->qts); int seq = DS_LVAL (DS_US->seq); if (pts > TLS->pts || qts > TLS->qts || seq > TLS->seq) { tgl_do_get_difference (TLS, 0, 0, 0); } return 0; } //int get_difference_active; static int get_difference_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_updates_difference *DS_UD = D; assert (TLS->locks & TGL_LOCK_DIFF); TLS->locks ^= TGL_LOCK_DIFF; if (DS_UD->magic == CODE_updates_difference_empty) { bl_do_set_date (TLS, DS_LVAL (DS_UD->date)); bl_do_set_seq (TLS, DS_LVAL (DS_UD->seq)); vlogprintf (E_DEBUG, "Empty difference. Seq = %d\n", TLS->seq); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } } else { int i; for (i = 0; i < DS_LVAL (DS_UD->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_UD->users->data[i]); } for (i = 0; i < DS_LVAL (DS_UD->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_UD->chats->data[i]); } int ml_pos = DS_LVAL (DS_UD->new_messages->cnt); struct tgl_message **ML = talloc (ml_pos * sizeof (void *)); for (i = 0; i < ml_pos; i++) { ML[i] = tglf_fetch_alloc_message (TLS, DS_UD->new_messages->data[i], NULL); } int el_pos = DS_LVAL (DS_UD->new_encrypted_messages->cnt); struct tgl_message **EL = talloc (el_pos * sizeof (void *)); for (i = 0; i < el_pos; i++) { EL[i] = tglf_fetch_alloc_encrypted_message (TLS, DS_UD->new_encrypted_messages->data[i]); } for (i = 0; i < DS_LVAL (DS_UD->other_updates->cnt); i++) { tglu_work_update (TLS, 1, DS_UD->other_updates->data[i]); } for (i = 0; i < DS_LVAL (DS_UD->other_updates->cnt); i++) { tglu_work_update (TLS, -1, DS_UD->other_updates->data[i]); } for (i = 0; i < ml_pos; i++) { // Ignore invalid messages, would cause a null ptr deref otherwise if (ML[i] == NULL) continue; bl_do_msg_update (TLS, &ML[i]->permanent_id); } for (i = 0; i < el_pos; i++) { // messages to secret chats that no longer exist are not initialized and NULL if (EL[i] == NULL) continue; bl_do_msg_update (TLS, &EL[i]->permanent_id); } tfree (ML, ml_pos * sizeof (void *)); tfree (EL, el_pos * sizeof (void *)); if (DS_UD->state) { bl_do_set_pts (TLS, DS_LVAL (DS_UD->state->pts)); bl_do_set_qts (TLS, DS_LVAL (DS_UD->state->qts)); bl_do_set_date (TLS, DS_LVAL (DS_UD->state->date)); bl_do_set_seq (TLS, DS_LVAL (DS_UD->state->seq)); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } } else { bl_do_set_pts (TLS, DS_LVAL (DS_UD->intermediate_state->pts)); bl_do_set_qts (TLS, DS_LVAL (DS_UD->intermediate_state->qts)); bl_do_set_date (TLS, DS_LVAL (DS_UD->intermediate_state->date)); tgl_do_get_difference (TLS, 0, q->callback, q->callback_extra); } } return 0; } static struct query_methods lookup_state_methods = { .on_answer = lookup_state_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(updates_state), .name = "lookup state" }; static struct query_methods get_state_methods = { .on_answer = get_state_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(updates_state), .name = "get state" }; static struct query_methods get_difference_methods = { .on_answer = get_difference_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(updates_difference), .name = "get difference" }; void tgl_do_lookup_state (struct tgl_state *TLS) { if (TLS->locks & TGL_LOCK_DIFF) { return; } clear_packet (); tgl_do_insert_header (TLS); out_int (CODE_updates_get_state); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &lookup_state_methods, 0, 0, 0); } void tgl_do_get_difference (struct tgl_state *TLS, int sync_from_start, void (*callback)(struct tgl_state *tls, void *callback_extra, int success), void *callback_extra) { //get_difference_active = 1; //difference_got = 0; if (TLS->locks & TGL_LOCK_DIFF) { if (callback) { callback (TLS, callback_extra, 0); } return; } TLS->locks |= TGL_LOCK_DIFF; clear_packet (); tgl_do_insert_header (TLS); if (TLS->pts > 0 || sync_from_start) { if (TLS->pts == 0) { TLS->pts = 1; } //if (TLS->qts == 0) { TLS->qts = 1; } if (TLS->date == 0) { TLS->date = 1; } out_int (CODE_updates_get_difference); out_int (TLS->pts); out_int (TLS->date); out_int (TLS->qts); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_difference_methods, 0, callback, callback_extra); } else { out_int (CODE_updates_get_state); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_state_methods, 0, callback, callback_extra); } } /* }}} */ /* {{{ Get channel difference */ void tgl_do_get_channel_difference (struct tgl_state *TLS, int id, void (*callback)(struct tgl_state *tls, void *callback_extra, int success), void *callback_extra); static int get_channel_difference_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_updates_channel_difference *DS_UD = D; tgl_peer_t *E = q->extra; assert (E->flags & TGLCHF_DIFF); E->flags ^= TGLCHF_DIFF; if (DS_UD->magic == CODE_updates_channel_difference_empty) { bl_do_set_channel_pts (TLS, tgl_get_peer_id (E->id), DS_LVAL (DS_UD->channel_pts)); vlogprintf (E_DEBUG, "Empty difference. Seq = %d\n", TLS->seq); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } } else { int i; for (i = 0; i < DS_LVAL (DS_UD->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_UD->users->data[i]); } for (i = 0; i < DS_LVAL (DS_UD->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_UD->chats->data[i]); } int ml_pos = DS_LVAL (DS_UD->new_messages->cnt); struct tgl_message **ML = talloc (ml_pos * sizeof (void *)); for (i = 0; i < ml_pos; i++) { ML[i] = tglf_fetch_alloc_message (TLS, DS_UD->new_messages->data[i], NULL); } for (i = 0; i < DS_LVAL (DS_UD->other_updates->cnt); i++) { tglu_work_update (TLS, 1, DS_UD->other_updates->data[i]); } for (i = 0; i < DS_LVAL (DS_UD->other_updates->cnt); i++) { tglu_work_update (TLS, -1, DS_UD->other_updates->data[i]); } for (i = 0; i < ml_pos; i++) { bl_do_msg_update (TLS, &ML[i]->permanent_id); } tfree (ML, ml_pos * sizeof (void *)); bl_do_set_channel_pts (TLS, tgl_get_peer_id (E->id), DS_LVAL (DS_UD->channel_pts)); if (DS_UD->magic != CODE_updates_channel_difference_too_long) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } } else { tgl_do_get_channel_difference (TLS, tgl_get_peer_id (E->id), q->callback, q->callback_extra); } } return 0; } static struct query_methods get_channel_difference_methods = { .on_answer = get_channel_difference_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(updates_channel_difference), .name = "get channel difference" }; void tgl_do_get_channel_difference (struct tgl_state *TLS, int id, void (*callback)(struct tgl_state *tls, void *callback_extra, int success), void *callback_extra) { tgl_peer_t *E = tgl_peer_get (TLS, TGL_MK_CHANNEL (id)); if (!E || !(E->flags & TGLPF_CREATED) || !E->channel.pts) { if (callback) { callback (TLS, callback_extra, 0); } return; } //get_difference_active = 1; //difference_got = 0; if (E->flags & TGLCHF_DIFF) { if (callback) { callback (TLS, callback_extra, 0); } return; } E->flags |= TGLCHF_DIFF; clear_packet (); tgl_do_insert_header (TLS); out_int (CODE_updates_get_channel_difference); out_int (CODE_input_channel); out_int (tgl_get_peer_id (E->id)); out_long (E->channel.access_hash); out_int (CODE_channel_messages_filter_empty); out_int (E->channel.pts); out_int (100); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_channel_difference_methods, E, callback, callback_extra); } /* }}} */ /* {{{ Visualize key */ int tgl_do_visualize_key (struct tgl_state *TLS, tgl_peer_id_t id, unsigned char buf[16]) { assert (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT); tgl_peer_t *P = tgl_peer_get (TLS, id); assert (P); if (P->encr_chat.state != sc_ok) { vlogprintf (E_WARNING, "Chat is not initialized yet\n"); return -1; } memcpy (buf, P->encr_chat.first_key_sha, 16); return 0; } /* }}} */ /* {{{ Add user to chat */ void tgl_do_add_user_to_chat (struct tgl_state *TLS, tgl_peer_id_t chat_id, tgl_peer_id_t id, int limit, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_messages_add_chat_user); out_int (tgl_get_peer_id (chat_id)); assert (tgl_get_peer_type (id) == TGL_PEER_USER); out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); out_int (limit); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } void tgl_do_del_user_from_chat (struct tgl_state *TLS, tgl_peer_id_t chat_id, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_messages_delete_chat_user); out_int (tgl_get_peer_id (chat_id)); assert (tgl_get_peer_type (id) == TGL_PEER_USER); out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Add user to channel */ void tgl_do_channel_invite_user (struct tgl_state *TLS, tgl_peer_id_t channel_id, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_channels_invite_to_channel); out_int (CODE_input_channel); out_int (channel_id.peer_id); out_long (channel_id.access_hash); out_int (CODE_vector); out_int (1); out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } void tgl_do_channel_kick_user (struct tgl_state *TLS, tgl_peer_id_t channel_id, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_channels_kick_from_channel); out_int (CODE_input_channel); out_int (channel_id.peer_id); out_long (channel_id.access_hash); out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); out_int (CODE_bool_true); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Create secret chat */ void tgl_do_create_secret_chat (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra) { assert (tgl_get_peer_type (id) == TGL_PEER_USER); tgl_peer_t *U = tgl_peer_get (TLS, id); if (!U) { tgl_set_query_error (TLS, EINVAL, "Can not create secret chat with unknown user"); if (callback) { callback (TLS, callback_extra, 0, NULL); } return; } tgl_do_create_encr_chat_request (TLS, tgl_get_peer_id (id), callback, callback_extra); } /* }}} */ /* {{{ Create group chat */ void tgl_do_create_group_chat (struct tgl_state *TLS, int users_num, tgl_peer_id_t ids[], const char *chat_topic, int chat_topic_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_messages_create_chat); out_int (CODE_vector); out_int (users_num); // Number of users, currently we support only 1 user. int i; for (i = 0; i < users_num; i++) { tgl_peer_id_t id = ids[i]; if (tgl_get_peer_type (id) != TGL_PEER_USER) { tgl_set_query_error (TLS, EINVAL, "Can not create chat with unknown user"); if (callback) { callback (TLS, callback_extra, 0); } return; } out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); } out_cstring (chat_topic, chat_topic_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Create channel */ void tgl_do_create_channel (struct tgl_state *TLS, int users_num, tgl_peer_id_t ids[], const char *chat_topic, int chat_topic_len, const char *about, int about_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_channels_create_channel); out_int (flags); // looks like 2 is disable non-admin messages out_cstring (chat_topic, chat_topic_len); out_cstring (about, about_len); //out_int (CODE_vector); //out_int (users_num); int i; for (i = 0; i < users_num; i++) { tgl_peer_id_t id = ids[i]; if (tgl_get_peer_type (id) != TGL_PEER_USER) { tgl_set_query_error (TLS, EINVAL, "Can not create chat with unknown user"); if (callback) { callback (TLS, callback_extra, 0); } return; } out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); } tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Delete msg */ static int delete_msg_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_messages_affected_messages *DS_MAM = D; tgl_message_id_t *id = q->extra; q->extra = NULL; struct tgl_message *M = tgl_message_get (TLS, id); if (M) { bl_do_message_delete (TLS, &M->permanent_id); } tfree (id, sizeof (*id)); int r = tgl_check_pts_diff (TLS, DS_LVAL (DS_MAM->pts), DS_LVAL (DS_MAM->pts_count)); if (r > 0) { bl_do_set_pts (TLS, DS_LVAL (DS_MAM->pts)); } if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } return 0; } static int delete_msg_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); if (q->callback) { ((void (*)(struct tgl_state *,void *, int))(q->callback))(TLS, q->callback_extra, 0); } tfree (q->extra, sizeof (tgl_message_id_t)); return 0; } static struct query_methods delete_msg_methods = { .on_answer = delete_msg_on_answer, .on_error = delete_msg_on_error, .type = TYPE_TO_PARAM(messages_affected_messages), .name = "delete message" }; void tgl_do_delete_msg (struct tgl_state *TLS, tgl_message_id_t *_msg_id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { tgl_message_id_t msg_id = *_msg_id; if (msg_id.peer_type == TGL_PEER_TEMP_ID) { msg_id = tgl_convert_temp_msg_id (TLS, msg_id); } if (msg_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0); } return; } clear_packet (); if (msg_id.peer_type == TGL_PEER_CHANNEL) { out_int (CODE_channels_delete_messages); out_int (CODE_input_channel); out_int (msg_id.peer_id); out_long (msg_id.access_hash); out_int (CODE_vector); out_int (1); out_int (msg_id.id); } else { out_int (CODE_messages_delete_messages); out_int (CODE_vector); out_int (1); out_int (msg_id.id); } tgl_message_id_t *id = talloc (sizeof (*id)); *id = msg_id; tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &delete_msg_methods, id, callback, callback_extra); } /* }}} */ /* {{{ Export card */ static int export_card_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_vector *DS_V = D; int n = DS_LVAL (DS_V->f1); int *r = talloc (4 * n); int i; for (i = 0; i < n; i++) { r[i] = *(int *)DS_V->f2[i]; } if (q->callback) { ((void (*)(struct tgl_state *, void *, int, int, int *))q->callback) (TLS, q->callback_extra, 1, n, r); } tfree (r, 4 * n); return 0; } static struct query_methods export_card_methods = { .on_answer = export_card_on_answer, .on_error = q_list_on_error, .type = TYPE_TO_PARAM_1(vector, TYPE_TO_PARAM (bare_int)), .name = "export card" }; void tgl_do_export_card (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, int *card), void *callback_extra) { clear_packet (); out_int (CODE_contacts_export_card); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &export_card_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Import card */ static int import_card_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tgl_user *U = tglf_fetch_alloc_user (TLS, D); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, struct tgl_user *))q->callback) (TLS, q->callback_extra, 1, U); } return 0; } static struct query_methods import_card_methods = { .on_answer = import_card_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM (user), .name = "import card" }; void tgl_do_import_card (struct tgl_state *TLS, int size, int *card, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *U), void *callback_extra) { clear_packet (); out_int (CODE_contacts_import_card); out_int (CODE_vector); out_int (size); out_ints (card, size); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &import_card_methods, 0, callback, callback_extra); } /* }}} */ void tgl_do_start_bot (struct tgl_state *TLS, tgl_peer_id_t bot, tgl_peer_id_t chat, const char *str, int str_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_messages_start_bot); out_int (CODE_input_user); out_int (tgl_get_peer_id (bot)); out_long (bot.access_hash); out_int (tgl_get_peer_id (chat)); long long m; tglt_secure_random (&m, 8); out_long (m); out_cstring (str, str_len); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* {{{ Send typing */ static int send_typing_on_answer (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 1); } return 0; } static struct query_methods send_typing_methods = { .on_answer = send_typing_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(bool), .name = "send typing" }; void tgl_do_send_typing (struct tgl_state *TLS, tgl_peer_id_t id, enum tgl_typing_status status, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { if (tgl_get_peer_type (id) != TGL_PEER_ENCR_CHAT) { clear_packet (); out_int (CODE_messages_set_typing); out_peer_id (TLS, id); switch (status) { case tgl_typing_none: case tgl_typing_typing: out_int (CODE_send_message_typing_action); break; case tgl_typing_cancel: out_int (CODE_send_message_cancel_action); break; case tgl_typing_record_video: out_int (CODE_send_message_record_video_action); break; case tgl_typing_upload_video: out_int (CODE_send_message_upload_video_action); break; case tgl_typing_record_audio: out_int (CODE_send_message_record_audio_action); break; case tgl_typing_upload_audio: out_int (CODE_send_message_upload_audio_action); break; case tgl_typing_upload_photo: out_int (CODE_send_message_upload_photo_action); break; case tgl_typing_upload_document: out_int (CODE_send_message_upload_document_action); break; case tgl_typing_geo: out_int (CODE_send_message_geo_location_action); break; case tgl_typing_choose_contact: out_int (CODE_send_message_choose_contact_action); break; } tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_typing_methods, 0, callback, callback_extra); } else { if (callback) { callback (TLS, callback_extra, 0); } } } /* }}} */ /* {{{ Extd query */ #ifndef DISABLE_EXTF char *tglf_extf_print_ds (struct tgl_state *TLS, void *DS, struct paramed_type *T); static int ext_query_on_answer (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { char *buf = tglf_extf_print_ds (TLS, D, q->type); ((void (*)(struct tgl_state *, void *, int, char *))q->callback) (TLS, q->callback_extra, 1, buf); } tgl_paramed_type_free (q->type); return 0; } static struct query_methods ext_query_methods = { .on_answer = ext_query_on_answer, .on_error = q_list_on_error, .name = "ext query" }; void tgl_do_send_extf (struct tgl_state *TLS, const char *data, int data_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *buf), void *callback_extra) { clear_packet (); ext_query_methods.type = tglf_extf_store (TLS, data, data_len); if (ext_query_methods.type) { tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &ext_query_methods, 0, callback, callback_extra); } } #else void tgl_do_send_extf (struct tgl_state *TLS, const char *data, int data_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *buf), void *callback_extra) { assert (0); } #endif /* }}} */ /* {{{ get messages */ static int get_messages_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_messages_messages *DS_MM = D; int i; for (i = 0; i < DS_LVAL (DS_MM->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_MM->users->data[i]); } for (i = 0; i < DS_LVAL (DS_MM->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_MM->chats->data[i]); } struct tgl_message **ML; if (q->extra) { ML = talloc0 (sizeof (void *) * DS_LVAL (DS_MM->messages->cnt)); } else { static struct tgl_message *M; M = NULL; ML = &M; assert (DS_LVAL (DS_MM->messages->cnt) <= 1); } for (i = 0; i < DS_LVAL (DS_MM->messages->cnt); i++) { ML[i] = tglf_fetch_alloc_message (TLS, DS_MM->messages->data[i], NULL); } if (q->callback) { if (q->extra) { ((void (*)(struct tgl_state *, void *, int, int, struct tgl_message **))q->callback)(TLS, q->callback_extra, 1, DS_LVAL (DS_MM->messages->cnt), ML); } else { if (DS_LVAL (DS_MM->messages->cnt) > 0) { ((void (*)(struct tgl_state *, void *, int, struct tgl_message *))q->callback)(TLS, q->callback_extra, 1, *ML); } else { tgl_set_query_error (TLS, ENOENT, "no such message"); ((void (*)(struct tgl_state *, void *, int, struct tgl_message *))q->callback)(TLS, q->callback_extra, 0, NULL); } } } if (q->extra) { tfree (ML, sizeof (void *) * DS_LVAL (DS_MM->messages->cnt)); } return 0; } static struct query_methods get_messages_methods = { .on_answer = get_messages_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM (messages_messages), .name = "get messages" }; void tgl_do_get_message (struct tgl_state *TLS, tgl_message_id_t *_msg_id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { tgl_message_id_t msg_id = *_msg_id; if (msg_id.peer_type == TGL_PEER_TEMP_ID) { msg_id = tgl_convert_temp_msg_id (TLS, msg_id); } if (msg_id.peer_type == TGL_PEER_TEMP_ID) { tgl_set_query_error (TLS, EINVAL, "unknown message"); if (callback) { callback (TLS, callback_extra, 0, NULL); } return; } struct tgl_message *M = tgl_message_get (TLS, &msg_id); if (M) { if (callback) { callback (TLS, callback_extra, 1, M); } return; } clear_packet (); vlogprintf (E_ERROR, "id=%" INT64_PRINTF_MODIFIER "d\n", msg_id.id); out_int (CODE_messages_get_messages); out_int (CODE_vector); out_int (1); out_int (msg_id.id); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_messages_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Export/import chat link */ static int export_chat_link_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_exported_chat_invite *DS_ECI = D; char *s = DS_STR_DUP (DS_ECI->link); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, const char *))q->callback)(TLS, q->callback_extra, s ? 1 : 0, s); } tfree_str (s); return 0; } static struct query_methods export_chat_link_methods = { .on_answer = export_chat_link_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM(exported_chat_invite), .name = "export chat link" }; void tgl_do_export_chat_link (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *link), void *callback_extra) { if (tgl_get_peer_type (id) != TGL_PEER_CHAT) { tgl_set_query_error (TLS, EINVAL, "Can only export chat link for chat"); if (callback) { callback (TLS, callback_extra, 0, NULL); } return; } clear_packet (); out_int (CODE_messages_export_chat_invite); out_int (tgl_get_peer_id (id)); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &export_chat_link_methods, 0, callback, callback_extra); } void tgl_do_import_chat_link (struct tgl_state *TLS, const char *link, int len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { const char *l = link + len - 1; while (l >= link && *l != '/') { l --; } l ++; clear_packet (); out_int (CODE_messages_import_chat_invite); out_cstring (l, len - (l - link)); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ Export/import channel link */ void tgl_do_export_channel_link (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *link), void *callback_extra) { if (tgl_get_peer_type (id) != TGL_PEER_CHANNEL) { tgl_set_query_error (TLS, EINVAL, "Can only export chat link for chat"); if (callback) { callback (TLS, callback_extra, 0, NULL); } return; } clear_packet (); out_int (CODE_channels_export_invite); out_int (CODE_input_channel); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &export_chat_link_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ set password */ static int set_password_on_answer (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 1); } return 0; } static int set_password_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { if (error_code == 400) { if (!strcmp (error, "PASSWORD_HASH_INVALID")) { vlogprintf (E_WARNING, "Bad old password\n"); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 0); } return 0; } if (!strcmp (error, "NEW_PASSWORD_BAD")) { vlogprintf (E_WARNING, "Bad new password (unchanged or equals hint)\n"); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 0); } return 0; } if (!strcmp (error, "NEW_SALT_INVALID")) { vlogprintf (E_WARNING, "Bad new salt\n"); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 0); } return 0; } } tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 0); } return 0; } static struct query_methods set_password_methods = { .on_answer = set_password_on_answer, .on_error = set_password_on_error, .type = TYPE_TO_PARAM(bool), .name = "set password" }; static void tgl_do_act_set_password (struct tgl_state *TLS, const char *current_password, int current_password_len, const char *new_password, int new_password_len, const char *current_salt, int current_salt_len, const char *new_salt, int new_salt_len, const char *hint, int hint_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); static char s[512]; static unsigned char shab[32]; assert (current_salt_len <= 128); assert (current_password_len <= 128); assert (new_salt_len <= 128); assert (new_password_len <= 128); out_int (CODE_account_update_password_settings); if (current_password_len && current_salt_len) { memcpy (s, current_salt, current_salt_len); memcpy (s + current_salt_len, current_password, current_password_len); memcpy (s + current_salt_len + current_password_len, current_salt, current_salt_len); TGLC_sha256 ((void *)s, 2 * current_salt_len + current_password_len, shab); out_cstring ((void *)shab, 32); } else { out_string (""); } out_int (CODE_account_password_input_settings); if (new_password_len) { out_int (1); static char d[256]; memcpy (d, new_salt, new_salt_len); int l = new_salt_len; tglt_secure_random (d + l, 16); l += 16; memcpy (s, d, l); memcpy (s + l, new_password, new_password_len); memcpy (s + l + new_password_len, d, l); TGLC_sha256 ((void *)s, 2 * l + new_password_len, shab); out_cstring (d, l); out_cstring ((void *)shab, 32); out_cstring (hint, hint_len); } else { out_int (0); } tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &set_password_methods, 0, callback, callback_extra); } struct change_password_extra { char *current_password; char *new_password; char *current_salt; char *new_salt; char *hint; int current_password_len; int new_password_len; int current_salt_len; int new_salt_len; int hint_len; void (*callback)(struct tgl_state *, void *, int); void *callback_extra; }; void tgl_on_new_pwd (struct tgl_state *TLS, const char *pwd[], void *_T); void tgl_on_new2_pwd (struct tgl_state *TLS, const char *pwd, void *_T) { struct change_password_extra *E = _T; if (strlen (pwd) != (size_t)E->new_password_len || memcmp (E->new_password, pwd, E->new_password_len)) { tfree (E->new_password, E->new_password_len); E->new_password = NULL; E->new_password_len = 0; vlogprintf (E_ERROR, "passwords do not match\n"); TLS->callback.get_values (TLS, tgl_new_password, "new password: ", 2, tgl_on_new_pwd, E); return; } tgl_do_act_set_password (TLS, E->current_password, E->current_password_len, E->new_password, E->new_password_len, E->current_salt, E->current_salt_len, E->new_salt, E->new_salt_len, E->hint, E->hint_len, E->callback, E->callback_extra); tfree (E->current_password, E->current_password_len); tfree (E->new_password, E->new_password_len); tfree (E->current_salt, E->current_salt_len); tfree (E->new_salt, E->new_salt_len); tfree_str (E->hint); tfree (E, sizeof (*E)); } void tgl_on_new_pwd (struct tgl_state *TLS, const char *pwd[], void *_T) { struct change_password_extra *E = _T; E->new_password_len = strlen (pwd[0]); E->new_password = tmemdup (pwd[0], E->new_password_len); tgl_on_new2_pwd(TLS, pwd[1], E); } void tgl_on_old_pwd (struct tgl_state *TLS, const char *pwd[], void *_T) { struct change_password_extra *E = _T; E->current_password_len = strlen (pwd[0]); E->current_password = tmemdup (pwd[0], E->current_password_len); tgl_on_new_pwd(TLS, pwd + 1, E); } static int set_get_password_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_account_password *DS_AP = D; char *new_hint = q->extra; struct change_password_extra *E = talloc0 (sizeof (*E)); if (DS_AP->current_salt) { E->current_salt_len = DS_AP->current_salt->len; E->current_salt = tmemdup (DS_AP->current_salt->data, E->current_salt_len); } if (DS_AP->new_salt) { E->new_salt_len = DS_AP->new_salt->len; E->new_salt = tmemdup (DS_AP->new_salt->data, E->new_salt_len); } if (new_hint) { E->hint_len = strlen (new_hint); E->hint = new_hint; } E->callback = q->callback; E->callback_extra = q->callback_extra; if (DS_AP->magic == CODE_account_no_password) { TLS->callback.get_values (TLS, tgl_new_password, "new password: ", 2, tgl_on_new_pwd, E); } else { static char s[512]; snprintf (s, 511, "old password (hint %.*s): ", DS_RSTR (DS_AP->hint)); TLS->callback.get_values (TLS, tgl_cur_and_new_password, s, 3, tgl_on_old_pwd, E); } return 0; } static struct query_methods set_get_password_methods = { .on_answer = set_get_password_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(account_password), .name = "get password" }; void tgl_do_set_password (struct tgl_state *TLS, const char *hint, int hint_len, void (*callback)(struct tgl_state *TLS, void *extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_account_get_password); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &set_get_password_methods, hint ? tstrndup (hint, hint_len) : NULL, callback, callback_extra); } /* }}} */ /* {{{ check password */ static int check_password_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { if (error_code == 400) { vlogprintf (E_ERROR, "bad password\n"); tgl_do_check_password (TLS, q->callback, q->callback_extra); return 0; } TLS->locks ^= TGL_LOCK_PASSWORD; tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 0); } return 0; } static int check_password_on_answer (struct tgl_state *TLS, struct query *q, void *D) { TLS->locks ^= TGL_LOCK_PASSWORD; if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 1); } return 0; } static struct query_methods check_password_methods = { .on_answer = check_password_on_answer, .on_error = check_password_on_error, .type = TYPE_TO_PARAM(auth_authorization), .name = "check password" }; struct check_password_extra { char *current_salt; int current_salt_len; void (*callback)(struct tgl_state *, void *, int); void *callback_extra; }; static void tgl_pwd_got (struct tgl_state *TLS, const char *pwd[], void *_T) { struct check_password_extra *E = _T; clear_packet (); static char s[512]; static unsigned char shab[32]; assert (E->current_salt_len <= 128); assert (strlen (pwd[0]) <= 128); out_int (CODE_auth_check_password); if (pwd[0] && E->current_salt_len) { int l = E->current_salt_len; memcpy (s, E->current_salt, l); int r = strlen (pwd[0]); strcpy (s + l, pwd[0]); memcpy (s + l + r, E->current_salt, l); TGLC_sha256 ((void *)s, 2 * l + r, shab); out_cstring ((void *)shab, 32); } else { out_string (""); } tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &check_password_methods, 0, E->callback, E->callback_extra); tfree (E->current_salt, E->current_salt_len); tfree (E, sizeof (*E)); } static int check_get_password_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { TLS->locks ^= TGL_LOCK_PASSWORD; tgl_set_query_error (TLS, EPROTO, "RPC_CALL_FAIL %d: %.*s", error_code, error_len, error); if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 0); } return 0; } static int check_get_password_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_account_password *DS_AP = D; if (DS_AP->magic == CODE_account_no_password) { TLS->locks ^= TGL_LOCK_PASSWORD; return 0; } static char s[512]; snprintf (s, 511, "type password (hint %.*s): ", DS_RSTR (DS_AP->hint)); struct check_password_extra *E = talloc0 (sizeof (*E)); if (DS_AP->current_salt) { E->current_salt_len = DS_AP->current_salt->len; E->current_salt = tmemdup (DS_AP->current_salt->data, E->current_salt_len); } E->callback = q->callback; E->callback_extra = q->callback_extra; TLS->callback.get_values (TLS, tgl_cur_password, s, 1, tgl_pwd_got, E); return 0; } static struct query_methods check_get_password_methods = { .on_answer = check_get_password_on_answer, .on_error = check_get_password_on_error, .type = TYPE_TO_PARAM(account_password), .name = "get password" }; void tgl_do_check_password (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, void *extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_account_get_password); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &check_get_password_methods, NULL, callback, callback_extra); } /* }}} */ /* {{{ send broadcast */ void tgl_do_send_broadcast (struct tgl_state *TLS, int num, tgl_peer_id_t peer_id[], const char *text, int text_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]), void *callback_extra) { assert (num <= 1000); struct messages_send_extra *E = talloc0 (sizeof (*E)); E->multi = 1; E->count = num; E->list = talloc (sizeof (tgl_message_id_t) * num); int date = time (0); struct tl_ds_message_media TDSM; TDSM.magic = CODE_message_media_empty; int i; for (i = 0; i < num; i++) { assert (tgl_get_peer_type (peer_id[i]) == TGL_PEER_USER); int disable_preview = flags & TGL_SEND_MSG_FLAG_DISABLE_PREVIEW; if (!(flags & TGL_SEND_MSG_FLAG_ENABLE_PREVIEW) && TLS->disable_link_preview) { disable_preview = 1; } if (disable_preview) { disable_preview = TGLMF_DISABLE_PREVIEW; } struct tgl_message_id id = tgl_peer_id_to_random_msg_id (peer_id[i]); E->list[i] = id; tgl_peer_id_t from_id = TLS->our_id; bl_do_edit_message (TLS, &id, &from_id, &peer_id[i], NULL, NULL, &date, text, text_len, &TDSM, NULL, NULL, NULL, NULL, TGLMF_UNREAD | TGLMF_OUT | TGLMF_PENDING | TGLMF_CREATE | TGLMF_CREATED | disable_preview); } clear_packet (); out_int (CODE_messages_send_broadcast); out_int (CODE_vector); out_int (num); for (i = 0; i < num; i++) { assert (tgl_get_peer_type (peer_id[i]) == TGL_PEER_USER); out_int (CODE_input_user); out_int (tgl_get_peer_id (peer_id[i])); out_long (peer_id[i].access_hash); } out_int (CODE_vector); out_int (num); for (i = 0; i < num; i++) { out_long (E->list[i].id); } out_cstring (text, text_len); out_int (CODE_message_media_empty); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, E, callback, callback_extra); } /* }}} */ /* {{{ block user */ static int block_user_on_answer (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback)(TLS, q->callback_extra, 1); } return 0; } static struct query_methods block_user_methods = { .on_answer = block_user_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM (bool), .name = "block user" }; void tgl_do_block_user (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { if (tgl_get_peer_type (id) != TGL_PEER_USER) { tgl_set_query_error (TLS, EINVAL, "id should be user id"); if (callback) { callback (TLS, callback_extra, 0); } return; } clear_packet (); out_int (CODE_contacts_block); out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &block_user_methods, 0, callback, callback_extra); } void tgl_do_unblock_user (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { if (tgl_get_peer_type (id) != TGL_PEER_USER) { tgl_set_query_error (TLS, EINVAL, "id should be user id"); if (callback) { callback (TLS, callback_extra, 0); } return; } clear_packet (); out_int (CODE_contacts_unblock); out_int (CODE_input_user); out_int (tgl_get_peer_id (id)); out_long (id.access_hash); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &block_user_methods, 0, callback, callback_extra); } /* }}} */ /* {{{ get terms of service */ static int get_tos_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_help_terms_of_service *DS_T = D; int l = DS_T->text->len; char *s = talloc (l + 1); char *str = DS_T->text->data; int p = 0; int pp = 0; while (p < l) { if (*str == '\\' && p < l - 1) { str ++; p ++; switch (*str) { case 'n': s[pp ++] = '\n'; break; case 't': s[pp ++] = '\t'; break; case 'r': s[pp ++] = '\r'; break; default: s[pp ++] = *str; } str ++; p ++; } else { s[pp ++] = *str; str ++; p ++; } } s[pp] = 0; if (q->callback) { ((void (*)(struct tgl_state *, void *, int, char *))q->callback)(TLS, q->callback_extra, 1, s); } tfree (s, l + 1); return 0; } static struct query_methods get_tos_methods = { .on_answer = get_tos_on_answer, .on_error = q_ptr_on_error, .type = TYPE_TO_PARAM (help_terms_of_service), .name = "get tos" }; void tgl_do_get_terms_of_service (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *ans), void *callback_extra) { clear_packet (); out_int (CODE_help_get_terms_of_service); out_string (""); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &get_tos_methods, 0, callback, callback_extra); } /* }}} */ void tgl_do_upgrade_group (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_messages_migrate_chat); out_int (tgl_get_peer_id (id)); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_msgs_methods, 0, callback, callback_extra); } static void set_flag_4 (struct tgl_state *TLS, void *_D, int success) { struct tgl_dc *D = _D; assert (success); D->flags |= 4; TLS->timer_methods->insert (D->ev, TLS->temp_key_expire_time * 0.9); } static int send_bind_temp_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tgl_dc *DC = q->extra; DC->flags |= 2; tgl_do_help_get_config_dc (TLS, DC, set_flag_4, DC); vlogprintf (E_DEBUG, "Bind successful in dc %d\n", DC->id); return 0; } static int send_bind_on_error (struct tgl_state *TLS, struct query *q, int error_code, int l, const char *error) { vlogprintf (E_WARNING, "bind: error %d: %.*s\n", error_code, l, error); if (error_code == 400) { return -11; } return 0; } static struct query_methods send_bind_temp_methods = { .on_answer = send_bind_temp_on_answer, .on_error = send_bind_on_error, .type = TYPE_TO_PARAM (bool), .name = "bind temp auth key" }; void tgl_do_send_bind_temp_key (struct tgl_state *TLS, struct tgl_dc *D, long long nonce, int expires_at, void *data, int len, long long msg_id) { clear_packet (); out_int (CODE_auth_bind_temp_auth_key); out_long (D->auth_key_id); out_long (nonce); out_int (expires_at); out_cstring (data, len); struct query *q = tglq_send_query_ex (TLS, D, packet_ptr - packet_buffer, packet_buffer, &send_bind_temp_methods, D, 0, 0, 2); assert (q->msg_id == msg_id); } static int update_status_on_answer (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *, void *, int))q->callback) (TLS, q->callback_extra, 1); } return 0; } static struct query_methods update_status_methods = { .on_answer = update_status_on_answer, .on_error = q_void_on_error, .type = TYPE_TO_PARAM(bool), .name = "update status" }; void tgl_do_update_status (struct tgl_state *TLS, int online, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { clear_packet (); out_int (CODE_account_update_status); out_int (online ? CODE_bool_false : CODE_bool_true); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &update_status_methods, 0, callback, callback_extra); } void tgl_do_request_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E) { assert (0); exit (2); } void tgl_do_accept_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E, long long exchange_id, unsigned char ga[]) { assert (0); exit (2); } void tgl_do_confirm_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E, int sen_nop) { assert (0); exit (2); } void tgl_do_commit_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E, unsigned char gb[]) { assert (0); exit (2); } void tgl_do_abort_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E) { assert (0); exit (2); } void tgl_started_cb (struct tgl_state *TLS, void *arg, int success) { if (!success) { vlogprintf (E_ERROR, "login problem: error #%d (%s)\n", TLS->error_code, TLS->error); if (TLS->callback.on_failed_login) { TLS->callback.on_failed_login (TLS); } else { assert (success); } return; } TLS->started = 1; if (TLS->callback.started) { TLS->callback.started (TLS); } } void tgl_export_auth_callback (struct tgl_state *TLS, void *arg, int success) { if (!success) { vlogprintf (E_ERROR, "login problem: error #%d (%s)\n", TLS->error_code, TLS->error); if (TLS->callback.on_failed_login) { TLS->callback.on_failed_login (TLS); } else { assert (success); } return; } int i; for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i] && !tgl_signed_dc (TLS, TLS->DC_list[i])) { return; } if (TLS->callback.logged_in) { TLS->callback.logged_in (TLS); } tglm_send_all_unsent (TLS); tgl_do_get_difference (TLS, 0, tgl_started_cb, 0); } void tgl_export_all_auth (struct tgl_state *TLS) { int i; int ok = 1; for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i] && !tgl_signed_dc (TLS, TLS->DC_list[i])) { tgl_do_export_auth (TLS, i, tgl_export_auth_callback, TLS->DC_list[i]); ok = 0; } if (ok) { if (TLS->callback.logged_in) { TLS->callback.logged_in (TLS); } tglm_send_all_unsent (TLS); tgl_do_get_difference (TLS, 0, tgl_started_cb, 0); } } struct sign_up_extra { char *phone; char *hash; char *first_name; char *last_name; int phone_len; int hash_len; int first_name_len; int last_name_len; }; void tgl_sign_in_code (struct tgl_state *TLS, const char *code[], void *_T); void tgl_sign_in_result (struct tgl_state *TLS, void *_T, int success, struct tgl_user *U) { struct sign_up_extra *E = _T; if (success) { tfree (E->phone, E->phone_len); tfree (E->hash, E->hash_len); tfree (E, sizeof (*E)); } else { vlogprintf (E_ERROR, "incorrect code\n"); TLS->callback.get_values (TLS, tgl_code, "code ('call' for phone call):", 1, tgl_sign_in_code, E); return; } tgl_export_all_auth (TLS); } void tgl_sign_in_code (struct tgl_state *TLS, const char *code[], void *_T) { struct sign_up_extra *E = _T; if (!strcmp (code[0], "call")) { tgl_do_phone_call (TLS, E->phone, E->phone_len, E->hash, E->hash_len, 0, 0); TLS->callback.get_values (TLS, tgl_code, "code ('call' for phone call):", 1, tgl_sign_in_code, E); return; } tgl_do_send_code_result (TLS, E->phone, E->phone_len, E->hash, E->hash_len, code[0], strlen (code[0]), tgl_sign_in_result, E); } void tgl_sign_up_code (struct tgl_state *TLS, const char *code[], void *_T); void tgl_sign_up_result (struct tgl_state *TLS, void *_T, int success, struct tgl_user *U) { struct sign_up_extra *E = _T; if (success) { tfree (E->phone, E->phone_len); tfree (E->hash, E->hash_len); tfree (E->first_name, E->first_name_len); tfree (E->last_name, E->last_name_len); tfree (E, sizeof (*E)); } else { vlogprintf (E_ERROR, "incorrect code\n"); TLS->callback.get_values (TLS, tgl_code, "code ('call' for phone call):", 1, tgl_sign_up_code, E); return; } tgl_export_all_auth (TLS); } void tgl_sign_up_code (struct tgl_state *TLS, const char *code[], void *_T) { struct sign_up_extra *E = _T; if (!strcmp (code[0], "call")) { tgl_do_phone_call (TLS, E->phone, E->phone_len, E->hash, E->hash_len, 0, 0); TLS->callback.get_values (TLS, tgl_code, "code ('call' for phone call):", 1, tgl_sign_up_code, E); return; } tgl_do_send_code_result_auth (TLS, E->phone, E->phone_len, E->hash, E->hash_len, code[0], strlen (code[0]), E->first_name, E->first_name_len, E->last_name, E->last_name_len, tgl_sign_up_result, E); } void tgl_set_last_name (struct tgl_state *TLS, const char *last_name, struct sign_up_extra *E) { E->last_name_len = strlen (last_name); E->last_name = tmemdup (last_name, E->last_name_len); } int tgl_set_first_name (struct tgl_state *TLS, const char *first_name, struct sign_up_extra *E) { if (strlen (first_name) < 1) { return -1; } E->first_name_len = strlen (first_name); E->first_name = tmemdup (first_name, E->first_name_len); return 0; } void tgl_register_cb (struct tgl_state *TLS, const char *rinfo[], void *_T) { struct sign_up_extra *E = _T; const char *yn = rinfo[0]; if (strlen (yn) > 1) { TLS->callback.get_values (TLS, tgl_register_info, "registration info:", 3, tgl_register_cb, E); } else if (strlen (yn) == 0 || *yn == 'y' || *yn == 'Y') { if (!tgl_set_first_name(TLS, rinfo[1], E)) { tgl_set_last_name(TLS, rinfo[2], E); TLS->callback.get_values (TLS, tgl_code, "code ('call' for phone call):", 1, tgl_sign_up_code, E); } else { TLS->callback.get_values (TLS, tgl_register_info, "registration info:", 3, tgl_register_cb, E); } } else if (*yn == 'n' || *yn == 'N') { vlogprintf (E_ERROR, "stopping registration"); tfree (E->phone, E->phone_len); tfree (E->hash, E->hash_len); tfree (E, sizeof (*E)); tgl_login (TLS); } else { TLS->callback.get_values (TLS, tgl_register_info, "registration info:", 3, tgl_register_cb, E); } } void tgl_sign_in_phone (struct tgl_state *TLS, const char *phone[], void *arg); void tgl_sign_in_phone_cb (struct tgl_state *TLS, void *extra, int success, int registered, const char *mhash) { struct sign_up_extra *E = extra; if (!success) { vlogprintf (E_ERROR, "Incorrect phone number\n"); tfree (E->phone, E->phone_len); tfree (E, sizeof (*E)); TLS->callback.get_values (TLS, tgl_phone_number, "phone number:", 1, tgl_sign_in_phone, NULL); return; } E->hash_len = strlen (mhash); E->hash = tmemdup (mhash, E->hash_len); if (registered) { TLS->callback.get_values (TLS, tgl_code, "code ('call' for phone call):", 1, tgl_sign_in_code, E); } else { TLS->callback.get_values (TLS, tgl_register_info, "registration info:", 3, tgl_register_cb, E); } } void tgl_sign_in_phone (struct tgl_state *TLS, const char *phone[], void *arg) { struct sign_up_extra *E = talloc0 (sizeof (*E)); E->phone_len = strlen (phone[0]); E->phone = tmemdup (phone[0], E->phone_len); tgl_do_send_code (TLS, E->phone, E->phone_len, tgl_sign_in_phone_cb, E); } void tgl_bot_hash_cb (struct tgl_state *TLS, const char *code[], void *arg); void tgl_sign_in_bot_cb (struct tgl_state *TLS, void *_T, int success, struct tgl_user *U) { if (!success) { vlogprintf (E_ERROR, "incorrect bot hash\n"); TLS->callback.get_values (TLS, tgl_bot_hash, "bot hash:", 1, tgl_bot_hash_cb, NULL); return; } tgl_export_all_auth (TLS); } void tgl_bot_hash_cb (struct tgl_state *TLS, const char *code[], void *arg) { tgl_do_send_bot_auth (TLS, code[0], strlen (code[0]), tgl_sign_in_bot_cb, NULL); } void tgl_sign_in (struct tgl_state *TLS) { if (!tgl_signed_dc (TLS, TLS->DC_working)) { if (TLS->is_bot) { TLS->callback.get_values (TLS, tgl_bot_hash, "bot hash:", 1, tgl_bot_hash_cb, NULL); } else { TLS->callback.get_values (TLS, tgl_phone_number, "phone number:", 1, tgl_sign_in_phone, NULL); } } else { tgl_export_all_auth (TLS); } } static void check_authorized (struct tgl_state *TLS, void *arg) { int i; int ok = 1; for (i = 0; i <= TLS->max_dc_num; i++) { if (TLS->DC_list[i]) { tgl_dc_authorize (TLS, TLS->DC_list[i]); } } for (i = 0; i <= TLS->max_dc_num; i++) { if (TLS->DC_list[i] && !tgl_signed_dc (TLS, TLS->DC_list[i]) && !tgl_authorized_dc (TLS, TLS->DC_list[i])) { ok = 0; break; } } if (ok) { TLS->timer_methods->free (TLS->ev_login); TLS->ev_login = NULL; tgl_sign_in (TLS); } else { TLS->timer_methods->insert (TLS->ev_login, 0.1); } } void tgl_login (struct tgl_state *TLS) { int i; int ok = 1; for (i = 0; i <= TLS->max_dc_num; i++) { if (TLS->DC_list[i] && !tgl_signed_dc (TLS, TLS->DC_list[i]) && !tgl_authorized_dc (TLS, TLS->DC_list[i])) { ok = 0; break; } } if (!ok) { TLS->ev_login = TLS->timer_methods->alloc (TLS, check_authorized, NULL); TLS->timer_methods->insert (TLS->ev_login, 0.1); } else { tgl_sign_in (TLS); } } static int callback (struct tgl_state *TLS, struct query *q, void *D) { if (q->callback) { ((void (*)(struct tgl_state *, void *))(q->callback)) (TLS, q->callback_extra); } return 0; } static int send_change_code_on_answer (struct tgl_state *TLS, struct query *q, void *D) { struct tl_ds_account_sent_change_phone_code *DS_ASCPC= D; char *phone_code_hash = DS_STR_DUP (DS_ASCPC->phone_code_hash); if (q->callback) { ((void (*)(struct tgl_state *, void *, int, const char *))(q->callback)) (TLS, q->callback_extra, 1, phone_code_hash); } tfree_str (phone_code_hash); return 0; } struct change_phone_extra { char *phone; char *hash; char *first_name; char *last_name; int phone_len; int hash_len; int first_name_len; int last_name_len; void (*callback)(struct tgl_state *TLS, void *extra, int success); void *callback_extra; }; static struct query_methods set_phone_methods = { .on_answer = callback, .on_error = sign_in_on_error, .type = TYPE_TO_PARAM(user), .name = "set phone" }; static struct query_methods send_change_code_methods = { .on_answer = send_change_code_on_answer, .on_error = q_list_on_error, .type = TYPE_TO_PARAM(account_sent_change_phone_code), .name = "send change phone code" }; void tgl_set_number_code (struct tgl_state *TLS, const char *code[], void *_T); void tgl_set_number_result (struct tgl_state *TLS, void *_T, int success, struct tgl_user *U) { struct change_phone_extra *E = _T; if (success) { if (E->callback) { E->callback (TLS, E->callback_extra, 1); } tfree (E->phone, E->phone_len); tfree (E->hash, E->hash_len); tfree (E, sizeof (*E)); } else { vlogprintf (E_ERROR, "incorrect code\n"); TLS->callback.get_values (TLS, tgl_code, "code:", 1, tgl_set_number_code, E); } } void tgl_set_number_code (struct tgl_state *TLS, const char *code[], void *_T) { struct change_phone_extra *E = _T; clear_packet (); out_int (CODE_account_change_phone); out_cstring (E->phone, E->phone_len); out_cstring (E->hash, E->hash_len); out_cstring (code[0], strlen (code[0])); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &set_phone_methods, 0, tgl_set_number_result, E); } void tgl_set_phone_number_cb (struct tgl_state *TLS, void *extra, int success, const char *mhash) { struct change_phone_extra *E = extra; if (!success) { vlogprintf (E_ERROR, "Incorrect phone number\n"); if (E->callback) { E->callback (TLS, E->callback_extra, 0); } tfree (E->phone, E->phone_len); tfree (E, sizeof (*E)); return; } E->hash_len = strlen (mhash); E->hash = tmemdup (mhash, E->hash_len); TLS->callback.get_values (TLS, tgl_code, "code:", 1, tgl_set_number_code, E); } void tgl_do_set_phone_number (struct tgl_state *TLS, const char *phonenumber, int phonenumber_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra) { struct change_phone_extra *E = talloc0 (sizeof (*E)); E->phone_len = phonenumber_len; E->phone = tmemdup (phonenumber, E->phone_len); clear_packet (); tgl_do_insert_header (TLS); out_int (CODE_account_send_change_phone_code); out_cstring (E->phone, E->phone_len); E->callback = callback; E->callback_extra = callback_extra; tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_change_code_methods, NULL, tgl_set_phone_number_cb, E); } telegram-purple/tgl/queries.h000066400000000000000000000062661357227200100166100ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ //#include "net.h" #ifndef __QUERIES_H__ #define __QUERIES_H__ #include "tgl-structures.h" #include "auto.h" #include "tgl-layout.h" #define QUERY_ACK_RECEIVED 1 #define QUERY_FORCE_SEND 2 struct query; struct query_methods { int (*on_answer)(struct tgl_state *TLS, struct query *q, void *DS); int (*on_error)(struct tgl_state *TLS, struct query *q, int error_code, int len, const char *error); int (*on_timeout)(struct tgl_state *TLS, struct query *q); struct paramed_type *type; char *name; double timeout; }; struct query { long long msg_id; int data_len; int flags; int seq_no; long long session_id; void *data; struct query_methods *methods; struct tgl_timer *ev; struct tgl_dc *DC; struct tgl_session *session; struct paramed_type *type; void *extra; void *callback; void *callback_extra; }; struct query *tglq_send_query (struct tgl_state *TLS, struct tgl_dc *DC, int len, void *data, struct query_methods *methods, void *extra, void *callback, void *callback_extra); void tglq_query_ack (struct tgl_state *TLS, long long id); int tglq_query_error (struct tgl_state *TLS, long long id); int tglq_query_result (struct tgl_state *TLS, long long id); void tglq_query_restart (struct tgl_state *TLS, long long id); //double next_timer_in (void); //void work_timers (void); //extern struct query_methods help_get_config_methods; double get_double_time (void); void tgl_do_send_bind_temp_key (struct tgl_state *TLS, struct tgl_dc *D, long long nonce, int expires_at, void *data, int len, long long msg_id); void tgl_do_request_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E); void tgl_do_confirm_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E, int sen_nop); void tgl_do_accept_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E, long long exchange_id, unsigned char g_a[]); void tgl_do_commit_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E, unsigned char g_a[]); void tgl_do_abort_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E); void tglq_regen_query (struct tgl_state *TLS, long long id); void tglq_query_delete (struct tgl_state *TLS, long long id); void tglq_query_free_all (struct tgl_state *TLS); void tglq_regen_queries_from_old_session (struct tgl_state *TLS, struct tgl_dc *DC, struct tgl_session *S); // For binlog //int get_dh_config_on_answer (struct query *q); //void fetch_dc_option (void); #endif telegram-purple/tgl/scheme.tl000066400000000000000000001361011357227200100165570ustar00rootroot00000000000000int ?= Int; long ?= Long; double ?= Double; string ?= String; bytes string = Bytes; int128 long long = Int128; int256 long long long long = Int256; boolFalse#bc799737 = Bool; boolTrue#997275b5 = Bool; true#3fedd339 = True; vector#1cb5c415 {t:Type} # [ t ] = Vector t; error#c4b9f9bb code:int text:string = Error; null#56730bcc = Null; inputPeerEmpty#7f3b18ea = InputPeer; inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; inputMediaUploadedPhoto#f7aff1c0 file:InputFile caption:string = InputMedia; inputMediaPhoto#e9bfb4f3 id:InputPhoto caption:string = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; inputMediaUploadedVideo#82713fdf file:InputFile duration:int w:int h:int mime_type:string caption:string = InputMedia; inputMediaUploadedThumbVideo#7780ddf9 file:InputFile thumb:InputFile duration:int w:int h:int mime_type:string caption:string = InputMedia; inputMediaVideo#936a4ebd video:InputVideo caption:string = InputMedia; inputMediaUploadedAudio#4e498cab file:InputFile duration:int mime_type:string = InputMedia; inputMediaAudio#89938781 audio:InputAudio = InputMedia; inputMediaUploadedDocument#1d89306d file:InputFile mime_type:string attributes:Vector caption:string = InputMedia; inputMediaUploadedThumbDocument#ad613491 file:InputFile thumb:InputFile mime_type:string attributes:Vector caption:string = InputMedia; inputMediaDocument#1a77f29c document_id:InputDocument caption:string = InputMedia; inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#94254732 file:InputFile crop:InputPhotoCrop = InputChatPhoto; inputChatPhoto#b2e1bf08 id:InputPhoto crop:InputPhotoCrop = InputChatPhoto; inputGeoPointEmpty#e4c123d6 = InputGeoPoint; inputGeoPoint#f3b7acc9 latitude:double longitude:double = InputGeoPoint; inputPhotoEmpty#1cd7bf0d = InputPhoto; inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputVideoEmpty#5508ec75 = InputVideo; inputVideo#ee579652 id:long access_hash:long = InputVideo; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputVideoFileLocation#3d0364ec id:long access_hash:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputAudioFileLocation#74dc404d id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#4e45abe9 id:long access_hash:long = InputFileLocation; inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; inputPhotoCropAuto#ade6b004 = InputPhotoCrop; inputPhotoCrop#d9915325 crop_left:double crop_top:double crop_width:double = InputPhotoCrop; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; peerUser#9db1bc6d user_id:int = Peer; peerChat#bad0e5bb chat_id:int = Peer; peerChannel#bddde532 channel_id:int = Peer; storage.fileUnknown#aa963b05 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.filePdf#ae1e508d = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation; fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation; userEmpty#200250ba id:int = User; user#d10d979a flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; userStatusOffline#8c703f was_online:int = UserStatus; userStatusRecently#e26f42f1 = UserStatus; userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#4b1b7506 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true id:int access_hash:long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat; channelForbidden#2d85832c id:int access_hash:long title:string = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; channelFull#9e341ddf flags:# can_view_participants:flags.3?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int unread_count:int unread_important_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants; chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto; messageEmpty#83e5de54 id:int = Message; message#c992e15c flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:flags.8?int to_id:Peer fwd_from_id:flags.2?Peer fwd_date:flags.2?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int = Message; messageService#c06b9607 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:flags.8?int to_id:Peer date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia; messageMediaVideo#5bcf1675 video:Video caption:string = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia; messageMediaAudio#c6b68300 audio:Audio = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#a6638b9a title:string users:Vector = MessageAction; messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; messageActionChatDeletePhoto#95e3fbef = MessageAction; messageActionChatAddUser#488a7337 users:Vector = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction; messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction; messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; dialog#c1dd804a peer:Peer top_message:int read_inbox_max_id:int unread_count:int notify_settings:PeerNotifySettings = Dialog; dialogChannel#5b8496b2 peer:Peer top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int notify_settings:PeerNotifySettings pts:int = Dialog; photoEmpty#2331b22d id:long = Photo; photo#cded42fe id:long access_hash:long date:int sizes:Vector = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; videoEmpty#c10658a8 id:long = Video; video#f72887d3 id:long access_hash:long date:int duration:int mime_type:string size:int thumb:PhotoSize dc_id:int w:int h:int = Video; geoPointEmpty#1117dd5f = GeoPoint; geoPoint#2049d70c longitude:double latitude:double = GeoPoint; auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone; auth.sentCode#efed51d9 phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode; auth.sentAppCode#e325edcf phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode; auth.authorization#ff036af1 user:User = auth.Authorization; auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization; inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; inputNotifyUsers#193b4417 = InputNotifyPeer; inputNotifyChats#4a95e84e = InputNotifyPeer; inputNotifyAll#a429b886 = InputNotifyPeer; inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents; inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents; inputPeerNotifySettings#46a2ce98 mute_until:int sound:string show_previews:Bool events_mask:int = InputPeerNotifySettings; peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents; peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents; peerNotifySettingsEmpty#70a68512 = PeerNotifySettings; peerNotifySettings#8d5e11ee mute_until:int sound:string show_previews:Bool events_mask:int = PeerNotifySettings; wallPaper#ccb03657 id:int title:string sizes:Vector color:int = WallPaper; wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper; inputReportReasonSpam#58dbcab8 = ReportReason; inputReportReasonViolence#1e22c78d = ReportReason; inputReportReasonPornography#2e59d922 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; userFull#5a89ac5b user:User link:contacts.Link profile_photo:Photo notify_settings:PeerNotifySettings blocked:Bool bot_info:BotInfo = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; importedContact#d0028438 user_id:int client_id:long = ImportedContact; contactBlocked#561bc879 user_id:int date:int = ContactBlocked; contactSuggested#3de191a1 user_id:int mutual_contacts:int = ContactSuggested; contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus; contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link; contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; contacts.contacts#6f8b8cb2 contacts:Vector users:Vector = contacts.Contacts; contacts.importedContacts#ad524315 imported:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; contacts.suggested#5649dcc5 results:Vector users:Vector = contacts.Suggested; messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesSlice#b446ae3 count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#bc0f17bc flags:# pts:int count:int messages:Vector collapsed:flags.0?Vector chats:Vector users:Vector = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; inputMessagesFilterEmpty#57e2f66c = MessagesFilter; inputMessagesFilterPhotos#9609a51c = MessagesFilter; inputMessagesFilterVideo#9fc00e65 = MessagesFilter; inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter; inputMessagesFilterDocument#9eddf188 = MessagesFilter; inputMessagesFilterAudio#cfc87522 = MessagesFilter; inputMessagesFilterAudioDocuments#5afbf764 = MessagesFilter; inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; inputMessagesFilterGif#ffc86587 = MessagesFilter; updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; updateMessageID#4e90bfd6 id:int random_id:long = Update; updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update; updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update; updateChatParticipants#7761198 participants:ChatParticipants = Update; updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update; updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update; updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update; updateContactRegistered#2575bbb9 user_id:int date:int = Update; updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update; updateNewAuthorization#8f06529a auth_key_id:long date:int device:string location:string = Update; updateNewEncryptedMessage#12bcbd9a encr_message:EncryptedMessage qts:int = Update; updateEncryptedChatTyping#1710f156 chat_id:int = Update; updateEncryption#b4a2e88d encr_chat:EncryptedChat date:int = Update; updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update; updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update; updateDcOptions#8e5e9873 dc_options:Vector = Update; updateUserBlocked#80ece81a user_id:int blocked:Bool = Update; updateNotifySettings#bec268ef notify_peer:NotifyPeer notify_settings:PeerNotifySettings = Update; updateServiceNotification#382dd3e4 type:string message_text:string media:MessageMedia popup:Bool = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#60946422 channel_id:int = Update; updateChannel#b6d45656 channel_id:int = Update; updateChannelGroup#c36c1e3c channel_id:int group:MessageGroup = Update; updateNewChannelMessage#62ba04d9 message:Message channel_pts:int channel_pts_count:int = Update; updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector channel_pts:int channel_pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; updateStickerSetsOrder#f0dfb451 order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#c01eea08 query_id:long user_id:int query:string offset:string = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; updatesTooLong#e317af7e = Updates; updateShortMessage#13e4deaa flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShortChatMessage#248afa62 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector = Updates; updateShort#78d4dec1 update:Update date:int = Updates; updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; updateShortSentMessage#11f1331c flags:# unread:flags.0?true out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector = Updates; photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true id:int ip_address:string port:int = DcOption; config#6bbc5f8 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int disabled_features:Vector = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate; help.noAppUpdate#c45a6536 = help.AppUpdate; help.inviteText#18cb9f78 message:string = help.InviteText; encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat; encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat; encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat; encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat; inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; encryptedFileEmpty#c21f497e = EncryptedFile; encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile; inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; inputAudioEmpty#d95adc84 = InputAudio; inputAudio#77d440ff id:long access_hash:long = InputAudio; inputDocumentEmpty#72f0eaae = InputDocument; inputDocument#18798952 id:long access_hash:long = InputDocument; audioEmpty#586988d8 id:long = Audio; audio#f9e35055 id:long access_hash:long date:int duration:int mime_type:string size:int dc_id:int = Audio; documentEmpty#36f8c871 id:long = Document; document#f9a39f4f id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector = Document; help.support#17c6b5f6 phone_number:string user:User = help.Support; notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; notifyUsers#b4c83b4c = NotifyPeer; notifyChats#c007cec3 = NotifyPeer; notifyAll#74d07c60 = NotifyPeer; sendMessageTypingAction#16bf744e = SendMessageAction; sendMessageCancelAction#fd5ec8f5 = SendMessageAction; sendMessageRecordVideoAction#a187d66f = SendMessageAction; sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; sendMessageChooseContactAction#628cbc6f = SendMessageAction; contacts.found#1aa1f784 results:Vector chats:Vector users:Vector = contacts.Found; inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; account.sentChangePhoneCode#a4f58c4c phone_code_hash:string send_call_timeout:int = account.SentChangePhoneCode; documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; documentAttributeAnimated#11b58939 = DocumentAttribute; documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute; documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute; documentAttributeAudio#ded218e0 duration:int title:string performer:string = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; disabledFeature#ae636f24 feature:string description:string = DisabledFeature; messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#ca820ed7 flags:# id:long url:string display_url:string type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; account.authorizations#1250abde authorizations:Vector = account.Authorizations; account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; account.passwordInputSettings#bcfc532c flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; chatInviteEmpty#69df3769 = ExportedChatInvite; chatInviteExported#fc2e05bc link:string = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#93e99b60 flags:# channel:flags.0?true broadcast:flags.1?true public_:flags.2?true megagroup:flags.3?true title:string = ChatInvite; inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; stickerSet#cd303b41 flags:# installed:flags.0?true disabled:flags.1?true official:flags.2?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; botCommand#c27ac8c7 command:string description:string = BotCommand; botInfoEmpty#bb2e37ce = BotInfo; botInfo#9cf585d user_id:int version:int share_text:string description:string commands:Vector = BotInfo; keyboardButton#a2fa4880 text:string = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup; replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector = ReplyMarkup; help.appChangelogEmpty#af7e0394 = help.AppChangelog; help.appChangelog#4668e6bd text:string = help.AppChangelog; messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; messageEntityMention#fa04579d offset:int length:int = MessageEntity; messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; messageEntityCode#28a20571 offset:int length:int = MessageEntity; messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; messageRange#ae30253 min_id:int max_id:int = MessageRange; messageGroup#e8346f53 min_id:int max_id:int count:int date:int = MessageGroup; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true channel_pts:int timeout:flags.1?int = updates.ChannelDifference; updates.channelDifferenceTooLong#5e167646 flags:# final:flags.0?true channel_pts:int timeout:flags.1?int top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true channel_pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# important_only:flags.0?true exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; channelMessagesFilterCollapsed#fa01232e = ChannelMessagesFilter; channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantModerator#91057fef user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantEditor#98192d61 user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantKicked#8cc5e69a user_id:int kicked_by:int date:int = ChannelParticipant; channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter; channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelRoleEmpty#b285a0c6 = ChannelParticipantRole; channelRoleModerator#9618d975 = ChannelParticipantRole; channelRoleEditor#820bfe8c = ChannelParticipantRole; channels.channelParticipants#f56ee2a8 count:int participants:Vector users:Vector = channels.ChannelParticipants; channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector = channels.ChannelParticipant; help.termsOfService#f1ee3e90 text:string = help.TermsOfService; foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif; foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif; messages.foundGifs#450a1c0a next_offset:int results:Vector = messages.FoundGifs; messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; inputBotInlineMessageMediaAuto#2e43e587 caption:string = InputBotInlineMessage; inputBotInlineMessageText#adf0df71 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector = InputBotInlineMessage; inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; botInlineMessageMediaAuto#fc56e87d caption:string = BotInlineMessage; botInlineMessageText#a56197a9 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector = BotInlineMessage; botInlineMediaResultDocument#f897d33e id:string type:string document:Document send_message:BotInlineMessage = BotInlineResult; botInlineMediaResultPhoto#c5528587 id:string type:string photo:Photo send_message:BotInlineMessage = BotInlineResult; botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; messages.botResults#1170b0a3 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string results:Vector = messages.BotResults; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; initConnection#69796de9 {X:Type} api_id:int device_model:string system_version:string app_version:string lang_code:string query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone; auth.sendCode#768d5f4d phone_number:string sms_type:int api_id:int api_hash:string lang_code:string = auth.SentCode; auth.sendCall#3c51564 phone_number:string phone_code_hash:string = Bool; auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.logOut#5717da40 = Bool; auth.resetAuthorizations#9fab0d1a = Bool; auth.sendInvites#771c1d97 phone_numbers:Vector message:string = Bool; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization; auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; auth.sendSms#da9f3e8 phone_number:string phone_code_hash:string = Bool; auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; auth.checkPassword#a63011e password_hash:bytes = auth.Authorization; auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; auth.recoverPassword#4ea56e92 code:string = auth.Authorization; account.registerDevice#446c712c token_type:int token:string device_model:string system_version:string app_version:string app_sandbox:Bool lang_code:string = Bool; account.unregisterDevice#65c55b40 token_type:int token:string = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; account.resetNotifySettings#db7e1747 = Bool; account.updateProfile#f0888d68 first_name:string last_name:string = User; account.updateStatus#6628562c offline:Bool = Bool; account.getWallPapers#c04cfac2 = Vector; account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool; account.checkUsername#2714d86c username:string = Bool; account.updateUsername#3e0bdd7c username:string = User; account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; account.deleteAccount#418d4e0b reason:string = Bool; account.getAccountTTL#8fc711d = AccountDaysTTL; account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; account.sendChangePhoneCode#a407a8f4 phone_number:string = account.SentChangePhoneCode; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.updateDeviceLocked#38df3532 period:int = Bool; account.getAuthorizations#e320c158 = account.Authorizations; account.resetAuthorization#df77f3bc hash:long = Bool; account.getPassword#548a30f5 = account.Password; account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings; account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; contacts.getStatuses#c4a353ee = Vector; contacts.getContacts#22c6aa08 hash:string = contacts.Contacts; contacts.importContacts#da30b32d contacts:Vector replace:Bool = contacts.ImportedContacts; contacts.getSuggested#cd773428 limit:int = contacts.Suggested; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.exportCard#84e53737 = Vector; contacts.importCard#4fe196fe export_card:Vector = User; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; messages.getMessages#4222fa74 id:Vector = messages.Messages; messages.getDialogs#6b47f94d offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs; messages.getHistory#8a8ec2da peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.search#d4569248 flags:# important_only:flags.0?true peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#b7c13bd9 peer:InputPeer max_id:int = messages.AffectedHistory; messages.deleteMessages#a5f18925 id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.sendMedia#c8f16791 flags:# broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; messages.forwardMessages#708e0195 flags:# broadcast:flags.4?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.sendBroadcast#bf73f4da contacts:Vector random_id:Vector message:string media:InputMedia = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; messages.discardEncryption#edd923c5 chat_id:int = Bool; messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; messages.getStickers#ae22e045 emoticon:string hash:string = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#25223e24 message:string = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.installStickerSet#7b30c3a6 stickerset:InputStickerSet disabled:Bool = Bool; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#9fcfbc30 order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.getInlineBotResults#9324600d bot:InputUser query:string offset:string = messages.BotResults; messages.setInlineBotResults#3f23ec12 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string = Bool; messages.sendInlineBotResult#b16e06fe flags:# broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference; updates.getChannelDifference#bb32d7c0 channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; photos.updateProfilePhoto#eef579a0 id:InputPhoto crop:InputPhotoCrop = UserProfilePhoto; photos.uploadProfilePhoto#d50f9c88 file:InputFile caption:string geo_point:InputGeoPoint crop:InputPhotoCrop = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; help.getAppUpdate#c812ac7e device_model:string system_version:string app_version:string lang_code:string = help.AppUpdate; help.saveAppLog#6f02f748 events:Vector = Bool; help.getInviteText#a4a95186 lang_code:string = help.InviteText; help.getSupport#9cdf08cd = help.Support; help.getAppChangelog#5bab7fb2 device_model:string system_version:string app_version:string lang_code:string = help.AppChangelog; help.getTermsOfService#37d78f83 lang_code:string = help.TermsOfService; channels.getDialogs#a9d3d249 offset:int limit:int = messages.Dialogs; channels.getImportantHistory#ddb929cb channel:InputChannel offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector = Bool; channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants; channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getChannels#a7f6bbb id:Vector = messages.Chats; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates; channels.editAbout#13e27f1e channel:InputChannel about:string = Bool; channels.editAdmin#eb7611d0 channel:InputChannel user_id:InputUser role:ChannelParticipantRole = Updates; channels.editTitle#566decd0 channel:InputChannel title:string = Updates; channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; channels.toggleComments#aaa29e88 channel:InputChannel enabled:Bool = Updates; channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; channels.joinChannel#24b524c5 channel:InputChannel = Updates; channels.leaveChannel#f836aa95 channel:InputChannel = Updates; channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = Updates; channels.kickFromChannel#a672de14 channel:InputChannel user_id:InputUser kicked:Bool = Updates; channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite; channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; telegram-purple/tgl/structures.c000066400000000000000000002363001357227200100173430ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "tgl-structures.h" #include "mtproto-common.h" //#include "telegram.h" #include "tree.h" #include "crypto/aes.h" #include "crypto/bn.h" #include "crypto/sha.h" #include "queries.h" #include "tgl-binlog.h" #include "tgl-methods-in.h" #include "updates.h" #include "mtproto-client.h" #include "tgl.h" #include "auto.h" #include "auto/auto-types.h" #include "auto/auto-skip.h" #include "auto/auto-fetch-ds.h" #include "auto/auto-free-ds.h" static int id_cmp (struct tgl_message *M1, struct tgl_message *M2); #define peer_cmp(a,b) (tgl_cmp_peer_id (a->id, b->id)) #define peer_cmp_name(a,b) (strcmp (a->print_name, b->print_name)) static int random_id_cmp (struct tgl_message *L, struct tgl_message *R) { if (L->random_id < R->random_id) { return -1; } if (L->random_id > R->random_id) { return 1; } return 0; } static int temp_id_cmp (struct tgl_message *L, struct tgl_message *R) { if (L->temp_id < R->temp_id) { return -1; } if (L->temp_id > R->temp_id) { return 1; } return 0; } static int photo_id_cmp (struct tgl_photo *L, struct tgl_photo *R) { if (L->id < R->id) { return -1; } if (L->id > R->id) { return 1; } return 0; } static int document_id_cmp (struct tgl_document *L, struct tgl_document *R) { if (L->id < R->id) { return -1; } if (L->id > R->id) { return 1; } return 0; } static int webpage_id_cmp (struct tgl_webpage *L, struct tgl_webpage *R) { if (L->id < R->id) { return -1; } if (L->id > R->id) { return 1; } return 0; } DEFINE_TREE(peer,tgl_peer_t *,peer_cmp,0) DEFINE_TREE(peer_by_name,tgl_peer_t *,peer_cmp_name,0) DEFINE_TREE(message,struct tgl_message *,id_cmp,0) DEFINE_TREE(random_id,struct tgl_message *, random_id_cmp,0) DEFINE_TREE(temp_id,struct tgl_message *, temp_id_cmp,0) DEFINE_TREE(photo,struct tgl_photo *,photo_id_cmp,0) DEFINE_TREE(document,struct tgl_document *,document_id_cmp,0) DEFINE_TREE(webpage,struct tgl_webpage *,webpage_id_cmp,0) static void increase_peer_size (struct tgl_state *TLS); char *tgls_default_create_print_name (struct tgl_state *TLS, tgl_peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4) { const char *d[4]; d[0] = a1; d[1] = a2; d[2] = a3; d[3] = a4; static char buf[10000]; buf[0] = 0; int i; int p = 0; for (i = 0; i < 4; i++) { if (d[i] && strlen (d[i])) { p += tsnprintf (buf + p, 9999 - p, "%s%s", p ? "_" : "", d[i]); assert (p < 9990); } } char *s = buf; while (*s) { if (((unsigned char)*s) <= ' ') { *s = '_'; } if (*s == '#') { *s = '_'; } if (*s == '$') { *s = '_'; } if (*s == '@') { *s = '_'; } s++; } s = buf; int fl = strlen (s); int cc = 0; while (1) { tgl_peer_t *P = tgl_peer_get_by_name (TLS, s); if (!P || !tgl_cmp_peer_id (P->id, id)) { break; } cc ++; assert (cc <= 9999); tsnprintf (s + fl, 9999 - fl, "#%d", cc); } return tstrdup (s); } enum tgl_typing_status tglf_fetch_typing (struct tl_ds_send_message_action *DS_SMA) { if (!DS_SMA) { return 0; } switch (DS_SMA->magic) { case CODE_send_message_typing_action: return tgl_typing_typing; case CODE_send_message_cancel_action: return tgl_typing_cancel; case CODE_send_message_record_video_action: return tgl_typing_record_video; case CODE_send_message_upload_video_action: return tgl_typing_upload_video; case CODE_send_message_record_audio_action: return tgl_typing_record_audio; case CODE_send_message_upload_audio_action: return tgl_typing_upload_audio; case CODE_send_message_upload_photo_action: return tgl_typing_upload_photo; case CODE_send_message_upload_document_action: return tgl_typing_upload_document; case CODE_send_message_geo_location_action: return tgl_typing_geo; case CODE_send_message_choose_contact_action: return tgl_typing_choose_contact; default: assert (0); return tgl_typing_none; } } /*enum tgl_typing_status tglf_fetch_typing (void) { struct tl_ds_send_message_action *DS_SMA = fetch_ds_type_send_message_action (TYPE_TO_PARAM (send_message_action)); enum tgl_typing_status res = tglf_fetch_typing (DS_SMA); free_ds_type_send_message_action (DS_SMA, TYPE_TO_PARAM (send_message_action)); return res; }*/ /* {{{ Fetch */ tgl_peer_id_t tglf_fetch_peer_id (struct tgl_state *TLS, struct tl_ds_peer *DS_P) { switch (DS_P->magic) { case CODE_peer_user: return TGL_MK_USER (DS_LVAL (DS_P->user_id)); case CODE_peer_chat: return TGL_MK_CHAT (DS_LVAL (DS_P->chat_id)); case CODE_peer_channel: return TGL_MK_CHANNEL (DS_LVAL (DS_P->channel_id)); default: assert (0); exit (2); } } int tglf_fetch_file_location (struct tgl_state *TLS, struct tgl_file_location *loc, struct tl_ds_file_location *DS_FL) { if (!DS_FL) { return 0; } loc->dc = DS_LVAL (DS_FL->dc_id); loc->volume = DS_LVAL (DS_FL->volume_id); loc->local_id = DS_LVAL (DS_FL->local_id); loc->secret = DS_LVAL (DS_FL->secret); return 0; } int tglf_fetch_user_status (struct tgl_state *TLS, struct tgl_user_status *S, struct tgl_user *U, struct tl_ds_user_status *DS_US) { if (!DS_US) { return 0; } switch (DS_US->magic) { case CODE_user_status_empty: if (S->online) { tgl_insert_status_update (TLS, U); if (S->online == 1) { tgl_remove_status_expire (TLS, U); } } S->online = 0; S->when = 0; break; case CODE_user_status_online: { if (S->online != 1) { S->when = DS_LVAL (DS_US->expires); if (S->online) { tgl_insert_status_update (TLS, U); } tgl_insert_status_expire (TLS, U); S->online = 1; } else { if (DS_LVAL (DS_US->expires) != S->when) { S->when = DS_LVAL (DS_US->expires); tgl_remove_status_expire (TLS, U); tgl_insert_status_expire (TLS, U); } } } break; case CODE_user_status_offline: if (S->online != -1) { if (S->online) { tgl_insert_status_update (TLS, U); } if (S->online == 1) { tgl_remove_status_expire (TLS, U); } } S->online = -1; S->when = DS_LVAL (DS_US->was_online); break; case CODE_user_status_recently: if (S->online != -2) { if (S->online) { tgl_insert_status_update (TLS, U); } if (S->online == 1) { tgl_remove_status_expire (TLS, U); } } S->online = -2; break; case CODE_user_status_last_week: if (S->online != -3) { if (S->online) { tgl_insert_status_update (TLS, U); } if (S->online == 1) { tgl_remove_status_expire (TLS, U); } } S->online = -3; break; case CODE_user_status_last_month: if (S->online != -4) { if (S->online) { tgl_insert_status_update (TLS, U); } if (S->online == 1) { tgl_remove_status_expire (TLS, U); } } S->online = -4; break; default: assert (0); } return 0; } struct tgl_user *tglf_fetch_alloc_user (struct tgl_state *TLS, struct tl_ds_user *DS_U) { if (!DS_U) { return 0; } if (DS_U->magic == CODE_user_empty) { return 0; } tgl_peer_id_t user_id = TGL_MK_USER (DS_LVAL (DS_U->id)); user_id.access_hash = DS_LVAL (DS_U->access_hash); struct tgl_user *U = (struct tgl_user *)tgl_peer_get (TLS, user_id); if (!U) { TLS->users_allocated ++; U = talloc0 (sizeof (tgl_peer_t)); U->id = user_id; TLS->peer_tree = tree_insert_peer (TLS->peer_tree, (tgl_peer_t *)U, rand ()); increase_peer_size (TLS); TLS->Peers[TLS->peer_num ++] = (tgl_peer_t *)U; } int flags = U->flags; if (DS_LVAL (DS_U->flags) & (1 << 10)) { bl_do_set_our_id (TLS, U->id); flags |= TGLUF_SELF; } else { flags &= ~TGLUF_SELF; } if (DS_LVAL (DS_U->flags) & (1 << 11)) { flags |= TGLUF_CONTACT; } else { flags &= ~TGLUF_CONTACT; } if (DS_LVAL (DS_U->flags) & (1 << 12)) { flags |= TGLUF_MUTUAL_CONTACT; } else { flags &= ~TGLUF_MUTUAL_CONTACT; } if (DS_LVAL (DS_U->flags) & (1 << 14)) { flags |= TGLUF_BOT; U->bot = 1; } else { flags &= ~TGLUF_BOT; U->bot = 0; } /* if (DS_LVAL (DS_U->flags) & (1 << 15)) { flags |= TGLUF_BOT_FULL_ACCESS; } if (DS_LVAL (DS_U->flags) & (1 << 16)) { flags |= TGLUF_BOT_NO_GROUPS; }*/ if (DS_LVAL (DS_U->flags) & (1 << 17)) { flags |= TGLUF_OFFICIAL; } else { flags &= ~TGLUF_OFFICIAL; } if (!(flags & TGLUF_CREATED)) { flags |= TGLUF_CREATE | TGLUF_CREATED; } bl_do_user (TLS, tgl_get_peer_id (U->id), DS_U->access_hash, DS_STR (DS_U->first_name), DS_STR (DS_U->last_name), DS_STR (DS_U->phone), DS_STR (DS_U->username), NULL, DS_U->photo, NULL, NULL, NULL, flags ); if (DS_U->status) { assert (tglf_fetch_user_status (TLS, &U->status, U, DS_U->status) >= 0); } if (DS_LVAL (DS_U->flags) & (1 << 13)) { if (!(U->flags & TGLUF_DELETED)) { bl_do_peer_delete (TLS, U->id); } } return U; } struct tgl_user *tglf_fetch_alloc_user_full (struct tgl_state *TLS, struct tl_ds_user_full *DS_UF) { if (!DS_UF) { return NULL; } struct tgl_user *U = tglf_fetch_alloc_user (TLS, DS_UF->user); if (!U) { return NULL; } int flags = U->flags; if (DS_BVAL (DS_UF->blocked)) { flags |= TGLUF_BLOCKED; } else { flags &= ~TGLUF_BLOCKED; } bl_do_user (TLS, tgl_get_peer_id (U->id), NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, DS_UF->profile_photo, NULL, NULL, NULL, DS_UF->bot_info, flags ); return U; } void str_to_256 (unsigned char *dst, char *src, int src_len) { if (src_len >= 256) { memcpy (dst, src + src_len - 256, 256); } else { memset(dst, 0, 256 - src_len); memcpy (dst + 256 - src_len, src, src_len); } } void str_to_32 (unsigned char *dst, char *src, int src_len) { if (src_len >= 32) { memcpy (dst, src + src_len - 32, 32); } else { memset(dst, 0, 32 - src_len); memcpy (dst + 32 - src_len, src, src_len); } } struct tgl_secret_chat *tglf_fetch_alloc_encrypted_chat (struct tgl_state *TLS, struct tl_ds_encrypted_chat *DS_EC) { if (!DS_EC) { return NULL; } if (DS_EC->magic == CODE_encrypted_chat_empty) { return NULL; } tgl_peer_id_t chat_id = TGL_MK_ENCR_CHAT (DS_LVAL (DS_EC->id)); chat_id.access_hash = DS_LVAL (DS_EC->access_hash); struct tgl_secret_chat *U = (void *)tgl_peer_get (TLS, chat_id); if (!U) { TLS->encr_chats_allocated ++; U = talloc0 (sizeof (tgl_peer_t)); U->id = chat_id; TLS->peer_tree = tree_insert_peer (TLS->peer_tree, (tgl_peer_t *)U, rand ()); increase_peer_size (TLS); TLS->Peers[TLS->peer_num ++] = (tgl_peer_t *)U; } int new = !(U->flags & TGLPF_CREATED); if (DS_EC->magic == CODE_encrypted_chat_discarded) { if (new) { vlogprintf (E_WARNING, "Unknown chat in deleted state. May be we forgot something...\n"); return U; } bl_do_peer_delete (TLS, U->id); //write_secret_chat_file (); return U; } static unsigned char g_key[256]; if (new) { if (DS_EC->magic != CODE_encrypted_chat_requested) { vlogprintf (E_WARNING, "Unknown chat. May be we forgot something...\n"); return U; } str_to_256 (g_key, DS_STR (DS_EC->g_a)); int user_id = DS_LVAL (DS_EC->participant_id) + DS_LVAL (DS_EC->admin_id) - tgl_get_peer_id (TLS->our_id); int r = sc_request; bl_do_encr_chat (TLS, tgl_get_peer_id (U->id), DS_EC->access_hash, DS_EC->date, DS_EC->admin_id, &user_id, NULL, (void *)g_key, NULL, &r, NULL, NULL, NULL, NULL, NULL, NULL, TGLECF_CREATE | TGLECF_CREATED, NULL, 0 ); } else { if (DS_EC->magic == CODE_encrypted_chat_waiting) { int r = sc_waiting; bl_do_encr_chat (TLS, tgl_get_peer_id (U->id), DS_EC->access_hash, DS_EC->date, NULL, NULL, NULL, NULL, NULL, &r, NULL, NULL, NULL, NULL, NULL, NULL, TGL_FLAGS_UNCHANGED, NULL, 0 ); return U; // We needed only access hash from here } str_to_256 (g_key, DS_STR (DS_EC->g_a_or_b)); //write_secret_chat_file (); int r = sc_ok; bl_do_encr_chat (TLS, tgl_get_peer_id (U->id), DS_EC->access_hash, DS_EC->date, NULL, NULL, NULL, g_key, NULL, &r, NULL, NULL, NULL, NULL, NULL, DS_EC->key_fingerprint, TGL_FLAGS_UNCHANGED, NULL, 0 ); } return U; } struct tgl_chat *tglf_fetch_alloc_chat (struct tgl_state *TLS, struct tl_ds_chat *DS_C) { if (!DS_C) { return NULL; } if (DS_C->magic == CODE_chat_empty) { return NULL; } if (DS_C->magic == CODE_channel || DS_C->magic == CODE_channel_forbidden) { return (void *)tglf_fetch_alloc_channel (TLS, DS_C); } tgl_peer_id_t chat_id = TGL_MK_CHAT (DS_LVAL (DS_C->id)); chat_id.access_hash = 0; // chats don't have access hash struct tgl_chat *C = (void *)tgl_peer_get (TLS, chat_id); if (!C) { TLS->chats_allocated ++; C = talloc0 (sizeof (tgl_peer_t)); C->id = chat_id; TLS->peer_tree = tree_insert_peer (TLS->peer_tree, (tgl_peer_t *)C, rand ()); increase_peer_size (TLS); TLS->Peers[TLS->peer_num ++] = (tgl_peer_t *)C; } C->id = chat_id; int flags = C->flags; if (!(flags & TGLCF_CREATED)) { flags |= TGLCF_CREATE | TGLCF_CREATED; } if (DS_LVAL (DS_C->flags) & 1) { flags |= TGLCF_CREATOR; } else { flags &= ~TGLCF_CREATOR; } if (DS_LVAL (DS_C->flags) & 2) { flags |= TGLCF_KICKED; } else { flags &= ~TGLCF_KICKED; } if (DS_LVAL (DS_C->flags) & 4) { flags |= TGLCF_LEFT; } else { flags &= ~TGLCF_LEFT; } if (DS_LVAL (DS_C->flags) & 8) { flags |= TGLCF_ADMINS_ENABLED; } else { flags &= ~TGLCF_ADMINS_ENABLED; } if (DS_LVAL (DS_C->flags) & 16) { flags |= TGLCF_ADMIN; } else { flags &= ~TGLCF_ADMIN; } if (DS_LVAL (DS_C->flags) & 32) { flags |= TGLCF_DEACTIVATED; } else { flags &= ~TGLCF_DEACTIVATED; } bl_do_chat (TLS, tgl_get_peer_id (C->id), DS_STR (DS_C->title), DS_C->participants_count, DS_C->date, NULL, NULL, DS_C->photo, NULL, NULL, NULL, NULL, flags ); return C; } struct tgl_chat *tglf_fetch_alloc_chat_full (struct tgl_state *TLS, struct tl_ds_messages_chat_full *DS_MCF) { if (!DS_MCF) { return NULL; } if (DS_MCF->full_chat->magic == CODE_channel_full) { return (void *)tglf_fetch_alloc_channel_full (TLS, DS_MCF); } if (DS_MCF->users) { int i; for (i = 0; i < DS_LVAL (DS_MCF->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_MCF->users->data[i]); } } if (DS_MCF->chats) { int i; for (i = 0; i < DS_LVAL (DS_MCF->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_MCF->chats->data[i]); } } struct tl_ds_chat_full *DS_CF = DS_MCF->full_chat; if (DS_CF->bot_info) { int n = DS_LVAL (DS_CF->bot_info->cnt); int i; for (i = 0; i < n; i++) { struct tl_ds_bot_info *DS_BI = DS_CF->bot_info->data[i]; tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_BI->user_id))); if (P && (P->flags & TGLCF_CREATED)) { bl_do_user (TLS, tgl_get_peer_id (P->id), NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, DS_BI, TGL_FLAGS_UNCHANGED ); } } } tgl_peer_id_t chat_id = TGL_MK_CHAT (DS_LVAL (DS_CF->id)); struct tgl_chat *C = (void *)tgl_peer_get (TLS, chat_id); assert (C); bl_do_chat (TLS, tgl_get_peer_id (C->id), NULL, 0, NULL, NULL, DS_CF->participants->version, (struct tl_ds_vector *)DS_CF->participants->participants, NULL, DS_CF->chat_photo, NULL, //DS_CF->participants->admin_id, NULL, NULL, C->flags & 0xffff ); return C; } struct tgl_channel *tglf_fetch_alloc_channel (struct tgl_state *TLS, struct tl_ds_chat *DS_C) { if (!DS_C) { return NULL; } tgl_peer_id_t chat_id = TGL_MK_CHANNEL (DS_LVAL (DS_C->id)); chat_id.access_hash = DS_LVAL (DS_C->access_hash); struct tgl_channel *C = (void *)tgl_peer_get (TLS, chat_id); if (!C) { TLS->channels_allocated ++; C = talloc0 (sizeof (tgl_peer_t)); C->id = chat_id; TLS->peer_tree = tree_insert_peer (TLS->peer_tree, (tgl_peer_t *)C, rand ()); increase_peer_size (TLS); TLS->Peers[TLS->peer_num ++] = (tgl_peer_t *)C; } C->id = chat_id; int flags = C->flags; if (!(flags & TGLCHF_CREATED)) { flags |= TGLCHF_CREATE | TGLCHF_CREATED; } if (DS_LVAL (DS_C->flags) & 1) { flags |= TGLCHF_CREATOR; } else { flags &= ~TGLCHF_CREATOR; } if (DS_LVAL (DS_C->flags) & 2) { flags |= TGLCHF_KICKED; } else { flags &= ~TGLCHF_KICKED; } if (DS_LVAL (DS_C->flags) & 4) { flags |= TGLCHF_LEFT; } else { flags &= ~TGLCHF_LEFT; } if (DS_LVAL (DS_C->flags) & 8) { flags |= TGLCHF_EDITOR; } else { flags &= ~TGLCHF_EDITOR; } if (DS_LVAL (DS_C->flags) & 16) { flags |= TGLCHF_MODERATOR; } else { flags &= ~TGLCHF_MODERATOR; } if (DS_LVAL (DS_C->flags) & 32) { flags |= TGLCHF_BROADCAST; } else { flags &= ~TGLCHF_BROADCAST; } if (DS_LVAL (DS_C->flags) & 128) { flags |= TGLCHF_OFFICIAL; } else { flags &= ~TGLCHF_OFFICIAL; } if (DS_LVAL (DS_C->flags) & 256) { flags |= TGLCHF_MEGAGROUP; } else { flags &= ~TGLCHF_MEGAGROUP; } bl_do_channel (TLS, tgl_get_peer_id (C->id), DS_C->access_hash, DS_C->date, DS_STR (DS_C->title), DS_STR (DS_C->username), DS_C->photo, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, flags ); return C; } struct tgl_channel *tglf_fetch_alloc_channel_full (struct tgl_state *TLS, struct tl_ds_messages_chat_full *DS_MCF) { if (!DS_MCF) { return NULL; } if (DS_MCF->users) { int i; for (i = 0; i < DS_LVAL (DS_MCF->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_MCF->users->data[i]); } } if (DS_MCF->chats) { int i; for (i = 0; i < DS_LVAL (DS_MCF->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_MCF->chats->data[i]); } } struct tl_ds_chat_full *DS_CF = DS_MCF->full_chat; tgl_peer_id_t chat_id = TGL_MK_CHANNEL (DS_LVAL (DS_CF->id)); struct tgl_channel *C = (void *)tgl_peer_get (TLS, chat_id); assert (C); bl_do_channel (TLS, tgl_get_peer_id (C->id), NULL, NULL, NULL, 0, NULL, 0, NULL, DS_CF->chat_photo, NULL, DS_STR (DS_CF->about), DS_CF->participants_count, DS_CF->admins_count, DS_CF->kicked_count, DS_CF->read_inbox_max_id, TGL_FLAGS_UNCHANGED ); return C; } void tglf_fetch_photo_size (struct tgl_state *TLS, struct tgl_photo_size *S, struct tl_ds_photo_size *DS_PS) { memset (S, 0, sizeof (*S)); S->type = DS_STR_DUP (DS_PS->type); S->w = DS_LVAL (DS_PS->w); S->h = DS_LVAL (DS_PS->h); S->size = DS_LVAL (DS_PS->size); if (DS_PS->bytes) { S->size = DS_PS->bytes->len; } tglf_fetch_file_location (TLS, &S->loc, DS_PS->location); } void tglf_fetch_geo (struct tgl_state *TLS, struct tgl_geo *G, struct tl_ds_geo_point *DS_GP) { G->longitude = DS_LVAL (DS_GP->longitude); G->latitude = DS_LVAL (DS_GP->latitude); } struct tgl_photo *tglf_fetch_alloc_photo (struct tgl_state *TLS, struct tl_ds_photo *DS_P) { if (!DS_P) { return NULL; } if (DS_P->magic == CODE_photo_empty) { return NULL; } struct tgl_photo *P = tgl_photo_get (TLS, DS_LVAL (DS_P->id)); if (P) { P->refcnt ++; return P; } P = talloc0 (sizeof (*P)); P->id = DS_LVAL (DS_P->id); P->refcnt = 1; tgl_photo_insert (TLS, P); P->access_hash = DS_LVAL (DS_P->access_hash); //P->user_id = DS_LVAL (DS_P->user_id); P->date = DS_LVAL (DS_P->date); P->caption = NULL;//DS_STR_DUP (DS_P->caption); /*if (DS_P->geo) { tglf_fetch_geo (TLS, &P->geo, DS_P->geo); }*/ P->sizes_num = DS_LVAL (DS_P->sizes->cnt); P->sizes = talloc (sizeof (struct tgl_photo_size) * P->sizes_num); int i; for (i = 0; i < P->sizes_num; i++) { tglf_fetch_photo_size (TLS, &P->sizes[i], DS_P->sizes->data[i]); } return P; } struct tgl_document *tglf_fetch_alloc_video (struct tgl_state *TLS, struct tl_ds_video *DS_V) { if (!DS_V) { return NULL; } if (DS_V->magic == CODE_video_empty) { return NULL; } struct tgl_document *D = tgl_document_get (TLS, DS_LVAL (DS_V->id)); if (D) { D->refcnt ++; return D; } D = talloc0 (sizeof (*D)); D->id = DS_LVAL (DS_V->id); D->refcnt = 1; tgl_document_insert (TLS, D); D->flags = TGLDF_VIDEO; D->access_hash = DS_LVAL (DS_V->access_hash); //D->user_id = DS_LVAL (DS_V->user_id); D->date = DS_LVAL (DS_V->date); D->caption = NULL;//DS_STR_DUP (DS_V->caption); D->duration = DS_LVAL (DS_V->duration); D->mime_type = tstrdup ("video/");//DS_STR_DUP (DS_V->mime_type); D->size = DS_LVAL (DS_V->size); tglf_fetch_photo_size (TLS, &D->thumb, DS_V->thumb); D->dc_id = DS_LVAL (DS_V->dc_id); D->w = DS_LVAL (DS_V->w); D->h = DS_LVAL (DS_V->h); return D; } struct tgl_document *tglf_fetch_alloc_audio (struct tgl_state *TLS, struct tl_ds_audio *DS_A) { if (!DS_A) { return NULL; } if (DS_A->magic == CODE_audio_empty) { return NULL; } struct tgl_document *D = tgl_document_get (TLS, DS_LVAL (DS_A->id)); if (D) { D->refcnt ++; return D; } D = talloc0 (sizeof (*D)); D->id = DS_LVAL (DS_A->id); D->refcnt = 1; tgl_document_insert (TLS, D); D->flags = TGLDF_AUDIO; D->access_hash = DS_LVAL (DS_A->access_hash); //D->user_id = DS_LVAL (DS_A->user_id); D->date = DS_LVAL (DS_A->date); D->duration = DS_LVAL (DS_A->duration); D->mime_type = DS_STR_DUP (DS_A->mime_type); D->size = DS_LVAL (DS_A->size); D->dc_id = DS_LVAL (DS_A->dc_id); return D; } void tglf_fetch_document_attribute (struct tgl_state *TLS, struct tgl_document *D, struct tl_ds_document_attribute *DS_DA) { switch (DS_DA->magic) { case CODE_document_attribute_image_size: D->flags |= TGLDF_IMAGE; D->w = DS_LVAL (DS_DA->w); D->h = DS_LVAL (DS_DA->h); return; case CODE_document_attribute_animated: D->flags |= TGLDF_ANIMATED; return; case CODE_document_attribute_sticker: D->flags |= TGLDF_STICKER; return; case CODE_document_attribute_video: D->flags |= TGLDF_VIDEO; D->duration = DS_LVAL (DS_DA->duration); D->w = DS_LVAL (DS_DA->w); D->h = DS_LVAL (DS_DA->h); return; case CODE_document_attribute_audio: D->flags |= TGLDF_AUDIO; D->duration = DS_LVAL (DS_DA->duration); return; case CODE_document_attribute_filename: D->caption = DS_STR_DUP (DS_DA->file_name); return; default: assert (0); } } struct tgl_document *tglf_fetch_alloc_document (struct tgl_state *TLS, struct tl_ds_document *DS_D) { if (!DS_D) { return NULL; } if (DS_D->magic == CODE_document_empty) { return NULL; } struct tgl_document *D = tgl_document_get (TLS, DS_LVAL (DS_D->id)); if (D) { D->refcnt ++; return D; } D = talloc0 (sizeof (*D)); D->id = DS_LVAL (DS_D->id); D->refcnt = 1; tgl_document_insert (TLS, D); D->access_hash = DS_LVAL (DS_D->access_hash); //D->user_id = DS_LVAL (DS_D->user_id); D->date = DS_LVAL (DS_D->date); //D->caption = DS_STR_DUP (DS_D->file_name); D->mime_type = DS_STR_DUP (DS_D->mime_type); D->size = DS_LVAL (DS_D->size); D->dc_id = DS_LVAL (DS_D->dc_id); tglf_fetch_photo_size (TLS, &D->thumb, DS_D->thumb); if (DS_D->attributes) { int i; for (i = 0; i < DS_LVAL (DS_D->attributes->cnt); i++) { tglf_fetch_document_attribute (TLS, D, DS_D->attributes->data[i]); } } return D; } struct tgl_webpage *tglf_fetch_alloc_webpage (struct tgl_state *TLS, struct tl_ds_web_page *DS_W) { if (!DS_W) { return NULL; } struct tgl_webpage *W = tgl_webpage_get (TLS, DS_LVAL (DS_W->id)); if (W) { W->refcnt ++; } else { W = talloc0 (sizeof (*W)); W->id = DS_LVAL (DS_W->id); W->refcnt = 1; tgl_webpage_insert (TLS, W); } if (!W->url) { W->url = DS_STR_DUP (DS_W->url); } if (!W->display_url) { W->display_url = DS_STR_DUP (DS_W->display_url); } if (!W->type) { W->type = DS_STR_DUP (DS_W->type); } if (!W->site_name) { W->site_name = DS_STR_DUP (DS_W->site_name); } if (!W->title) { W->title = DS_STR_DUP (DS_W->title); } if (!W->photo) { W->photo = tglf_fetch_alloc_photo (TLS, DS_W->photo); } if (!W->description) { W->description = DS_STR_DUP (DS_W->description); } if (!W->embed_url) { W->embed_url = DS_STR_DUP (DS_W->embed_url); } if (!W->embed_type) { W->embed_type = DS_STR_DUP (DS_W->embed_type); } W->embed_width = DS_LVAL (DS_W->embed_width); W->embed_height = DS_LVAL (DS_W->embed_height); W->duration = DS_LVAL (DS_W->duration); if (!W->author) { W->author = DS_STR_DUP (DS_W->author); } return W; } void tglf_fetch_message_action (struct tgl_state *TLS, struct tgl_message_action *M, struct tl_ds_message_action *DS_MA) { if (!DS_MA) { return; } memset (M, 0, sizeof (*M)); switch (DS_MA->magic) { case CODE_message_action_empty: M->type = tgl_message_action_none; break; /*case CODE_message_action_geo_chat_create: { M->type = tgl_message_action_geo_chat_create; assert (0); } break;*/ /*case CODE_message_action_geo_chat_checkin: M->type = tgl_message_action_geo_chat_checkin; break;*/ case CODE_message_action_chat_create: { M->type = tgl_message_action_chat_create; M->title = DS_STR_DUP (DS_MA->title); M->user_num = DS_LVAL (DS_MA->users->cnt); M->users = talloc (M->user_num * 4); int i; for (i = 0; i < M->user_num; i++) { M->users[i] = DS_LVAL (DS_MA->users->data[i]); } } break; case CODE_message_action_chat_edit_title: M->type = tgl_message_action_chat_edit_title; M->new_title = DS_STR_DUP (DS_MA->title); break; case CODE_message_action_chat_edit_photo: M->type = tgl_message_action_chat_edit_photo; M->photo = tglf_fetch_alloc_photo (TLS, DS_MA->photo); break; case CODE_message_action_chat_delete_photo: M->type = tgl_message_action_chat_delete_photo; break; case CODE_message_action_chat_add_user: M->type = tgl_message_action_chat_add_users; M->user_num = DS_LVAL (DS_MA->users->cnt); M->users = talloc (4 * M->user_num); { int i; for (i = 0; i < M->user_num; i++) { M->users[i] = DS_LVAL (DS_MA->users->data[i]); } } break; case CODE_message_action_chat_delete_user: M->type = tgl_message_action_chat_delete_user; M->user = DS_LVAL (DS_MA->user_id); break; case CODE_message_action_chat_joined_by_link: M->type = tgl_message_action_chat_add_user_by_link; M->user = DS_LVAL (DS_MA->inviter_id); break; case CODE_message_action_channel_create: M->type = tgl_message_action_channel_create; M->title = DS_STR_DUP (DS_MA->title); break; case CODE_message_action_chat_migrate_to: M->type = tgl_message_action_migrated_to; M->channel_id = DS_LVAL (DS_MA->channel_id); break; case CODE_message_action_channel_migrate_from: M->type = tgl_message_action_migrated_from; M->title = DS_STR_DUP (DS_MA->title); break; default: vlogprintf (E_WARNING, "Unknown MessageAction code: magic = 0x%08x\n", DS_MA->magic); M->type = tgl_message_action_noop; break; } } struct tgl_message *tglf_fetch_alloc_message_short (struct tgl_state *TLS, struct tl_ds_updates *DS_U) { tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_U->user_id))); if (!P || !(P->flags & TGLPF_CREATED)) { tgl_do_get_difference (TLS, 0, 0, 0); return NULL; } tgl_message_id_t msg_id = tgl_peer_id_to_msg_id (P->id, DS_LVAL (DS_U->id)); struct tgl_message *M = tgl_message_get (TLS, &msg_id); if (!M) { M = talloc0 (sizeof (*M)); M->permanent_id = msg_id; tglm_message_insert_tree (TLS, M); TLS->messages_allocated ++; assert (tgl_message_get (TLS, &msg_id) == M); } int flags = M->flags & 0xffff; if (M->flags & TGLMF_PENDING) { M->flags ^= TGLMF_PENDING; } if (!(flags & TGLMF_CREATED)) { flags |= TGLMF_CREATE | TGLMF_CREATED; } int f = DS_LVAL (DS_U->flags); if (f & 1) { flags |= TGLMF_UNREAD; } if (f & 2) { flags |= TGLMF_OUT; } if (f & 16) { flags |= TGLMF_MENTION; } struct tl_ds_message_media A; A.magic = CODE_message_media_empty; tgl_peer_id_t our_id = TLS->our_id; tgl_peer_id_t peer_id = P->id; tgl_peer_id_t fwd_from_id; if (DS_U->fwd_from_id) { fwd_from_id = tglf_fetch_peer_id (TLS, DS_U->fwd_from_id); } else { fwd_from_id = TGL_MK_USER (0); } bl_do_edit_message (TLS, &msg_id, (f & 2) ? &our_id : &peer_id, (f & 2) ? &peer_id : &our_id, DS_U->fwd_from_id ? &fwd_from_id : NULL, DS_U->fwd_date, DS_U->date, DS_STR (DS_U->message), &A, NULL, DS_U->reply_to_msg_id, NULL, (void *)DS_U->entities, flags ); return M; } struct tgl_message *tglf_fetch_alloc_message_short_chat (struct tgl_state *TLS, struct tl_ds_updates *DS_U) { tgl_peer_t *F = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_U->from_id))); if (!F || !(F->flags & TGLPF_CREATED)) { tgl_do_get_difference (TLS, 0, 0, 0); return NULL; } tgl_peer_t *T = tgl_peer_get (TLS, TGL_MK_CHAT (DS_LVAL (DS_U->chat_id))); if (!T || !(T->flags & TGLPF_CREATED)) { tgl_do_get_difference (TLS, 0, 0, 0); return NULL; } tgl_message_id_t msg_id = tgl_peer_id_to_msg_id (T->id, DS_LVAL (DS_U->id)); struct tgl_message *M = tgl_message_get (TLS, &msg_id); if (!M) { M = talloc0 (sizeof (*M)); M->permanent_id = msg_id; tglm_message_insert_tree (TLS, M); TLS->messages_allocated ++; } int flags = M->flags & 0xffff; if (M->flags & TGLMF_PENDING) { M->flags ^= TGLMF_PENDING; } if (!(flags & TGLMF_CREATED)) { flags |= TGLMF_CREATE | TGLMF_CREATED; } int f = DS_LVAL (DS_U->flags); if (f & 1) { flags |= TGLMF_UNREAD; } if (f & 2) { flags |= TGLMF_OUT; } if (f & 16) { flags |= TGLMF_MENTION; } struct tl_ds_message_media A; A.magic = CODE_message_media_empty; tgl_peer_id_t from_id = F->id; tgl_peer_id_t to_id = T->id; tgl_peer_id_t fwd_from_id; if (DS_U->fwd_from_id) { fwd_from_id = tglf_fetch_peer_id (TLS, DS_U->fwd_from_id); } else { fwd_from_id = TGL_MK_USER (0); } bl_do_edit_message (TLS, &msg_id, &from_id, &to_id, DS_U->fwd_from_id ? &fwd_from_id : NULL, DS_U->fwd_date, DS_U->date, DS_STR (DS_U->message), &A, NULL, DS_U->reply_to_msg_id, NULL, NULL, flags ); return M; } void tglf_fetch_message_media (struct tgl_state *TLS, struct tgl_message_media *M, struct tl_ds_message_media *DS_MM) { if (!DS_MM) { return; } memset (M, 0, sizeof (*M)); switch (DS_MM->magic) { case CODE_message_media_empty: M->type = tgl_message_media_none; break; case CODE_message_media_photo: case CODE_message_media_photo_l27: M->type = tgl_message_media_photo; M->photo = tglf_fetch_alloc_photo (TLS, DS_MM->photo); M->caption = DS_STR_DUP (DS_MM->caption); break; case CODE_message_media_video: case CODE_message_media_video_l27: M->type = tgl_message_media_video; M->document = tglf_fetch_alloc_video (TLS, DS_MM->video); M->caption = DS_STR_DUP (DS_MM->caption); break; case CODE_message_media_audio: M->type = tgl_message_media_audio; M->document = tglf_fetch_alloc_audio (TLS, DS_MM->audio); M->caption = DS_STR_DUP (DS_MM->caption); break; case CODE_message_media_document: M->type = tgl_message_media_document; M->document = tglf_fetch_alloc_document (TLS, DS_MM->document); M->caption = DS_STR_DUP (DS_MM->caption); break; case CODE_message_media_geo: M->type = tgl_message_media_geo; tglf_fetch_geo (TLS, &M->geo, DS_MM->geo); break; case CODE_message_media_contact: M->type = tgl_message_media_contact; M->phone = DS_STR_DUP (DS_MM->phone_number); M->first_name = DS_STR_DUP (DS_MM->first_name); M->last_name = DS_STR_DUP (DS_MM->last_name); M->user_id = DS_LVAL (DS_MM->user_id); break; case CODE_message_media_web_page: M->type = tgl_message_media_webpage; M->webpage = tglf_fetch_alloc_webpage (TLS, DS_MM->webpage); break; case CODE_message_media_venue: M->type = tgl_message_media_venue; tglf_fetch_geo (TLS, &M->venue.geo, DS_MM->geo); M->venue.title = DS_STR_DUP (DS_MM->title); M->venue.address = DS_STR_DUP (DS_MM->address); M->venue.provider = DS_STR_DUP (DS_MM->provider); M->venue.venue_id = DS_STR_DUP (DS_MM->venue_id); break; case CODE_message_media_unsupported: M->type = tgl_message_media_unsupported; break; default: M->type = tgl_message_media_unsupported; break; } } void tglf_fetch_message_media_encrypted (struct tgl_state *TLS, struct tgl_message_media *M, struct tl_ds_decrypted_message_media *DS_DMM) { if (!DS_DMM) { return; } memset (M, 0, sizeof (*M)); switch (DS_DMM->magic) { case CODE_decrypted_message_media_empty: M->type = tgl_message_media_none; //M->type = CODE_message_media_empty; break; case CODE_decrypted_message_media_photo: case CODE_decrypted_message_media_video: case CODE_decrypted_message_media_video_l12: case CODE_decrypted_message_media_document: case CODE_decrypted_message_media_audio: //M->type = CODE_decrypted_message_media_video; M->type = tgl_message_media_document_encr; M->encr_document = talloc0 (sizeof (*M->encr_document)); switch (DS_DMM->magic) { case CODE_decrypted_message_media_photo: M->encr_document->flags = TGLDF_IMAGE; break; case CODE_decrypted_message_media_video: case CODE_decrypted_message_media_video_l12: M->encr_document->flags = TGLDF_VIDEO; break; case CODE_decrypted_message_media_document: //M->encr_document->flags = TGLDF_DOCUMENT; break; case CODE_decrypted_message_media_audio: M->encr_document->flags = TGLDF_AUDIO; break; } M->encr_document->w = DS_LVAL (DS_DMM->w); M->encr_document->h = DS_LVAL (DS_DMM->h); M->encr_document->size = DS_LVAL (DS_DMM->size); M->encr_document->duration = DS_LVAL (DS_DMM->duration); M->encr_document->mime_type = DS_STR_DUP (DS_DMM->mime_type); M->encr_document->key = talloc (32); str_to_32 (M->encr_document->key, DS_STR (DS_DMM->key)); M->encr_document->iv = talloc (32); str_to_32 (M->encr_document->iv, DS_STR (DS_DMM->iv)); break; case CODE_decrypted_message_media_geo_point: M->type = tgl_message_media_geo; M->geo.latitude = DS_LVAL (DS_DMM->latitude); M->geo.longitude = DS_LVAL (DS_DMM->longitude); break; case CODE_decrypted_message_media_contact: M->type = tgl_message_media_contact; M->phone = DS_STR_DUP (DS_DMM->phone_number); M->first_name = DS_STR_DUP (DS_DMM->first_name); M->last_name = DS_STR_DUP (DS_DMM->last_name); M->user_id = DS_LVAL (DS_DMM->user_id); break; default: assert (0); } } void tglf_fetch_message_action_encrypted (struct tgl_state *TLS, struct tgl_message_action *M, struct tl_ds_decrypted_message_action *DS_DMA) { if (!DS_DMA) { return; } switch (DS_DMA->magic) { case CODE_decrypted_message_action_set_message_t_t_l: M->type = tgl_message_action_set_message_ttl; M->ttl = DS_LVAL (DS_DMA->ttl_seconds); break; case CODE_decrypted_message_action_read_messages: M->type = tgl_message_action_read_messages; { M->read_cnt = DS_LVAL (DS_DMA->random_ids->cnt); int i; for (i = 0; i < M->read_cnt; i++) { tgl_message_id_t id; id.peer_type = TGL_PEER_RANDOM_ID; id.id = DS_LVAL (DS_DMA->random_ids->data[i]); struct tgl_message *N = tgl_message_get (TLS, &id); if (N) { N->flags &= ~TGLMF_UNREAD; } } } break; case CODE_decrypted_message_action_delete_messages: M->type = tgl_message_action_delete_messages; break; case CODE_decrypted_message_action_screenshot_messages: M->type = tgl_message_action_screenshot_messages; { M->screenshot_cnt = DS_LVAL (DS_DMA->random_ids->cnt); } break; case CODE_decrypted_message_action_notify_layer: M->type = tgl_message_action_notify_layer; M->layer = DS_LVAL (DS_DMA->layer); break; case CODE_decrypted_message_action_flush_history: M->type = tgl_message_action_flush_history; break; case CODE_decrypted_message_action_typing: M->type = tgl_message_action_typing; M->typing = tglf_fetch_typing (DS_DMA->action); break; case CODE_decrypted_message_action_resend: M->type = tgl_message_action_resend; M->start_seq_no = DS_LVAL (DS_DMA->start_seq_no); M->end_seq_no = DS_LVAL (DS_DMA->end_seq_no); break; case CODE_decrypted_message_action_noop: M->type = tgl_message_action_noop; break; case CODE_decrypted_message_action_request_key: M->type = tgl_message_action_request_key; M->exchange_id = DS_LVAL (DS_DMA->exchange_id); M->g_a = talloc (256); str_to_256 (M->g_a, DS_STR (DS_DMA->g_a)); break; case CODE_decrypted_message_action_accept_key: M->type = tgl_message_action_accept_key; M->exchange_id = DS_LVAL (DS_DMA->exchange_id); M->g_a = talloc (256); str_to_256 (M->g_a, DS_STR (DS_DMA->g_b)); M->key_fingerprint = DS_LVAL (DS_DMA->key_fingerprint); break; case CODE_decrypted_message_action_commit_key: M->type = tgl_message_action_commit_key; M->exchange_id = DS_LVAL (DS_DMA->exchange_id); M->key_fingerprint = DS_LVAL (DS_DMA->key_fingerprint); break; case CODE_decrypted_message_action_abort_key: M->type = tgl_message_action_abort_key; M->exchange_id = DS_LVAL (DS_DMA->exchange_id); break; default: assert (0); } } void tglf_fetch_message_entity (struct tgl_state *TLS, struct tgl_message_entity *E, struct tl_ds_message_entity *DS_ME) { E->start = DS_LVAL (DS_ME->offset); E->length = DS_LVAL (DS_ME->length); switch (DS_ME->magic) { case CODE_message_entity_unknown: E->type = tgl_message_entity_unknown; break; case CODE_message_entity_mention: E->type = tgl_message_entity_mention; break; case CODE_message_entity_hashtag: E->type = tgl_message_entity_hashtag; break; case CODE_message_entity_bot_command: E->type = tgl_message_entity_bot_command; break; case CODE_message_entity_url: E->type = tgl_message_entity_url; break; case CODE_message_entity_email: E->type = tgl_message_entity_email; break; case CODE_message_entity_bold: E->type = tgl_message_entity_bold; break; case CODE_message_entity_italic: E->type = tgl_message_entity_italic; break; case CODE_message_entity_code: E->type = tgl_message_entity_code; break; case CODE_message_entity_pre: E->type = tgl_message_entity_pre; break; case CODE_message_entity_text_url: E->type = tgl_message_entity_text_url; E->extra = DS_STR_DUP (DS_ME->url); break; default: assert (0); } } void tglf_fetch_message_entities (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_vector *DS) { M->entities_num = DS_LVAL (DS->f1); M->entities = talloc0 (M->entities_num * sizeof (struct tgl_message_entity)); int i; for (i = 0; i < M->entities_num; i++) { struct tl_ds_message_entity *D = DS->f2[i]; tglf_fetch_message_entity (TLS, &M->entities[i], D); } } struct tgl_message *tglf_fetch_alloc_message (struct tgl_state *TLS, struct tl_ds_message *DS_M, int *new_msg) { if (new_msg) { *new_msg = 0; } //assert (0); if (!DS_M || DS_M->magic == CODE_message_empty) { vlogprintf (E_NOTICE, "empty message\n"); return NULL; } tgl_peer_id_t to_id = tglf_fetch_peer_id (TLS, DS_M->to_id); tgl_peer_t *T = tgl_peer_get (TLS, to_id); if (!T || !(T->flags & TGLPF_CREATED)) { tgl_do_get_difference (TLS, 0, 0, 0); vlogprintf (E_NOTICE, "unknown to_id\n"); return NULL; } tgl_peer_t *P = T; tgl_peer_t *F = NULL; if (DS_M->from_id) { F = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_M->from_id))); if (!F || !(F->flags & TGLPF_CREATED)) { tgl_do_get_difference (TLS, 0, 0, 0); vlogprintf (E_NOTICE, "unknown from_id %d\n", DS_LVAL (DS_M->from_id)); return NULL; } if (!tgl_cmp_peer_id (to_id, TLS->our_id)) { P = F; } } tgl_peer_t *FF = NULL; if (DS_M->fwd_from_id) { tgl_peer_id_t FF_id = tglf_fetch_peer_id (TLS, DS_M->fwd_from_id); FF = tgl_peer_get (TLS, FF_id); if (!FF) { tgl_do_get_difference (TLS, 0, 0, 0); vlogprintf (E_NOTICE, "unknown fwd_id\n"); return NULL; } } tgl_message_id_t msg_id = tgl_peer_id_to_msg_id (P->id, DS_LVAL (DS_M->id)); struct tgl_message *M = tgl_message_get (TLS, &msg_id); if (!M) { M = talloc0 (sizeof (*M)); M->permanent_id = msg_id; tglm_message_insert_tree (TLS, M); TLS->messages_allocated ++; assert (tgl_message_get (TLS, &msg_id) == M); } int new = !(M->flags & TGLMF_CREATED); if (new_msg) { *new_msg = new; } if (new) { int flags = 0; if (DS_LVAL (DS_M->flags) & 1) { flags |= TGLMF_UNREAD; } if (DS_LVAL (DS_M->flags) & 2) { flags |= TGLMF_OUT; } if (DS_LVAL (DS_M->flags) & 16) { flags |= TGLMF_MENTION; } tgl_peer_id_t from_id; if (DS_M->from_id) { from_id = F->id; } else { from_id = TGL_MK_USER (0); } tgl_peer_id_t to_id = T->id; tgl_peer_id_t fwd_from_id; if (DS_M->fwd_from_id) { fwd_from_id = FF->id; } else { fwd_from_id = TGL_MK_USER (0); } bl_do_edit_message (TLS, &msg_id, DS_M->from_id ? &from_id : NULL, &to_id, DS_M->fwd_from_id ? &fwd_from_id : NULL, DS_M->fwd_date, DS_M->date, DS_STR (DS_M->message), DS_M->media, DS_M->action, DS_M->reply_to_msg_id, DS_M->reply_markup, (void *)DS_M->entities, flags | TGLMF_CREATE | TGLMF_CREATED ); } return M; } static int *decr_ptr; static int *decr_end; static int decrypt_encrypted_message (struct tgl_secret_chat *E) { int *msg_key = decr_ptr; decr_ptr += 4; assert (decr_ptr < decr_end); static unsigned char sha1a_buffer[20]; static unsigned char sha1b_buffer[20]; static unsigned char sha1c_buffer[20]; static unsigned char sha1d_buffer[20]; static unsigned char buf[64]; int *e_key = E->exchange_state != tgl_sce_committed ? E->key : E->exchange_key; memcpy (buf, msg_key, 16); memcpy (buf + 16, e_key, 32); TGLC_sha1 (buf, 48, sha1a_buffer); memcpy (buf, e_key + 8, 16); memcpy (buf + 16, msg_key, 16); memcpy (buf + 32, e_key + 12, 16); TGLC_sha1 (buf, 48, sha1b_buffer); memcpy (buf, e_key + 16, 32); memcpy (buf + 32, msg_key, 16); TGLC_sha1 (buf, 48, sha1c_buffer); memcpy (buf, msg_key, 16); memcpy (buf + 16, e_key + 24, 32); TGLC_sha1 (buf, 48, sha1d_buffer); static unsigned char key[32]; memcpy (key, sha1a_buffer + 0, 8); memcpy (key + 8, sha1b_buffer + 8, 12); memcpy (key + 20, sha1c_buffer + 4, 12); static unsigned char iv[32]; memcpy (iv, sha1a_buffer + 8, 12); memcpy (iv + 12, sha1b_buffer + 0, 8); memcpy (iv + 20, sha1c_buffer + 16, 4); memcpy (iv + 24, sha1d_buffer + 0, 8); TGLC_aes_key aes_key; TGLC_aes_set_decrypt_key (key, 256, &aes_key); TGLC_aes_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0); memset (&aes_key, 0, sizeof (aes_key)); int x = *(decr_ptr); if (x < 0 || (x & 3)) { return -1; } assert (x >= 0 && !(x & 3)); TGLC_sha1 ((void *)decr_ptr, 4 + x, sha1a_buffer); if (memcmp (sha1a_buffer + 4, msg_key, 16)) { return -1; } return 0; } struct tgl_message *tglf_fetch_encrypted_message (struct tgl_state *TLS, struct tl_ds_encrypted_message *DS_EM) { if (!DS_EM) { return NULL; } tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (DS_LVAL (DS_EM->chat_id))); if (!P || P->encr_chat.state != sc_ok) { vlogprintf (E_WARNING, "Encrypted message to unknown chat. Dropping\n"); return NULL; } tgl_message_id_t msg_id = tgl_peer_id_to_msg_id (P->id, DS_LVAL (DS_EM->random_id)); struct tgl_message *M = tgl_message_get (TLS, &msg_id); if (!M) { M = talloc0 (sizeof (*M)); M->permanent_id = msg_id; tglm_message_insert_tree (TLS, M); TLS->messages_allocated ++; assert (tgl_message_get (TLS, &msg_id) == M); } int new = !(M->flags & TGLMF_CREATED); if (!new) { return M; } decr_ptr = (void *)DS_EM->bytes->data; decr_end = decr_ptr + (DS_EM->bytes->len / 4); if (P->encr_chat.exchange_state == tgl_sce_committed && P->encr_chat.key_fingerprint == *(long long *)decr_ptr) { tgl_do_confirm_exchange (TLS, (void *)P, 0); assert (P->encr_chat.exchange_state == tgl_sce_none); } long long key_fingerprint = P->encr_chat.exchange_state != tgl_sce_committed ? P->encr_chat.key_fingerprint : P->encr_chat.exchange_key_fingerprint; if (*(long long *)decr_ptr != key_fingerprint) { vlogprintf (E_WARNING, "Encrypted message with bad fingerprint to chat %s\n", P->print_name); return M; } decr_ptr += 2; if (decrypt_encrypted_message (&P->encr_chat) < 0) { vlogprintf (E_WARNING, "can not decrypt message\n"); return M; } int *save_in_ptr = in_ptr; int *save_in_end = in_end; in_ptr = decr_ptr; int ll = *in_ptr; in_end = in_ptr + ll / 4 + 1; assert (fetch_int () == ll); if (skip_type_decrypted_message_layer (TYPE_TO_PARAM (decrypted_message_layer)) < 0 || in_ptr != in_end) { vlogprintf (E_WARNING, "can not fetch message\n"); in_ptr = save_in_ptr; in_end = save_in_end; return M; } in_ptr = decr_ptr; assert (fetch_int () == ll); struct tl_ds_decrypted_message_layer *DS_DML = fetch_ds_type_decrypted_message_layer (TYPE_TO_PARAM (decrypted_message_layer)); assert (DS_DML); in_ptr = save_in_ptr; in_end = save_in_end; //bl_do_encr_chat_set_layer (TLS, (void *)P, DS_LVAL (DS_DML->layer)); bl_do_encr_chat (TLS, tgl_get_peer_id (P->id), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, DS_DML->layer, NULL, NULL, NULL, NULL, TGL_FLAGS_UNCHANGED, NULL, 0 ); int in_seq_no = DS_LVAL (DS_DML->out_seq_no); int out_seq_no = DS_LVAL (DS_DML->in_seq_no); if (in_seq_no / 2 != P->encr_chat.in_seq_no) { vlogprintf (E_WARNING, "Hole in seq in secret chat. in_seq_no = %d, expect_seq_no = %d\n", in_seq_no / 2, P->encr_chat.in_seq_no); free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); return M; } if ((in_seq_no & 1) != 1 - (P->encr_chat.admin_id == tgl_get_peer_id (TLS->our_id)) || (out_seq_no & 1) != (P->encr_chat.admin_id == tgl_get_peer_id (TLS->our_id))) { vlogprintf (E_WARNING, "Bad msg admin\n"); free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); return M; } if (out_seq_no / 2 > P->encr_chat.out_seq_no) { vlogprintf (E_WARNING, "In seq no is bigger than our's out seq no (out_seq_no = %d, our_out_seq_no = %d). Drop\n", out_seq_no / 2, P->encr_chat.out_seq_no); free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); return M; } if (out_seq_no / 2 < P->encr_chat.last_in_seq_no) { vlogprintf (E_WARNING, "Clients in_seq_no decreased (out_seq_no = %d, last_out_seq_no = %d). Drop\n", out_seq_no / 2, P->encr_chat.last_in_seq_no); free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); return M; } struct tl_ds_decrypted_message *DS_DM = DS_DML->message; if (M->permanent_id.id != DS_LVAL (DS_DM->random_id)) { vlogprintf (E_ERROR, "Incorrect message: id = %" INT64_PRINTF_MODIFIER "d, new_id = %" INT64_PRINTF_MODIFIER "d\n", M->permanent_id.id, DS_LVAL (DS_DM->random_id)); free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); return M; } tgl_peer_id_t from_id = TGL_MK_USER (P->encr_chat.user_id); bl_do_edit_message_encr (TLS, &M->permanent_id, &from_id, &P->id, DS_EM->date, DS_STR (DS_DM->message), DS_DM->media, DS_DM->action, DS_EM->file, TGLMF_CREATE | TGLMF_CREATED | TGLMF_ENCRYPTED); if (in_seq_no >= 0 && out_seq_no >= 0) { //bl_do_encr_chat_update_seq (TLS, (void *)P, in_seq_no / 2 + 1, out_seq_no / 2); in_seq_no = in_seq_no / 2 + 1; out_seq_no = out_seq_no / 2; bl_do_encr_chat (TLS, tgl_get_peer_id (P->id), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &in_seq_no, &out_seq_no, NULL, NULL, TGL_FLAGS_UNCHANGED, NULL, 0 ); assert (P->encr_chat.in_seq_no == in_seq_no); } free_ds_type_decrypted_message_layer (DS_DML, TYPE_TO_PARAM(decrypted_message_layer)); return M; } void tglf_fetch_encrypted_message_file (struct tgl_state *TLS, struct tgl_message_media *M, struct tl_ds_encrypted_file *DS_EF) { if (DS_EF->magic == CODE_encrypted_file_empty) { assert (M->type != tgl_message_media_document_encr); } else { assert (M->type == tgl_message_media_document_encr); assert (M->encr_document); M->encr_document->id = DS_LVAL (DS_EF->id); M->encr_document->access_hash = DS_LVAL (DS_EF->access_hash); if (!M->encr_document->size) { M->encr_document->size = DS_LVAL (DS_EF->size); } M->encr_document->dc_id = DS_LVAL (DS_EF->dc_id); M->encr_document->key_fingerprint = DS_LVAL (DS_EF->key_fingerprint); } } static int id_cmp (struct tgl_message *M1, struct tgl_message *M2) { if (M1->permanent_id.peer_type < M2->permanent_id.peer_type) { return -1; } if (M1->permanent_id.peer_type > M2->permanent_id.peer_type) { return 1; } if (M1->permanent_id.peer_id < M2->permanent_id.peer_id) { return -1; } if (M1->permanent_id.peer_id > M2->permanent_id.peer_id) { return 1; } if (M1->permanent_id.id < M2->permanent_id.id) { return -1; } if (M1->permanent_id.id > M2->permanent_id.id) { return 1; } else { return 0; } } static void increase_peer_size (struct tgl_state *TLS) { if (TLS->peer_num == TLS->peer_size) { int new_size = TLS->peer_size ? 2 * TLS->peer_size : 10; int old_size = TLS->peer_size; if (old_size) { TLS->Peers = trealloc (TLS->Peers, old_size * sizeof (void *), new_size * sizeof (void *)); } else { TLS->Peers = talloc (new_size * sizeof (void *)); } TLS->peer_size = new_size; } } struct tgl_message *tglf_fetch_alloc_encrypted_message (struct tgl_state *TLS, struct tl_ds_encrypted_message *DS_EM) { struct tgl_message *M = tglf_fetch_encrypted_message (TLS, DS_EM); if (!M) { return M; } if (M->flags & TGLMF_CREATED) { tgl_peer_t *_E = tgl_peer_get (TLS, M->to_id); assert (_E); struct tgl_secret_chat *E = &_E->encr_chat; if (M->action.type == tgl_message_action_request_key) { if (E->exchange_state == tgl_sce_none || (E->exchange_state == tgl_sce_requested && E->exchange_id > M->action.exchange_id )) { tgl_do_accept_exchange (TLS, E, M->action.exchange_id, M->action.g_a); } else { vlogprintf (E_WARNING, "Exchange: Incorrect state (received request, state = %d)\n", E->exchange_state); } } if (M->action.type == tgl_message_action_accept_key) { if (E->exchange_state == tgl_sce_requested && E->exchange_id == M->action.exchange_id) { tgl_do_commit_exchange (TLS, E, M->action.g_a); } else { vlogprintf (E_WARNING, "Exchange: Incorrect state (received accept, state = %d)\n", E->exchange_state); } } if (M->action.type == tgl_message_action_commit_key) { if (E->exchange_state == tgl_sce_accepted && E->exchange_id == M->action.exchange_id) { tgl_do_confirm_exchange (TLS, E, 1); } else { vlogprintf (E_WARNING, "Exchange: Incorrect state (received commit, state = %d)\n", E->exchange_state); } } if (M->action.type == tgl_message_action_abort_key) { if (E->exchange_state != tgl_sce_none && E->exchange_id == M->action.exchange_id) { tgl_do_abort_exchange (TLS, E); } else { vlogprintf (E_WARNING, "Exchange: Incorrect state (received abort, state = %d)\n", E->exchange_state); } } if (M->action.type == tgl_message_action_notify_layer) { bl_do_encr_chat (TLS, tgl_get_peer_id (E->id), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &M->action.layer, NULL, NULL, NULL, NULL, TGL_FLAGS_UNCHANGED, NULL, 0 ); } if (M->action.type == tgl_message_action_set_message_ttl) { //bl_do_encr_chat_set_ttl (TLS, E, M->action.ttl); bl_do_encr_chat (TLS, tgl_get_peer_id (E->id), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &M->action.ttl, NULL, NULL, NULL, NULL, NULL, TGL_FLAGS_UNCHANGED, NULL, 0 ); } } return M; } struct tgl_bot_info *tglf_fetch_alloc_bot_info (struct tgl_state *TLS, struct tl_ds_bot_info *DS_BI) { if (!DS_BI || DS_BI->magic == CODE_bot_info_empty) { return NULL; } struct tgl_bot_info *B = talloc (sizeof (*B)); B->version = DS_LVAL (DS_BI->version); B->share_text = DS_STR_DUP (DS_BI->share_text); B->description = DS_STR_DUP (DS_BI->description); B->commands_num = DS_LVAL (DS_BI->commands->cnt); B->commands = talloc (sizeof (struct tgl_bot_command) * B->commands_num); int i; for (i = 0; i < B->commands_num; i++) { struct tl_ds_bot_command *BC = DS_BI->commands->data[i]; B->commands[i].command = DS_STR_DUP (BC->command); B->commands[i].description = DS_STR_DUP (BC->description); } return B; } struct tgl_message_reply_markup *tglf_fetch_alloc_reply_markup (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_reply_markup *DS_RM) { if (!DS_RM) { return NULL; } struct tgl_message_reply_markup *R = talloc0 (sizeof (*R)); R->flags = DS_LVAL (DS_RM->flags); R->refcnt = 1; R->rows = DS_RM->rows ? DS_LVAL (DS_RM->rows->cnt) : 0; int total = 0; R->row_start = talloc ((R->rows + 1) * 4); R->row_start[0] = 0; int i; for (i = 0; i < R->rows; i++) { struct tl_ds_keyboard_button_row *DS_K = DS_RM->rows->data[i]; total += DS_LVAL (DS_K->buttons->cnt); R->row_start[i + 1] = total; } R->buttons = talloc (sizeof (void *) * total); int r = 0; for (i = 0; i < R->rows; i++) { struct tl_ds_keyboard_button_row *DS_K = DS_RM->rows->data[i]; int j; for (j = 0; j < DS_LVAL (DS_K->buttons->cnt); j++) { struct tl_ds_keyboard_button *DS_KB = DS_K->buttons->data[j]; R->buttons[r ++] = DS_STR_DUP (DS_KB->text); } } assert (r == total); return R; } /* }}} */ void tglp_insert_encrypted_chat (struct tgl_state *TLS, tgl_peer_t *P) { TLS->encr_chats_allocated ++; TLS->peer_tree = tree_insert_peer (TLS->peer_tree, P, rand ()); increase_peer_size (TLS); TLS->Peers[TLS->peer_num ++] = P; } void tglp_insert_user (struct tgl_state *TLS, tgl_peer_t *P) { TLS->users_allocated ++; TLS->peer_tree = tree_insert_peer (TLS->peer_tree, P, rand ()); increase_peer_size (TLS); TLS->Peers[TLS->peer_num ++] = P; } void tglp_insert_chat (struct tgl_state *TLS, tgl_peer_t *P) { TLS->chats_allocated ++; TLS->peer_tree = tree_insert_peer (TLS->peer_tree, P, rand ()); increase_peer_size (TLS); TLS->Peers[TLS->peer_num ++] = P; } void tglp_insert_channel (struct tgl_state *TLS, tgl_peer_t *P) { TLS->channels_allocated ++; TLS->peer_tree = tree_insert_peer (TLS->peer_tree, P, rand ()); increase_peer_size (TLS); TLS->Peers[TLS->peer_num ++] = P; } void tgl_insert_empty_user (struct tgl_state *TLS, int uid) { tgl_peer_id_t id = TGL_MK_USER (uid); if (tgl_peer_get (TLS, id)) { return; } tgl_peer_t *P = talloc0 (sizeof (*P)); P->id = id; tglp_insert_user (TLS, P); } void tgl_insert_empty_chat (struct tgl_state *TLS, int cid) { tgl_peer_id_t id = TGL_MK_CHAT (cid); if (tgl_peer_get (TLS, id)) { return; } tgl_peer_t *P = talloc0 (sizeof (*P)); P->id = id; tglp_insert_chat (TLS, P); } /* {{{ Free */ void tgls_free_photo_size (struct tgl_state *TLS, struct tgl_photo_size *S) { tfree_str (S->type); if (S->data) { tfree (S->data, S->size); } } void tgls_free_photo (struct tgl_state *TLS, struct tgl_photo *P) { if (--P->refcnt) { assert (P->refcnt > 0); return; } if (P->caption) { tfree_str (P->caption); } if (P->sizes) { int i; for (i = 0; i < P->sizes_num; i++) { tgls_free_photo_size (TLS, &P->sizes[i]); } tfree (P->sizes, sizeof (struct tgl_photo_size) * P->sizes_num); } TLS->photo_tree = tree_delete_photo (TLS->photo_tree, P); tfree (P, sizeof (*P)); } void tgls_free_document (struct tgl_state *TLS, struct tgl_document *D) { if (--D->refcnt) { assert (D->refcnt); return; } if (D->mime_type) { tfree_str (D->mime_type);} if (D->caption) {tfree_str (D->caption);} tgls_free_photo_size (TLS, &D->thumb); TLS->document_tree = tree_delete_document (TLS->document_tree, D); tfree (D, sizeof (*D)); } void tgls_free_webpage (struct tgl_state *TLS, struct tgl_webpage *W) { if (--W->refcnt) { assert (W->refcnt); return; } if (W->url) { tfree_str (W->url); } if (W->display_url) { tfree_str (W->display_url); } if (W->title) { tfree_str (W->title); } if (W->site_name) { tfree_str (W->site_name); } if (W->type) { tfree_str (W->type); } if (W->description) { tfree_str (W->description); } if (W->photo) { tgls_free_photo (TLS, W->photo); } if (W->embed_url) { tfree_str (W->embed_url); } if (W->embed_type) { tfree_str (W->embed_type); } if (W->author) { tfree_str (W->author); } TLS->webpage_tree = tree_delete_webpage (TLS->webpage_tree, W); tfree (W, sizeof (*W)); } void tgls_free_message_media (struct tgl_state *TLS, struct tgl_message_media *M) { switch (M->type) { case tgl_message_media_none: case tgl_message_media_geo: return; case tgl_message_media_photo: if (M->photo) { tgls_free_photo (TLS, M->photo); } if (M->caption) { tfree_str (M->caption); } M->photo = NULL; return; case tgl_message_media_contact: tfree_str (M->phone); tfree_str (M->first_name); tfree_str (M->last_name); return; case tgl_message_media_document: case tgl_message_media_video: case tgl_message_media_audio: tgls_free_document (TLS, M->document); if (M->caption) { tfree_str (M->caption); } return; case tgl_message_media_unsupported: return; case tgl_message_media_document_encr: tfree_secure (M->encr_document->key, 32); tfree_secure (M->encr_document->iv, 32); tfree (M->encr_document, sizeof (*M->encr_document)); return; case tgl_message_media_webpage: tgls_free_webpage (TLS, M->webpage); return; case tgl_message_media_venue: if (M->venue.title) { tfree_str (M->venue.title); } if (M->venue.address) { tfree_str (M->venue.address); } if (M->venue.provider) { tfree_str (M->venue.provider); } if (M->venue.venue_id) { tfree_str (M->venue.venue_id); } return; default: vlogprintf (E_ERROR, "type = 0x%08x\n", M->type); assert (0); } } void tgls_free_message_action (struct tgl_state *TLS, struct tgl_message_action *M) { switch (M->type) { case tgl_message_action_none: return; case tgl_message_action_chat_create: tfree_str (M->title); tfree (M->users, M->user_num * 4); return; case tgl_message_action_chat_edit_title: tfree_str (M->new_title); return; case tgl_message_action_chat_edit_photo: tgls_free_photo (TLS, M->photo); M->photo = NULL; return; case tgl_message_action_chat_add_users: tfree (M->users, M->user_num * 4); return; case tgl_message_action_chat_delete_photo: case tgl_message_action_chat_add_user_by_link: case tgl_message_action_chat_delete_user: case tgl_message_action_geo_chat_create: case tgl_message_action_geo_chat_checkin: case tgl_message_action_set_message_ttl: case tgl_message_action_read_messages: case tgl_message_action_delete_messages: case tgl_message_action_screenshot_messages: case tgl_message_action_flush_history: case tgl_message_action_typing: case tgl_message_action_resend: case tgl_message_action_notify_layer: case tgl_message_action_commit_key: case tgl_message_action_abort_key: case tgl_message_action_noop: case tgl_message_action_migrated_to: return; case tgl_message_action_request_key: case tgl_message_action_accept_key: tfree (M->g_a, 256); return; case tgl_message_action_channel_create: case tgl_message_action_migrated_from: tfree_str (M->title); return; /* default: vlogprintf (E_ERROR, "type = 0x%08x\n", M->type); assert (0);*/ } vlogprintf (E_ERROR, "type = 0x%08x\n", M->type); assert (0); } void tgls_free_message_entity (struct tgl_state *TLS, struct tgl_message_entity *E) { if (E->extra) { tfree_str (E->extra); } } void tgls_clear_message (struct tgl_state *TLS, struct tgl_message *M) { if (!(M->flags & TGLMF_SERVICE)) { if (M->message) { tfree (M->message, M->message_len + 1); } tgls_free_message_media (TLS, &M->media); } else { tgls_free_message_action (TLS, &M->action); } int i; for (i = 0; i < M->entities_num; i++) { tgls_free_message_entity (TLS, &M->entities[i]); } tfree (M->entities, M->entities_num * sizeof (struct tgl_message_entity)); } void tgls_free_reply_markup (struct tgl_state *TLS, struct tgl_message_reply_markup *R) { if (!--R->refcnt) { int i; for (i = 0; i < R->row_start[R->rows]; i++) { tfree_str (R->buttons[i]); } tfree (R->buttons, R->row_start[R->rows] * sizeof (void *)); tfree (R->row_start, 4 * (R->rows + 1)); tfree (R, sizeof (*R)); } else { assert (R->refcnt > 0); } } void tgls_free_message (struct tgl_state *TLS, struct tgl_message *M) { tgls_clear_message (TLS, M); if (M->reply_markup) { tgls_free_reply_markup (TLS, M->reply_markup); } tfree (M, sizeof (*M)); } void tgls_free_chat (struct tgl_state *TLS, struct tgl_chat *U) { if (U->title) { tfree_str (U->title); } if (U->print_title) { tfree_str (U->print_title); } if (U->user_list) { tfree (U->user_list, U->user_list_size * 12); } if (U->photo) { tgls_free_photo (TLS, U->photo); } tfree (U, sizeof (tgl_peer_t)); } void tgls_free_user (struct tgl_state *TLS, struct tgl_user *U) { if (U->first_name) { tfree_str (U->first_name); } if (U->last_name) { tfree_str (U->last_name); } if (U->print_name) { tfree_str (U->print_name); } if (U->phone) { tfree_str (U->phone); } if (U->username) { tfree_str (U->username); } if (U->real_first_name) { tfree_str (U->real_first_name); } if (U->real_last_name) { tfree_str (U->real_last_name); } if (U->status.ev) { tgl_remove_status_expire (TLS, U); } if (U->photo) { tgls_free_photo (TLS, U->photo); } if (U->bot_info) { tgls_free_bot_info (TLS, U->bot_info); } tfree (U, sizeof (tgl_peer_t)); } void tgls_free_encr_chat (struct tgl_state *TLS, struct tgl_secret_chat *U) { if (U->print_name) { tfree_str (U->print_name); } if (U->g_key) { tfree (U->g_key, 256); } tfree (U, sizeof (tgl_peer_t)); } void tgls_free_channel (struct tgl_state *TLS, struct tgl_channel *U) { if (U->print_title) { tfree_str (U->print_title); } if (U->username) { tfree_str (U->username); } if (U->title) { tfree_str (U->title); } if (U->about) { tfree_str (U->about); } if (U->photo) { tgls_free_photo (TLS, U->photo); } tfree (U, sizeof (tgl_peer_t)); } void tgls_free_peer (struct tgl_state *TLS, tgl_peer_t *P) { if (tgl_get_peer_type (P->id) == TGL_PEER_USER) { tgls_free_user (TLS, (void *)P); } else if (tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { tgls_free_chat (TLS, (void *)P); } else if (tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT) { tgls_free_encr_chat (TLS, (void *)P); } else if (tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL) { tgls_free_channel (TLS, (void *)P); } else { assert (0); } } void tgls_free_bot_info (struct tgl_state *TLS, struct tgl_bot_info *B) { if (!B) { return; } int i; for (i = 0; i < B->commands_num; i++) { tfree_str (B->commands[i].command); tfree_str (B->commands[i].description); } tfree (B->commands, sizeof (struct tgl_bot_command) * B->commands_num); tfree_str (B->share_text); tfree_str (B->description); tfree (B, sizeof (*B)); } /* }}} */ /* Messages {{{ */ void tglm_message_del_use (struct tgl_state *TLS, struct tgl_message *M) { M->next_use->prev_use = M->prev_use; M->prev_use->next_use = M->next_use; } void tglm_message_add_use (struct tgl_state *TLS, struct tgl_message *M) { M->next_use = TLS->message_list.next_use; M->prev_use = &TLS->message_list; M->next_use->prev_use = M; M->prev_use->next_use = M; } void tglm_message_add_peer (struct tgl_state *TLS, struct tgl_message *M) { tgl_peer_id_t id; if (!tgl_cmp_peer_id (M->to_id, TLS->our_id)) { id = M->from_id; } else { id = M->to_id; } tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P) { P = talloc0 (sizeof (*P)); P->id = id; switch (tgl_get_peer_type (id)) { case TGL_PEER_USER: TLS->users_allocated ++; break; case TGL_PEER_CHAT: TLS->chats_allocated ++; break; case TGL_PEER_GEO_CHAT: TLS->geo_chats_allocated ++; break; case TGL_PEER_ENCR_CHAT: TLS->encr_chats_allocated ++; break; } TLS->peer_tree = tree_insert_peer (TLS->peer_tree, P, rand ()); increase_peer_size (TLS); TLS->Peers[TLS->peer_num ++] = P; } if (!P->last) { P->last = M; M->prev = M->next = 0; } else { if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) { struct tgl_message *N = P->last; struct tgl_message *NP = 0; while (N && N->permanent_id.id > M->permanent_id.id) { NP = N; N = N->next; } if (N) { assert (N->permanent_id.id < M->permanent_id.id); } M->next = N; M->prev = NP; if (N) { N->prev = M; } if (NP) { NP->next = M; } else { P->last = M; } } else { struct tgl_message *N = P->last; struct tgl_message *NP = 0; M->next = N; M->prev = NP; if (N) { N->prev = M; } if (NP) { NP->next = M; } else { P->last = M; } } } } void tglm_message_del_peer (struct tgl_state *TLS, struct tgl_message *M) { tgl_peer_id_t id; if (!tgl_cmp_peer_id (M->to_id, TLS->our_id)) { id = M->from_id; } else { id = M->to_id; } tgl_peer_t *P = tgl_peer_get (TLS, id); if (M->prev) { M->prev->next = M->next; } if (M->next) { M->next->prev = M->prev; } if (P && P->last == M) { P->last = M->next; } } struct tgl_message *tglm_message_alloc (struct tgl_state *TLS, tgl_message_id_t *id) { struct tgl_message *M = talloc0 (sizeof (*M)); M->permanent_id = *id; tglm_message_insert_tree (TLS, M); TLS->messages_allocated ++; return M; } void tglm_message_insert_tree (struct tgl_state *TLS, struct tgl_message *M) { assert (M->permanent_id.id); TLS->message_tree = tree_insert_message (TLS->message_tree, M, rand ()); } void tglm_message_remove_tree (struct tgl_state *TLS, struct tgl_message *M) { assert (M->permanent_id.id); TLS->message_tree = tree_delete_message (TLS->message_tree, M); } void tglm_message_insert (struct tgl_state *TLS, struct tgl_message *M) { tglm_message_add_use (TLS, M); tglm_message_add_peer (TLS, M); } void tglm_message_insert_unsent (struct tgl_state *TLS, struct tgl_message *M) { TLS->message_unsent_tree = tree_insert_message (TLS->message_unsent_tree, M, rand ()); } void tglm_message_remove_unsent (struct tgl_state *TLS, struct tgl_message *M) { TLS->message_unsent_tree = tree_delete_message (TLS->message_unsent_tree, M); } static void __send_msg (struct tgl_message *M, void *_TLS) { struct tgl_state *TLS = _TLS; vlogprintf (E_NOTICE, "Resending message...\n"); //print_message (M); if (M->media.type != tgl_message_media_none) { assert (M->flags & TGLMF_ENCRYPTED); bl_do_message_delete (TLS, &M->permanent_id); } else { tgl_do_send_msg (TLS, M, 0, 0); } } void tglm_send_all_unsent (struct tgl_state *TLS) { tree_act_ex_message (TLS->message_unsent_tree, __send_msg, TLS); } /* }}} */ struct tgl_photo *tgl_photo_get (struct tgl_state *TLS, long long id) { struct tgl_photo P; P.id = id; return tree_lookup_photo (TLS->photo_tree, &P); } void tgl_photo_insert (struct tgl_state *TLS, struct tgl_photo *P) { TLS->photo_tree = tree_insert_photo (TLS->photo_tree, P, rand ()); } struct tgl_document *tgl_document_get (struct tgl_state *TLS, long long id) { struct tgl_document P; P.id = id; return tree_lookup_document (TLS->document_tree, &P); } void tgl_document_insert (struct tgl_state *TLS, struct tgl_document *P) { TLS->document_tree = tree_insert_document (TLS->document_tree, P, rand ()); } struct tgl_webpage *tgl_webpage_get (struct tgl_state *TLS, long long id) { struct tgl_webpage P; P.id = id; return tree_lookup_webpage (TLS->webpage_tree, &P); } void tgl_webpage_insert (struct tgl_state *TLS, struct tgl_webpage *P) { TLS->webpage_tree = tree_insert_webpage (TLS->webpage_tree, P, rand ()); } void tglp_peer_insert_name (struct tgl_state *TLS, tgl_peer_t *P) { TLS->peer_by_name_tree = tree_insert_peer_by_name (TLS->peer_by_name_tree, P, rand ()); } void tglp_peer_delete_name (struct tgl_state *TLS, tgl_peer_t *P) { TLS->peer_by_name_tree = tree_delete_peer_by_name (TLS->peer_by_name_tree, P); } tgl_peer_t *tgl_peer_get (struct tgl_state *TLS, tgl_peer_id_t id) { static tgl_peer_t U; U.id = id; return tree_lookup_peer (TLS->peer_tree, &U); } struct tgl_message *tgl_message_get (struct tgl_state *TLS, tgl_message_id_t *msg_id) { struct tgl_message M; if (msg_id->peer_type == TGL_PEER_RANDOM_ID) { msg_id = tgls_get_local_by_random (TLS, msg_id->id); } else if (msg_id->peer_type == TGL_PEER_TEMP_ID) { msg_id = tgls_get_local_by_temp (TLS, msg_id->id); } if (!msg_id) { return NULL; } M.permanent_id = *msg_id; return tree_lookup_message (TLS->message_tree, &M); } tgl_peer_t *tgl_peer_get_by_name (struct tgl_state *TLS, const char *s) { static tgl_peer_t P; P.print_name = (void *)s; tgl_peer_t *R = tree_lookup_peer_by_name (TLS->peer_by_name_tree, &P); return R; } void tgl_peer_iterator_ex (struct tgl_state *TLS, void (*it)(tgl_peer_t *P, void *extra), void *extra) { tree_act_ex_peer (TLS->peer_tree, it, extra); } int tgl_complete_user_list (struct tgl_state *TLS, int index, const char *text, int len, char **R) { index ++; while (index < TLS->peer_num && (!TLS->Peers[index]->print_name || strncmp (TLS->Peers[index]->print_name, text, len) || tgl_get_peer_type (TLS->Peers[index]->id) != TGL_PEER_USER)) { index ++; } if (index < TLS->peer_num) { *R = strdup (TLS->Peers[index]->print_name); assert (*R); return index; } else { return -1; } } int tgl_complete_chat_list (struct tgl_state *TLS, int index, const char *text, int len, char **R) { index ++; while (index < TLS->peer_num && (!TLS->Peers[index]->print_name || strncmp (TLS->Peers[index]->print_name, text, len) || tgl_get_peer_type (TLS->Peers[index]->id) != TGL_PEER_CHAT)) { index ++; } if (index < TLS->peer_num) { *R = strdup (TLS->Peers[index]->print_name); assert (*R); return index; } else { return -1; } } int tgl_complete_channel_list (struct tgl_state *TLS, int index, const char *text, int len, char **R) { index ++; while (index < TLS->peer_num && (!TLS->Peers[index]->print_name || strncmp (TLS->Peers[index]->print_name, text, len) || tgl_get_peer_type (TLS->Peers[index]->id) != TGL_PEER_CHANNEL)) { index ++; } if (index < TLS->peer_num) { *R = strdup (TLS->Peers[index]->print_name); assert (*R); return index; } else { return -1; } } int tgl_complete_encr_chat_list (struct tgl_state *TLS, int index, const char *text, int len, char **R) { index ++; while (index < TLS->peer_num && (!TLS->Peers[index]->print_name || strncmp (TLS->Peers[index]->print_name, text, len) || tgl_get_peer_type (TLS->Peers[index]->id) != TGL_PEER_ENCR_CHAT)) { index ++; } if (index < TLS->peer_num) { *R = strdup (TLS->Peers[index]->print_name); assert (*R); return index; } else { return -1; } } int tgl_complete_peer_list (struct tgl_state *TLS, int index, const char *text, int len, char **R) { index ++; while (index < TLS->peer_num && (!TLS->Peers[index]->print_name || strncmp (TLS->Peers[index]->print_name, text, len))) { index ++; } if (index < TLS->peer_num) { *R = strdup (TLS->Peers[index]->print_name); assert (*R); return index; } else { return -1; } } int tgl_secret_chat_for_user (struct tgl_state *TLS, tgl_peer_id_t user_id) { int index = 0; while (index < TLS->peer_num && (tgl_get_peer_type (TLS->Peers[index]->id) != TGL_PEER_ENCR_CHAT || TLS->Peers[index]->encr_chat.user_id != tgl_get_peer_id (user_id) || TLS->Peers[index]->encr_chat.state != sc_ok)) { index ++; } if (index < TLS->peer_num) { return tgl_get_peer_id (TLS->Peers[index]->encr_chat.id); } else { return -1; } } void tgls_free_peer_gw (tgl_peer_t *P, void *TLS) { tgls_free_peer (TLS, P); } void tgls_free_message_gw (struct tgl_message *M, void *TLS) { tgls_free_message (TLS, M); } void tgls_remove_message_gw (struct tgl_state *TLS, struct tgl_message *M) { if (tree_lookup_message (TLS->message_unsent_tree, M)) { tglm_message_remove_unsent (TLS, M); } } void tgls_remove_and_free_message_gw (struct tgl_message *M, void *TLS) { tgls_remove_message_gw (TLS, M); tgls_free_message (TLS, M); } void tgl_free_all (struct tgl_state *TLS) { tree_act_ex_peer (TLS->peer_tree, tgls_free_peer_gw, TLS); TLS->peer_tree = tree_clear_peer (TLS->peer_tree); TLS->peer_by_name_tree = tree_clear_peer_by_name (TLS->peer_by_name_tree); tree_act_ex_message (TLS->message_tree, tgls_remove_and_free_message_gw, TLS); TLS->message_tree = tree_clear_message (TLS->message_tree); tree_act_ex_message (TLS->message_unsent_tree, tgls_free_message_gw, TLS); TLS->message_unsent_tree = tree_clear_message (TLS->message_unsent_tree); tglq_query_free_all (TLS); TLS->random_id_tree = tree_clear_random_id (TLS->random_id_tree); TLS->temp_id_tree = tree_clear_temp_id (TLS->temp_id_tree); if (TLS->encr_prime) { tfree (TLS->encr_prime, 256); } if (TLS->binlog_name) { tfree_str (TLS->binlog_name); } if (TLS->auth_file) { tfree_str (TLS->auth_file); } if (TLS->downloads_directory) { tfree_str (TLS->downloads_directory); } if (TLS->app_hash) { tfree_str (TLS->app_hash); } if (TLS->app_version) { tfree_str (TLS->app_version); } if (TLS->error) { tfree_str (TLS->error); } int i; for (i = 0; i < TLS->rsa_key_num; i++) { if (TLS->rsa_key_list[i]) { tfree_str (TLS->rsa_key_list[i]); } } for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i]) { tgls_free_dc (TLS, TLS->DC_list[i]); } TGLC_bn_ctx_free (TLS->TGLC_bn_ctx); tgls_free_pubkey (TLS); if (TLS->ev_login) { TLS->timer_methods->free (TLS->ev_login); } if (TLS->online_updates_timer) { TLS->timer_methods->free (TLS->online_updates_timer); } tfree (TLS->Peers, TLS->peer_size * sizeof (void *)); tfree (TLS, sizeof (*TLS)); } int tgl_print_stat (struct tgl_state *TLS, char *s, int len) { return tsnprintf (s, len, "users_allocated\t%d\n" "chats_allocated\t%d\n" "encr_chats_allocated\t%d\n" "peer_num\t%d\n" "messages_allocated\t%d\n", TLS->users_allocated, TLS->chats_allocated, TLS->encr_chats_allocated, TLS->peer_num, TLS->messages_allocated ); } void tglf_fetch_int_array (int *dst, struct tl_ds_vector *src, int len) { int i; assert (len <= *src->f1); for (i = 0; i < len; i++) { dst[i] = *(int *)src->f2[i]; } } void tglf_fetch_int_tuple (int *dst, int **src, int len) { int i; for (i = 0; i < len; i++) { dst[i] = *src[i]; } } void tgls_messages_mark_read (struct tgl_state *TLS, struct tgl_message *M, int out, int seq) { while (M && M->permanent_id.id > seq) { if ((M->flags & TGLMF_OUT) == out) { if (!(M->flags & TGLMF_UNREAD)) { return; } } M = M->next; } while (M) { if ((M->flags & TGLMF_OUT) == out) { if (M->flags & TGLMF_UNREAD) { M->flags &= ~TGLMF_UNREAD; TLS->callback.marked_read (TLS, 1, &M); } else { return; } } M = M->next; } } /* void tgls_insert_random2local (struct tgl_state *TLS, long long random_id, tgl_message_id_t *msg_id) { struct random2local *X = talloc (sizeof (*X)); X->random_id = random_id; X->local_id = *msg_id; struct random2local *R = tree_lookup_random_id (TLS->random_id_tree, X); assert (!R); TLS->random_id_tree = tree_insert_random_id (TLS->random_id_tree, X, rand ()); } tgl_message_id_t *tgls_get_local_by_random (struct tgl_state *TLS, long long random_id) { struct random2local X; X.random_id = random_id; struct random2local *Y = tree_lookup_random_id (TLS->random_id_tree, &X); if (Y) { //TLS->random_id_tree = tree_delete_random_id (TLS->random_id_tree, Y); return &Y->local_id; } else { return NULL; } } void tgls_insert_temp2local (struct tgl_state *TLS, int temp_id, tgl_message_id_t *msg_id) { struct random2local *X = talloc (sizeof (*X)); X->random_id = temp_id; X->local_id = *msg_id; struct random2local *R = tree_lookup_random_id (TLS->temp_id_tree, X); assert (!R); TLS->temp_id_tree = tree_insert_random_id (TLS->temp_id_tree, X, rand ()); } }*/ tgl_message_id_t *tgls_get_local_by_random (struct tgl_state *TLS, long long random_id) { struct tgl_message M; M.random_id = random_id; struct tgl_message *N = tree_lookup_random_id (TLS->random_id_tree, &M); if (N) { return &N->permanent_id; } else { return NULL; } } tgl_message_id_t *tgls_get_local_by_temp (struct tgl_state *TLS, int temp_id) { struct tgl_message M; M.temp_id = temp_id; struct tgl_message *N = tree_lookup_temp_id (TLS->temp_id_tree, &M); if (N) { return &N->permanent_id; } else { return NULL; } } tgl_message_id_t tgl_convert_temp_msg_id (struct tgl_state *TLS, tgl_message_id_t msg_id) { struct tgl_message M; M.temp_id = msg_id.id; struct tgl_message *N = tree_lookup_temp_id (TLS->temp_id_tree, &M); if (N) { return N->permanent_id; } else { return msg_id; } } void tgls_message_change_temp_id (struct tgl_state *TLS, struct tgl_message *M, int temp_id) { if (M->temp_id == temp_id) { return; } assert (!M->temp_id); M->temp_id = temp_id; TLS->temp_id_tree = tree_insert_temp_id (TLS->temp_id_tree, M, rand ()); } void tgls_message_change_random_id (struct tgl_state *TLS, struct tgl_message *M, long long random_id) { if (M->random_id == random_id) { return; } assert (!M->random_id); M->random_id = random_id; TLS->random_id_tree = tree_insert_random_id (TLS->random_id_tree, M, rand ()); } void tglm_message_del_temp_id (struct tgl_state *TLS, struct tgl_message *M) { if (M->temp_id) { TLS->temp_id_tree = tree_delete_temp_id (TLS->temp_id_tree, M); } } void tglm_message_del_random_id (struct tgl_state *TLS, struct tgl_message *M) { if (M->random_id) { TLS->random_id_tree = tree_delete_random_id (TLS->random_id_tree, M); } } telegram-purple/tgl/tg-mime-types.c000066400000000000000000000045271357227200100176250ustar00rootroot00000000000000#include #include #define MAX_MIME_TYPES_NUM 10000 #include "mime-types.c" static int mime_initialized; static int mime_type_number; static char *mime_type_names[MAX_MIME_TYPES_NUM]; static char *mime_type_extensions[MAX_MIME_TYPES_NUM]; static void mime_init (void) { char *start = (char *)mime_types; char *end = start + mime_types_len; mime_initialized = 1; char *c = start; while (c < end) { if (*c == '#') { while (c < end && *c != '\n') { c ++; } if (c < end) { c ++; } } else { while (*c <= ' ' && *c != '\n' && c < end) { c ++; } assert (*c > ' ' && *c != '\n' && c < end); char *name = c; while (*c > ' ' && *c != '\n' && c < end) { c ++; } assert (*c <= ' ' && *c != '\n' && c < end); *c = 0; c ++; while (1) { while (*c <= ' ' && *c != '\n' && c < end) { c ++; } if (*c == '\n' || c == end) { if (*c == '\n') { c ++; } break; } char *ext = c; while (*c > ' ' && *c != '\n' && c < end) { c ++; } assert (c != end); int br = (*c == '\n'); *c = 0; c ++; assert (mime_type_number < MAX_MIME_TYPES_NUM); mime_type_names[mime_type_number] = name; mime_type_extensions[mime_type_number] = ext; mime_type_number ++; if (br) { break; } } } } } char *tg_extension_by_mime (const char *mime_type) { if (!mime_initialized) { mime_init (); } int i; for (i = 0; i < mime_type_number; i++) { if (!strcmp (mime_type_names[i], mime_type)) { return mime_type_extensions[i]; } } return NULL; } char *tg_mime_by_filename (const char *filename) { int l = strlen (filename); const char *p = filename - 1 + l; while (p >= filename && *p != '.') { p --; } p ++; if (!mime_initialized) { mime_init (); } static char *def = "application/octet-stream"; if (strlen (p) > 10) { return def; } static char s[11]; strcpy (s, p); char *q = s; while (*q) { if (*q >= 'A' && *p <= 'Z') { *q = *q + 'z' - 'Z'; } q ++; } int i; for (i = 0; i < mime_type_number; i++) { if (!strcmp (mime_type_extensions[i], s)) { return mime_type_names[i]; } } return def; } telegram-purple/tgl/tg-mime-types.h000066400000000000000000000001471357227200100176240ustar00rootroot00000000000000char *tg_mime_by_filename (const char *filename); char *tg_extension_by_mime (const char *mime_type); telegram-purple/tgl/tgl-binlog.h000066400000000000000000000110361357227200100171600ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifndef __BINLOG_H__ #define __BINLOG_H__ //#include "structures.h" #include "tgl.h" #include "auto/auto-types.h" #ifdef __cplusplus extern "C" { #endif void bl_do_dc_option (struct tgl_state *TLS, int flags, int id, const char *name, int l1, const char *ip, int l2, int port); void bl_do_set_working_dc (struct tgl_state *TLS, int num); void bl_do_dc_signed (struct tgl_state *TLS, int id); void bl_do_set_our_id (struct tgl_state *TLS, tgl_peer_id_t id); void bl_do_set_dh_params (struct tgl_state *TLS, int root, unsigned char prime[], int version); void bl_do_set_pts (struct tgl_state *TLS, int pts); void bl_do_set_qts (struct tgl_state *TLS, int qts); void bl_do_set_date (struct tgl_state *TLS, int date); void bl_do_set_seq (struct tgl_state *TLS, int seq); void bl_do_set_channel_pts (struct tgl_state *TLS, int id, int pts); void bl_do_set_auth_key (struct tgl_state *TLS, int num, unsigned char *buf); void bl_do_set_msg_id (struct tgl_state *TLS, struct tgl_message_id *old_id, struct tgl_message_id *new_id); void bl_do_message_delete (struct tgl_state *TLS, struct tgl_message_id *id); void bl_do_peer_delete (struct tgl_state *TLS, tgl_peer_id_t id); void bl_do_chat_add_user (struct tgl_state *TLS, tgl_peer_id_t id, int version, int user, int inviter, int date); void bl_do_chat_del_user (struct tgl_state *TLS, tgl_peer_id_t id, int version, int user); void bl_do_msg_update (struct tgl_state *TLS, struct tgl_message_id *id); void bl_do_reset_authorization (struct tgl_state *TLS); void bl_do_edit_message (struct tgl_state *TLS, struct tgl_message_id *id, tgl_peer_id_t *from_id, tgl_peer_id_t *to_id, tgl_peer_id_t *fwd_from_id, int *fwd_date, int *date, const char *message, int message_len, struct tl_ds_message_media *media, struct tl_ds_message_action *action, int *reply_id, struct tl_ds_reply_markup *reply_markup, struct tl_ds_vector *entities, int flags); void bl_do_edit_message_encr (struct tgl_state *TLS, struct tgl_message_id *id, tgl_peer_id_t *from_id, tgl_peer_id_t *to_id, int *date, const char *message, int message_len, struct tl_ds_decrypted_message_media *media, struct tl_ds_decrypted_message_action *action, struct tl_ds_encrypted_file *file, int flags); void bl_do_encr_chat_exchange (struct tgl_state *TLS, tgl_peer_id_t id, long long *exchange_id, const void *key, int *state); void bl_do_user (struct tgl_state *TLS, int id, long long *access_hash, const char *first_name, int first_name_len, const char *last_name, int last_name_len, const char *phone, int phone_len, const char *username, int username_len, struct tl_ds_photo *photo, struct tl_ds_user_profile_photo *profile_photo, int *last_read_in, int *last_read_out, struct tl_ds_bot_info *bot_info, int flags); void bl_do_chat (struct tgl_state *TLS, int id, const char *title, int title_len, int *user_num, int *date, int *version, struct tl_ds_vector *participants, struct tl_ds_chat_photo *chat_photo, struct tl_ds_photo *photo, int *admin, int *last_read_in, int *last_read_out, int flags); void bl_do_encr_chat (struct tgl_state *TLS, int id, long long *access_hash, int *date, int *admin, int *user_id, void *key, void *g_key, void *first_key_id, int *state, int *ttl, int *layer, int *in_seq_no, int *last_in_seq_no, int *out_seq_no, long long *key_fingerprint, int flags, const char *print_name, int print_name_len); void bl_do_channel (struct tgl_state *TLS, int id, long long *access_hash, int *date, const char *title, int title_len, const char *username, int username_len, struct tl_ds_chat_photo *chat_photo, struct tl_ds_photo *photo, int *version, char *about, int about_len, int *participants_count, int *admins_count, int *kicked_count, int *last_read_in, int flags); void bl_do_peer_delete (struct tgl_state *TLS, tgl_peer_id_t id); #ifdef __cplusplus } #endif #endif telegram-purple/tgl/tgl-fetch.h000066400000000000000000000105261357227200100170020ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2014-2015 */ #ifndef __TGL_FETCH_H__ #define __TGL_FETCH_H__ #include "tgl.h" #include "auto/auto-types.h" struct tgl_user *tglf_fetch_alloc_user (struct tgl_state *TLS, struct tl_ds_user *DS_U); struct tgl_user *tglf_fetch_alloc_user_full (struct tgl_state *TLS, struct tl_ds_user_full *DS_U); struct tgl_chat *tglf_fetch_alloc_chat (struct tgl_state *TLS, struct tl_ds_chat *DS_C); struct tgl_chat *tglf_fetch_alloc_chat_full (struct tgl_state *TLS, struct tl_ds_messages_chat_full *DS_MCF); struct tgl_channel *tglf_fetch_alloc_channel (struct tgl_state *TLS, struct tl_ds_chat *DS_C); struct tgl_channel *tglf_fetch_alloc_channel_full (struct tgl_state *TLS, struct tl_ds_messages_chat_full *DS_MCF); struct tgl_secret_chat *tglf_fetch_alloc_encrypted_chat (struct tgl_state *TLS, struct tl_ds_encrypted_chat *DS_EC); struct tgl_message *tglf_fetch_alloc_message (struct tgl_state *TLS, struct tl_ds_message *DS_M, int *new_msg); struct tgl_message *tglf_fetch_alloc_message_short_buf (struct tgl_state *TLS); struct tgl_message *tglf_fetch_alloc_message_short_chat_buf (struct tgl_state *TLS); struct tgl_message *tglf_fetch_alloc_encrypted_message (struct tgl_state *TLS, struct tl_ds_encrypted_message *DS_EM); tgl_peer_id_t tglf_fetch_peer_id (struct tgl_state *TLS, struct tl_ds_peer *DS_P); long long tglf_fetch_user_photo (struct tgl_state *TLS, struct tgl_user *U, struct tl_ds_user_profile_photo *DS_UPP); void tglf_fetch_message_media (struct tgl_state *TLS, struct tgl_message_media *M, struct tl_ds_message_media *DS_MM); void tglf_fetch_message_action (struct tgl_state *TLS, struct tgl_message_action *M, struct tl_ds_message_action *DS_MA); //void tglf_fetch_chat_full (struct tgl_state *TLS, struct tgl_chat *C); void tglf_fetch_encrypted_message_file (struct tgl_state *TLS, struct tgl_message_media *M, struct tl_ds_encrypted_file *DS_EF); void tglf_fetch_message_media_encrypted (struct tgl_state *TLS, struct tgl_message_media *M, struct tl_ds_decrypted_message_media *DS_DMM); void tglf_fetch_message_action_encrypted (struct tgl_state *TLS, struct tgl_message_action *M, struct tl_ds_decrypted_message_action *DS_DMA); int tglf_fetch_user_status (struct tgl_state *TLS, struct tgl_user_status *S, struct tgl_user *U, struct tl_ds_user_status *DS_US); enum tgl_typing_status tglf_fetch_typing (struct tl_ds_send_message_action *DS_SMA); void tglf_fetch_chat_participants (struct tgl_state *TLS, struct tgl_chat *C, struct tl_ds_chat_participants *DS_CP); void tglf_fetch_int_array (int *dst, struct tl_ds_vector *src, int len); void tglf_fetch_int_tuple (int *dst, int **src, int len); int tglf_fetch_file_location (struct tgl_state *TLS, struct tgl_file_location *loc, struct tl_ds_file_location *DS_FL); void tglf_fetch_message_short (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_updates *DS_U); void tglf_fetch_message_short_chat (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_updates *DS_U); struct tgl_message *tglf_fetch_alloc_message_short (struct tgl_state *TLS, struct tl_ds_updates *DS_U); struct tgl_message *tglf_fetch_alloc_message_short_chat (struct tgl_state *TLS, struct tl_ds_updates *DS_U); struct tgl_photo *tglf_fetch_alloc_photo (struct tgl_state *TLS, struct tl_ds_photo *DS_P); struct tgl_bot_info *tglf_fetch_alloc_bot_info (struct tgl_state *TLS, struct tl_ds_bot_info *DS_BI); struct tgl_message_reply_markup *tglf_fetch_alloc_reply_markup (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_reply_markup *DS_RM); void tglf_fetch_message_entities (struct tgl_state *TLS, struct tgl_message *M, struct tl_ds_vector *DS); #endif telegram-purple/tgl/tgl-inner.h000066400000000000000000000020741357227200100170230ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2014-2015 */ #ifndef __TGL_INNER_H__ #define __TGL_INNER_H__ #ifndef vlogprintf #define vlogprintf(verbosity_level,...) \ do { \ if (TLS->verbosity >= verbosity_level) { \ TLS->callback.logprintf (__VA_ARGS__); \ } \ } while (0) #endif #endif telegram-purple/tgl/tgl-layout.h000066400000000000000000000333561357227200100172340ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2014-2015 */ #ifndef __TGL_LAYOUT_H__ #define __TGL_LAYOUT_H__ #define TGLDF_IMAGE 1 #define TGLDF_STICKER 2 #define TGLDF_ANIMATED 4 #define TGLDF_AUDIO 8 #define TGLDF_VIDEO 16 #define TGLMF_UNREAD 1 #define TGLMF_OUT 2 #define TGLMF_DISABLE_PREVIEW 4 #define TGLMF_MENTION 16 #define TGLMF_CREATED (1 << 8) #define TGLMF_PENDING (1 << 9) #define TGLMF_DELETED (1 << 10) #define TGLMF_ENCRYPTED (1 << 11) #define TGLMF_EMPTY (1 << 12) #define TGLMF_SERVICE (1 << 13) #define TGLMF_SESSION_OUTBOUND (1 << 14) #define TGLMF_POST_AS_CHANNEL (1 << 8) #define TGLMF_HTML (1 << 9) #define TGLMF_CREATE 0x10000 #define TGLPF_CREATED (1 << 0) #define TGLPF_CREATE 0x80000000 #define TGLPF_HAS_PHOTO (1 << 1) #define TGLPF_DELETED (1 << 2) #define TGLPF_OFFICIAL (1 << 3) #define TGLPF_KICKED (1 << 4) #define TGLPF_ADMIN (1 << 5) #define TGLPF_CREATOR (1 << 6) #define TGLPF_LEFT (1 << 7) #define TGLPF_DEACTIVATED (1 << 8) #define TGLUF_CONTACT (1 << 16) #define TGLUF_MUTUAL_CONTACT (1 << 17) #define TGLUF_BLOCKED (1 << 18) #define TGLUF_SELF (1 << 19) #define TGLUF_CREATED TGLPF_CREATED #define TGLUF_DELETED TGLPF_DELETED #define TGLUF_HAS_PHOTO TGLPF_HAS_PHOTO #define TGLUF_CREATE TGLPF_CREATE #define TGLUF_BOT (1 << 20) #define TGLUF_OFFICIAL TGLPF_OFFICIAL #define TGLUF_TYPE_MASK \ (TGLUF_CONTACT | TGLUF_MUTUAL_CONTACT | TGLUF_BLOCKED | TGLUF_SELF | TGLUF_CREATED | TGLUF_DELETED | TGLUF_OFFICIAL) #define TGLCF_CREATED TGLPF_CREATED #define TGLCF_CREATE TGLPF_CREATE #define TGLCF_HAS_PHOTO TGLPF_HAS_PHOTO #define TGLCF_KICKED TGLPF_KICKED #define TGLCF_CREATOR TGLPF_CREATOR #define TGLCF_ADMIN TGLPF_ADMIN #define TGLCF_OFFICIAL TGLPF_OFFICIAL #define TGLCF_LEFT TGLPF_LEFT #define TGLCF_DEACTIVATED TGLPF_DEACTIVATED #define TGLCF_ADMINS_ENABLED (1 << 16) #define TGLCF_TYPE_MASK \ (TGLCF_CREATED | TGLCF_KICKED | TGLCF_CREATOR | TGLCF_ADMIN | TGLCF_OFFICIAL | TGLCF_LEFT | TGLCF_DEACTIVATED | TGLCF_ADMINS_ENABLED) #define TGLECF_CREATED TGLPF_CREATED #define TGLECF_CREATE TGLPF_CREATE #define TGLECF_HAS_PHOTO TGLPF_HAS_PHOTO #define TGLECF_KICKED TGLPF_KICKED #define TGLECF_CREATOR TGLPF_CREATOR #define TGLECF_ADMIN TGLPF_ADMIN #define TGLECF_TYPE_MASK \ (TGLECF_CREATED | TGLECF_KICKED | TGLECF_CREATOR | TGLECF_ADMIN) #define TGLCHF_CREATED TGLPF_CREATED #define TGLCHF_CREATE TGLPF_CREATE #define TGLCHF_HAS_PHOTO TGLPF_HAS_PHOTO #define TGLCHF_KICKED TGLPF_KICKED #define TGLCHF_CREATOR TGLPF_CREATOR #define TGLCHF_ADMIN TGLPF_ADMIN #define TGLCHF_OFFICIAL TGLPF_OFFICIAL #define TGLCHF_LEFT TGLPF_LEFT #define TGLCHF_DEACTIVATED TGLPF_DEACTIVATED #define TGLCHF_BROADCAST (1 << 16) #define TGLCHF_EDITOR (1 << 17) #define TGLCHF_MODERATOR (1 << 18) #define TGLCHF_MEGAGROUP (1 << 19) #define TGLCHF_TYPE_MASK \ (TGLCHF_CREATED | TGLCHF_KICKED | TGLCHF_CREATOR | TGLCHF_ADMIN | TGLCHF_OFFICIAL | TGLCHF_LEFT | TGLCHF_DEACTIVATED | TGLCHF_BROADCAST | TGLCHF_EDITOR | TGLCHF_MODERATOR | TGLCHF_MEGAGROUP) #define TGLCHF_DIFF 0x20000000 #define TGL_FLAGS_UNCHANGED 0x40000000 #define TGLDCF_AUTHORIZED 1 #define TGLDCF_LOGGED_IN 8 #define TGL_PERMANENT_ID_SIZE 24 #pragma pack(push,4) typedef struct { int peer_type; int peer_id; long long access_hash; } tgl_peer_id_t; enum tgl_dc_state { st_init, st_reqpq_sent, st_reqdh_sent, st_client_dh_sent, st_init_temp, st_reqpq_sent_temp, st_reqdh_sent_temp, st_client_dh_sent_temp, st_authorized, st_error }; #define MAX_DC_SESSIONS 3 struct tgl_session { struct tgl_dc *dc; long long session_id; long long last_msg_id; // See tglmp_encrypt_send_message int seq_no; int received_messages; struct connection *c; struct tree_long *ack_tree; struct tgl_timer *ev; }; struct tgl_dc_option { struct tgl_dc_option *next; char *ip; int port; }; struct tgl_dc { int id; //int port; int flags; int rsa_key_idx; enum tgl_dc_state state; //char *ip; //char *user; struct tgl_session *sessions[MAX_DC_SESSIONS]; char auth_key[256]; char temp_auth_key[256]; char nonce[256]; char new_nonce[256]; char server_nonce[256]; long long auth_key_id; long long temp_auth_key_id; long long temp_auth_key_bind_query_id; long long server_salt; struct tgl_timer *ev; int server_time_delta; double server_time_udelta; // ipv4, ipv6, ipv4_media, ipv6_media struct tgl_dc_option *options[4]; }; enum tgl_message_entity_type { tgl_message_entity_unknown, tgl_message_entity_mention, tgl_message_entity_hashtag, tgl_message_entity_bot_command, tgl_message_entity_url, tgl_message_entity_email, tgl_message_entity_bold, tgl_message_entity_italic, tgl_message_entity_code, tgl_message_entity_pre, tgl_message_entity_text_url }; struct tgl_message_entity { enum tgl_message_entity_type type; int start; int length; char *extra; }; enum tgl_message_media_type { tgl_message_media_none, tgl_message_media_photo, tgl_message_media_document, tgl_message_media_geo, tgl_message_media_contact, tgl_message_media_unsupported, //tgl_message_media_photo_encr, //tgl_message_media_video_encr, //tgl_message_media_audio_encr, tgl_message_media_document_encr, tgl_message_media_webpage, tgl_message_media_venue, tgl_message_media_video, tgl_message_media_audio }; enum tgl_message_action_type { tgl_message_action_none, tgl_message_action_geo_chat_create, tgl_message_action_geo_chat_checkin, tgl_message_action_chat_create, tgl_message_action_chat_edit_title, tgl_message_action_chat_edit_photo, tgl_message_action_chat_delete_photo, tgl_message_action_chat_add_users, tgl_message_action_chat_add_user_by_link, tgl_message_action_chat_delete_user, tgl_message_action_set_message_ttl, tgl_message_action_read_messages, tgl_message_action_delete_messages, tgl_message_action_screenshot_messages, tgl_message_action_flush_history, tgl_message_action_resend, tgl_message_action_notify_layer, tgl_message_action_typing, tgl_message_action_noop, tgl_message_action_commit_key, tgl_message_action_abort_key, tgl_message_action_request_key, tgl_message_action_accept_key, tgl_message_action_channel_create, tgl_message_action_migrated_to, tgl_message_action_migrated_from }; enum tgl_typing_status { tgl_typing_none, tgl_typing_typing, tgl_typing_cancel, tgl_typing_record_video, tgl_typing_upload_video, tgl_typing_record_audio, tgl_typing_upload_audio, tgl_typing_upload_photo, tgl_typing_upload_document, tgl_typing_geo, tgl_typing_choose_contact }; struct tgl_file_location { int dc; long long volume; int local_id; long long secret; }; struct tgl_photo_size { char *type; struct tgl_file_location loc; int w; int h; int size; char *data; }; struct tgl_geo { double longitude; double latitude; }; struct tgl_photo { long long id; long long access_hash; int refcnt; //int user_id; int date; char *caption; //struct tgl_geo geo; int sizes_num; struct tgl_photo_size *sizes; }; struct tgl_encr_document { long long id; long long access_hash; int refcnt; int dc_id; int size; int key_fingerprint; int flags; unsigned char *key; unsigned char *iv; int w; int h; char *caption; char *mime_type; int duration; }; struct tgl_user_status { int online; int when; struct tgl_timer *ev; }; struct tgl_bot_command { char *command; char *description; }; struct tgl_bot_info { int version; char *share_text; char *description; int commands_num; struct tgl_bot_command *commands; }; struct tgl_user { tgl_peer_id_t id; int flags; struct tgl_message *last; char *print_name; char *username; int structure_version; struct tgl_file_location photo_big; struct tgl_file_location photo_small; int last_read_in; int last_read_out; long long photo_id; struct tgl_photo *photo; void *extra; char *first_name; char *last_name; char *phone; long long access_hash; struct tgl_user_status status; int blocked; char *real_first_name; char *real_last_name; int bot; struct tgl_bot_info *bot_info; }; struct tgl_channel { tgl_peer_id_t id; int flags; struct tgl_message *last; char *print_title; char *username; int structure_version; struct tgl_file_location photo_big; struct tgl_file_location photo_small; int last_read_in; int last_read_out; long long photo_id; struct tgl_photo *photo; void *extra; long long access_hash; int date; char *title; int version; char *about; int participants_count; int admins_count; int kicked_count; int pts; }; struct tgl_chat_user { int user_id; int inviter_id; int date; }; struct tgl_chat { tgl_peer_id_t id; int flags; struct tgl_message *last; char *print_title; char *username; int structure_version; struct tgl_file_location photo_big; struct tgl_file_location photo_small; int last_read_in; int last_read_out; long long pad; struct tgl_photo *photo; void *extra; char *title; int users_num; int user_list_size; int user_list_version; struct tgl_chat_user *user_list; int date; int version; int admin_id; }; enum tgl_secret_chat_state { sc_none, sc_waiting, sc_request, sc_ok, sc_deleted }; enum tgl_secret_chat_exchange_state { tgl_sce_none, tgl_sce_requested, tgl_sce_accepted, tgl_sce_committed, tgl_sce_confirmed, tgl_sce_aborted }; struct tgl_secret_chat { tgl_peer_id_t id; int flags; struct tgl_message *last; char *print_name; char *username; int structure_version; struct tgl_file_location photo_big; struct tgl_file_location photo_small; int pad1; int pad2; long long pad; struct tgl_photo *photo; void *extra; int user_id; int admin_id; int date; int ttl; int layer; int in_seq_no; int out_seq_no; int last_in_seq_no; long long access_hash; unsigned char *g_key; enum tgl_secret_chat_state state; int key[64]; long long key_fingerprint; unsigned char first_key_sha[20]; long long exchange_id; enum tgl_secret_chat_exchange_state exchange_state; int exchange_key[64]; long long exchange_key_fingerprint; }; typedef union tgl_peer { struct { tgl_peer_id_t id; int flags; struct tgl_message *last; char *print_name; char *username; int structure_version; struct tgl_file_location photo_big; struct tgl_file_location photo_small; struct tgl_photo *photo; int last_read_in; int last_read_out; long long photo_id; void *extra; }; struct tgl_user user; struct tgl_chat chat; struct tgl_channel channel; struct tgl_secret_chat encr_chat; } tgl_peer_t; struct tgl_document { long long id; long long access_hash; int refcnt; //int user_id; int date; int size; int dc_id; struct tgl_photo_size thumb; char *caption; char *mime_type; int w; int h; int flags; int duration; }; struct tgl_message_action { enum tgl_message_action_type type; union { struct { char *title; int user_num; int *users; }; char *new_title; struct tgl_photo *photo; int user; int ttl; int layer; int read_cnt; int delete_cnt; int screenshot_cnt; int channel_id; enum tgl_typing_status typing; struct { int start_seq_no; int end_seq_no; }; struct { unsigned char *g_a; long long exchange_id; long long key_fingerprint; }; }; }; struct tgl_webpage { long long id; int refcnt; char *url; char *display_url; char *type; char *site_name; char *title; char *description; struct tgl_photo *photo; char *embed_url; char *embed_type; int embed_width; int embed_height; int duration; char *author; }; struct tgl_message_media { enum tgl_message_media_type type; union { struct { union { struct tgl_photo *photo; struct tgl_document *document; }; char *caption; }; struct tgl_encr_document *encr_document; struct tgl_webpage *webpage; struct tgl_geo geo; struct { char *phone; char *first_name; char *last_name; int user_id; }; struct { void *data; int data_size; }; struct { struct tgl_geo geo; char *title; char *address; char *provider; char *venue_id; } venue; }; }; typedef struct tgl_message_reply_markup { int refcnt; int flags; int rows; int *row_start; char **buttons; } tgl_message_reply_markup; typedef struct tgl_message_id { unsigned peer_type; unsigned peer_id; long long id; long long access_hash; } tgl_message_id_t; struct tgl_message { struct tgl_message *next_use, *prev_use; struct tgl_message *next, *prev; int temp_id; long long server_id; long long random_id; struct tgl_message_id permanent_id; int flags; tgl_peer_id_t fwd_from_id; int fwd_date; int reply_id; tgl_peer_id_t from_id; tgl_peer_id_t to_id; int date; struct tgl_message_reply_markup *reply_markup; int entities_num; struct tgl_message_entity *entities; union { struct tgl_message_action action; struct { char *message; int message_len; struct tgl_message_media media; }; }; }; #pragma pack(pop) #endif telegram-purple/tgl/tgl-methods-in.h000066400000000000000000000062441357227200100177620ustar00rootroot00000000000000// normally you should not use these methods // use them with caution #ifndef __TGL_METHODS_IN_H__ #define __TGL_METHODS_IN_H__ /* {{{ AUTHORIZATION METHODS. NORMALLY YOU DON'T NEED THEM */ // send query to updated DCs' ips // automatically renews data on update void tgl_do_help_get_config (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // requests server to send code to specified phone number // if user is logged in elsewhere message will first appear as telegram message // and SMS will be sent some time after void tgl_do_send_code (struct tgl_state *TLS, const char *phone, int phone_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int registered, const char *hash), void *callback_extra); // request server to send code via phone call void tgl_do_phone_call (struct tgl_state *TLS, const char *phone, int phone_len, const char *hash, int hash_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // sends code from SMS to server. This step should end authorization, unless user have password int tgl_do_send_code_result (struct tgl_state *TLS, const char *phone, int phone_len, const char *hash, int hash_len, const char *code, int code_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *Self), void *callback_extra); // sends code from SMS, username and lastname to server. This step should end new user registration int tgl_do_send_code_result_auth (struct tgl_state *TLS, const char *phone, int phone_len, const char *hash, int hash_len, const char *code, int code_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *Self), void *callback_extra); /* }}} */ void tgl_do_send_msg (struct tgl_state *TLS, struct tgl_message *M, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); void tgl_do_check_password (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, void *extra, int success), void *callback_extra); void tgl_do_export_auth (struct tgl_state *TLS, int num, void (*callback) (struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_create_secret_chat (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra); void tgl_do_get_difference (struct tgl_state *TLS, int sync_from_start, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_lookup_state (struct tgl_state *TLS); void tgl_do_help_get_config_dc (struct tgl_state *TLS, struct tgl_dc *D, void (*callback)(struct tgl_state *TLS, void *, int), void *callback_extra); void tgl_do_request_exchange (struct tgl_state *TLS, struct tgl_secret_chat *E); void tgl_do_create_keys_end (struct tgl_state *TLS, struct tgl_secret_chat *U); void tgl_do_send_encr_chat_layer (struct tgl_state *TLS, struct tgl_secret_chat *E); #endif telegram-purple/tgl/tgl-net-inner.h000066400000000000000000000052301357227200100176040ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifndef __NET_H__ #define __NET_H__ struct connection_buffer { unsigned char *start; unsigned char *end; unsigned char *rptr; unsigned char *wptr; struct connection_buffer *next; }; enum conn_state { conn_none, conn_connecting, conn_ready, conn_failed, conn_stopped }; struct connection { int fd; char *ip; int port; int flags; enum conn_state state; int ipv6[4]; struct connection_buffer *in_head; struct connection_buffer *in_tail; struct connection_buffer *out_head; struct connection_buffer *out_tail; int in_bytes; int out_bytes; int packet_num; int out_packet_num; int last_connect_time; int in_fail_timer; struct mtproto_methods *methods; struct tgl_state *TLS; struct tgl_session *session; struct tgl_dc *dc; void *extra; struct event *ping_ev; struct event *fail_ev; struct event *read_ev; struct event *write_ev; double last_receive_time; }; //extern struct connection *Connections[]; int tgln_write_out (struct connection *c, const void *data, int len); void tgln_flush_out (struct connection *c); int tgln_read_in (struct connection *c, void *data, int len); int tgln_read_in_lookup (struct connection *c, void *data, int len); //void tgln_insert_msg_id (struct tgl_session *S, long long id); extern struct tgl_net_methods tgl_conn_methods; //void create_all_outbound_connections (void); //struct connection *create_connection (const char *host, int port, struct tgl_session *session, struct connection_methods *methods); //struct tgl_dc *tgln_alloc_dc (int id, char *ip, int port); //void tgln_dc_create_session (struct tgl_dc *DC, struct mtproto_methods *methods); struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods); #define GET_DC(c) (c->session->dc) #endif telegram-purple/tgl/tgl-net.c000066400000000000000000000362521357227200100164760ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "crypto/rand.h" #include #ifdef EVENT_V2 #include #else #include #include "event-old.h" #endif #include #include #include "tgl-net-inner.h" #include "tgl-net.h" #include "tgl.h" #include "tgl-inner.h" //#include "mtproto-client.h" //#include "mtproto-common.h" #include "tree.h" #include "tools.h" #include "mtproto-client.h" #ifndef POLLRDHUP #define POLLRDHUP 0 #endif //double get_utime (int clock_id); //extern struct mtproto_methods auth_methods; static void fail_connection (struct connection *c); #define PING_TIMEOUT 10 static void start_ping_timer (struct connection *c); static void ping_alarm (evutil_socket_t fd, short what, void *arg) { struct connection *c = arg; struct tgl_state *TLS = c->TLS; vlogprintf (E_DEBUG + 2,"ping alarm\n"); assert (c->state == conn_ready || c->state == conn_connecting); if (tglt_get_double_time () - c->last_receive_time > 6 * PING_TIMEOUT) { vlogprintf (E_WARNING, "fail connection: reason: ping timeout\n"); c->state = conn_failed; fail_connection (c); } else if (tglt_get_double_time () - c->last_receive_time > 3 * PING_TIMEOUT && c->state == conn_ready) { tgl_do_send_ping (c->TLS, c); start_ping_timer (c); } else { start_ping_timer (c); } } static void stop_ping_timer (struct connection *c) { event_del (c->ping_ev); } static void start_ping_timer (struct connection *c) { static struct timeval ptimeout = { PING_TIMEOUT, 0}; event_add (c->ping_ev, &ptimeout); } static void restart_connection (struct connection *c); static void fail_alarm (evutil_socket_t fd, short what, void *arg) { struct connection *c = arg; c->in_fail_timer = 0; restart_connection (c); } static void start_fail_timer (struct connection *c) { if (c->in_fail_timer) { return; } c->in_fail_timer = 1; static struct timeval ptimeout = { 10, 0}; event_add (c->fail_ev, &ptimeout); } static struct connection_buffer *new_connection_buffer (int size) { struct connection_buffer *b = talloc0 (sizeof (*b)); b->start = talloc (size); b->end = b->start + size; b->rptr = b->wptr = b->start; return b; } static void delete_connection_buffer (struct connection_buffer *b) { tfree (b->start, b->end - b->start); tfree (b, sizeof (*b)); } int tgln_write_out (struct connection *c, const void *_data, int len) { struct tgl_state *TLS = c->TLS; vlogprintf (E_DEBUG, "write_out: %d bytes\n", len); const unsigned char *data = _data; if (!len) { return 0; } assert (len > 0); int x = 0; if (!c->out_bytes) { event_add (c->write_ev, 0); } if (!c->out_head) { struct connection_buffer *b = new_connection_buffer (1 << 20); c->out_head = c->out_tail = b; } while (len) { if (c->out_tail->end - c->out_tail->wptr >= len) { memcpy (c->out_tail->wptr, data, len); c->out_tail->wptr += len; c->out_bytes += len; return x + len; } else { int y = c->out_tail->end - c->out_tail->wptr; assert (y < len); memcpy (c->out_tail->wptr, data, y); x += y; len -= y; data += y; struct connection_buffer *b = new_connection_buffer (1 << 20); c->out_tail->next = b; b->next = 0; c->out_tail = b; c->out_bytes += y; } } return x; } int tgln_read_in (struct connection *c, void *_data, int len) { unsigned char *data = _data; if (!len) { return 0; } assert (len > 0); if (len > c->in_bytes) { len = c->in_bytes; } int x = 0; while (len) { int y = c->in_head->wptr - c->in_head->rptr; if (y > len) { memcpy (data, c->in_head->rptr, len); c->in_head->rptr += len; c->in_bytes -= len; return x + len; } else { memcpy (data, c->in_head->rptr, y); c->in_bytes -= y; x += y; data += y; len -= y; void *old = c->in_head; c->in_head = c->in_head->next; if (!c->in_head) { c->in_tail = 0; } delete_connection_buffer (old); } } return x; } int tgln_read_in_lookup (struct connection *c, void *_data, int len) { unsigned char *data = _data; if (!len || !c->in_bytes) { return 0; } assert (len > 0); if (len > c->in_bytes) { len = c->in_bytes; } int x = 0; struct connection_buffer *b = c->in_head; while (len) { int y = b->wptr - b->rptr; if (y >= len) { memcpy (data, b->rptr, len); return x + len; } else { memcpy (data, b->rptr, y); x += y; data += y; len -= y; b = b->next; } } return x; } void tgln_flush_out (struct connection *c) { } #define MAX_CONNECTIONS 100 static struct connection *Connections[MAX_CONNECTIONS]; static int max_connection_fd; static void rotate_port (struct connection *c) { switch (c->port) { case 443: c->port = 80; break; case 80: c->port = 25; break; case 25: c->port = 443; break; } } static void try_read (struct connection *c); static void try_write (struct connection *c); static void conn_try_read (evutil_socket_t fd, short what, void *arg) { struct connection *c = arg; struct tgl_state *TLS = c->TLS; vlogprintf (E_DEBUG + 1, "Try read. Fd = %d\n", c->fd); try_read (c); } static void conn_try_write (evutil_socket_t fd, short what, void *arg) { struct connection *c = arg; struct tgl_state *TLS = c->TLS; if (c->state == conn_connecting) { c->state = conn_ready; c->methods->ready (TLS, c); } try_write (c); if (c->out_bytes) { event_add (c->write_ev, 0); } } static int my_connect (struct connection *c, const char *host) { struct tgl_state *TLS = c->TLS; int v6 = TLS->ipv6_enabled; int fd = socket (v6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0); if (fd < 0) { vlogprintf (E_ERROR, "Can not create socket: %s\n", strerror(errno)); start_fail_timer (c); return -1; } assert (fd >= 0 && fd < MAX_CONNECTIONS); if (fd > max_connection_fd) { max_connection_fd = fd; } int flags = -1; setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags)); setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags)); struct sockaddr_in addr; struct sockaddr_in6 addr6; memset (&addr, 0, sizeof (addr)); memset (&addr6, 0, sizeof (addr6)); if (v6) { addr6.sin6_family = AF_INET6; addr6.sin6_port = htons (c->port); if (inet_pton (AF_INET6, host, &addr6.sin6_addr.s6_addr) != 1) { vlogprintf (E_ERROR, "Bad ipv6 %s\n", host); close (fd); return -1; } } else { addr.sin_family = AF_INET; addr.sin_port = htons (c->port); if (inet_pton (AF_INET, host, &addr.sin_addr.s_addr) != 1) { vlogprintf (E_ERROR, "Bad ipv4 %s\n", host); close (fd); return -1; } } fcntl (fd, F_SETFL, O_NONBLOCK); if (connect (fd, (struct sockaddr *) (v6 ? (void *)&addr6 : (void *)&addr), v6 ? sizeof (addr6) : sizeof (addr)) == -1) { if (errno != EINPROGRESS) { close (fd); return -1; } } return fd; } struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods) { struct connection *c = talloc0 (sizeof (*c)); c->TLS = TLS; c->ip = tstrdup (host); c->port = port; int fd = my_connect (c, c->ip); if (fd < 0) { vlogprintf (E_ERROR, "Can not connect to %s:%d %s\n", host, port, strerror(errno)); tfree (c, sizeof (*c)); return 0; } c->fd = fd; c->state = conn_connecting; c->last_receive_time = tglt_get_double_time (); c->flags = 0; assert (!Connections[fd]); Connections[fd] = c; c->ping_ev = evtimer_new (TLS->ev_base, ping_alarm, c); c->fail_ev = evtimer_new (TLS->ev_base, fail_alarm, c); c->write_ev = event_new (TLS->ev_base, c->fd, EV_WRITE, conn_try_write, c); struct timeval tv = {5, 0}; c->read_ev = event_new (TLS->ev_base, c->fd, EV_READ | EV_PERSIST, conn_try_read, c); event_add (c->read_ev, &tv); start_ping_timer (c); c->dc = dc; c->session = session; c->methods = methods; char byte = 0xef; assert (tgln_write_out (c, &byte, 1) == 1); tgln_flush_out (c); return c; } static void restart_connection (struct connection *c) { struct tgl_state *TLS = c->TLS; if (c->last_connect_time == time (0)) { start_fail_timer (c); return; } /*if (strcmp (c->ip, c->dc->ip)) { tfree_str (c->ip); c->ip = tstrdup (c->dc->ip); }*/ c->last_connect_time = time (0); int fd = my_connect (c, c->ip); if (fd < 0) { vlogprintf (E_WARNING, "Can not connect to %s:%d %s\n", c->ip, c->port, strerror(errno)); start_fail_timer (c); return; } c->fd = fd; c->state = conn_connecting; c->last_receive_time = tglt_get_double_time (); start_ping_timer (c); Connections[fd] = c; c->write_ev = event_new (TLS->ev_base, c->fd, EV_WRITE, conn_try_write, c); struct timeval tv = {5, 0}; c->read_ev = event_new (TLS->ev_base, c->fd, EV_READ | EV_PERSIST, conn_try_read, c); event_add (c->read_ev, &tv); char byte = 0xef; assert (tgln_write_out (c, &byte, 1) == 1); tgln_flush_out (c); } static void fail_connection (struct connection *c) { struct tgl_state *TLS = c->TLS; if (c->state == conn_ready || c->state == conn_connecting) { stop_ping_timer (c); } event_free (c->write_ev); event_free (c->read_ev); rotate_port (c); struct connection_buffer *b = c->out_head; while (b) { struct connection_buffer *d = b; b = b->next; delete_connection_buffer (d); } b = c->in_head; while (b) { struct connection_buffer *d = b; b = b->next; delete_connection_buffer (d); } c->out_head = c->out_tail = c->in_head = c->in_tail = 0; c->state = conn_failed; c->out_bytes = c->in_bytes = 0; close (c->fd); Connections[c->fd] = 0; vlogprintf (E_NOTICE, "Lost connection to server... %s:%d\n", c->ip, c->port); restart_connection (c); } //extern FILE *log_net_f; static void try_write (struct connection *c) { struct tgl_state *TLS = c->TLS; vlogprintf (E_DEBUG, "try write: fd = %d\n", c->fd); int x = 0; while (c->out_head) { int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); if (r >= 0) { x += r; c->out_head->rptr += r; if (c->out_head->rptr != c->out_head->wptr) { break; } struct connection_buffer *b = c->out_head; c->out_head = b->next; if (!c->out_head) { c->out_tail = 0; } delete_connection_buffer (b); } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { vlogprintf (E_NOTICE, "fail_connection: write_error %s\n", strerror(errno)); fail_connection (c); return; } else { break; } } } vlogprintf (E_DEBUG, "Sent %d bytes to %d\n", x, c->fd); c->out_bytes -= x; } static void try_rpc_read (struct connection *c) { assert (c->in_head); struct tgl_state *TLS = c->TLS; while (1) { if (c->in_bytes < 1) { return; } unsigned len = 0; unsigned t = 0; assert (tgln_read_in_lookup (c, &len, 1) == 1); if (len >= 1 && len <= 0x7e) { if (c->in_bytes < (int)(1 + 4 * len)) { return; } } else { if (c->in_bytes < 4) { return; } assert (tgln_read_in_lookup (c, &len, 4) == 4); len = (len >> 8); if (c->in_bytes < (int)(4 + 4 * len)) { return; } len = 0x7f; } if (len >= 1 && len <= 0x7e) { assert (tgln_read_in (c, &t, 1) == 1); assert (t == len); assert (len >= 1); } else { assert (len == 0x7f); assert (tgln_read_in (c, &len, 4) == 4); len = (len >> 8); assert (len >= 1); } len *= 4; int op; assert (tgln_read_in_lookup (c, &op, 4) == 4); if (c->methods->execute (TLS, c, op, len) < 0) { return; } } } static void try_read (struct connection *c) { struct tgl_state *TLS = c->TLS; vlogprintf (E_DEBUG, "try read: fd = %d\n", c->fd); if (!c->in_tail) { c->in_head = c->in_tail = new_connection_buffer (1 << 20); } #ifdef EVENT_V1 struct timeval tv = {5, 0}; event_add (c->read_ev, &tv); #endif int x = 0; while (1) { int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); if (r > 0) { c->last_receive_time = tglt_get_double_time (); stop_ping_timer (c); start_ping_timer (c); } if (r >= 0) { c->in_tail->wptr += r; x += r; if (c->in_tail->wptr != c->in_tail->end) { break; } struct connection_buffer *b = new_connection_buffer (1 << 20); c->in_tail->next = b; c->in_tail = b; } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { vlogprintf (E_NOTICE, "fail_connection: read_error %s\n", strerror(errno)); fail_connection (c); return; } else { break; } } } vlogprintf (E_DEBUG, "Received %d bytes from %d\n", x, c->fd); c->in_bytes += x; if (x) { try_rpc_read (c); } } static void incr_out_packet_num (struct connection *c) { c->out_packet_num ++; } static struct tgl_dc *get_dc (struct connection *c) { return c->dc; } static struct tgl_session *get_session (struct connection *c) { return c->session; } static void tgln_free (struct connection *c) { if (c->ip) { tfree_str (c->ip); } if (c->ping_ev) { event_free (c->ping_ev); } if (c->fail_ev) { event_free (c->fail_ev); } if (c->read_ev) { event_free (c->read_ev); } if (c->write_ev) { event_free (c->write_ev); } struct connection_buffer *b = c->out_head; while (b) { struct connection_buffer *d = b; b = b->next; delete_connection_buffer (d); } b = c->in_head; while (b) { struct connection_buffer *d = b; b = b->next; delete_connection_buffer (d); } if (c->fd >= 0) { Connections[c->fd] = 0; close (c->fd); } tfree (c, sizeof (*c)); } struct tgl_net_methods tgl_conn_methods = { .write_out = tgln_write_out, .read_in = tgln_read_in, .read_in_lookup = tgln_read_in_lookup, .flush_out = tgln_flush_out, .incr_out_packet_num = incr_out_packet_num, .get_dc = get_dc, .get_session = get_session, .create_connection = tgln_create_connection, .free = tgln_free }; telegram-purple/tgl/tgl-net.h000066400000000000000000000016351357227200100165000ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifndef __NET_H__ #define __NET_H__ extern struct tgl_net_methods tgl_conn_methods; #endif telegram-purple/tgl/tgl-queries.h000066400000000000000000000537371357227200100174010ustar00rootroot00000000000000#ifndef __TGL_QUERIES_H__ #define __TGL_QUERIES_H__ #include "tgl.h" #ifdef __cplusplus extern "C" { #endif void tgl_do_get_terms_of_service (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *ans), void *callback_extra); /* {{{ WORK WITH ACCOUNT */ // sets account password // user will be requested to type his current password and new password (twice) void tgl_do_set_password (struct tgl_state *TLS, const char *hint, int hint_len, void (*callback)(struct tgl_state *TLS, void *extra, int success), void *extra); void tgl_do_set_phone_number (struct tgl_state *TLS, const char *phonenumber, int phonenumber_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); /* }}} */ /* {{{ SENDING MESSAGES */ struct tl_ds_reply_markup; // send plain text message to peer id // flags is combination of TGL_SEND_MSG_FLAG_* // reply markup can be NULL void tgl_do_send_message (struct tgl_state *TLS, tgl_peer_id_t peer_id, const char *text, int text_len, unsigned long long flags, struct tl_ds_reply_markup *reply_markup, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // sends plain text reply on message *reply_id* // message *reply_id* should be cached void tgl_do_reply_message (struct tgl_state *TLS, tgl_message_id_t *msg_id, const char *text, int text_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // sends contents of text file *file_name* as plain text message void tgl_do_send_text (struct tgl_state *TLS, tgl_peer_id_t peer_id, const char *file_name, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); void tgl_do_reply_text (struct tgl_state *TLS, tgl_message_id_t *msg_id, const char *file_name, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // send media from file *file_name* to peer *to_id* // if reply > 0 this message is sent as reply to message *reply* // *caption* is used only for photos void tgl_do_send_document (struct tgl_state *TLS, tgl_peer_id_t to_id, const char *file_name, const char *caption, int caption_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); void tgl_do_reply_document (struct tgl_state *TLS, tgl_message_id_t *msg_id, const char *file_name, const char *caption, int caption_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // forward message *msg_id* to peer *id* // message can not be encrypted and peer can not be secret chat void tgl_do_forward_message (struct tgl_state *TLS, tgl_user_or_chat_id_t id, tgl_message_id_t *msg_id, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // forward messages *ids* to peer *id* // messages can not be encrypted and peer can not be secret chat void tgl_do_forward_messages (struct tgl_state *TLS, tgl_user_or_chat_id_t id, int size, const tgl_message_id_t *msg_ids[], unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int count, struct tgl_message *ML[]), void *callback_extra); // sends contact to another user. // This contact may be or may not be telegram user void tgl_do_send_contact (struct tgl_state *TLS, tgl_peer_id_t id, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // reply on message *reply_id* with contact void tgl_do_reply_contact (struct tgl_state *TLS, tgl_message_id_t *reply_id, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // sends media from message *msg_id* to another dialog // a bit different from forwarding message with media // secret message media can be forwarded to secret chats // and non-secret - to non-secret chats and users void tgl_do_forward_media (struct tgl_state *TLS, tgl_peer_id_t id, tgl_message_id_t *msg_id, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // sends location to chat *id* void tgl_do_send_location (struct tgl_state *TLS, tgl_peer_id_t id, double latitude, double longitude, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // replies on message *reply_id* with location void tgl_do_reply_location (struct tgl_state *TLS, tgl_message_id_t *reply_id, double latitude, double longitude, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // sends broadcast (i.e. message to several users at once) // flags are same as in tgl_do_send_message void tgl_do_send_broadcast (struct tgl_state *TLS, int num, tgl_user_id_t id[], const char *text, int text_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]), void *callback_extra); /* }}} */ /* {{{ EDITING SELF PROFILE */ // sets self profile photo // server will cut central square from this photo void tgl_do_set_profile_photo (struct tgl_state *TLS, const char *file_name, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // rename self account void tgl_do_set_profile_name (struct tgl_state *TLS, const char *first_name, int first_name_len, const char *last_name, int last_name_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *U), void *callback_extra); // sets self username void tgl_do_set_username (struct tgl_state *TLS, const char *username, int username_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *U), void *callback_extra); // updates online/offline status void tgl_do_update_status (struct tgl_state *TLS, int online, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // exports card. This card can be later be used by another user to add you to dialog list. void tgl_do_export_card (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, int *card), void *callback_extra); /* }}} */ /* {{{ WORKING WITH GROUP CHATS */ // sets chat photo // server will cut central square from this photo void tgl_do_set_chat_photo (struct tgl_state *TLS, tgl_chat_id_t chat_id, const char *file_name, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // sets chat title void tgl_do_rename_chat (struct tgl_state *TLS, tgl_chat_id_t id, const char *new_title, int new_title_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // requests full info about chat *id*. // if *offline_mode* is set no actual query is sent void tgl_do_get_chat_info (struct tgl_state *TLS, tgl_chat_id_t id, int offline_mode, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_chat *C), void *callback_extra); // adds user *id* to chat *chat_id* // sends *limit* last messages from this chat to user void tgl_do_add_user_to_chat (struct tgl_state *TLS, tgl_chat_id_t chat_id, tgl_user_id_t id, int limit, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // deleted user *id* from chat *chat_id* // you can do it if you are admin (=creator) of chat or if you invited this user or if it is yourself void tgl_do_del_user_from_chat (struct tgl_state *TLS, tgl_chat_id_t chat_id, tgl_user_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // creates group chat with users ids // there should be at least one user other then you in chat void tgl_do_create_group_chat (struct tgl_state *TLS, int users_num, tgl_user_id_t ids[], const char *chat_topic, int chat_topic_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // receives invitation link to this chat // only chat admin can create one // prevoius link invalidated, if existed void tgl_do_export_chat_link (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *link), void *callback_extra); // joins to secret chat by link (or hash of this link) void tgl_do_import_chat_link (struct tgl_state *TLS, const char *link, int link_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // upgrades chat to channel. void tgl_do_upgrade_group (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); /* }}} */ /* {{{ WORKING WITH USERS */ // requests full info about user *id*. // if *offline_mode* is set no actual query is sent void tgl_do_get_user_info (struct tgl_state *TLS, tgl_user_id_t id, int offline_mode, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *U), void *callback_extra); // adds contact to contact list by phone number // user will be named *first_name* *last_name* in contact list // force should be set to 0 void tgl_do_add_contact (struct tgl_state *TLS, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_user *users[]), void *callback_extra); // deletes user *id* from contact list void tgl_do_del_contact (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // imports card exported by another user void tgl_do_import_card (struct tgl_state *TLS, int size, int *card, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *U), void *callback_extra); // blocks user void tgl_do_block_user (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // unblocks blocked user void tgl_do_unblock_user (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); /* }}} */ /* {{{ WORKING WITH SECRET CHATS */ // requests creation of secret chat with user *user_id* //void tgl_do_create_encr_chat_request (struct tgl_state *TLS, int user_id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra); // accepts secret chat request // method can fail if another device will be first to accept it void tgl_do_accept_encr_chat_request (struct tgl_state *TLS, struct tgl_secret_chat *E, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra); // sets ttl of secret chat void tgl_do_set_encr_chat_ttl (struct tgl_state *TLS, struct tgl_secret_chat *E, int ttl, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); // returns secret chat fingerprint int tgl_do_visualize_key (struct tgl_state *TLS, tgl_secret_chat_id_t id, unsigned char buf[16]); // requests creation of secret chat with user id void tgl_do_create_secret_chat (struct tgl_state *TLS, tgl_user_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra); // cancel a working secret chat void tgl_do_discard_secret_chat (struct tgl_state *TLS, struct tgl_secret_chat *E, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra); /* }}} */ /* {{{ WORKING WITH CHANNELS */ void tgl_do_get_channels_dialog_list (struct tgl_state *TLS, int limit, int offset, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]), void *callback_extra); void tgl_do_get_channel_info (struct tgl_state *TLS, tgl_peer_id_t id, int offline_mode, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_channel *C), void *callback_extra); void tgl_do_rename_channel (struct tgl_state *TLS, tgl_peer_id_t id, const char *name, int name_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_set_channel_photo (struct tgl_state *TLS, tgl_peer_id_t chat_id, const char *file_name, void (*callback)(struct tgl_state *TLS,void *callback_extra, int success), void *callback_extra); void tgl_do_channel_set_about (struct tgl_state *TLS, tgl_peer_id_t id, const char *about, int about_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_create_channel (struct tgl_state *TLS, int users_num, tgl_peer_id_t ids[], const char *chat_topic, int chat_topic_len, const char *about, int about_len, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_channel_set_username (struct tgl_state *TLS, tgl_peer_id_t id, const char *username, int username_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_join_channel (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_leave_channel (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_channel_invite_user (struct tgl_state *TLS, tgl_peer_id_t channel_id, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_channel_kick_user (struct tgl_state *TLS, tgl_peer_id_t channel_id, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_export_channel_link (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *link), void *callback_extra); // type: // 0 - none // 1 - moderator // 2 - editor // 3 - kicked void tgl_do_channel_set_admin (struct tgl_state *TLS, tgl_peer_id_t channel_id, tgl_peer_id_t user_id, int type, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); void tgl_do_channel_get_members (struct tgl_state *TLS, tgl_peer_id_t channel_id, int limit, int offset, int type, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_user *UL[]), void *callback_extra); /* }}} */ /* {{{ WORKING WITH DIALOG LIST */ // receives all dialogs (except secret chats) from offset=*offset* with limit=*limit* // dialogs are sorted by last message received // if limit is > 100 there is a (small) chance of one dialog received twice void tgl_do_get_dialog_list (struct tgl_state *TLS, int limit, int offset, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]), void *callback_extra); // resolves username void tgl_do_contact_search (struct tgl_state *TLS, const char *name, int name_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, tgl_peer_t *U), void *callback_extra); // requests contact list void tgl_do_update_contact_list (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_user *contacts[]), void *callback_extra); /* }}} */ /* {{{ WORKING WITH ONE DIALOG */ // marks all inbound messages from peer id as read void tgl_do_mark_read (struct tgl_state *TLS, tgl_peer_id_t id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // extended mark read void tgl_do_messages_mark_read (struct tgl_state *TLS, tgl_peer_id_t id, int max_id, int offset, void (*callback)(struct tgl_state *TLS, void *callback_extra, int), void *callback_extra); // requests last *limit* from offset *offset* (offset = 0 means most recent) messages from dialog with peer id // if offline_mode=1 then no actual query is sent // only locally cached messages returned // also marks messages from this chat as read void tgl_do_get_history (struct tgl_state *TLS, tgl_peer_id_t id, int offset, int limit, int offline_mode, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra); // like tgl_do_get_history, but will fetch any messages between *min_id* and *max_id* // when *limit* is too small, the older messages will not be displayed despite being bigger than *min_id* // when *max_id* is 0, all messages newer than *min_id* are fetched // when *min_id* is 0, all messages older than *max_id* are fetched void tgl_do_get_history_range (struct tgl_state *TLS, tgl_peer_id_t id, int min_id, int max_id, int limit, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra); // sends typing event to chat // set status=tgl_typing_typing for default typing event void tgl_do_send_typing (struct tgl_state *TLS, tgl_peer_id_t id, enum tgl_typing_status status, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); /* }}} */ /* {{{ WORKING WITH MEDIA */ // loads photo/document/document_thumb to downloads directory // if file is presented it is not redownloaded (but if it is shortened tail will be downloaded) // returns file name in callback void tgl_do_load_photo (struct tgl_state *TLS, struct tgl_photo *photo, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *file_name), void *callback_extra); void tgl_do_load_encr_document (struct tgl_state *TLS, struct tgl_encr_document *V, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *file_name), void *callback_extra); void tgl_do_load_document (struct tgl_state *TLS, struct tgl_document *V, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *file_name), void *callback_extra); void tgl_do_load_video (struct tgl_state *TLS, struct tgl_document *V, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *file_name), void *callback_extra); void tgl_do_load_audio (struct tgl_state *TLS, struct tgl_document *V, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *file_name), void *callback_extra); void tgl_do_load_audio (struct tgl_state *TLS, struct tgl_document *V, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *file_name), void *callback_extra); void tgl_do_load_document_thumb (struct tgl_state *TLS, struct tgl_document *video, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *file_name), void *callback_extra); // loads file by location. Use only for small files! void tgl_do_load_file_location (struct tgl_state *TLS, struct tgl_file_location *FL, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *file_name), void *callback_extra); /* }}} */ /* {{{ ANOTHER MESSAGES FUNCTIONS */ // search messages with ids *from* .. *to* in dialog id // id type of id is UNKNOWN uses global search (in all dialogs) instead // if *from* or *to* is means *from*=0 and *to*=+INF // return up to *limit* entries from offset=*offset* void tgl_do_msg_search (struct tgl_state *TLS, tgl_user_or_chat_id_t id, int from, int to, int limit, int offset, const char *query, int query_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra); // deletes message *id* void tgl_do_delete_msg (struct tgl_state *TLS, tgl_message_id_t *msg_id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); // gets message by *id* void tgl_do_get_message (struct tgl_state *TLS, tgl_message_id_t *msg_id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra); /* }}} */ /* {{{ EXTENDED QUERIES USE WITH CAUTION */ //#ifndef DISABLE_EXTF // sends query with extended text syntax // use only for debug or when you known what are you doing // since answer is not interpreted by library in any way void tgl_do_send_extf (struct tgl_state *TLS, const char *data, int data_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, const char *data), void *callback_extra); int tglf_extf_autocomplete (struct tgl_state *TLS, const char *text, int text_len, int index, char **R, char *data, int data_len); struct paramed_type *tglf_extf_store (struct tgl_state *TLS, const char *data, int data_len); char *tglf_extf_fetch (struct tgl_state *TLS, struct paramed_type *T); //#endif /* }}} */ /* {{{ BOT */ void tgl_do_start_bot (struct tgl_state *TLS, tgl_peer_id_t bot, tgl_peer_id_t chat, const char *str, int str_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); /* }}} */ #ifdef __cplusplus } #endif #endif telegram-purple/tgl/tgl-structures.h000066400000000000000000000114671357227200100201410ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifndef __STRUCTURES_H__ #define __STRUCTURES_H__ #include #include "tgl-layout.h" #include "tgl-fetch.h" #include "tgl.h" char *tgls_default_create_print_name (struct tgl_state *TLS, tgl_peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); void tgls_free_user (struct tgl_state *TLS, struct tgl_user *U); void tgls_free_chat (struct tgl_state *TLS, struct tgl_chat *U); void tgls_free_photo (struct tgl_state *TLS, struct tgl_photo *P); void tgls_free_message (struct tgl_state *TLS, struct tgl_message *M); void tgls_free_bot_info (struct tgl_state *TLS, struct tgl_bot_info *B); void tgls_clear_message (struct tgl_state *TLS, struct tgl_message *M); struct tgl_message *tglm_message_alloc (struct tgl_state *TLS, tgl_message_id_t *id); void tglm_message_insert_tree (struct tgl_state *TLS, struct tgl_message *M); void tglm_update_message_id (struct tgl_state *TLS, struct tgl_message *M, long long id); void tglm_message_insert (struct tgl_state *TLS, struct tgl_message *M); void tglm_message_insert_unsent (struct tgl_state *TLS, struct tgl_message *M); void tglm_message_remove_unsent (struct tgl_state *TLS, struct tgl_message *M); void tglm_send_all_unsent (struct tgl_state *TLS); void tglm_message_remove_tree (struct tgl_state *TLS, struct tgl_message *M); void tglm_message_add_peer (struct tgl_state *TLS, struct tgl_message *M); void tglm_message_del_peer (struct tgl_state *TLS, struct tgl_message *M); void tglm_message_del_use (struct tgl_state *TLS, struct tgl_message *M); void tglm_message_add_use (struct tgl_state *TLS, struct tgl_message *M); void tglm_message_del_temp_id (struct tgl_state *TLS, struct tgl_message *M); void tglm_message_del_random_id (struct tgl_state *TLS, struct tgl_message *M); void tglp_peer_insert_name (struct tgl_state *TLS, tgl_peer_t *P); void tglp_peer_delete_name (struct tgl_state *TLS, tgl_peer_t *P); void tglp_insert_encrypted_chat (struct tgl_state *TLS, tgl_peer_t *P); void tglp_insert_user (struct tgl_state *TLS, tgl_peer_t *P); void tglp_insert_chat (struct tgl_state *TLS, tgl_peer_t *P); void tglp_insert_channel (struct tgl_state *TLS, tgl_peer_t *P); //enum tgl_typing_status tglf_fetch_typing_buf (void); void tgls_messages_mark_read (struct tgl_state *TLS, struct tgl_message *M, int out, int seq); //void tgls_insert_random2local (struct tgl_state *TLS, long long random_id, tgl_message_id_t *local_id); //void tgls_insert_temp2local (struct tgl_state *TLS, int temp_id, tgl_message_id_t *local_id); tgl_message_id_t *tgls_get_local_by_random (struct tgl_state *TLS, long long random_id); tgl_message_id_t *tgls_get_local_by_temp (struct tgl_state *TLS, int temp_id); void tgls_message_change_temp_id (struct tgl_state *TLS, struct tgl_message *M, int temp_id); void tgls_message_change_random_id (struct tgl_state *TLS, struct tgl_message *M, long long random_id); void tgl_photo_insert (struct tgl_state *TLS, struct tgl_photo *P); struct tgl_photo *tgl_photo_get (struct tgl_state *TLS, long long id); struct tgl_document *tgl_document_get (struct tgl_state *TLS, long long id); void tgl_document_insert (struct tgl_state *TLS, struct tgl_document *P); struct tgl_webpage *tgl_webpage_get (struct tgl_state *TLS, long long id); void tgl_webpage_insert (struct tgl_state *TLS, struct tgl_webpage *P); tgl_message_id_t tgl_convert_temp_msg_id (struct tgl_state *TLS, tgl_message_id_t msg_id); static inline tgl_peer_id_t tgl_msg_id_to_peer_id (tgl_message_id_t msg_id) { tgl_peer_id_t id; id.peer_type = msg_id.peer_type; id.peer_id = msg_id.peer_id; id.access_hash = msg_id.access_hash; return id; } static inline tgl_message_id_t tgl_peer_id_to_msg_id (tgl_peer_id_t peer_id, long long msg_id) { tgl_message_id_t id; id.peer_type = peer_id.peer_type; id.peer_id = peer_id.peer_id; id.access_hash = peer_id.access_hash; id.id = msg_id; return id; } static inline tgl_message_id_t tgl_peer_id_to_random_msg_id (tgl_peer_id_t peer_id) { long long id; tglt_secure_random (&id, 8); return tgl_peer_id_to_msg_id (peer_id, id); } #endif telegram-purple/tgl/tgl-timers.c000066400000000000000000000040051357227200100172020ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #include "config.h" #ifdef EVENT_V2 #include #include #include #else #include #include "event-old.h" #endif #include "tgl.h" #include static void timer_alarm (evutil_socket_t fd, short what, void *arg) { void **p = arg; ((void (*)(struct tgl_state *, void *))p[1]) (p[0], p[2]); } struct tgl_timer *tgl_timer_alloc (struct tgl_state *TLS, void (*cb)(struct tgl_state *TLS, void *arg), void *arg) { void **p = malloc (sizeof (void *) * 3); p[0] = TLS; p[1] = cb; p[2] = arg; return (void *)evtimer_new (TLS->ev_base, timer_alarm, p); } void tgl_timer_insert (struct tgl_timer *t, double p) { if (p < 0) { p = 0; } double e = p - (int)p; if (e < 0) { e = 0; } struct timeval pv = { (int)p, (int)(e * 1e6)}; event_add ((void *)t, &pv); } void tgl_timer_delete (struct tgl_timer *t) { event_del ((void *)t); } void tgl_timer_free (struct tgl_timer *t) { void *arg = event_get_callback_arg ((void *)t); free (arg); event_free ((void *)t); } struct tgl_timer_methods tgl_libevent_timers = { .alloc = tgl_timer_alloc, .insert = tgl_timer_insert, .remove = tgl_timer_delete, .free = tgl_timer_free }; telegram-purple/tgl/tgl-timers.h000066400000000000000000000017031357227200100172110ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifndef __TGL_TIMERS_H__ #define __TGL_TIMERS_H__ #include "tgl.h" extern struct tgl_timer_methods tgl_libevent_timers; #endif telegram-purple/tgl/tgl.c000066400000000000000000000104651357227200100157100ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2014-2015 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "crypto/err.h" #include "crypto/rsa_pem.h" #include "tgl.h" #include "tools.h" #include "mtproto-client.h" #include "tgl-structures.h" //#include "net.h" #include struct tgl_state tgl_state; void tgl_set_binlog_mode (struct tgl_state *TLS, int mode) { TLS->binlog_enabled = mode; } void tgl_set_binlog_path (struct tgl_state *TLS, const char *path) { TLS->binlog_name = tstrdup (path); } void tgl_set_auth_file_path (struct tgl_state *TLS, const char *path) { TLS->auth_file = tstrdup (path); } void tgl_set_download_directory (struct tgl_state *TLS, const char *path) { if (TLS->downloads_directory) { tfree_str (TLS->downloads_directory); } TLS->downloads_directory = tstrdup (path); } void tgl_set_callback (struct tgl_state *TLS, struct tgl_update_callback *cb) { TLS->callback = *cb; } void tgl_set_rsa_key (struct tgl_state *TLS, const char *key) { assert (TLS->rsa_key_num < TGL_MAX_RSA_KEYS_NUM); TLS->rsa_key_list[TLS->rsa_key_num ++] = tstrdup (key); } void tgl_set_rsa_key_direct (struct tgl_state *TLS, unsigned long e, int n_bytes, const unsigned char *n) { assert (TLS->rsa_key_num < TGL_MAX_RSA_KEYS_NUM); TLS->rsa_key_list[TLS->rsa_key_num] = NULL; TLS->rsa_key_loaded[TLS->rsa_key_num] = TGLC_rsa_new (e, n_bytes, n); TLS->rsa_key_num ++; } int tgl_init (struct tgl_state *TLS) { assert (TLS->timer_methods); assert (TLS->net_methods); if (!TLS->callback.create_print_name) { TLS->callback.create_print_name = tgls_default_create_print_name; } if (!TLS->temp_key_expire_time) { TLS->temp_key_expire_time = 100000; } TLS->message_list.next_use = &TLS->message_list; TLS->message_list.prev_use = &TLS->message_list; if (TGLC_init (TLS) != 0) { return -1; } if (tglmp_on_start (TLS) < 0) { return -1; } if (!TLS->app_id) { TLS->app_id = TG_APP_ID; TLS->app_hash = tstrdup (TG_APP_HASH); } return 0; } int tgl_authorized_dc (struct tgl_state *TLS, struct tgl_dc *DC) { assert (DC); return (DC->flags & 4) != 0;//DC->auth_key_id; } int tgl_signed_dc (struct tgl_state *TLS, struct tgl_dc *DC) { assert (DC); return (DC->flags & TGLDCF_LOGGED_IN) != 0; } void tgl_register_app_id (struct tgl_state *TLS, int app_id, const char *app_hash) { TLS->app_id = app_id; TLS->app_hash = tstrdup (app_hash); } struct tgl_state *tgl_state_alloc (void) { return (struct tgl_state *)talloc0 (sizeof (struct tgl_state)); } void tgl_incr_verbosity (struct tgl_state *TLS) { TLS->verbosity ++; } void tgl_set_verbosity (struct tgl_state *TLS, int val) { TLS->verbosity = val; } void tgl_enable_pfs (struct tgl_state *TLS) { TLS->enable_pfs = 1; } void tgl_set_test_mode (struct tgl_state *TLS) { TLS->test_mode ++; } void tgl_set_net_methods (struct tgl_state *TLS, struct tgl_net_methods *methods) { TLS->net_methods = methods; } void tgl_set_timer_methods (struct tgl_state *TLS, struct tgl_timer_methods *methods) { TLS->timer_methods = methods; } void tgl_set_ev_base (struct tgl_state *TLS, void *ev_base) { TLS->ev_base = ev_base; } void tgl_set_app_version (struct tgl_state *TLS, const char *app_version) { if (TLS->app_version) { tfree_str (TLS->app_version); } TLS->app_version = tstrdup (app_version); } void tgl_enable_ipv6 (struct tgl_state *TLS) { TLS->ipv6_enabled = 1; } void tgl_disable_link_preview (struct tgl_state *TLS) { TLS->disable_link_preview = 1; } void tgl_enable_bot (struct tgl_state *TLS) { TLS->is_bot = 1; } telegram-purple/tgl/tgl.h000066400000000000000000000331621357227200100157140ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2014-2015 */ #ifndef __TGL_H__ #define __TGL_H__ #include "crypto/bn.h" #include "tgl-layout.h" #include #include #define TGL_MAX_DC_NUM 100 #define TG_SERVER_1 "149.154.175.50" #define TG_SERVER_2 "149.154.167.51" #define TG_SERVER_3 "149.154.175.100" #define TG_SERVER_4 "149.154.167.91" #define TG_SERVER_5 "149.154.171.5" #define TG_SERVER_IPV6_1 "2001:b28:f23d:f001::a" #define TG_SERVER_IPV6_2 "2001:67c:4e8:f002::a" #define TG_SERVER_IPV6_3 "2001:b28:f23d:f003::a" #define TG_SERVER_IPV6_4 "2001:67c:4e8:f004::a" #define TG_SERVER_IPV6_5 "2001:b28:f23f:f005::a" #define TG_SERVER_DEFAULT 2 #define TG_SERVER_TEST_1 "149.154.175.10" #define TG_SERVER_TEST_2 "149.154.167.40" #define TG_SERVER_TEST_3 "149.154.175.117" #define TG_SERVER_TEST_IPV6_1 "2001:b28:f23d:f001::e" #define TG_SERVER_TEST_IPV6_2 "2001:67c:4e8:f002::e" #define TG_SERVER_TEST_IPV6_3 "2001:b28:f23d:f003::e" #define TG_SERVER_TEST_DEFAULT 2 #define TGL_VERSION "2.1.0" #define TGL_ENCRYPTED_LAYER 17 #define TGL_SCHEME_LAYER 45 struct connection; struct mtproto_methods; struct tgl_session; struct tgl_dc; #define TGL_UPDATE_CREATED 1 #define TGL_UPDATE_DELETED 2 #define TGL_UPDATE_PHONE 4 #define TGL_UPDATE_CONTACT 8 #define TGL_UPDATE_PHOTO 16 #define TGL_UPDATE_BLOCKED 32 #define TGL_UPDATE_REAL_NAME 64 #define TGL_UPDATE_NAME 128 #define TGL_UPDATE_REQUESTED 256 #define TGL_UPDATE_WORKING 512 #define TGL_UPDATE_FLAGS 1024 #define TGL_UPDATE_TITLE 2048 #define TGL_UPDATE_ADMIN 4096 #define TGL_UPDATE_MEMBERS 8192 #define TGL_UPDATE_ACCESS_HASH 16384 #define TGL_UPDATE_USERNAME (1 << 15) /*struct tgl_allocator { void *(*alloc)(size_t size); void *(*realloc)(void *ptr, size_t old_size, size_t size); void (*free)(void *ptr, int size); void (*check)(void); void (*exists)(void *ptr, int size); };*/ struct tgl_allocator; extern struct tgl_allocator tgl_allocator_release; extern struct tgl_allocator tgl_allocator_debug; struct tgl_state; enum tgl_value_type { tgl_phone_number, // user phone number tgl_code, // telegram login code, or 'call' for phone call request tgl_register_info, // "Y/n" register?, first name, last name tgl_new_password, // new pass, confirm new pass tgl_cur_and_new_password, // curr pass, new pass, confirm new pass tgl_cur_password, // current pass tgl_bot_hash }; struct tgl_update_callback { void (*new_msg)(struct tgl_state *TLS, struct tgl_message *M); void (*marked_read)(struct tgl_state *TLS, int num, struct tgl_message *list[]); void (*logprintf)(const char *format, ...) __attribute__ ((format (__printf__, 1, 2))); void (*get_values)(struct tgl_state *TLS, enum tgl_value_type type, const char *prompt, int num_values, void (*callback)(struct tgl_state *TLS, const char *string[], void *arg), void *arg); void (*logged_in)(struct tgl_state *TLS); void (*started)(struct tgl_state *TLS); void (*type_notification)(struct tgl_state *TLS, struct tgl_user *U, enum tgl_typing_status status); void (*type_in_chat_notification)(struct tgl_state *TLS, struct tgl_user *U, struct tgl_chat *C, enum tgl_typing_status status); void (*type_in_secret_chat_notification)(struct tgl_state *TLS, struct tgl_secret_chat *E); void (*status_notification)(struct tgl_state *TLS, struct tgl_user *U); void (*user_registered)(struct tgl_state *TLS, struct tgl_user *U); void (*user_activated)(struct tgl_state *TLS, struct tgl_user *U); void (*new_authorization)(struct tgl_state *TLS, const char *device, const char *location); void (*chat_update)(struct tgl_state *TLS, struct tgl_chat *C, unsigned flags); void (*channel_update)(struct tgl_state *TLS, struct tgl_channel *C, unsigned flags); void (*user_update)(struct tgl_state *TLS, struct tgl_user *C, unsigned flags); void (*secret_chat_update)(struct tgl_state *TLS, struct tgl_secret_chat *C, unsigned flags); void (*msg_receive)(struct tgl_state *TLS, struct tgl_message *M); void (*our_id)(struct tgl_state *TLS, tgl_peer_id_t id); void (*notification)(struct tgl_state *TLS, const char *type, const char *message); void (*user_status_update)(struct tgl_state *TLS, struct tgl_user *U); char *(*create_print_name) (struct tgl_state *TLS, tgl_peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); void (*on_failed_login) (struct tgl_state *TLS); }; struct tgl_net_methods { int (*write_out) (struct connection *c, const void *data, int len); int (*read_in) (struct connection *c, void *data, int len); int (*read_in_lookup) (struct connection *c, void *data, int len); void (*flush_out) (struct connection *c); void (*incr_out_packet_num) (struct connection *c); void (*free) (struct connection *c); struct tgl_dc *(*get_dc) (struct connection *c); struct tgl_session *(*get_session) (struct connection *c); struct connection *(*create_connection) (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods); }; struct mtproto_methods { int (*ready) (struct tgl_state *TLS, struct connection *c); int (*close) (struct tgl_state *TLS, struct connection *c); int (*execute) (struct tgl_state *TLS, struct connection *c, int op, int len); }; struct tgl_timer; struct tree_random_id; struct tree_temp_id; struct tgl_timer_methods { struct tgl_timer *(*alloc) (struct tgl_state *TLS, void (*cb)(struct tgl_state *TLS, void *arg), void *arg); void (*insert) (struct tgl_timer *t, double timeout); void (*remove) (struct tgl_timer *t); void (*free) (struct tgl_timer *t); }; #define E_ERROR 0 #define E_WARNING 1 #define E_NOTICE 2 #define E_DEBUG 6 #define TGL_LOCK_DIFF 1 #define TGL_LOCK_PASSWORD 2 #define TGL_MAX_RSA_KEYS_NUM 10 // Do not modify this structure, unless you know what you do #pragma pack(push,4) struct tgl_state { tgl_peer_id_t our_id; int encr_root; unsigned char *encr_prime; TGLC_bn *encr_prime_bn; int encr_param_version; int pts; int qts; int date; int seq; int binlog_enabled; int test_mode; int verbosity; int unread_messages; int active_queries; int max_msg_id; int started; int disable_link_preview; long long locks; struct tgl_dc *DC_list[TGL_MAX_DC_NUM]; struct tgl_dc *DC_working; int max_dc_num; int dc_working_num; int enable_pfs; int temp_key_expire_time; long long cur_uploading_bytes; long long cur_uploaded_bytes; long long cur_downloading_bytes; long long cur_downloaded_bytes; char *binlog_name; char *auth_file; char *downloads_directory; struct tgl_update_callback callback; struct tgl_net_methods *net_methods; void *ev_base; char *rsa_key_list[TGL_MAX_RSA_KEYS_NUM]; // (TGLC_rsa *) void *rsa_key_loaded[TGL_MAX_RSA_KEYS_NUM]; long long rsa_key_fingerprint[TGL_MAX_RSA_KEYS_NUM]; int rsa_key_num; struct TGLC_bn_ctx *TGLC_bn_ctx; struct tgl_allocator *allocator; struct tree_peer *peer_tree; struct tree_peer_by_name *peer_by_name_tree; struct tree_message *message_tree; struct tree_message *message_unsent_tree; struct tree_photo *photo_tree; struct tree_document *document_tree; struct tree_webpage *webpage_tree; struct tree_encr_document *encr_document_tree; int users_allocated; int chats_allocated; int messages_allocated; int channels_allocated; int peer_num; int peer_size; int encr_chats_allocated; int geo_chats_allocated; tgl_peer_t **Peers; struct tgl_message message_list; int binlog_fd; struct tgl_timer_methods *timer_methods; struct tree_query *queries_tree; char *base_path; struct tree_user *online_updates; struct tgl_timer *online_updates_timer; int app_id; char *app_hash; void *ev_login; char *app_version; int ipv6_enabled; struct tree_random_id *random_id_tree; struct tree_temp_id *temp_id_tree; char *error; int error_code; int is_bot; int last_temp_id; long long last_msg_id; }; #pragma pack(pop) //extern struct tgl_state tgl_state; #ifdef __cplusplus extern "C" { #endif void tgl_reopen_binlog_for_writing (struct tgl_state *TLS); void tgl_replay_log (struct tgl_state *TLS); int tgl_print_stat (struct tgl_state *TLS, char *s, int len); tgl_peer_t *tgl_peer_get (struct tgl_state *TLS, tgl_peer_id_t id); tgl_peer_t *tgl_peer_get_by_name (struct tgl_state *TLS, const char *s); struct tgl_message *tgl_message_get (struct tgl_state *TLS, tgl_message_id_t *id); void tgl_peer_iterator_ex (struct tgl_state *TLS, void (*it)(tgl_peer_t *P, void *extra), void *extra); int tgl_complete_user_list (struct tgl_state *TLS, int index, const char *text, int len, char **R); int tgl_complete_chat_list (struct tgl_state *TLS, int index, const char *text, int len, char **R); int tgl_complete_encr_chat_list (struct tgl_state *TLS, int index, const char *text, int len, char **R); int tgl_complete_peer_list (struct tgl_state *TLS, int index, const char *text, int len, char **R); int tgl_complete_channel_list (struct tgl_state *TLS, int index, const char *text, int len, char **R); int tgl_secret_chat_for_user (struct tgl_state *TLS, tgl_peer_id_t user_id); int tgl_do_send_bot_auth (struct tgl_state *TLS, const char *code, int code_len, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_user *Self), void *callback_extra); #define TGL_PEER_USER 1 #define TGL_PEER_CHAT 2 #define TGL_PEER_GEO_CHAT 3 #define TGL_PEER_ENCR_CHAT 4 #define TGL_PEER_CHANNEL 5 #define TGL_PEER_TEMP_ID 100 #define TGL_PEER_RANDOM_ID 101 #define TGL_PEER_UNKNOWN 0 #define TGL_MK_USER(id) tgl_set_peer_id (TGL_PEER_USER,id) #define TGL_MK_CHAT(id) tgl_set_peer_id (TGL_PEER_CHAT,id) #define TGL_MK_CHANNEL(id) tgl_set_peer_id (TGL_PEER_CHANNEL,id) #define TGL_MK_GEO_CHAT(id) tgl_set_peer_id (TGL_PEER_GEO_CHAT,id) #define TGL_MK_ENCR_CHAT(id) tgl_set_peer_id (TGL_PEER_ENCR_CHAT,id) void tgl_set_binlog_mode (struct tgl_state *TLS, int mode); void tgl_set_binlog_path (struct tgl_state *TLS, const char *path); void tgl_set_auth_file_path (struct tgl_state *TLS, const char *path); void tgl_set_download_directory (struct tgl_state *TLS, const char *path); void tgl_set_callback (struct tgl_state *TLS, struct tgl_update_callback *cb); void tgl_set_rsa_key (struct tgl_state *TLS, const char *key); void tgl_set_rsa_key_direct (struct tgl_state *TLS, unsigned long e, int n_bytes, const unsigned char *n); void tgl_set_app_version (struct tgl_state *TLS, const char *app_version); static inline int tgl_get_peer_type (tgl_peer_id_t id) { return id.peer_type; } static inline int tgl_get_peer_id (tgl_peer_id_t id) { return id.peer_id; } static inline tgl_peer_id_t tgl_set_peer_id (int type, int id) { tgl_peer_id_t ID; ID.peer_id = id; ID.peer_type = type; ID.access_hash = 0; return ID; } static inline int tgl_cmp_peer_id (tgl_peer_id_t a, tgl_peer_id_t b) { return memcmp (&a, &b, 8); } void tgl_incr_verbosity (struct tgl_state *TLS); void tgl_set_verbosity (struct tgl_state *TLS, int val); void tgl_enable_pfs (struct tgl_state *TLS); void tgl_set_test_mode (struct tgl_state *TLS); void tgl_set_net_methods (struct tgl_state *TLS, struct tgl_net_methods *methods); void tgl_set_timer_methods (struct tgl_state *TLS, struct tgl_timer_methods *methods); void tgl_set_ev_base (struct tgl_state *TLS, void *ev_base); int tgl_authorized_dc (struct tgl_state *TLS, struct tgl_dc *DC); int tgl_signed_dc (struct tgl_state *TLS, struct tgl_dc *DC); int tgl_init (struct tgl_state *TLS); void tgl_dc_authorize (struct tgl_state *TLS, struct tgl_dc *DC); void tgl_dc_iterator (struct tgl_state *TLS, void (*iterator)(struct tgl_dc *DC)); void tgl_dc_iterator_ex (struct tgl_state *TLS, void (*iterator)(struct tgl_dc *DC, void *extra), void *extra); #define TGL_SEND_MSG_FLAG_DISABLE_PREVIEW 1 #define TGL_SEND_MSG_FLAG_ENABLE_PREVIEW 2 #define TGL_SEND_MSG_FLAG_DOCUMENT_IMAGE TGLDF_IMAGE #define TGL_SEND_MSG_FLAG_DOCUMENT_STICKER TGLDF_STICKER #define TGL_SEND_MSG_FLAG_DOCUMENT_ANIMATED TGLDF_ANIMATED #define TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO TGLDF_AUDIO #define TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO TGLDF_VIDEO #define TGL_SEND_MSG_FLAG_DOCUMENT_AUTO 32 #define TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO 64 #define TGL_SEND_MSG_FLAG_REPLY(x) (((unsigned long long)x) << 32) typedef tgl_peer_id_t tgl_user_id_t; typedef tgl_peer_id_t tgl_chat_id_t; typedef tgl_peer_id_t tgl_secret_chat_id_t; typedef tgl_peer_id_t tgl_user_or_chat_id_t; void tgl_insert_empty_user (struct tgl_state *TLS, int id); void tgl_insert_empty_chat (struct tgl_state *TLS, int id); void tgl_free_all (struct tgl_state *TLS); void tgl_register_app_id (struct tgl_state *TLS, int app_id, const char *app_hash); void tgl_login (struct tgl_state *TLS); void tgl_enable_ipv6 (struct tgl_state *TLS); void tgl_enable_bot (struct tgl_state *TLS); struct tgl_state *tgl_state_alloc (void); void tgl_disable_link_preview (struct tgl_state *TLS); void tgl_do_lookup_state (struct tgl_state *TLS); long long tgl_get_allocated_bytes (void); #ifdef __cplusplus } #endif #endif telegram-purple/tgl/tl-parser/000077500000000000000000000000001357227200100166615ustar00rootroot00000000000000telegram-purple/tgl/tl-parser/.gitignore000066400000000000000000000001071357227200100206470ustar00rootroot00000000000000Makefile config.h dep objs bin autom4te.cache config.log config.status telegram-purple/tgl/tl-parser/LICENSE000066400000000000000000000432541357227200100176760ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. telegram-purple/tgl/tl-parser/README.md000066400000000000000000000000721357227200100201370ustar00rootroot00000000000000Parse tl scheme to tlo file. Formely part of telegram-cli telegram-purple/tgl/tl-parser/portable_endian.h000066400000000000000000000071501357227200100221630ustar00rootroot00000000000000// "License": Public Domain // I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. // In case there are jurisdictions that don't support putting things in the public domain you can also consider it to // be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it // an example on how to get the endian conversion functions on different platforms. /* Originally cloned from https://gist.github.com/PkmX/63dd23f28ba885be53a5 * Commit was: 1eca2ab34f2301b9641aa73d1016b951fff3fc39 * Re-published at https://github.com/BenWiederhake/portable-endian.h to provide a means to submit patches and report issues. */ #ifndef PORTABLE_ENDIAN_H__ #define PORTABLE_ENDIAN_H__ #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) # define __WINDOWS__ #endif #if defined(__linux__) || defined(__CYGWIN__) # include #elif defined(__APPLE__) # include # define htobe16(x) OSSwapHostToBigInt16(x) # define htole16(x) OSSwapHostToLittleInt16(x) # define be16toh(x) OSSwapBigToHostInt16(x) # define le16toh(x) OSSwapLittleToHostInt16(x) # define htobe32(x) OSSwapHostToBigInt32(x) # define htole32(x) OSSwapHostToLittleInt32(x) # define be32toh(x) OSSwapBigToHostInt32(x) # define le32toh(x) OSSwapLittleToHostInt32(x) # define htobe64(x) OSSwapHostToBigInt64(x) # define htole64(x) OSSwapHostToLittleInt64(x) # define be64toh(x) OSSwapBigToHostInt64(x) # define le64toh(x) OSSwapLittleToHostInt64(x) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # define __PDP_ENDIAN PDP_ENDIAN #elif defined(__OpenBSD__) || defined(__FreeBSD__) # include #elif defined(__sun) # include # define htobe16(x) BE_16(x) # define htole16(x) LE_16(x) # define be16toh(x) BE_IN16(x) # define le16toh(x) LE_IN16(x) # define htobe32(x) BE_32(x) # define htole32(x) LE_32(x) # define be32toh(x) BE_IN32(x) # define le32toh(x) LE_IN32(x) # define htobe64(x) BE_64(x) # define htole64(x) LE_64(x) # define be64toh(x) BE_IN64(x) # define le64toh(x) LE_IN64(x) #elif defined(__NetBSD__) || defined(__DragonFly__) # include # define be16toh(x) betoh16(x) # define le16toh(x) letoh16(x) # define be32toh(x) betoh32(x) # define le32toh(x) letoh32(x) # define be64toh(x) betoh64(x) # define le64toh(x) letoh64(x) #elif defined(__WINDOWS__) # include # include # if BYTE_ORDER == LITTLE_ENDIAN # define htobe16(x) htons(x) # define htole16(x) (x) # define be16toh(x) ntohs(x) # define le16toh(x) (x) # define htobe32(x) htonl(x) # define htole32(x) (x) # define be32toh(x) ntohl(x) # define le32toh(x) (x) # define htobe64(x) __builtin_bswap64(x) # define htole64(x) (x) # define be64toh(x) __builtin_bswap64(x) # define le64toh(x) (x) # elif BYTE_ORDER == BIG_ENDIAN /* that would be xbox 360 */ # define htobe16(x) (x) # define htole16(x) __builtin_bswap16(x) # define be16toh(x) (x) # define le16toh(x) __builtin_bswap16(x) # define htobe32(x) (x) # define htole32(x) __builtin_bswap32(x) # define be32toh(x) (x) # define le32toh(x) __builtin_bswap32(x) # define htobe64(x) (x) # define htole64(x) __builtin_bswap64(x) # define be64toh(x) (x) # define le64toh(x) __builtin_bswap64(x) # else # error byte order not supported # endif # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # define __PDP_ENDIAN PDP_ENDIAN #else # error platform not supported #endif #endif telegram-purple/tgl/tl-parser/tl-parser-tree.h000066400000000000000000000134421357227200100217040ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2014 */ #ifndef __TREE_H__ #define __TREE_H__ #include #include #include #pragma pack(push,4) #define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ struct tree_ ## X_NAME { \ struct tree_ ## X_NAME *left, *right;\ X_TYPE x;\ int y;\ };\ \ static struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\ struct tree_ ## X_NAME *T = malloc (sizeof (*T));\ T->x = x;\ T->y = y;\ T->left = T->right = 0;\ return T;\ }\ \ static void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\ free (T);\ }\ \ static void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\ if (!T) {\ *L = *R = 0;\ } else {\ int c = X_CMP (x, T->x);\ if (c < 0) {\ tree_split_ ## X_NAME (T->left, x, L, &T->left);\ *R = T;\ } else {\ tree_split_ ## X_NAME (T->right, x, &T->right, R);\ *L = T;\ }\ }\ }\ \ static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result,unused));\ static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\ if (!T) {\ return new_tree_node_ ## X_NAME (x, y);\ } else {\ if (y > T->y) {\ struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\ tree_split_ ## X_NAME (T, x, &N->left, &N->right);\ return N;\ } else {\ int c = X_CMP (x, T->x);\ assert (c);\ if (c < 0) { \ T->left = tree_insert_ ## X_NAME (T->left, x, y);\ } else { \ T->right = tree_insert_ ## X_NAME (T->right, x, y);\ } \ return T; \ }\ }\ }\ \ static struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\ if (!L || !R) {\ return L ? L : R;\ } else {\ if (L->y > R->y) {\ L->right = tree_merge_ ## X_NAME (L->right, R);\ return L;\ } else {\ R->left = tree_merge_ ## X_NAME (L, R->left);\ return R;\ }\ }\ }\ \ static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result,unused));\ static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ assert (T);\ int c = X_CMP (x, T->x);\ if (!c) {\ struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\ delete_tree_node_ ## X_NAME (T);\ return N;\ } else {\ if (c < 0) { \ T->left = tree_delete_ ## X_NAME (T->left, x); \ } else { \ T->right = tree_delete_ ## X_NAME (T->right, x); \ } \ return T; \ }\ }\ \ static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *t) __attribute__ ((unused));\ static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\ if (!T) { return X_UNSET; } \ while (T->left) { T = T->left; }\ return T->x; \ } \ \ static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((unused));\ static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ int c;\ while (T && (c = X_CMP (x, T->x))) {\ T = (c < 0 ? T->left : T->right);\ }\ return T ? T->x : X_UNSET;\ }\ \ static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) __attribute__ ((unused));\ static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\ if (!T) { return; } \ tree_act_ ## X_NAME (T->left, act); \ act (T->x); \ tree_act_ ## X_NAME (T->right, act); \ }\ \ static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) __attribute__ ((unused));\ static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) {\ if (!T) { return; } \ tree_act_ex_ ## X_NAME (T->left, act, extra); \ act (T->x, extra); \ tree_act_ex_ ## X_NAME (T->right, act, extra); \ }\ \ static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \ if (!T) { return 0; }\ return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \ }\ static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \ if (!T) { return; }\ if (T->left) { \ assert (T->left->y <= T->y);\ assert (X_CMP (T->left->x, T->x) < 0); \ }\ if (T->right) { \ assert (T->right->y <= T->y);\ assert (X_CMP (T->right->x, T->x) > 0); \ }\ tree_check_ ## X_NAME (T->left); \ tree_check_ ## X_NAME (T->right); \ }\ static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) { \ if (!T) { return 0; }\ tree_clear_ ## X_NAME (T->left); \ tree_clear_ ## X_NAME (T->right); \ delete_tree_node_ ## X_NAME (T); \ return 0; \ } \ #define int_cmp(a,b) ((a) - (b)) #pragma pack(pop) #endif telegram-purple/tgl/tl-parser/tl-parser.c000066400000000000000000002321341357227200100207430ustar00rootroot00000000000000/* This file is part of tl-parser tl-parser 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. tl-parser 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 tl-parser. If not, see . Copyright Vitaly Valtman 2014 It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) Copyright 2012-2013 Vkontakte Ltd 2012-2013 Vitaliy Valtman */ #define _FILE_OFFSET_BITS 64 #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "portable_endian.h" #include "tl-parser-tree.h" #include "tl-parser.h" #include "tl-tl.h" #include "config.h" extern int verbosity; extern int schema_version; extern int output_expressions; int total_types_num; int total_constructors_num; int total_functions_num; /*char *tstrdup (const char *s) { assert (s); char *r = talloc (strlen (s) + 1); memcpy (r, s, strlen (s) + 1); return r; }*/ #define talloc(a) malloc(a) #define tfree(a,b) free (a) #define talloc0(a) calloc(a,1) #define tstrdup(a) strdup(a) typedef char error_int_must_be_4_byte[(sizeof (int) == 4) ? 1 : -1]; typedef char error_long_long_must_be_8_byte[(sizeof (long long) == 8) ? 1 : -1]; char curch; struct parse parse; struct tree *tree; struct tree *tree_alloc (void) { struct tree *T = talloc (sizeof (*T)); assert (T); memset (T, 0, sizeof (*T)); return T; } #define CRC32_INITIAL crc32 (0, 0, 0) void tree_add_child (struct tree *P, struct tree *C) { if (P->nc == P->size) { void **t = talloc (sizeof (void *) * (++P->size)); memcpy (t, P->c, sizeof (void *) * (P->size - 1)); if (P->c) { tfree (P->c, sizeof (void *) * (P->size - 1)); } P->c = (void *)t; assert (P->c); } P->c[P->nc ++] = C; } void tree_delete (struct tree *T) { assert (T); int i; for (i = 0; i < T->nc; i++) { assert (T->c[i]); tree_delete (T->c[i]); } if (T->c) { tfree (T->c, sizeof (void *) * T->nc); } tfree (T, sizeof (*T)); } void tree_del_child (struct tree *P) { assert (P->nc); tree_delete (P->c[--P->nc]); } char nextch (void) { if (parse.pos < parse.len - 1) { curch = parse.text[++parse.pos]; } else { curch = 0; } if (curch == 10) { parse.line ++; parse.line_pos = 0; } else { if (curch) { parse.line_pos ++; } } return curch; } struct parse save_parse (void) { return parse; } void load_parse (struct parse _parse) { parse = _parse; curch = parse.pos > parse.len ? 0: parse.text[parse.pos] ; } int is_whitespace (char c) { return (c <= 32); } int is_uletter (char c) { return (c >= 'A' && c <= 'Z'); } int is_lletter (char c) { return (c >= 'a' && c <= 'z'); } int is_letter (char c) { return is_uletter (c) || is_lletter (c); } int is_digit (char c) { return (c >= '0' && c <= '9'); } int is_hexdigit (char c) { return is_digit (c) || (c >= 'a' && c <= 'f'); } int is_ident_char (char c) { return is_digit (c) || is_letter (c) || c == '_'; } int last_error_pos; int last_error_line; int last_error_line_pos; char *last_error; void parse_error (const char *e) { if (parse.pos > last_error_pos) { last_error_pos = parse.pos; last_error_line = parse.line; last_error_line_pos = parse.line_pos; if (last_error) { tfree (last_error, strlen (last_error) + 1); } last_error = tstrdup (e); } } void tl_print_parse_error (void) { fprintf (stderr, "Error near line %d pos %d: `%s`\n", last_error_line + 1, last_error_line_pos + 1, last_error); } char *parse_lex (void) { while (1) { while (curch && is_whitespace (curch)) { nextch (); } if (curch == '/' && nextch () == '/') { while (nextch () != 10); nextch (); } else { break; } } if (!curch) { parse.lex.len = 0; parse.lex.type = lex_eof; return (parse.lex.ptr = 0); } char *p = parse.text + parse.pos; parse.lex.flags = 0; switch (curch) { case '-': if (nextch () != '-' || nextch () != '-') { parse_error ("Can not parse triple minus"); parse.lex.type = lex_error; return (parse.lex.ptr = (void *)-1); } else { parse.lex.len = 3; parse.lex.type = lex_triple_minus; nextch (); return (parse.lex.ptr = p); } case ':': case ';': case '(': case ')': case '[': case ']': case '{': case '}': case '=': case '#': case '?': case '%': case '<': case '>': case '+': case ',': case '*': case '_': case '!': case '.': nextch (); parse.lex.len = 1; parse.lex.type = lex_char; return (parse.lex.ptr = p); case 'a'...'z': case 'A'...'Z': parse.lex.flags = 0; if (is_uletter (curch)) { while (is_ident_char (nextch ())); parse.lex.len = parse.text + parse.pos - p; parse.lex.ptr = p; if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Final", 5)) { parse.lex.type = lex_final; } else if (parse.lex.len == 3 && !memcmp (parse.lex.ptr, "New", 3)) { parse.lex.type = lex_new; } else if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Empty", 5)) { parse.lex.type = lex_empty; } else { parse.lex.type = lex_uc_ident; } return (parse.lex.ptr = p); } while (is_ident_char (nextch ())); if (curch == '.' && !is_letter (parse.text[parse.pos + 1])) { parse.lex.len = parse.text + parse.pos - p; parse.lex.type = lex_lc_ident; return (parse.lex.ptr = p); } if (curch == '.') { parse.lex.flags |= 1; nextch (); if (is_uletter (curch)) { while (is_ident_char (nextch ())); parse.lex.len = parse.text + parse.pos - p; parse.lex.type = lex_uc_ident; return (parse.lex.ptr = p); } if (is_lletter (curch)) { while (is_ident_char (nextch ())); } else { parse_error ("Expected letter"); parse.lex.type = lex_error; return (parse.lex.ptr = (void *)-1); } } if (curch == '#') { parse.lex.flags |= 2; int i; int ok = 1; for (i = 0; i < 8; i++) { if (!is_hexdigit (nextch())) { if (curch == ' ' && i >= 5) { ok = 2; break; } else { parse_error ("Hex digit expected"); parse.lex.type = lex_error; return (parse.lex.ptr = (void *)-1); } } } if (ok == 1) { nextch (); } } parse.lex.len = parse.text + parse.pos - p; parse.lex.type = lex_lc_ident; return (parse.lex.ptr = p); case '0'...'9': while (is_digit (nextch ())); parse.lex.len = parse.text + parse.pos - p; parse.lex.type = lex_num; return (parse.lex.ptr = p); default: parse_error ("Unknown lexem"); parse.lex.type = lex_error; return (parse.lex.ptr = (void *)-1); } } int expect (char *s) { if (!parse.lex.ptr || parse.lex.ptr == (void *)-1 || parse.lex.type == lex_error || parse.lex.type == lex_none || parse.lex.len != (int)strlen (s) || memcmp (s, parse.lex.ptr, parse.lex.len)) { static char buf[1000]; sprintf (buf, "Expected %s", s); parse_error (buf); return -1; } else { parse_lex (); } return 1; } struct parse *tl_init_parse_file (const char *fname) { int fd = open (fname, O_RDONLY); if (fd < 0) { fprintf (stderr, "Error %m\n"); assert (0); return 0; } long long size = lseek (fd, 0, SEEK_END); if (size <= 0) { fprintf (stderr, "size is %lld. Too small.\n", size); return 0; } static struct parse save; save.text = talloc (size); lseek (fd, 0, SEEK_SET); save.len = read (fd, save.text, size); assert (save.len == size); save.pos = 0; save.line = 0; save.line_pos = 0; save.lex.ptr = save.text; save.lex.len = 0; save.lex.type = lex_none; return &save; } #define PARSE_INIT(_type) struct parse save = save_parse (); struct tree *T = tree_alloc (); T->type = (_type); T->lex_line = parse.line; T->lex_line_pos = parse.line_pos; struct tree *S __attribute__ ((unused)); #define PARSE_FAIL load_parse (save); tree_delete (T); return 0; #define PARSE_OK return T; #define PARSE_TRY_PES(x) if (!(S = x ())) { PARSE_FAIL; } { tree_add_child (T, S); } #define PARSE_TRY_OPT(x) if ((S = x ())) { tree_add_child (T, S); PARSE_OK } #define PARSE_TRY(x) S = x (); #define PARSE_ADD(_type) S = tree_alloc (); S->type = _type; tree_add_child (T, S); #define EXPECT(s) if (expect (s) < 0) { PARSE_FAIL; } #define LEX_CHAR(c) (parse.lex.type == lex_char && *parse.lex.ptr == c) struct tree *parse_args (void); struct tree *parse_expr (void); struct tree *parse_boxed_type_ident (void) { PARSE_INIT (type_boxed_type_ident); if (parse.lex.type != lex_uc_ident) { parse_error ("Can not parse boxed type"); PARSE_FAIL; } else { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } } struct tree *parse_full_combinator_id (void) { PARSE_INIT (type_full_combinator_id); if (parse.lex.type == lex_lc_ident || LEX_CHAR('_')) { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } else { parse_error ("Can not parse full combinator id"); PARSE_FAIL; } } struct tree *parse_combinator_id (void) { PARSE_INIT (type_combinator_id); if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } else { parse_error ("Can not parse combinator id"); PARSE_FAIL; } } struct tree *parse_var_ident (void) { PARSE_INIT (type_var_ident); if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident) && !(parse.lex.flags & 3)) { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } else { parse_error ("Can not parse var ident"); PARSE_FAIL; } } struct tree *parse_var_ident_opt (void) { PARSE_INIT (type_var_ident_opt); if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident)&& !(parse.lex.flags & 3)) { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } else if (LEX_CHAR ('_')) { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } else { parse_error ("Can not parse var ident opt"); PARSE_FAIL; } } struct tree *parse_nat_const (void) { PARSE_INIT (type_nat_const); if (parse.lex.type == lex_num) { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } else { parse_error ("Can not parse nat const"); PARSE_FAIL; } } struct tree *parse_type_ident (void) { PARSE_INIT (type_type_ident); if (parse.lex.type == lex_uc_ident && !(parse.lex.flags & 2)) { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } else if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } else if (LEX_CHAR ('#')) { T->text = parse.lex.ptr; T->len = parse.lex.len; T->flags = parse.lex.flags; parse_lex (); PARSE_OK; } else { parse_error ("Can not parse type ident"); PARSE_FAIL; } } struct tree *parse_term (void) { PARSE_INIT (type_term); while (LEX_CHAR ('%')) { EXPECT ("%") PARSE_ADD (type_percent); } if (LEX_CHAR ('(')) { EXPECT ("("); PARSE_TRY_PES (parse_expr); EXPECT (")"); PARSE_OK; } PARSE_TRY (parse_type_ident); if (S) { tree_add_child (T, S); if (LEX_CHAR ('<')) { EXPECT ("<"); while (1) { PARSE_TRY_PES (parse_expr); if (LEX_CHAR ('>')) { break; } EXPECT (","); } EXPECT (">"); } PARSE_OK; } PARSE_TRY_OPT (parse_type_ident); PARSE_TRY_OPT (parse_var_ident); PARSE_TRY_OPT (parse_nat_const); PARSE_FAIL; } struct tree *parse_nat_term (void) { PARSE_INIT (type_nat_term); PARSE_TRY_PES (parse_term); PARSE_OK; } struct tree *parse_subexpr (void) { PARSE_INIT (type_subexpr); int was_term = 0; int cc = 0; while (1) { PARSE_TRY (parse_nat_const); if (S) { tree_add_child (T, S); } else if (!was_term) { was_term = 1; PARSE_TRY (parse_term); if (S) { tree_add_child (T, S); } else { break; } } cc ++; if (!LEX_CHAR ('+')) { break; } EXPECT ("+"); } if (!cc) { PARSE_FAIL; } else { PARSE_OK; } } struct tree *parse_expr (void) { PARSE_INIT (type_expr); int cc = 0; while (1) { PARSE_TRY (parse_subexpr); if (S) { tree_add_child (T, S); cc ++; } else { if (cc < 1) { PARSE_FAIL; } else { PARSE_OK; } } } } struct tree *parse_final_empty (void) { PARSE_INIT (type_final_empty); EXPECT ("Empty"); PARSE_TRY_PES (parse_boxed_type_ident); PARSE_OK; } struct tree *parse_final_new (void) { PARSE_INIT (type_final_new); EXPECT ("New"); PARSE_TRY_PES (parse_boxed_type_ident); PARSE_OK; } struct tree *parse_final_final (void) { PARSE_INIT (type_final_final); EXPECT ("Final"); PARSE_TRY_PES (parse_boxed_type_ident); PARSE_OK; } struct tree *parse_partial_comb_app_decl (void) { PARSE_INIT (type_partial_comb_app_decl); PARSE_TRY_PES (parse_combinator_id); while (1) { PARSE_TRY_PES (parse_subexpr); if (LEX_CHAR (';')) { break; } } PARSE_OK; } struct tree *parse_partial_type_app_decl (void) { PARSE_INIT (type_partial_type_app_decl); PARSE_TRY_PES (parse_boxed_type_ident); if (LEX_CHAR ('<')) { EXPECT ("<"); while (1) { PARSE_TRY_PES (parse_expr); if (LEX_CHAR ('>')) { break; } EXPECT (","); } EXPECT (">"); PARSE_OK; } else { while (1) { PARSE_TRY_PES (parse_subexpr); if (LEX_CHAR (';')) { break; } } PARSE_OK; } } struct tree *parse_multiplicity (void) { PARSE_INIT (type_multiplicity); PARSE_TRY_PES (parse_nat_term); PARSE_OK; } struct tree *parse_type_term (void) { PARSE_INIT (type_type_term); PARSE_TRY_PES (parse_term); PARSE_OK; } struct tree *parse_optional_arg_def (void) { PARSE_INIT (type_optional_arg_def); PARSE_TRY_PES (parse_var_ident); EXPECT ("."); PARSE_TRY_PES (parse_nat_const); EXPECT ("?"); PARSE_OK; } struct tree *parse_args4 (void) { PARSE_INIT (type_args4); struct parse so = save_parse (); PARSE_TRY (parse_optional_arg_def); if (S) { tree_add_child (T, S); } else { load_parse (so); } if (LEX_CHAR ('!')) { PARSE_ADD (type_exclam); EXPECT ("!"); } PARSE_TRY_PES (parse_type_term); PARSE_OK; } struct tree *parse_args3 (void) { PARSE_INIT (type_args3); PARSE_TRY_PES (parse_var_ident_opt); EXPECT (":"); struct parse so = save_parse (); PARSE_TRY (parse_optional_arg_def); if (S) { tree_add_child (T, S); } else { load_parse (so); } if (LEX_CHAR ('!')) { PARSE_ADD (type_exclam); EXPECT ("!"); } PARSE_TRY_PES (parse_type_term); PARSE_OK; } struct tree *parse_args2 (void) { PARSE_INIT (type_args2); PARSE_TRY (parse_var_ident_opt); if (S && LEX_CHAR (':')) { tree_add_child (T, S); EXPECT (":"); } else { load_parse (save); } struct parse so = save_parse (); PARSE_TRY (parse_optional_arg_def); if (S) { tree_add_child (T, S); } else { load_parse (so); } struct parse save2 = save_parse (); PARSE_TRY (parse_multiplicity); if (S && LEX_CHAR ('*')) { tree_add_child (T, S); EXPECT ("*"); } else { load_parse (save2); } EXPECT ("["); while (1) { if (LEX_CHAR (']')) { break; } PARSE_TRY_PES (parse_args); } EXPECT ("]"); PARSE_OK; } struct tree *parse_args1 (void) { PARSE_INIT (type_args1); EXPECT ("("); while (1) { PARSE_TRY_PES (parse_var_ident_opt); if (LEX_CHAR(':')) { break; } } EXPECT (":"); struct parse so = save_parse (); PARSE_TRY (parse_optional_arg_def); if (S) { tree_add_child (T, S); } else { load_parse (so); } if (LEX_CHAR ('!')) { PARSE_ADD (type_exclam); EXPECT ("!"); } PARSE_TRY_PES (parse_type_term); EXPECT (")"); PARSE_OK; } struct tree *parse_args (void) { PARSE_INIT (type_args); PARSE_TRY_OPT (parse_args1); PARSE_TRY_OPT (parse_args2); PARSE_TRY_OPT (parse_args3); PARSE_TRY_OPT (parse_args4); PARSE_FAIL; } struct tree *parse_opt_args (void) { PARSE_INIT (type_opt_args); while (1) { PARSE_TRY_PES (parse_var_ident); if (parse.lex.type == lex_char && *parse.lex.ptr == ':') { break;} } EXPECT (":"); PARSE_TRY_PES (parse_type_term); PARSE_OK; } struct tree *parse_final_decl (void) { PARSE_INIT (type_final_decl); PARSE_TRY_OPT (parse_final_new); PARSE_TRY_OPT (parse_final_final); PARSE_TRY_OPT (parse_final_empty); PARSE_FAIL; } struct tree *parse_partial_app_decl (void) { PARSE_INIT (type_partial_app_decl); PARSE_TRY_OPT (parse_partial_type_app_decl); PARSE_TRY_OPT (parse_partial_comb_app_decl); PARSE_FAIL; } struct tree *parse_result_type (void) { PARSE_INIT (type_result_type); PARSE_TRY_PES (parse_boxed_type_ident); if (LEX_CHAR ('<')) { EXPECT ("<"); while (1) { PARSE_TRY_PES (parse_expr); if (LEX_CHAR ('>')) { break; } EXPECT (","); } EXPECT (">"); PARSE_OK; } else { while (1) { if (LEX_CHAR (';')) { PARSE_OK; } PARSE_TRY_PES (parse_subexpr); } } } struct tree *parse_combinator_decl (void) { PARSE_INIT (type_combinator_decl); PARSE_TRY_PES (parse_full_combinator_id) while (1) { if (LEX_CHAR ('{')) { parse_lex (); PARSE_TRY_PES (parse_opt_args); EXPECT ("}"); } else { break; } } while (1) { if (LEX_CHAR ('=')) { break; } PARSE_TRY_PES (parse_args); } EXPECT ("="); PARSE_ADD (type_equals); PARSE_TRY_PES (parse_result_type); PARSE_OK; } struct tree *parse_builtin_combinator_decl (void) { PARSE_INIT (type_builtin_combinator_decl); PARSE_TRY_PES (parse_full_combinator_id) EXPECT ("?"); EXPECT ("="); PARSE_TRY_PES (parse_boxed_type_ident); PARSE_OK; } struct tree *parse_declaration (void) { PARSE_INIT (type_declaration); PARSE_TRY_OPT (parse_combinator_decl); PARSE_TRY_OPT (parse_partial_app_decl); PARSE_TRY_OPT (parse_final_decl); PARSE_TRY_OPT (parse_builtin_combinator_decl); PARSE_FAIL; } struct tree *parse_constr_declarations (void) { PARSE_INIT (type_constr_declarations); if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; } while (1) { PARSE_TRY_PES (parse_declaration); EXPECT (";"); if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; } } } struct tree *parse_fun_declarations (void) { PARSE_INIT (type_fun_declarations); if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; } while (1) { PARSE_TRY_PES (parse_declaration); EXPECT (";"); if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; } } } struct tree *parse_program (void) { PARSE_INIT (type_tl_program); while (1) { PARSE_TRY_PES (parse_constr_declarations); if (parse.lex.type == lex_eof) { PARSE_OK; } if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("functions") < 0 || expect ("---") < 0) { PARSE_FAIL; } PARSE_TRY_PES (parse_fun_declarations); if (parse.lex.type == lex_eof) { PARSE_OK; } if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("types") < 0 || expect ("---") < 0) { PARSE_FAIL; } } } struct tree *tl_parse_lex (struct parse *_parse) { assert (_parse); load_parse (*_parse); if (parse.lex.type == lex_none) { parse_lex (); } if (parse.lex.type == lex_error) { return 0; } return parse_program (); } int mystrcmp2 (const char *b, int len, const char *a) { int c = strncmp (b, a, len); return c ? a[len] ? -1 : 0 : c; } char *mystrdup (const char *a, int len) { char *z = talloc (len + 1); memcpy (z, a, len); z[len] = 0; return z; } struct tl_program *tl_program_cur; #define TL_TRY_PES(x) if (!(x)) { return 0; } #define tl_type_cmp(a,b) (strcmp (a->id, b->id)) DEFINE_TREE (tl_type,struct tl_type *,tl_type_cmp,0) struct tree_tl_type *tl_type_tree; DEFINE_TREE (tl_constructor,struct tl_constructor *,tl_type_cmp,0) struct tree_tl_constructor *tl_constructor_tree; struct tree_tl_constructor *tl_function_tree; DEFINE_TREE (tl_var,struct tl_var *,tl_type_cmp,0) struct tl_var_value { struct tl_combinator_tree *ptr; struct tl_combinator_tree *val; int num_val; }; #define tl_var_value_cmp(a,b) (((char *)a.ptr) - ((char *)b.ptr)) struct tl_var_value empty; DEFINE_TREE (var_value, struct tl_var_value, tl_var_value_cmp, empty) //tree_tl_var_t *tl_var_tree; DEFINE_TREE (tl_field,char *,strcmp, 0) //tree_tl_field_t *tl_field_tree; #define TL_FAIL return 0; #define TL_INIT(x) struct tl_combinator_tree *x = 0; #define TL_TRY(f,x) { struct tl_combinator_tree *_t = f; if (!_t) { TL_FAIL;} x = tl_union (x, _t); if (!x) { TL_FAIL; }} #define TL_ERROR(...) fprintf (stderr, __VA_ARGS__); #define TL_WARNING(...) fprintf (stderr, __VA_ARGS__); void tl_set_var_value (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value) { struct tl_var_value t = {.ptr = var, .val = value, .num_val = 0}; if (tree_lookup_var_value (*T, t).ptr) { *T = tree_delete_var_value (*T, t); } *T = tree_insert_var_value (*T, t, lrand48 ()); } void tl_set_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value, long long num_value) { struct tl_var_value t = {.ptr = var, .val = value, .num_val = num_value}; if (tree_lookup_var_value (*T, t).ptr) { *T = tree_delete_var_value (*T, t); } *T = tree_insert_var_value (*T, t, lrand48 ()); } struct tl_combinator_tree *tl_get_var_value (struct tree_var_value **T, struct tl_combinator_tree *var) { struct tl_var_value t = {.ptr = var, .val = 0, .num_val = 0}; struct tl_var_value r = tree_lookup_var_value (*T, t); return r.ptr ? r.val : 0; } int tl_get_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var) { struct tl_var_value t = {.ptr = var, .val = 0}; struct tl_var_value r = tree_lookup_var_value (*T, t); return r.ptr ? r.num_val : 0; } int namespace_level; struct tree_tl_var *vars[10]; struct tree_tl_field *fields[10]; struct tl_var *last_num_var[10]; int tl_is_type_name (const char *id, int len) { if (len == 1 && *id == '#') { return 1;} int ok = id[0] >= 'A' && id[0] <= 'Z'; int i; for (i = 0; i < len - 1; i++) if (id[i] == '.') { ok = id[i + 1] >= 'A' && id[i + 1] <= 'Z'; } return ok; } int tl_add_field (char *id) { assert (namespace_level < 10); assert (namespace_level >= 0); if (tree_lookup_tl_field (fields[namespace_level], id)) { return 0; } fields[namespace_level] = tree_insert_tl_field (fields[namespace_level], id, lrand48 ()); return 1; } void tl_clear_fields (void) { // tree_act_tl_field (fields[namespace_level], (void *)free); fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]); } struct tl_var *tl_add_var (char *id, struct tl_combinator_tree *ptr, int type) { struct tl_var *v = talloc (sizeof (*v)); v->id = tstrdup (id); v->type = type; v->ptr = ptr; v->flags = 0; if (tree_lookup_tl_var (vars[namespace_level], v)) { return 0; } vars[namespace_level] = tree_insert_tl_var (vars[namespace_level], v, lrand48 ()); if (type) { last_num_var[namespace_level] = v; } return v; } void tl_del_var (struct tl_var *v) { // free (v->id); tfree (v, sizeof (*v)); } void tl_clear_vars (void) { tree_act_tl_var (vars[namespace_level], tl_del_var); vars[namespace_level] = tree_clear_tl_var (vars[namespace_level]); last_num_var[namespace_level] = 0; } struct tl_var *tl_get_last_num_var (void) { return last_num_var[namespace_level]; } struct tl_var *tl_get_var (char *_id, int len) { char *id = mystrdup (_id, len); struct tl_var v = {.id = id}; int i; for (i = namespace_level; i >= 0; i--) { struct tl_var *w = tree_lookup_tl_var (vars[i], &v); if (w) { tfree (id, len + 1); return w; } } tfree (id, len + 1); return 0; } void namespace_push (void) { namespace_level ++; assert (namespace_level < 10); tl_clear_vars (); tl_clear_fields (); } void namespace_pop (void) { namespace_level --; assert (namespace_level >= 0); } struct tl_type *tl_get_type (const char *_id, int len) { char *id = mystrdup (_id, len); struct tl_type _t = {.id = id}; struct tl_type *r = tree_lookup_tl_type (tl_type_tree, &_t); tfree (id, len + 1); return r; } struct tl_type *tl_add_type (const char *_id, int len, int params_num, long long params_types) { char *id = talloc (len + 1); memcpy (id, _id, len); id[len] = 0; struct tl_type _t = {.id = id}; struct tl_type *_r = 0; if ((_r = tree_lookup_tl_type (tl_type_tree, &_t))) { tfree (id, len + 1); if (params_num >= 0 && (_r->params_num != params_num || _r->params_types != params_types)) { TL_ERROR ("Wrong params_num or types for type %s\n", _r->id); return 0; } return _r; } struct tl_type *t = talloc (sizeof (*t)); t->id = id; t->print_id = tstrdup (t->id); int i; for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { t->print_id[i] = '$'; } t->name = 0; t->constructors_num = 0; t->constructors = 0; t->flags = 0; t->real_id = 0; if (params_num >= 0) { assert (params_num <= 64); t->params_num = params_num; t->params_types = params_types; } else { t->flags |= 4; t->params_num = -1; } tl_type_tree = tree_insert_tl_type (tl_type_tree, t, lrand48 ()); total_types_num ++; return t; } void tl_add_type_param (struct tl_type *t, int x) { assert (t->flags & 4); assert (t->params_num <= 64); if (x) { t->params_types |= (1ull << (t->params_num ++)); } else { t->params_num ++; } } int tl_type_set_params (struct tl_type *t, int x, long long y) { if (t->flags & 4) { t->params_num = x; t->params_types = y; t->flags &= ~4; } else { if (t->params_num != x || t->params_types != y) { fprintf (stderr, "Wrong num of params (type %s)\n", t->id); return 0; } } return 1; } void tl_type_finalize (struct tl_type *t) { t->flags &= ~4; } struct tl_constructor *tl_get_constructor (const char *_id, int len) { char *id = mystrdup (_id, len); struct tl_constructor _t = {.id = id}; struct tl_constructor *r = tree_lookup_tl_constructor (tl_constructor_tree, &_t); tfree (id, len + 1); return r; } struct tl_constructor *tl_add_constructor (struct tl_type *a, const char *_id, int len, int force_magic) { assert (a); if (a->flags & 1) { TL_ERROR ("New constructor for type `%s` after final statement\n", a->id); return 0; } int x = 0; while (x < len && (_id[x] != '#' || force_magic)) { x++; } char *id = talloc (x + 1); memcpy (id, _id, x); id[x] = 0; unsigned magic = 0; if (x < len) { assert (len - x >= 6 && len - x <= 9); int i; for (i = 1; i < len - x; i++) { magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10); } assert (magic && magic != (unsigned)-1); } len = x; if (*id != '_') { struct tl_constructor _t = {.id = id}; if (tree_lookup_tl_constructor (tl_constructor_tree, &_t)) { TL_ERROR ("Duplicate constructor id `%s`\n", id); tfree (id, len + 1); return 0; } } else { assert (len == 1); } struct tl_constructor *t = talloc (sizeof (*t)); t->type = a; t->name = magic; t->id = id; t->print_id = tstrdup (id); t->real_id = 0; int i; for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { t->print_id[i] = '$'; } t->left = t->right = 0; a->constructors = realloc (a->constructors, sizeof (void *) * (a->constructors_num + 1)); assert (a->constructors); a->constructors[a->constructors_num ++] = t; if (*id != '_') { tl_constructor_tree = tree_insert_tl_constructor (tl_constructor_tree, t, lrand48 ()); } else { a->flags |= FLAG_DEFAULT_CONSTRUCTOR; } total_constructors_num ++; return t; } struct tl_constructor *tl_get_function (const char *_id, int len) { char *id = mystrdup (_id, len); struct tl_constructor _t = {.id = id}; struct tl_constructor *r = tree_lookup_tl_constructor (tl_function_tree, &_t); tfree (id, len + 1); return r; } struct tl_constructor *tl_add_function (struct tl_type *a, const char *_id, int len, int force_magic) { // assert (a); int x = 0; while (x < len && ((_id[x] != '#') || force_magic)) { x++; } char *id = talloc (x + 1); memcpy (id, _id, x); id[x] = 0; unsigned magic = 0; if (x < len) { assert (len - x >= 6 && len - x <= 9); int i; for (i = 1; i < len - x; i++) { magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10); } assert (magic && magic != (unsigned)-1); } len = x; struct tl_constructor _t = {.id = id}; if (tree_lookup_tl_constructor (tl_function_tree, &_t)) { TL_ERROR ("Duplicate function id `%s`\n", id); tfree (id, len + 1); return 0; } struct tl_constructor *t = talloc (sizeof (*t)); t->type = a; t->name = magic; t->id = id; t->print_id = tstrdup (id); t->real_id = 0; int i; for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { t->print_id[i] = '$'; } t->left = t->right = 0; tl_function_tree = tree_insert_tl_constructor (tl_function_tree, t, lrand48 ()); total_functions_num ++; return t; } static char buf[(1 << 20)]; int buf_pos; struct tl_combinator_tree *alloc_ctree_node (void) { struct tl_combinator_tree *T = talloc (sizeof (*T)); assert (T); memset (T, 0, sizeof (*T)); return T; } struct tl_combinator_tree *tl_tree_dup (struct tl_combinator_tree *T) { if (!T) { return 0; } struct tl_combinator_tree *S = talloc (sizeof (*S)); memcpy (S, T, sizeof (*S)); S->left = tl_tree_dup (T->left); S->right = tl_tree_dup (T->right); return S; } struct tl_type *tl_tree_get_type (struct tl_combinator_tree *T) { assert (T->type == type_type); if (T->act == act_array) { return 0;} while (T->left) { T = T->left; if (T->act == act_array) { return 0;} assert (T->type == type_type); } assert (T->act == act_type || T->act == act_var || T->act == act_array); return T->act == act_type ? T->data : 0; } void tl_tree_set_len (struct tl_combinator_tree *T) { TL_INIT (H); H = T; while (H->left) { H->left->type_len = H->type_len + 1; H = H->left; } assert (H->type == type_type); struct tl_type *t = H->data; assert (t); assert (H->type_len == t->params_num); } void tl_buf_reset (void) { buf_pos = 0; } void tl_buf_add_string (char *s, int len) { if (len < 0) { len = strlen (s); } buf[buf_pos ++] = ' '; memcpy (buf + buf_pos, s, len); buf_pos += len; buf[buf_pos] = 0; } void tl_buf_add_string_nospace (char *s, int len) { if (len < 0) { len = strlen (s); } // if (buf_pos) { buf[buf_pos ++] = ' '; } memcpy (buf + buf_pos, s, len); buf_pos += len; buf[buf_pos] = 0; } void tl_buf_add_string_q (char *s, int len, int x) { if (x) { tl_buf_add_string (s, len); } else { tl_buf_add_string_nospace (s, len); } } void tl_buf_add_tree (struct tl_combinator_tree *T, int x) { if (!T) { return; } assert (T != (void *)-1l && T != (void *)-2l); switch (T->act) { case act_question_mark: tl_buf_add_string_q ("?", -1, x); return; case act_type: if ((T->flags & 1) && !(T->flags & 4)) { tl_buf_add_string_q ("%", -1, x); x = 0; } if (T->flags & 2) { tl_buf_add_string_q ((char *)T->data, -1, x); } else { struct tl_type *t = T->data; if (T->flags & 4) { assert (t->constructors_num == 1); tl_buf_add_string_q (t->constructors[0]->real_id ? t->constructors[0]->real_id : t->constructors[0]->id, -1, x); } else { tl_buf_add_string_q (t->real_id ? t->real_id : t->id, -1, x); } } return; case act_field: if (T->data) { tl_buf_add_string_q ((char *)T->data, -1, x); x = 0; tl_buf_add_string_q (":", -1, 0); } tl_buf_add_tree (T->left, x); tl_buf_add_tree (T->right, 1); return; case act_union: tl_buf_add_tree (T->left, x); tl_buf_add_tree (T->right, 1); return; case act_var: { if (T->data == (void *)-1l) { return; } struct tl_combinator_tree *v = T->data; tl_buf_add_string_q ((char *)v->data, -1, x); if (T->type == type_num && T->type_flags) { static char _buf[30]; sprintf (_buf, "+%lld", T->type_flags); tl_buf_add_string_q (_buf, -1, 0); } } return; case act_arg: tl_buf_add_tree (T->left, x); tl_buf_add_tree (T->right, 1); return; case act_array: if (T->left && !(T->left->flags & 128)) { tl_buf_add_tree (T->left, x); x = 0; tl_buf_add_string_q ("*", -1, x); } tl_buf_add_string_q ("[", -1, x); tl_buf_add_tree (T->right, 1); tl_buf_add_string_q ("]", -1, 1); return; case act_plus: tl_buf_add_tree (T->left, x); tl_buf_add_string_q ("+", -1, 0); tl_buf_add_tree (T->right, 0); return; case act_nat_const: { static char _buf[30]; snprintf (_buf, 29, "%lld", T->type_flags); tl_buf_add_string_q (_buf, -1, x); return; } case act_opt_field: { struct tl_combinator_tree *v = T->left->data; tl_buf_add_string_q ((char *)v->data, -1, x); tl_buf_add_string_q (".", -1, 0); static char _buf[30]; sprintf (_buf, "%lld", T->left->type_flags); tl_buf_add_string_q (_buf, -1, 0); tl_buf_add_string_q ("?", -1, 0); tl_buf_add_tree (T->right, 0); return; } default: fprintf (stderr, "%s %s\n", TL_ACT (T->act), TL_TYPE (T->type)); assert (0); return; } } int tl_count_combinator_name (struct tl_constructor *c) { assert (c); tl_buf_reset (); tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1); tl_buf_add_tree (c->left, 1); tl_buf_add_string ("=", -1); tl_buf_add_tree (c->right, 1); //fprintf (stderr, "%.*s\n", buf_pos, buf); if (!c->name) { c->name = crc32 (CRC32_INITIAL, (void *) buf, buf_pos); } return c->name; } int tl_print_combinator (struct tl_constructor *c) { tl_buf_reset (); tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1); static char _buf[10]; sprintf (_buf, "#%08x", c->name); tl_buf_add_string_nospace (_buf, -1); tl_buf_add_tree (c->left, 1); tl_buf_add_string ("=", -1); tl_buf_add_tree (c->right, 1); if (output_expressions >= 1) { fprintf (stderr, "%.*s\n", buf_pos, buf); } /* if (!c->name) { c->name = crc32 (CRC32_INITIAL, (void *) bbuf, buf_pos); }*/ return c->name; } int _tl_finish_subtree (struct tl_combinator_tree *R, int x, long long y) { assert (R->type == type_type); assert (R->type_len < 0); assert (R->act == act_arg || R->act == act_type); R->type_len = x; R->type_flags = y; if (R->act == act_type) { struct tl_type *t = R->data; assert (t); return tl_type_set_params (t, x, y); } assert ((R->right->type == type_type && R->right->type_len == 0) || R->right->type == type_num || R->right->type == type_num_value); return _tl_finish_subtree (R->left, x + 1, y * 2 + (R->right->type == type_num || R->right->type == type_num_value)); } int tl_finish_subtree (struct tl_combinator_tree *R) { assert (R); if (R->type != type_type) { return 1; } if (R->type_len >= 0) { if (R->type_len > 0) { TL_ERROR ("Not enough params\n"); return 0; } return 1; } return _tl_finish_subtree (R, 0, 0); } struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_combinator_tree *R) { if (!L) { return R; } if (!R) { return L; } TL_INIT (v); v = alloc_ctree_node (); v->left = L; v->right = R; switch (L->type) { case type_num: if (R->type != type_num_value) { TL_ERROR ("Union: type mistmatch\n"); return 0; } tfree (v, sizeof (*v)); L->type_flags += R->type_flags; return L; case type_num_value: if (R->type != type_num_value && R->type != type_num) { TL_ERROR ("Union: type mistmatch\n"); return 0; } tfree (v, sizeof (*v)); R->type_flags += L->type_flags; return R; case type_list_item: case type_list: if (R->type != type_list_item) { TL_ERROR ("Union: type mistmatch\n"); return 0; } v->type = type_list; v->act = act_union; return v; case type_type: if (L->type_len == 0) { TL_ERROR ("Arguments number exceeds type arity\n"); return 0; } if (R->type != type_num && R->type != type_type && R->type != type_num_value) { TL_ERROR ("Union: type mistmatch\n"); return 0; } if (R->type_len < 0) { if (!tl_finish_subtree (R)) { return 0; } } if (R->type_len > 0) { TL_ERROR ("Argument type must have full number of arguments\n"); return 0; } if (L->type_len > 0 && ((L->type_flags & 1) != (R->type == type_num || R->type == type_num_value))) { TL_ERROR ("Argument types mistmatch: L->type_flags = %lld, R->type = %s\n", L->flags, TL_TYPE (R->type)); return 0; } v->type = type_type; v->act = act_arg; v->type_len = L->type_len > 0 ? L->type_len - 1 : -1; v->type_flags = L->type_flags >> 1; return v; default: assert (0); return 0; } } struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s); struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) { assert (T->type == type_term); int i = 0; while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; } assert (i < T->nc); TL_INIT (L); while (i < T->nc) { TL_TRY (tl_parse_any_term (T->c[i], s), L); s = 0; i ++; } return L; } struct tl_combinator_tree *tl_parse_type_term (struct tree *T, int s) { assert (T->type == type_type_term); assert (T->nc == 1); struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s); if (!Z || Z->type != type_type) { if (Z) { TL_ERROR ("type_term: found type %s\n", TL_TYPE (Z->type)); } TL_FAIL; } return Z; } struct tl_combinator_tree *tl_parse_nat_term (struct tree *T, int s) { assert (T->type == type_nat_term); assert (T->nc == 1); struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s); if (!Z || (Z->type != type_num && Z->type != type_num_value)) { if (Z) { TL_ERROR ("nat_term: found type %s\n", TL_TYPE (Z->type)); }TL_FAIL; } return Z; } struct tl_combinator_tree *tl_parse_subexpr (struct tree *T, int s) { assert (T->type == type_subexpr); assert (T->nc >= 1); int i; TL_INIT (L); for (i = 0; i < T->nc; i++) { TL_TRY (tl_parse_any_term (T->c[i], s), L); s = 0; } return L; } struct tl_combinator_tree *tl_parse_expr (struct tree *T, int s) { assert (T->type == type_expr); assert (T->nc >= 1); int i; TL_INIT (L); for (i = 0; i < T->nc; i++) { TL_TRY (tl_parse_subexpr (T->c[i], s), L); s = 0; } return L; } struct tl_combinator_tree *tl_parse_nat_const (struct tree *T, int s) { assert (T->type == type_nat_const); assert (!T->nc); if (s > 0) { TL_ERROR ("Nat const can not precede with %%\n"); TL_FAIL; } assert (T->type == type_nat_const); assert (!T->nc); TL_INIT (L); L = alloc_ctree_node (); L->act = act_nat_const; L->type = type_num_value; int i; long long x = 0; for (i = 0; i < T->len; i++) { x = x * 10 + T->text[i] - '0'; } L->type_flags = x; return L; } struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) { assert (T->type == type_type_ident || T->type == type_var_ident || T->type == type_boxed_type_ident); assert (!T->nc); struct tl_var *v = tl_get_var (T->text, T->len); TL_INIT (L); if (v) { L = alloc_ctree_node (); L->act = act_var; L->type = v->type ? type_num : type_type; if (L->type == type_num && s) { TL_ERROR ("Nat var can not precede with %%\n"); TL_FAIL; } else { if (s) { L->flags |= 1; } } L->type_len = 0; L->type_flags = 0; L->data = v->ptr; return L; } /* if (!mystrcmp2 (T->text, T->len, "#") || !mystrcmp2 (T->text, T->len, "Type")) { L = alloc_ctree_node (); L->act = act_type; L->flags |= 2; L->data = tl_get_type (T->text, T->len); assert (L->data); L->type = type_type; L->type_len = 0; L->type_flags = 0; return L; }*/ struct tl_constructor *c = tl_get_constructor (T->text, T->len); if (c) { assert (c->type); if (c->type->constructors_num != 1) { TL_ERROR ("Constructor can be used only if it is the only constructor of the type\n"); return 0; } c->type->flags |= 1; L = alloc_ctree_node (); L->act = act_type; L->flags |= 5; L->data = c->type; L->type = type_type; L->type_len = c->type->params_num; L->type_flags = c->type->params_types; return L; } int x = tl_is_type_name (T->text, T->len); if (x) { struct tl_type *t = tl_add_type (T->text, T->len, -1, 0); L = alloc_ctree_node (); if (s) { L->flags |= 1; t->flags |= 8; } L->act = act_type; L->data = t; L->type = type_type; L->type_len = t->params_num; L->type_flags = t->params_types; return L; } else { TL_ERROR ("Not a type/var ident `%.*s`\n", T->len, T->text); return 0; } } struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s) { switch (T->type) { case type_type_term: return tl_parse_type_term (T, s); case type_nat_term: return tl_parse_nat_term (T, s); case type_term: return tl_parse_term (T, s); case type_expr: return tl_parse_expr (T, s); case type_subexpr: return tl_parse_subexpr (T, s); case type_nat_const: return tl_parse_nat_const (T, s); case type_type_ident: case type_var_ident: return tl_parse_ident (T, s); default: fprintf (stderr, "type = %d\n", T->type); assert (0); return 0; } } struct tl_combinator_tree *tl_parse_multiplicity (struct tree *T) { assert (T->type == type_multiplicity); assert (T->nc == 1); return tl_parse_nat_term (T->c[0], 0); } struct tl_combinator_tree *tl_parse_opt_args (struct tree *T) { assert (T); assert (T->type == type_opt_args); assert (T->nc >= 2); TL_INIT (R); TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R); assert (R->type == type_type && !R->type_len); assert (tl_finish_subtree (R)); struct tl_type *t = tl_tree_get_type (R); //assert (t); int tt = -1; if (t && !strcmp (t->id, "#")) { tt = 1; } else if (t && !strcmp (t->id, "Type")) { tt = 0; } if (tt < 0) { TL_ERROR ("Optargs can be only of type # or Type\n"); TL_FAIL; } int i; for (i = 0; i < T->nc - 1; i++) { if (T->c[i]->type != type_var_ident) { TL_ERROR ("Variable name expected\n"); TL_FAIL; } if (T->c[i]->len == 1 && *T->c[i]->text == '_') { TL_ERROR ("Variables can not be unnamed\n"); TL_FAIL; } } TL_INIT (H); // for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) { for (i = 0; i <= T->nc - 2; i++) { TL_INIT (S); S = alloc_ctree_node (); S->left = (i == T->nc - 2) ? R : tl_tree_dup (R) ; S->right = 0; S->type = type_list_item; S->type_len = 0; S->act = act_field; S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0; if (tt >= 0) { assert (S->data); tl_add_var (S->data, S, tt); } S->flags = 33; H = tl_union (H, S); } return H; } struct tl_combinator_tree *tl_parse_args (struct tree *T); struct tl_combinator_tree *tl_parse_args2 (struct tree *T) { assert (T); assert (T->type == type_args2); assert (T->nc >= 1); TL_INIT (R); TL_INIT (L); int x = 0; char *field_name = 0; if (T->c[x]->type == type_var_ident_opt || T->c[x]->type == type_var_ident) { field_name = mystrdup (T->c[x]->text, T->c[x]->len); if (!tl_add_field (field_name)) { TL_ERROR ("Duplicate field name %s\n", field_name); TL_FAIL; } x ++; } //fprintf (stderr, "%d %d\n", x, T->nc); if (T->c[x]->type == type_multiplicity) { L = tl_parse_multiplicity (T->c[x]); if (!L) { TL_FAIL;} x ++; } else { struct tl_var *v = tl_get_last_num_var (); if (!v) { TL_ERROR ("Expected multiplicity or nat var\n"); TL_FAIL; } L = alloc_ctree_node (); L->act = act_var; L->type = type_num; L->flags |= 128; L->type_len = 0; L->type_flags = 0; L->data = v->ptr; ((struct tl_combinator_tree *)(v->ptr))->flags |= 256; } namespace_push (); while (x < T->nc) { TL_TRY (tl_parse_args (T->c[x]), R); x ++; } namespace_pop (); struct tl_combinator_tree *S = alloc_ctree_node (); S->type = type_type; S->type_len = 0; S->act = act_array; S->left = L; S->right = R; //S->data = field_name; struct tl_combinator_tree *H = alloc_ctree_node (); H->type = type_list_item; H->act = act_field; H->left = S; H->right = 0; H->data = field_name; H->type_len = 0; return H; } void tl_mark_vars (struct tl_combinator_tree *T); struct tl_combinator_tree *tl_parse_args134 (struct tree *T) { assert (T); assert (T->type == type_args1 || T->type == type_args3 || T->type == type_args4); assert (T->nc >= 1); TL_INIT (R); TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R); assert (tl_finish_subtree (R)); assert (R->type == type_type && !R->type_len); struct tl_type *t = tl_tree_get_type (R); //assert (t); int tt = -1; if (t && !strcmp (t->id, "#")) { tt = 1; } else if (t && !strcmp (t->id, "Type")) { tt = 0; } /* if (tt >= 0 && T->nc == 1) { TL_ERROR ("Variables can not be unnamed (type %d)\n", tt); }*/ int last = T->nc - 2; int excl = 0; if (last >= 0 && T->c[last]->type == type_exclam) { excl ++; tl_mark_vars (R); last --; } if (last >= 0 && T->c[last]->type == type_optional_arg_def) { assert (T->c[last]->nc == 2); TL_INIT (E); E = alloc_ctree_node (); E->type = type_type; E->act = act_opt_field; E->left = tl_parse_ident (T->c[last]->c[0], 0); int i; long long x = 0; for (i = 0; i < T->c[last]->c[1]->len; i++) { x = x * 10 + T->c[last]->c[1]->text[i] - '0'; } E->left->type_flags = x; E->type_flags = R->type_flags; E->type_len = R->type_len; E->right = R; R = E; last --; } int i; for (i = 0; i < last; i++) { if (T->c[i]->type != type_var_ident && T->c[i]->type != type_var_ident_opt) { TL_ERROR ("Variable name expected\n"); TL_FAIL; } /* if (tt >= 0 && (T->nc == 1 || (T->c[i]->len == 1 && *T->c[i]->text == '_'))) { TL_ERROR ("Variables can not be unnamed\n"); TL_FAIL; }*/ } TL_INIT (H); // for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) { for (i = (last >= 0 ? 0 : -1); i <= last; i++) { TL_INIT (S); S = alloc_ctree_node (); S->left = (i == last) ? R : tl_tree_dup (R) ; S->right = 0; S->type = type_list_item; S->type_len = 0; S->act = act_field; S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0; if (excl) { S->flags |= FLAG_EXCL; } if (S->data && (T->c[i]->len >= 2 || *T->c[i]->text != '_')) { if (!tl_add_field (S->data)) { TL_ERROR ("Duplicate field name %s\n", (char *)S->data); TL_FAIL; } } if (tt >= 0) { char *name = S->data; static char s[21]; if (!name) { sprintf (s, "%lld", lrand48 () * (1ll << 32) + lrand48 ()); name = s; // will be strdup'd, so reference-to-stack is fine. } struct tl_var *v = tl_add_var (name, S, tt); if (!v) {TL_FAIL;} v->flags |= 2; } H = tl_union (H, S); } return H; } struct tl_combinator_tree *tl_parse_args (struct tree *T) { assert (T->type == type_args); assert (T->nc == 1); switch (T->c[0]->type) { case type_args1: return tl_parse_args134 (T->c[0]); case type_args2: return tl_parse_args2 (T->c[0]); case type_args3: return tl_parse_args134 (T->c[0]); case type_args4: return tl_parse_args134 (T->c[0]); default: assert (0); return 0; } } void tl_mark_vars (struct tl_combinator_tree *T) { if (!T) { return; } if (T->act == act_var) { char *id = ((struct tl_combinator_tree *)(T->data))->data; struct tl_var *v = tl_get_var (id, strlen (id)); assert (v); v->flags |= 1; } tl_mark_vars (T->left); tl_mark_vars (T->right); } struct tl_combinator_tree *tl_parse_result_type (struct tree *T) { assert (T->type == type_result_type); assert (T->nc >= 1); assert (T->nc <= 64); TL_INIT (L); if (tl_get_var (T->c[0]->text, T->c[0]->len)) { if (T->nc != 1) { TL_ERROR ("Variable can not take params\n"); TL_FAIL; } L = alloc_ctree_node (); L->act = act_var; L->type = type_type; struct tl_var *v = tl_get_var (T->c[0]->text, T->c[0]->len); if (v->type) { TL_ERROR ("Type mistmatch\n"); TL_FAIL; } L->data = v->ptr; // assert (v->ptr); } else { L = alloc_ctree_node (); L->act = act_type; L->type = type_type; struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, -1, 0); assert (t); L->type_len = t->params_num; L->type_flags = t->params_types; L->data = t; int i; for (i = 1; i < T->nc; i++) { TL_TRY (tl_parse_any_term (T->c[i], 0), L); assert (L->right); assert (L->right->type == type_num || L->right->type == type_num_value || (L->right->type == type_type && L->right->type_len == 0)); } } if (!tl_finish_subtree (L)) { TL_FAIL; } tl_mark_vars (L); return L; } int __ok; void tl_var_check_used (struct tl_var *v) { __ok = __ok && (v->flags & 3); } int tl_parse_combinator_decl (struct tree *T, int fun) { assert (T->type == type_combinator_decl); assert (T->nc >= 3); namespace_level = 0; tl_clear_vars (); tl_clear_fields (); TL_INIT (L); TL_INIT (R); int i = 1; while (i < T->nc - 2 && T->c[i]->type == type_opt_args) { TL_TRY (tl_parse_opt_args (T->c[i]), L); i++; } while (i < T->nc - 2 && T->c[i]->type == type_args) { TL_TRY (tl_parse_args (T->c[i]), L); i++; } assert (i == T->nc - 2 && T->c[i]->type == type_equals); i ++; R = tl_parse_result_type (T->c[i]); if (!R) { TL_FAIL; } struct tl_type *t = tl_tree_get_type (R); if (!fun && !t) { TL_ERROR ("Only functions can return variables\n"); } assert (t || fun); assert (namespace_level == 0); __ok = 1; tree_act_tl_var (vars[0], tl_var_check_used); if (!__ok) { TL_ERROR ("Not all variables are used in right side\n"); TL_FAIL; } if (tl_get_constructor (T->c[0]->text, T->c[0]->len) || tl_get_function (T->c[0]->text, T->c[0]->len)) { TL_ERROR ("Duplicate combinator id %.*s\n", T->c[0]->len, T->c[0]->text); return 0; } struct tl_constructor *c = !fun ? tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0) : tl_add_function (t, T->c[0]->text, T->c[0]->len, 0); if (!c) { TL_FAIL; } c->left = L; c->right = R; if (!c->name) { tl_count_combinator_name (c); } tl_print_combinator (c); return 1; } void change_var_ptrs (struct tl_combinator_tree *O, struct tl_combinator_tree *D, struct tree_var_value **V) { if (!O || !D) { assert (!O && !D); return; } if (O->act == act_field) { struct tl_type *t = tl_tree_get_type (O->left); if (t && (!strcmp (t->id, "#") || !strcmp (t->id, "Type"))) { tl_set_var_value (V, O, D); } } if (O->act == act_var) { assert (D->data == O->data); D->data = tl_get_var_value (V, O->data); assert (D->data); } change_var_ptrs (O->left, D->left, V); change_var_ptrs (O->right, D->right, V); } struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struct tl_combinator_tree **X, struct tl_combinator_tree *Y) { if (!O) { return (void *)-2l; }; if (O->act == act_field && !*X) { struct tl_type *t = tl_tree_get_type (O->left); if (t && !strcmp (t->id, "#")) { if (Y->type != type_num && Y->type != type_num_value) { TL_ERROR ("change_var: Type mistmatch\n"); return 0; } else { *X = O; return (void *)-1l; } } if (t && !strcmp (t->id, "Type")) { if (Y->type != type_type || Y->type_len != 0) { TL_ERROR ("change_var: Type mistmatch\n"); return 0; } else { *X = O; return (void *)-1l; } } } if (O->act == act_var) { if (O->data == *X) { struct tl_combinator_tree *R = tl_tree_dup (Y); if (O->type == type_num || O->type == type_num_value) { R->type_flags += O->type_flags; } return R; } } struct tl_combinator_tree *t; t = change_first_var (O->left, X, Y); if (!t) { return 0;} if (t == (void *)-1l) { t = change_first_var (O->right, X, Y); if (!t) { return 0;} if (t == (void *)-1l) { return (void *)-1l; } if (t != (void *)-2l) { return t;} return (void *)-1l; } if (t != (void *)-2l) { O->left = t; } t = change_first_var (O->right, X, Y); if (!t) { return 0;} if (t == (void *)-1l) { return O->left; } if (t != (void *)-2l) { O->right = t; } return O; } int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T); struct tree_var_value **_T; int __tok; void check_nat_val (struct tl_var_value v) { if (!__tok) { return; } long long x = v.num_val; struct tl_combinator_tree *L = v.val; if (L->type == type_type) { return;} while (1) { if (L->type == type_num_value) { if (x + L->type_flags < 0) { __tok = 0; return; } else { return; } } assert (L->type == type_num); x += L->type_flags; x += tl_get_var_value_num (_T, L->data); L = tl_get_var_value (_T, L->data); if (!L) { return;} } } int check_constructors_equal (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) { if (!uniformize (L, R, T)) { return 0; } __tok = 1; _T = T; tree_act_var_value (*T, check_nat_val); return __tok; } struct tl_combinator_tree *reduce_type (struct tl_combinator_tree *A, struct tl_type *t) { assert (A); if (A->type_len == t->params_num) { assert (A->type_flags == t->params_types); A->act = act_type; A->type = type_type; A->left = A->right = 0; A->data = t; return A; } A->left = reduce_type (A->left, t); return A; } struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struct tree_var_value **X) { if (!O) { return (void *)-2l; }; while (O->act == act_var) { assert (O->data); if (!tl_get_var_value (X, O->data)) { break; } if (O->type == type_type) { O = tl_tree_dup (tl_get_var_value (X, O->data)); } else { long long n = tl_get_var_value_num (X, O->data); struct tl_combinator_tree *T = tl_get_var_value (X, O->data); O->data = T->data; O->type = T->type; O->act = T->act; O->type_flags = O->type_flags + n + T->type_flags; } } if (O->act == act_field) { if (tl_get_var_value (X, O)) { return (void *)-1l; } } struct tl_combinator_tree *t; t = change_value_var (O->left, X); if (!t) { return 0;} if (t == (void *)-1l) { t = change_value_var (O->right, X); if (!t) { return 0;} if (t == (void *)-1l) { return (void *)-1l; } if (t != (void *)-2l) { return t;} return (void *)-1l; } if (t != (void *)-2l) { O->left = t; } t = change_value_var (O->right, X); if (!t) { return 0;} if (t == (void *)-1l) { return O->left; } if (t != (void *)-2l) { O->right = t; } return O; } int tl_parse_partial_type_app_decl (struct tree *T) { assert (T->type == type_partial_type_app_decl); assert (T->nc >= 1); assert (T->c[0]->type == type_boxed_type_ident); struct tl_type *t = tl_get_type (T->c[0]->text, T->c[0]->len); if (!t) { TL_ERROR ("Can not make partial app for unknown type\n"); return 0; } tl_type_finalize (t); struct tl_combinator_tree *L = tl_parse_ident (T->c[0], 0); assert (L); int i; tl_buf_reset (); int cc = T->nc - 1; for (i = 1; i < T->nc; i++) { TL_TRY (tl_parse_any_term (T->c[i], 0), L); tl_buf_add_tree (L->right, 1); } while (L->type_len) { struct tl_combinator_tree *C = alloc_ctree_node (); C->act = act_var; C->type = (L->type_flags & 1) ? type_num : type_type; C->type_len = 0; C->type_flags = 0; C->data = (void *)-1l; L = tl_union (L, C); if (!L) { return 0; } } static char _buf[100000]; snprintf (_buf, 100000, "%s%.*s", t->id, buf_pos, buf); struct tl_type *nt = tl_add_type (_buf, strlen (_buf), t->params_num - cc, t->params_types >> cc); assert (nt); //snprintf (_buf, 100000, "%s #", t->id); //nt->real_id = strdup (_buf); for (i = 0; i < t->constructors_num; i++) { struct tl_constructor *c = t->constructors[i]; struct tree_var_value *V = 0; TL_INIT (A); TL_INIT (B); A = tl_tree_dup (c->left); B = tl_tree_dup (c->right); struct tree_var_value *W = 0; change_var_ptrs (c->left, A, &W); change_var_ptrs (c->right, B, &W); if (!check_constructors_equal (B, L, &V)) { continue; } B = reduce_type (B, nt); A = change_value_var (A, &V); if (A == (void *)-1l) { A = 0;} B = change_value_var (B, &V); assert (B != (void *)-1l); snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf); struct tl_constructor *r = tl_add_constructor (nt, _buf, strlen (_buf), 1); snprintf (_buf, 100000, "%s", c->id); r->real_id = tstrdup (_buf); r->left = A; r->right = B; if (!r->name) { tl_count_combinator_name (r); } tl_print_combinator (r); } return 1; } int tl_parse_partial_comb_app_decl (struct tree *T, int fun) { assert (T->type == type_partial_comb_app_decl); struct tl_constructor *c = !fun ? tl_get_constructor (T->c[0]->text, T->c[0]->len) : tl_get_function (T->c[0]->text, T->c[0]->len); if (!c) { TL_ERROR ("Can not make partial app for undefined combinator\n"); return 0; } //TL_INIT (K); //static char buf[1000]; //int x = sprintf (buf, "%s", c->id); TL_INIT (L); TL_INIT (R); L = tl_tree_dup (c->left); R = tl_tree_dup (c->right); struct tree_var_value *V = 0; change_var_ptrs (c->left, L, &V); change_var_ptrs (c->right, R, &V); V = tree_clear_var_value (V); int i; tl_buf_reset (); for (i = 1; i < T->nc; i++) { TL_INIT (X); TL_INIT (Z); X = tl_parse_any_term (T->c[i], 0); struct tl_combinator_tree *K = 0; if (!(Z = change_first_var (L, &K, X))) { TL_FAIL; } L = Z; if (!K) { TL_ERROR ("Partial app: not enougth variables (i = %d)\n", i); TL_FAIL; } if (!(Z = change_first_var (R, &K, X))) { TL_FAIL; } assert (Z == R); tl_buf_add_tree (X, 1); } static char _buf[100000]; snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf); // fprintf (stderr, "Local id: %s\n", _buf); struct tl_constructor *r = !fun ? tl_add_constructor (c->type, _buf, strlen (_buf), 1) : tl_add_function (c->type, _buf, strlen (_buf), 1); r->left = L; r->right = R; snprintf (_buf, 100000, "%s", c->id); r->real_id = tstrdup (_buf); if (!r->name) { tl_count_combinator_name (r); } tl_print_combinator (r); return 1; } int tl_parse_partial_app_decl (struct tree *T, int fun) { assert (T->type == type_partial_app_decl); assert (T->nc == 1); if (T->c[0]->type == type_partial_comb_app_decl) { return tl_parse_partial_comb_app_decl (T->c[0], fun); } else { if (fun) { TL_ERROR ("Partial type app in functions block\n"); TL_FAIL; } return tl_parse_partial_type_app_decl (T->c[0]); } } int tl_parse_final_final (struct tree *T) { assert (T->type == type_final_final); assert (T->nc == 1); struct tl_type *R; if ((R = tl_get_type (T->c[0]->text, T->c[0]->len))) { R->flags |= 1; return 1; } else { TL_ERROR ("Final statement for type `%.*s` before declaration\n", T->c[0]->len, T->c[0]->text); TL_FAIL; } } int tl_parse_final_new (struct tree *T) { assert (T->type == type_final_new); assert (T->nc == 1); if (tl_get_type (T->c[0]->text, T->c[0]->len)) { TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text); TL_FAIL; } else { return 1; } } int tl_parse_final_empty (struct tree *T) { assert (T->type == type_final_empty); assert (T->nc == 1); if (tl_get_type (T->c[0]->text, T->c[0]->len)) { TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text); TL_FAIL; } struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, 0, 0); assert (t); t->flags |= 1 | FLAG_EMPTY; return 1; } int tl_parse_final_decl (struct tree *T, int fun) { assert (T->type == type_final_decl); assert (!fun); assert (T->nc == 1); switch (T->c[0]->type) { case type_final_new: return tl_parse_final_new (T->c[0]); case type_final_final: return tl_parse_final_final (T->c[0]); case type_final_empty: return tl_parse_final_empty (T->c[0]); default: assert (0); return 0; } } int tl_parse_builtin_combinator_decl (struct tree *T, int fun) { if (fun) { TL_ERROR ("Builtin type can not be described in function block\n"); return -1; } assert (T->type == type_builtin_combinator_decl); assert (T->nc == 2); assert (T->c[0]->type == type_full_combinator_id); assert (T->c[1]->type == type_boxed_type_ident); if ((!mystrcmp2 (T->c[0]->text, T->c[0]->len, "int") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Int")) || (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "long") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Long")) || (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "double") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Double")) || (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "string") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "String"))) { struct tl_type *t = tl_add_type (T->c[1]->text, T->c[1]->len, 0, 0); if (!t) { return 0; } struct tl_constructor *c = tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0); if (!c) { return 0; } c->left = alloc_ctree_node (); c->left->act = act_question_mark; c->left->type = type_list_item; c->right = alloc_ctree_node (); c->right->act = act_type; c->right->data = t; c->right->type = type_type; if (!c->name) { tl_count_combinator_name (c); } tl_print_combinator (c); } else { TL_ERROR ("Unknown builting type `%.*s`\n", T->c[0]->len, T->c[0]->text); return 0; } return 1; } int tl_parse_declaration (struct tree *T, int fun) { assert (T->type == type_declaration); assert (T->nc == 1); switch (T->c[0]->type) { case type_combinator_decl: return tl_parse_combinator_decl (T->c[0], fun); case type_partial_app_decl: return tl_parse_partial_app_decl (T->c[0], fun); case type_final_decl: return tl_parse_final_decl (T->c[0], fun); case type_builtin_combinator_decl: return tl_parse_builtin_combinator_decl (T->c[0], fun); default: assert (0); return 0; } } int tl_parse_constr_declarations (struct tree *T) { assert (T->type == type_constr_declarations); int i; for (i = 0; i < T->nc; i++) { TL_TRY_PES (tl_parse_declaration (T->c[i], 0)); } return 1; } int tl_parse_fun_declarations (struct tree *T) { assert (T->type == type_fun_declarations); int i; for (i = 0; i < T->nc; i++) { TL_TRY_PES (tl_parse_declaration (T->c[i], 1)); } return 1; } int tl_tree_lookup_value (struct tl_combinator_tree *L, void *var, struct tree_var_value **T) { if (!L) { return -1; } if (L->act == act_var && L->data == var) { return 0; } if (L->act == act_var) { struct tl_combinator_tree *E = tl_get_var_value (T, L->data); if (!E) { return -1;} else { return tl_tree_lookup_value (E, var, T); } } if (tl_tree_lookup_value (L->left, var, T) >= 0) { return 1; } if (tl_tree_lookup_value (L->right, var, T) >= 0) { return 1; } return -1; } int tl_tree_lookup_value_nat (struct tl_combinator_tree *L, void *var, long long x, struct tree_var_value **T) { assert (L); if (L->type == type_num_value) { return -1; } assert (L->type == type_num); assert (L->act == act_var); if (L->data == var) { return x == L->type_flags ? 0 : 1; } else { if (!tl_get_var_value (T, L->data)) { return -1; } return tl_tree_lookup_value_nat (tl_get_var_value (T, L->data), var, x + tl_get_var_value_num (T, L->data), T); } } int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) { if (!L || !R) { assert (!L && !R); return 1; } if (R->act == act_var) { struct tl_combinator_tree *_ = R; R = L; L = _; } if (L->type == type_type) { if (R->type != type_type || L->type_len != R->type_len || L->type_flags != R->type_flags) { return 0; } if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;} if (L->act == act_var) { int x = tl_tree_lookup_value (R, L->data, T); if (x > 0) { // if (tl_tree_lookup_value (R, L->data, T) > 0) { return 0; } if (x == 0) { return 1; } struct tl_combinator_tree *E = tl_get_var_value (T, L->data); if (!E) { tl_set_var_value (T, L->data, R); return 1; } else { return uniformize (E, R, T); } } else { if (L->act != R->act || L->data != R->data) { return 0; } return uniformize (L->left, R->left, T) && uniformize (L->right, R->right, T); } } else { assert (L->type == type_num || L->type == type_num_value); if (R->type != type_num && R->type != type_num_value) { return 0; } assert (R->type == type_num || R->type == type_num_value); if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;} long long x = 0; struct tl_combinator_tree *K = L; while (1) { x += K->type_flags; if (K->type == type_num_value) { break; } if (!tl_get_var_value (T, K->data)) { int s = tl_tree_lookup_value_nat (R, K->data, K->type_flags, T); if (s > 0) { return 0; } if (s == 0) { return 1; } /*tl_set_var_value_num (T, K->data, R, -x); return 1;*/ break; } x += tl_get_var_value_num (T, K->data); K = tl_get_var_value (T, K->data); } long long y = 0; struct tl_combinator_tree *M = R; while (1) { y += M->type_flags; if (M->type == type_num_value) { break; } if (!tl_get_var_value (T, M->data)) { int s = tl_tree_lookup_value_nat (L, M->data, M->type_flags, T); if (s > 0) { return 0; } if (s == 0) { return 1; } /*tl_set_var_value_num (T, M->data, L, -y); return 1;*/ break; } y += tl_get_var_value_num (T, M->data); M = tl_get_var_value (T, M->data); } if (K->type == type_num_value && M->type == type_num_value) { return x == y; } if (M->type == type_num_value) { tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags)); return 1; } else if (K->type == type_num_value) { tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags)); return 1; } else { if (x >= y) { tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags)); } else { tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags)); } return 1; } } return 0; } void tl_type_check (struct tl_type *t) { if (!__ok) return; if (!strcmp (t->id, "#")) { t->name = 0x70659eff; return; } if (!strcmp (t->id, "Type")) { t->name = 0x2cecf817; return; } if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) { TL_ERROR ("Type %s has no constructors\n", t->id); __ok = 0; return; } int i, j; t->name = 0; for (i = 0; i < t->constructors_num; i++) { t->name ^= t->constructors[i]->name; } for (i = 0; i < t->constructors_num; i++) { for (j = i + 1; j < t->constructors_num; j++) { struct tree_var_value *v = 0; if (check_constructors_equal (t->constructors[i]->right, t->constructors[j]->right, &v)) { t->flags |= 16; } } } if ((t->flags & 24) == 24) { TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id); } int z = 0; int sid = 0; for (i = 0; i < t->constructors_num; i++) if (*t->constructors[i]->id == '_') { z ++; sid = i; } if (z > 1) { TL_ERROR ("Type %s has %d default constructors\n", t->id, z); __ok = 0; return; } if (z == 1 && (t->flags & 8)) { TL_ERROR ("Type %s has default constructors and used bare\n", t->id); __ok = 0; return; } if (z) { struct tl_constructor *c; c = t->constructors[sid]; t->constructors[sid] = t->constructors[t->constructors_num - 1]; t->constructors[t->constructors_num - 1] = c; } } struct tl_program *tl_parse (struct tree *T) { assert (T); assert (T->type == type_tl_program); int i; tl_program_cur = talloc (sizeof (*tl_program_cur)); tl_add_type ("#", 1, 0, 0); tl_add_type ("Type", 4, 0, 0); for (i = 0; i < T->nc; i++) { if (T->c[i]->type == type_constr_declarations) { TL_TRY_PES (tl_parse_constr_declarations (T->c[i])); } else { TL_TRY_PES (tl_parse_fun_declarations (T->c[i])) } } __ok = 1; tree_act_tl_type (tl_type_tree, tl_type_check); if (!__ok) { return 0; } return tl_program_cur; } int __f; int num = 0; void wint (int a) { // printf ("%d ", a); a = htole32 (a); assert (write (__f, &a, 4) == 4); } void wdata (const void *x, int len) { assert (write (__f, x, len) == len); } void wstr (const char *s) { if (s) { // printf ("\"%s\" ", s); int x = strlen (s); if (x <= 254) { unsigned char x_c = (unsigned char)x; assert (write (__f, &x_c, 1) == 1); } else { fprintf (stderr, "String is too big...\n"); assert (0); } wdata (s, x); x ++; // The header, containing the length, which is 1 byte int t = 0; if (x & 3) { // Let's hope it's truly zero on every platform wdata (&t, 4 - (x & 3)); } } else { // printf (" "); wint (0); } } void wll (long long a) { // printf ("%lld ", a); a = htole64 (a); assert (write (__f, &a, 8) == 8); } int count_list_size (struct tl_combinator_tree *T) { assert (T->type == type_list || T->type == type_list_item); if (T->type == type_list_item) { return 1; } else { return count_list_size (T->left) + count_list_size (T->right); } } void write_type_flags (long long flags) { int new_flags = 0; if (flags & 1) { new_flags |= FLAG_BARE; } if (flags & FLAG_DEFAULT_CONSTRUCTOR) { new_flags |= FLAG_DEFAULT_CONSTRUCTOR; } wint (new_flags); } void write_field_flags (long long flags) { int new_flags = 0; //fprintf (stderr, "%lld\n", flags); if (flags & 1) { new_flags |= FLAG_BARE; } if (flags & 32) { new_flags |= FLAG_OPT_VAR; } if (flags & FLAG_EXCL) { new_flags |= FLAG_EXCL; } if (flags & FLAG_OPT_FIELD) { // new_flags |= FLAG_OPT_FIELD; new_flags |= 2; } if (flags & (1 << 21)) { new_flags |= 4; } wint (new_flags); } void write_var_type_flags (long long flags) { int new_flags = 0; if (flags & 1) { new_flags |= FLAG_BARE; } if (new_flags & FLAG_BARE) { TL_ERROR ("Sorry, bare vars are not (yet ?) supported.\n"); assert (!(new_flags & FLAG_BARE)); } wint (new_flags); } void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var); void write_args (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { assert (T->type == type_list || T->type == type_list_item); if (T->type == type_list) { assert (T->act == act_union); assert (T->left); assert (T->right); write_args (T->left, v, last_var); write_args (T->right, v, last_var); return; } wint (TLS_ARG_V2); assert (T->act == act_field); assert (T->left); wstr (T->data && strcmp (T->data, "_") ? T->data : 0); long long f = T->flags; if (T->left->act == act_opt_field) { f |= (1 << 20); } if (T->left->act == act_type && T->left->data && (!strcmp (((struct tl_type *)T->left->data)->id, "#") || !strcmp (((struct tl_type *)T->left->data)->id, "Type"))) { write_field_flags (f | (1 << 21)); wint (*last_var); *last_var = (*last_var) + 1; tl_set_var_value_num (v, T, 0, (*last_var) - 1); } else { write_field_flags (f); } write_tree (T->left, 0, v, last_var); } void write_array (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { wint (TLS_ARRAY); write_tree (T->left, 0, v, last_var); write_tree (T->right, 0, v, last_var); } void write_type_rec (struct tl_combinator_tree *T, int cc, struct tree_var_value **v, int *last_var) { if (T->act == act_arg) { write_type_rec (T->left, cc + 1, v, last_var); if (T->right->type == type_num_value || T->right->type == type_num) { wint (TLS_EXPR_NAT); } else { wint (TLS_EXPR_TYPE); } write_tree (T->right, 0, v, last_var); } else { assert (T->act == act_var || T->act == act_type); if (T->act == act_var) { assert (!cc); wint (TLS_TYPE_VAR); wint (tl_get_var_value_num (v, T->data)); write_var_type_flags (T->flags); //wint (T->flags); } else { wint (TLS_TYPE_EXPR); struct tl_type *t = T->data; wint (t->name); write_type_flags (T->flags); // wint (T->flags); wint (cc); // fprintf (stderr, "cc = %d\n", cc); } } } void write_opt_type (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { wint (tl_get_var_value_num (v, T->left->data)); wint (T->left->type_flags); // write_tree (T->right, 0, v, last_var); assert (T); T = T->right; switch (T->type) { case type_type: if (T->act == act_array) { write_array (T, v, last_var); } else if (T->act == act_type || T->act == act_var || T->act == act_arg) { write_type_rec (T, 0, v, last_var); } else { assert (0); } break; default: assert (0); } } void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var) { assert (T); switch (T->type) { case type_list_item: case type_list: if (extra) { wint (TLS_COMBINATOR_RIGHT_V2); } wint (count_list_size (T)); write_args (T, v, last_var); break; case type_num_value: wint ((int)TLS_NAT_CONST); wint (T->type_flags); break; case type_num: wint ((int)TLS_NAT_VAR); wint (T->type_flags); wint (tl_get_var_value_num (v, T->data)); break; case type_type: if (T->act == act_array) { write_array (T, v, last_var); } else if (T->act == act_type || T->act == act_var || T->act == act_arg) { write_type_rec (T, 0, v, last_var); } else { assert (T->act == act_opt_field); write_opt_type (T, v, last_var); } break; default: assert (0); } } void write_type (struct tl_type *t) { wint (TLS_TYPE); wint (t->name); wstr (t->id); wint (t->constructors_num); wint (t->flags); wint (t->params_num); wll (t->params_types); } int is_builtin_type (const char *id) { return !strcmp (id, "int") || !strcmp (id, "long") || !strcmp (id, "double") || !strcmp (id, "string"); } void write_combinator (struct tl_constructor *c) { wint (c->name); wstr (c->id); wint (c->type ? c->type->name : 0); struct tree_var_value *T = 0; int x = 0; assert (c->right); if (c->left) { if (is_builtin_type (c->id)) { wint (TLS_COMBINATOR_LEFT_BUILTIN); } else { wint (TLS_COMBINATOR_LEFT); // FIXME: What is that? // wint (count_list_size (c->left)); write_tree (c->left, 0, &T, &x); } } else { wint (TLS_COMBINATOR_LEFT); wint (0); } wint (TLS_COMBINATOR_RIGHT_V2); write_tree (c->right, 1, &T, &x); } void write_constructor (struct tl_constructor *c) { wint (TLS_COMBINATOR); write_combinator (c); } void write_function (struct tl_constructor *c) { wint (TLS_COMBINATOR); write_combinator (c); } void write_type_constructors (struct tl_type *t) { int i; for (i = 0; i < t->constructors_num; i++) { write_constructor (t->constructors[i]); } } void write_types (int f) { __f = f; wint (TLS_SCHEMA_V2); wint (0); #ifdef TL_PARSER_NEED_TIME wint (time (0)); #else /* Make the tlo reproducible by default. Rationale: https://wiki.debian.org/ReproducibleBuilds/Howto#Introduction */ wint (0); #endif num = 0; wint (total_types_num); tree_act_tl_type (tl_type_tree, write_type); wint (total_constructors_num); tree_act_tl_type (tl_type_tree, write_type_constructors); wint (total_functions_num); tree_act_tl_constructor (tl_function_tree, write_function); } telegram-purple/tgl/tl-parser/tl-parser.h000066400000000000000000000105431357227200100207460ustar00rootroot00000000000000/* This file is part of tgl-libary/tlc Tgl-library/tlc 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. Tgl-library/tlc 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 tgl-library/tlc. If not, see . Copyright Vitaly Valtman 2014 It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) Copyright 2012-2013 Vkontakte Ltd 2012-2013 Vitaliy Valtman */ #ifndef __TL_PARSER_NEW_H__ #define __TL_PARSER_NEW_H__ enum lex_type { lex_error, lex_char, lex_triple_minus, lex_uc_ident, lex_lc_ident, lex_eof, lex_final, lex_new, lex_none, lex_num, lex_empty }; struct curlex { char *ptr; int len; enum lex_type type; int flags; }; struct parse { char *text; int pos; int len; int line; int line_pos; struct curlex lex; }; enum tree_type { type_tl_program, type_fun_declarations, type_constr_declarations, type_declaration, type_combinator_decl, type_equals, type_partial_app_decl, type_final_decl, type_full_combinator_id, type_opt_args, type_args, type_args1, type_args2, type_args3, type_args4, type_boxed_type_ident, type_subexpr, type_partial_comb_app_decl, type_partial_type_app_decl, type_final_new, type_final_final, type_final_empty, // type_type, type_var_ident, type_var_ident_opt, type_multiplicity, type_type_term, type_term, type_percent, type_result_type, type_expr, type_nat_term, type_combinator_id, type_nat_const, type_type_ident, type_builtin_combinator_decl, type_exclam, type_optional_arg_def }; struct tree { char *text; int len; enum tree_type type; int lex_line; int lex_line_pos; int flags; int size; int nc; struct tree **c; }; #define TL_ACT(x) (x == act_var ? "act_var" : x == act_field ? "act_field" : x == act_plus ? "act_plus" : x == act_type ? "act_type" : x == act_nat_const ? "act_nat_const" : x == act_array ? "act_array" : x == act_question_mark ? "act_question_mark" : \ x == act_union ? "act_union" : x == act_arg ? "act_arg" : x == act_opt_field ? "act_opt_field" : "act_unknown") #define TL_TYPE(x) (x == type_num ? "type_num" : x == type_type ? "type_type" : x == type_list_item ? "type_list_item" : x == type_list ? "type_list" : x == type_num_value ? "type_num_value" : "type_unknown") enum combinator_tree_action { act_var, act_field, act_plus, act_type, act_nat_const, act_array, act_question_mark, act_union, act_arg, act_opt_field }; enum combinator_tree_type { type_num, type_num_value, type_type, type_list_item, type_list }; struct tl_combinator_tree { enum combinator_tree_action act; struct tl_combinator_tree *left, *right; char *name; void *data; long long flags; enum combinator_tree_type type; int type_len; long long type_flags; }; struct tl_program { int types_num; int functions_num; int constructors_num; struct tl_type **types; struct tl_function **functions; // struct tl_constuctor **constructors; }; struct tl_type { char *id; char *print_id; char *real_id; unsigned name; int flags; int params_num; long long params_types; int constructors_num; struct tl_constructor **constructors; }; struct tl_constructor { char *id; char *print_id; char *real_id; unsigned name; struct tl_type *type; struct tl_combinator_tree *left; struct tl_combinator_tree *right; }; struct tl_var { char *id; struct tl_combinator_tree *ptr; int type; int flags; }; struct parse *tl_init_parse_file (const char *fname); struct tree *tl_parse_lex (struct parse *P); void tl_print_parse_error (void); struct tl_program *tl_parse (struct tree *T); void write_types (int f); #define FLAG_BARE 1 #define FLAG_OPT_VAR (1 << 17) #define FLAG_EXCL (1 << 18) #define FLAG_OPT_FIELD (1 << 20) #define FLAG_IS_VAR (1 << 21) #define FLAG_DEFAULT_CONSTRUCTOR (1 << 25) #define FLAG_EMPTY (1 << 10) #endif telegram-purple/tgl/tl-parser/tl-tl.h000066400000000000000000000034641357227200100200750ustar00rootroot00000000000000/* This file is part of VK/KittenPHP-DB-Engine. VK/KittenPHP-DB-Engine 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. VK/KittenPHP-DB-Engine 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 VK/KittenPHP-DB-Engine. If not, see . This program is released under the GPL with the additional exemption that compiling, linking, and/or using OpenSSL is allowed. You are free to remove this exemption from derived works. Copyright 2012-2013 Vkontakte Ltd 2012-2013 Vitaliy Valtman */ #ifndef __TL_TL_H__ #define __TL_TL_H__ // Current tl-tl schema is V2 // See https://core.telegram.org/mtproto/TL-tl #define TLS_SCHEMA_V2 0x3a2f9be2 #define TLS_TYPE 0x12eb4386 #define TLS_COMBINATOR 0x5c0a1ed5 #define TLS_COMBINATOR_LEFT_BUILTIN 0xcd211f63 #define TLS_COMBINATOR_LEFT 0x4c12c6d9 #define TLS_COMBINATOR_RIGHT_V2 0x2c064372 #define TLS_ARG_V2 0x29dfe61b #define TLS_EXPR_TYPE 0xecc9da78 #define TLS_EXPR_NAT 0xdcb49bd8 #define TLS_NAT_CONST 0xdcb49bd8 #define TLS_NAT_VAR 0x4e8a14f0 #define TLS_TYPE_VAR 0x0142ceae #define TLS_ARRAY 0xd9fb20de #define TLS_TYPE_EXPR 0xc1863d08 /* Deprecated (old versions), read-only */ #define TLS_TREE_NAT_CONST 0xc09f07d7 #define TLS_TREE_NAT_VAR 0x90ea6f58 #define TLS_TREE_TYPE_VAR 0x1caa237a #define TLS_TREE_ARRAY 0x80479360 #define TLS_TREE_TYPE 0x10f32190 #endif telegram-purple/tgl/tl-parser/tlc.c000066400000000000000000000073661357227200100176230ustar00rootroot00000000000000/* This file is part of tl-parser tl-parser 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. tl-parser 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 tl-parser. If not, see . Copyright Vitaly Valtman 2014 It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) Copyright 2012-2013 Vkontakte Ltd 2012-2013 Vitaliy Valtman */ #include "config.h" #include #include #include #include "tl-parser.h" #include #include #include #include #include #include "config.h" #ifdef HAVE_EXECINFO_H #include #endif #include int verbosity; int output_expressions; void usage (void) { printf ("usage: tl-parser [-v] [-h] \n" "\tTL compiler\n" "\t-v\toutput statistical and debug information into stderr\n" "\t-E\twhenever is possible output to stdout expressions\n" "\t-e \texport serialized schema to file\n" ); exit (2); } int vkext_write (const char *filename) { int f = open (filename, O_CREAT | O_WRONLY | O_TRUNC, 0640); assert (f >= 0); write_types (f); close (f); return 0; } void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); void logprintf (const char *format __attribute__ ((unused)), ...) { va_list ap; va_start (ap, format); vfprintf (stderr, format, ap); va_end (ap); } void hexdump (int *in_ptr, int *in_end) { int *ptr = in_ptr; while (ptr < in_end) { printf (" %08x", *(ptr ++)); } printf ("\n"); } #ifdef HAVE_EXECINFO_H void print_backtrace (void) { void *buffer[255]; const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); backtrace_symbols_fd (buffer, calls, 1); } #else void print_backtrace (void) { if (write (1, "No libexec. Backtrace disabled\n", 32) < 0) { // Sad thing } } #endif void sig_segv_handler (int signum __attribute__ ((unused))) { if (write (1, "SIGSEGV received\n", 18) < 0) { // Sad thing } print_backtrace (); exit (EXIT_FAILURE); } void sig_abrt_handler (int signum __attribute__ ((unused))) { if (write (1, "SIGABRT received\n", 18) < 0) { // Sad thing } print_backtrace (); exit (EXIT_FAILURE); } int main (int argc, char **argv) { signal (SIGSEGV, sig_segv_handler); signal (SIGABRT, sig_abrt_handler); int i; char *vkext_file = 0; while ((i = getopt (argc, argv, "Ehve:w:")) != -1) { switch (i) { case 'E': output_expressions++; break; case 'h': usage (); return 2; case 'e': vkext_file = optarg; break; case 'v': verbosity++; break; } } if (argc != optind + 1) { usage (); } struct parse *P = tl_init_parse_file (argv[optind]); if (!P) { return 0; } struct tree *T; if (!(T = tl_parse_lex (P))) { fprintf (stderr, "Error in parse:\n"); tl_print_parse_error (); return 0; } else { if (verbosity) { fprintf (stderr, "Parse ok\n"); } if (!tl_parse (T)) { if (verbosity) { fprintf (stderr, "Fail\n"); } return 1; } else { if (verbosity) { fprintf (stderr, "Ok\n"); } } } if (vkext_file) { vkext_write (vkext_file); } return 0; } telegram-purple/tgl/tools.c000066400000000000000000000223561357227200100162640ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define _GNU_SOURCE #include #include #include #include #include "crypto/rand.h" #include #include #include //#include "interface.h" #include "tools.h" #ifdef __MACH__ #include #include #endif #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 1 #endif #ifdef WIN32 #include #include int vasprintf(char ** __restrict__ ret, const char * __restrict__ format, va_list ap) { int len; /* Get Length */ len = _vsnprintf(NULL,0,format,ap); if (len < 0) return -1; /* +1 for \0 terminator. */ *ret = malloc(len + 1); /* Check malloc fail*/ if (!*ret) return -1; /* Write String */ _vsnprintf(*ret,len+1,format,ap); /* Terminate explicitly */ (*ret)[len] = '\0'; return len; } int clock_gettime(int ignored, struct timespec *spec) { __int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime); wintime -= 116444736000000000; //1jan1601 to 1jan1970 spec->tv_sec = wintime / 10000000; //seconds spec->tv_nsec = wintime % 10000000 *100; //nano-seconds return 0; } #endif #ifdef VALGRIND_FIXES #include "valgrind/memcheck.h" #endif #define RES_PRE 8 #define RES_AFTER 8 #define MAX_BLOCKS 1000000 static void *blocks[MAX_BLOCKS]; static void *free_blocks[MAX_BLOCKS]; static int used_blocks; static int free_blocks_cnt; static long long total_allocated_bytes; void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2), weak)); void logprintf (const char *format, ...) { va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); va_end (ap); } //extern int verbosity; //static long long total_allocated_bytes; int tgl_snprintf (char *buf, int len, const char *format, ...) { va_list ap; va_start (ap, format); int r = vsnprintf (buf, len, format, ap); va_end (ap); assert (r <= len && "tsnprintf buffer overflow"); return r; } int tgl_asprintf (char **res, const char *format, ...) { va_list ap; va_start (ap, format); int r = vasprintf (res, format, ap); assert (r >= 0); va_end (ap); void *rs = talloc (strlen (*res) + 1); memcpy (rs, *res, strlen (*res) + 1); free (*res); *res = rs; return r; } void tgl_free_debug (void *ptr, int size __attribute__ ((unused))) { if (!ptr) { assert (!size); return; } total_allocated_bytes -= size; ptr -= RES_PRE; if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); } assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); assert (*(int *)(ptr + 4) == size); int block_num = *(int *)(ptr + 4 + RES_PRE + size); if (block_num >= used_blocks) { logprintf ("block_num = %d, used = %d\n", block_num, used_blocks); } assert (block_num < used_blocks); if (block_num < used_blocks - 1) { void *p = blocks[used_blocks - 1]; int s = (*(int *)p) ^ 0xbedabeda; *(int *)(p + 4 + RES_PRE + s) = block_num; blocks[block_num] = p; } blocks[--used_blocks] = 0; memset (ptr, 0, size + RES_PRE + RES_AFTER); *(int *)ptr = size + 12; free_blocks[free_blocks_cnt ++] = ptr; } void tgl_free_release (void *ptr, int size) { total_allocated_bytes -= size; memset (ptr, 0, size); free (ptr); } void *tgl_realloc_debug (void *ptr, size_t old_size __attribute__ ((unused)), size_t size) { void *p = talloc (size); memcpy (p, ptr, size >= old_size ? old_size : size); if (ptr) { tfree (ptr, old_size); } else { assert (!old_size); } return p; } void *tgl_realloc_release (void *ptr, size_t old_size __attribute__ ((unused)), size_t size) { total_allocated_bytes += (size - old_size); void *p = realloc (ptr, size); ensure_ptr (p); return p; } void *tgl_alloc_debug (size_t size) { total_allocated_bytes += size; void *p = malloc (size + RES_PRE + RES_AFTER); ensure_ptr (p); *(int *)p = size ^ 0xbedabeda; *(int *)(p + 4) = size; *(int *)(p + RES_PRE + size) = size ^ 0x7bed7bed; *(int *)(p + RES_AFTER + 4 + size) = used_blocks; blocks[used_blocks ++] = p; //tcheck (); return p + 8; } void *tgl_alloc_release (size_t size) { total_allocated_bytes += size; void *p = malloc (size); ensure_ptr (p); return p; } void *tgl_alloc0 (size_t size) { void *p = talloc (size); memset (p, 0, size); return p; } char *tgl_strdup (const char *s) { int l = strlen (s); char *p = talloc (l + 1); memcpy (p, s, l + 1); return p; } char *tgl_strndup (const char *s, size_t n) { size_t l = 0; for (l = 0; l < n && s[l]; l++) { } char *p = talloc (l + 1); memcpy (p, s, l); p[l] = 0; return p; } void *tgl_memdup (const void *s, size_t n) { void *r = talloc (n); memcpy (r, s, n); return r; } int tgl_inflate (void *input, int ilen, void *output, int olen) { z_stream strm; memset (&strm, 0, sizeof (strm)); assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); strm.avail_in = ilen; strm.next_in = input; strm.avail_out = olen ; strm.next_out = output; int err = inflate (&strm, Z_FINISH); int total_out = strm.total_out; if (err != Z_OK && err != Z_STREAM_END) { logprintf ( "inflate error = %d\n", err); logprintf ( "inflated %d bytes\n", (int) strm.total_out); total_out = 0; } inflateEnd (&strm); return total_out; } void tgl_check_debug (void) { int i; for (i = 0; i < used_blocks; i++) { void *ptr = blocks[i]; int size = (*(int *)ptr) ^ 0xbedabeda; if (!(*(int *)(ptr + 4) == size) || !(*(int *)(ptr + RES_PRE + size) == (size ^ 0x7bed7bed)) || !(*(int *)(ptr + RES_PRE + 4 + size) == i)) { logprintf ("Bad block at address %p (size %d, num %d)\n", ptr, size, i); assert (0 && "Bad block"); } } for (i = 0; i < free_blocks_cnt; i++) { void *ptr = free_blocks[i]; int l = *(int *)ptr; int j = 0; for (j = 0; j < l; j++) { if (*(char *)(ptr + 4 + j)) { hexdump (ptr + 8, ptr + 8 + l + ((-l) & 3)); logprintf ("Used freed memory size = %d. ptr = %p\n", l + 4 - RES_PRE - RES_AFTER, ptr); assert (0); } } } //logprintf ("ok. Used_blocks = %d. Free blocks = %d\n", used_blocks, free_blocks_cnt); } void tgl_exists_debug (void *ptr, int size) { ptr -= RES_PRE; if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); } assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); assert (*(int *)(ptr + 4) == size); int block_num = *(int *)(ptr + 4 + RES_PRE + size); if (block_num >= used_blocks) { logprintf ("block_num = %d, used = %d\n", block_num, used_blocks); } assert (block_num < used_blocks); } void tgl_exists_release (void *ptr, int size) {} void tgl_check_release (void) {} void tgl_my_clock_gettime (int clock_id, struct timespec *T) { #ifdef __MACH__ // We are ignoring MONOTONIC and hope time doesn't go back too often clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); T->tv_sec = mts.tv_sec; T->tv_nsec = mts.tv_nsec; #else assert (clock_gettime(clock_id, T) >= 0); #endif } double tglt_get_double_time (void) { struct timespec tv; tgl_my_clock_gettime (CLOCK_REALTIME, &tv); return tv.tv_sec + 1e-9 * tv.tv_nsec; } void tglt_secure_random (void *s, int l) { if (TGLC_rand_bytes (s, l) <= 0) { /*if (allow_weak_random) { TGLC_rand_pseudo_bytes (s, l); } else {*/ assert (0 && "End of random. If you want, you can start with -w"); //} } else { #ifdef VALGRIND_FIXES VALGRIND_MAKE_MEM_DEFINED (s, l); VALGRIND_CHECK_MEM_IS_DEFINED (s, l); #endif } } struct tgl_allocator tgl_allocator_debug = { .alloc = tgl_alloc_debug, .realloc = tgl_realloc_debug, .free = tgl_free_debug, .check = tgl_check_debug, .exists = tgl_exists_debug }; struct tgl_allocator tgl_allocator_release = { .alloc = tgl_alloc_release, .realloc = tgl_realloc_release, .free = tgl_free_release, .check = tgl_check_release, .exists = tgl_exists_release }; long long tgl_get_allocated_bytes (void) { return total_allocated_bytes; } struct tgl_allocator *tgl_allocator = &tgl_allocator_release; telegram-purple/tgl/tools.h000066400000000000000000000073501357227200100162660ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifndef __TOOLS_H__ #define __TOOLS_H__ #include #include #include #include #include //#include "tgl.h" #include "crypto/err.h" #include "crypto/rand.h" struct tgl_allocator { void *(*alloc)(size_t size); void *(*realloc)(void *ptr, size_t old_size, size_t size); void (*free)(void *ptr, int size); void (*check)(void); void (*exists)(void *ptr, int size); }; #define talloc tgl_allocator->alloc #define talloc0 tgl_alloc0 #define tfree tgl_allocator->free #define tfree_str tgl_free_str #define tfree_secure tgl_free_secure #define trealloc tgl_allocator->realloc #define tcheck tgl_allocator->check #define texists tgl_allocator->exists #define tstrdup tgl_strdup #define tmemdup tgl_memdup #define tstrndup tgl_strndup #define tasprintf tgl_asprintf #define tsnprintf tgl_snprintf extern struct tgl_allocator *tgl_allocator; double tglt_get_double_time (void); int tgl_inflate (void *input, int ilen, void *output, int olen); //void ensure (int r); //void ensure_ptr (void *p); static inline void out_of_memory (void) { fprintf (stderr, "Out of memory\n"); exit (1); } static inline void ensure (int r) { if (!r) { fprintf (stderr, "Crypto error\n"); TGLC_err_print_errors_fp (stderr); assert (0); } } static inline void ensure_ptr (void *p) { if (p == NULL) { out_of_memory (); } } void *tgl_alloc_debug (size_t size); void *tgl_alloc_release (size_t size); void *tgl_realloc_debug (void *ptr, size_t old_size, size_t size); void *tgl_realloc_release (void *ptr, size_t old_size, size_t size); void *tgl_alloc0 (size_t size); char *tgl_strdup (const char *s); char *tgl_strndup (const char *s, size_t n); void tgl_free_debug (void *ptr, int size); void tgl_free_release (void *ptr, int size); //void tgl_free_str (void *ptr); //void tgl_free_secure (void *ptr, int size); void tgl_check_debug (void); void tgl_exists_debug (void *ptr, int size); void tgl_check_release (void); void tgl_exists_release (void *ptr, int size); void *tgl_memdup (const void *s, size_t n); int tgl_snprintf (char *buf, int len, const char *format, ...) __attribute__ ((format (__printf__, 3, 4))); int tgl_asprintf (char **res, const char *format, ...) __attribute__ ((format (__printf__, 2, 3))); void tglt_secure_random (void *s, int l); void tgl_my_clock_gettime (int clock_id, struct timespec *T); static inline void tgl_free_str (void *ptr) { if (!ptr) { return; } tfree (ptr, strlen ((const char *)ptr) + 1); } static inline void tgl_free_secure (void *ptr, int size) { memset (ptr, 0, size); tfree (ptr, size); } static inline void hexdump (void *ptr, void *end_ptr) { int total = 0; unsigned char *bptr = (unsigned char *)ptr; while (bptr < (unsigned char *)end_ptr) { fprintf (stderr, "%02x", (int)*bptr); bptr ++; total ++; if (total == 16) { fprintf (stderr, "\n"); total = 0; } } if (total) { fprintf (stderr, "\n"); } } #endif telegram-purple/tgl/tree.h000066400000000000000000000135031357227200100160620ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifndef __TREE_H__ #define __TREE_H__ #include #include #include #include "tools.h" #pragma pack(push,4) #define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ struct tree_ ## X_NAME { \ struct tree_ ## X_NAME *left, *right;\ X_TYPE x;\ int y;\ };\ \ static struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\ struct tree_ ## X_NAME *T = talloc (sizeof (*T));\ T->x = x;\ T->y = y;\ T->left = T->right = 0;\ return T;\ }\ \ static void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\ tfree (T, sizeof (*T));\ }\ \ static void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\ if (!T) {\ *L = *R = 0;\ } else {\ int c = X_CMP (x, T->x);\ if (c < 0) {\ tree_split_ ## X_NAME (T->left, x, L, &T->left);\ *R = T;\ } else {\ tree_split_ ## X_NAME (T->right, x, &T->right, R);\ *L = T;\ }\ }\ }\ \ static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result,unused));\ static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\ if (!T) {\ return new_tree_node_ ## X_NAME (x, y);\ } else {\ if (y > T->y) {\ struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\ tree_split_ ## X_NAME (T, x, &N->left, &N->right);\ return N;\ } else {\ int c = X_CMP (x, T->x);\ assert (c);\ if (c < 0) { \ T->left = tree_insert_ ## X_NAME (T->left, x, y);\ } else { \ T->right = tree_insert_ ## X_NAME (T->right, x, y);\ } \ return T; \ }\ }\ }\ \ static struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\ if (!L || !R) {\ return L ? L : R;\ } else {\ if (L->y > R->y) {\ L->right = tree_merge_ ## X_NAME (L->right, R);\ return L;\ } else {\ R->left = tree_merge_ ## X_NAME (L, R->left);\ return R;\ }\ }\ }\ \ static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result,unused));\ static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ assert (T);\ int c = X_CMP (x, T->x);\ if (!c) {\ struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\ delete_tree_node_ ## X_NAME (T);\ return N;\ } else {\ if (c < 0) { \ T->left = tree_delete_ ## X_NAME (T->left, x); \ } else { \ T->right = tree_delete_ ## X_NAME (T->right, x); \ } \ return T; \ }\ }\ \ static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *t) __attribute__ ((unused));\ static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\ if (!T) { return X_UNSET; } \ while (T->left) { T = T->left; }\ return T->x; \ } \ \ static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((unused));\ static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ int c;\ while (T && (c = X_CMP (x, T->x))) {\ T = (c < 0 ? T->left : T->right);\ }\ return T ? T->x : X_UNSET;\ }\ \ static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) __attribute__ ((unused));\ static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\ if (!T) { return; } \ tree_act_ ## X_NAME (T->left, act); \ act (T->x); \ tree_act_ ## X_NAME (T->right, act); \ }\ \ static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) __attribute__ ((unused));\ static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) {\ if (!T) { return; } \ tree_act_ex_ ## X_NAME (T->left, act, extra); \ act (T->x, extra); \ tree_act_ex_ ## X_NAME (T->right, act, extra); \ }\ \ static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \ if (!T) { return 0; }\ return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \ }\ static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \ if (!T) { return; }\ if (T->left) { \ assert (T->left->y <= T->y);\ assert (X_CMP (T->left->x, T->x) < 0); \ }\ if (T->right) { \ assert (T->right->y <= T->y);\ assert (X_CMP (T->right->x, T->x) > 0); \ }\ tree_check_ ## X_NAME (T->left); \ tree_check_ ## X_NAME (T->right); \ }\ static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) { \ if (!T) { return 0; }\ tree_clear_ ## X_NAME (T->left); \ tree_clear_ ## X_NAME (T->right); \ delete_tree_node_ ## X_NAME (T); \ return 0; \ } \ #define int_cmp(a,b) ((a) - (b)) #pragma pack(pop) #endif telegram-purple/tgl/updates.c000066400000000000000000000647341357227200100165770ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #include "tgl.h" #include "updates.h" #include "mtproto-common.h" #include "tgl-binlog.h" #include "auto.h" #include "auto/auto-types.h" #include "auto/auto-skip.h" #include "auto/auto-fetch-ds.h" #include "auto/auto-free-ds.h" #include "tgl-structures.h" #include "tgl-methods-in.h" #include "tree.h" #include void tgl_do_get_channel_difference (struct tgl_state *TLS, int channel_id, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success), void *callback_extra); static void fetch_dc_option (struct tgl_state *TLS, struct tl_ds_dc_option *DS_DO) { vlogprintf (E_DEBUG, "id = %d, %.*s:%d\n", DS_LVAL (DS_DO->id), DS_RSTR (DS_DO->ip_address), DS_LVAL (DS_DO->port)); bl_do_dc_option (TLS, DS_LVAL (DS_DO->flags), DS_LVAL (DS_DO->id), NULL, 0, DS_STR (DS_DO->ip_address), DS_LVAL (DS_DO->port)); } int tgl_check_pts_diff (struct tgl_state *TLS, int pts, int pts_count) { vlogprintf (E_DEBUG - 1, "pts = %d, pts_count = %d\n", pts, pts_count); if (!TLS->pts) { return 1; } //assert (TLS->pts); if (pts < TLS->pts + pts_count) { vlogprintf (E_NOTICE, "Duplicate message with pts=%d\n", pts); return -1; } if (pts > TLS->pts + pts_count) { vlogprintf (E_NOTICE, "Hole in pts (pts = %d, count = %d, cur_pts = %d)\n", pts, pts_count, TLS->pts); tgl_do_get_difference (TLS, 0, 0, 0); return -1; } if (TLS->locks & TGL_LOCK_DIFF) { vlogprintf (E_DEBUG, "Update during get_difference. pts = %d\n", pts); return -1; } vlogprintf (E_DEBUG, "Ok update. pts = %d\n", pts); return 1; } int tgl_check_qts_diff (struct tgl_state *TLS, int qts, int qts_count) { vlogprintf (E_ERROR, "qts = %d, qts_count = %d\n", qts, qts_count); if (qts < TLS->qts + qts_count) { vlogprintf (E_NOTICE, "Duplicate message with qts=%d\n", qts); return -1; } if (qts > TLS->qts + qts_count) { vlogprintf (E_NOTICE, "Hole in qts (qts = %d, count = %d, cur_qts = %d)\n", qts, qts_count, TLS->qts); tgl_do_get_difference (TLS, 0, 0, 0); return -1; } if (TLS->locks & TGL_LOCK_DIFF) { vlogprintf (E_DEBUG, "Update during get_difference. qts = %d\n", qts); return -1; } vlogprintf (E_DEBUG, "Ok update. qts = %d\n", qts); return 1; } int tgl_check_channel_pts_diff (struct tgl_state *TLS, tgl_peer_t *_E, int pts, int pts_count) { struct tgl_channel *E = &_E->channel; vlogprintf (E_DEBUG - 1, "channel %d: pts = %d, pts_count = %d, current_pts = %d\n", tgl_get_peer_id (E->id), pts, pts_count, E->pts); if (!E->pts) { return 1; } //assert (TLS->pts); if (pts < E->pts + pts_count) { vlogprintf (E_NOTICE, "Duplicate message with pts=%d\n", pts); return -1; } if (pts > E->pts + pts_count) { vlogprintf (E_NOTICE, "Hole in pts (pts = %d, count = %d, cur_pts = %d)\n", pts, pts_count, E->pts); tgl_do_get_channel_difference (TLS, tgl_get_peer_id (E->id), 0, 0); return -1; } if (E->flags & TGLCHF_DIFF) { vlogprintf (E_DEBUG, "Update during get_difference. pts = %d\n", pts); return -1; } vlogprintf (E_DEBUG, "Ok update. pts = %d\n", pts); return 1; } static int do_skip_seq (struct tgl_state *TLS, int seq) { if (!seq) { vlogprintf (E_DEBUG, "Ok update. seq = %d\n", seq); return 0; } if (TLS->seq) { if (seq <= TLS->seq) { vlogprintf (E_NOTICE, "Duplicate message with seq=%d\n", seq); return -1; } if (seq > TLS->seq + 1) { vlogprintf (E_NOTICE, "Hole in seq (seq = %d, cur_seq = %d)\n", seq, TLS->seq); //vlogprintf (E_NOTICE, "lock_diff = %s\n", (TLS->locks & TGL_LOCK_DIFF) ? "true" : "false"); tgl_do_get_difference (TLS, 0, 0, 0); return -1; } if (TLS->locks & TGL_LOCK_DIFF) { vlogprintf (E_DEBUG, "Update during get_difference. seq = %d\n", seq); return -1; } vlogprintf (E_DEBUG, "Ok update. seq = %d\n", seq); return 0; } else { return -1; } } void tglu_work_update (struct tgl_state *TLS, int check_only, struct tl_ds_update *DS_U) { if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { vlogprintf (E_DEBUG, "Update during get_difference. DROP\n"); return; } if (DS_U->pts) { assert (DS_U->pts_count); if (!check_only && tgl_check_pts_diff (TLS, DS_LVAL (DS_U->pts), DS_LVAL (DS_U->pts_count)) <= 0) { return; } } if (DS_U->qts) { if (!check_only && tgl_check_qts_diff (TLS, DS_LVAL (DS_U->qts), 1) <= 0) { return; } } if (DS_U->channel_pts) { assert (DS_U->channel_pts_count); int channel_id; if (DS_U->channel_id) { channel_id = DS_LVAL (DS_U->channel_id); } else { assert (DS_U->message); if (!DS_U->message->to_id) { return; } assert (DS_U->message->to_id); assert (DS_U->message->to_id->magic == CODE_peer_channel); channel_id = DS_LVAL (DS_U->message->to_id->channel_id); } tgl_peer_t *E = tgl_peer_get (TLS, TGL_MK_CHANNEL (channel_id)); if (!E) { return; } if (!check_only && tgl_check_channel_pts_diff (TLS, E, DS_LVAL (DS_U->channel_pts), DS_LVAL (DS_U->channel_pts_count)) <= 0) { return; } } vlogprintf (E_NOTICE, "update 0x%08x (check=%d)\n", DS_U->magic, check_only); if (check_only > 0 && DS_U->magic != CODE_update_message_i_d) { return; } switch (DS_U->magic) { case CODE_update_new_message: { //struct tgl_message *N = tgl_message_get (TLS, DS_LVAL (DS_U->id)); //int new = (!N || !(N->flags & TGLMF_CREATED)); int new_msg = 0; struct tgl_message *M = tglf_fetch_alloc_message (TLS, DS_U->message, &new_msg); assert (M); if (new_msg) { bl_do_msg_update (TLS, &M->permanent_id); } break; }; case CODE_update_message_i_d: { tgl_message_id_t msg_id; msg_id.peer_type = TGL_PEER_RANDOM_ID; msg_id.id = DS_LVAL (DS_U->random_id); struct tgl_message *M = tgl_message_get (TLS, &msg_id); if (M && (M->flags & TGLMF_PENDING)) { msg_id = M->permanent_id; msg_id.id = DS_LVAL (DS_U->id); bl_do_set_msg_id (TLS, &M->permanent_id, &msg_id); bl_do_msg_update (TLS, &msg_id); } } break; /* case CODE_update_read_messages: { int n = DS_LVAL (DS_U->messages->cnt); int i; for (i = 0; i < n; i++) { struct tgl_message *M = tgl_message_get (TLS, DS_LVAL (DS_U->messages->data[i])); if (M) { tgl_peer_t *P; if (M->flags & TGLMF_OUT) { P = tgl_peer_get (TLS, M->to_id); if (P && (P->flags & TGLMF_CREATED)) { if (tgl_get_peer_type (P->id) == TGL_PEER_USER) { bl_do_user (TLS, tgl_get_peer_id (P->id), NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL, (int *)&M->id, TGL_FLAGS_UNCHANGED); } else { bl_do_chat (TLS, tgl_get_peer_id (P->id), NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, (int *)&M->id, TGL_FLAGS_UNCHANGED); } } } else { if (tgl_get_peer_type (M->to_id) == TGL_PEER_USER) { P = tgl_peer_get (TLS, M->from_id); } else { P = tgl_peer_get (TLS, M->to_id); } if (P && (P->flags & TGLMF_CREATED)) { if (tgl_get_peer_type (P->id) == TGL_PEER_USER) { bl_do_user (TLS, tgl_get_peer_id (P->id), NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, (int *)&M->id, NULL, TGL_FLAGS_UNCHANGED); } else { bl_do_chat (TLS, tgl_get_peer_id (P->id), NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, (int *)&M->id, NULL, TGL_FLAGS_UNCHANGED); } } } } } } break;*/ case CODE_update_user_typing: { tgl_peer_id_t id = TGL_MK_USER (DS_LVAL (DS_U->user_id)); tgl_peer_t *U = tgl_peer_get (TLS, id); enum tgl_typing_status status = tglf_fetch_typing (DS_U->action); if (TLS->callback.type_notification && U) { TLS->callback.type_notification (TLS, (void *)U, status); } } break; case CODE_update_chat_user_typing: { tgl_peer_id_t chat_id = TGL_MK_CHAT (DS_LVAL (DS_U->chat_id)); tgl_peer_id_t id = TGL_MK_USER (DS_LVAL (DS_U->user_id)); tgl_peer_t *C = tgl_peer_get (TLS, chat_id); tgl_peer_t *U = tgl_peer_get (TLS, id); enum tgl_typing_status status = tglf_fetch_typing (DS_U->action); if (U && C) { if (TLS->callback.type_in_chat_notification) { TLS->callback.type_in_chat_notification (TLS, (void *)U, (void *)C, status); } } } break; case CODE_update_user_status: { tgl_peer_id_t user_id = TGL_MK_USER (DS_LVAL (DS_U->user_id)); tgl_peer_t *U = tgl_peer_get (TLS, user_id); if (U) { tglf_fetch_user_status (TLS, &U->user.status, &U->user, DS_U->status); if (TLS->callback.status_notification) { TLS->callback.status_notification (TLS, (void *)U); } } } break; case CODE_update_user_name: { tgl_peer_id_t user_id = TGL_MK_USER (DS_LVAL (DS_U->user_id)); tgl_peer_t *UC = tgl_peer_get (TLS, user_id); if (UC && (UC->flags & TGLPF_CREATED)) { bl_do_user (TLS, tgl_get_peer_id (user_id), NULL, DS_STR (DS_U->first_name), DS_STR (DS_U->last_name), NULL, 0, DS_STR (DS_U->username), NULL, NULL, NULL, NULL, NULL, TGL_FLAGS_UNCHANGED); } } break; case CODE_update_user_photo: { tgl_peer_id_t user_id = TGL_MK_USER (DS_LVAL (DS_U->user_id)); tgl_peer_t *UC = tgl_peer_get (TLS, user_id); if (UC && (UC->flags & TGLUF_CREATED)) { bl_do_user (TLS, tgl_get_peer_id (user_id), NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, DS_U->photo, NULL, NULL, NULL, TGL_FLAGS_UNCHANGED); } } break; case CODE_update_delete_messages: { } break; case CODE_update_chat_participants: { tgl_peer_id_t chat_id = TGL_MK_CHAT (DS_LVAL (DS_U->chat_id)); tgl_peer_t *C = tgl_peer_get (TLS, chat_id); if (C && (C->flags & TGLPF_CREATED) && DS_U->participants->magic == CODE_chat_participants) { bl_do_chat (TLS, tgl_get_peer_id (chat_id), NULL, 0, NULL, NULL, DS_U->participants->version, (struct tl_ds_vector *)DS_U->participants->participants, NULL, NULL, NULL, NULL, NULL, TGL_FLAGS_UNCHANGED); } } break; case CODE_update_contact_registered: { tgl_peer_id_t user_id = TGL_MK_USER (DS_LVAL (DS_U->user_id)); tgl_peer_t *U = tgl_peer_get (TLS, user_id); if (TLS->callback.user_registered && U) { TLS->callback.user_registered (TLS, (void *)U); } } break; case CODE_update_contact_link: { } break; /*case CODE_update_activation: { tgl_peer_id_t user_id = TGL_MK_USER (DS_LVAL (DS_U->user_id)); tgl_peer_t *U = tgl_peer_get (TLS, user_id); if (TLS->callback.user_activated && U) { TLS->callback.user_activated (TLS, (void *)U); } } break;*/ case CODE_update_new_authorization: { if (TLS->callback.new_authorization) { TLS->callback.new_authorization (TLS, DS_U->device->data, DS_U->location->data); } } break; /*case CODE_update_new_geo_chat_message: { } break;*/ case CODE_update_new_encrypted_message: { struct tgl_message *M = tglf_fetch_alloc_encrypted_message (TLS, DS_U->encr_message); if (M) { bl_do_msg_update (TLS, &M->permanent_id); } } break; case CODE_update_encryption: { struct tgl_secret_chat *E = tglf_fetch_alloc_encrypted_chat (TLS, DS_U->encr_chat); vlogprintf (E_DEBUG, "Secret chat state = %d\n", E->state); if (E->state == sc_ok) { tgl_do_send_encr_chat_layer (TLS, E); } } break; case CODE_update_encrypted_chat_typing: { tgl_peer_id_t id = TGL_MK_ENCR_CHAT (DS_LVAL (DS_U->chat_id)); tgl_peer_t *P = tgl_peer_get (TLS, id); if (P) { if (TLS->callback.type_in_secret_chat_notification) { TLS->callback.type_in_secret_chat_notification (TLS, (void *)P); } } } break; case CODE_update_encrypted_messages_read: { tgl_peer_id_t id = TGL_MK_ENCR_CHAT (DS_LVAL (DS_U->chat_id)); tgl_peer_t *P = tgl_peer_get (TLS, id); if (P && P->last) { struct tgl_message *M = P->last; while (M && (!(M->flags & TGLMF_OUT) || (M->flags & TGLMF_UNREAD))) { if (M->flags & TGLMF_OUT) { bl_do_edit_message_encr (TLS, &M->permanent_id, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, M->flags & ~TGLMF_UNREAD); } M = M->next; } } } break; case CODE_update_chat_participant_add: { tgl_peer_id_t chat_id = TGL_MK_CHAT (DS_LVAL (DS_U->chat_id)); tgl_peer_id_t user_id = TGL_MK_USER (DS_LVAL (DS_U->user_id)); tgl_peer_id_t inviter_id = TGL_MK_USER (DS_LVAL (DS_U->inviter_id)); int version = DS_LVAL (DS_U->version); tgl_peer_t *C = tgl_peer_get (TLS, chat_id); if (C && (C->flags & TGLPF_CREATED)) { bl_do_chat_add_user (TLS, C->id, version, tgl_get_peer_id (user_id), tgl_get_peer_id (inviter_id), time (0)); } } break; case CODE_update_chat_participant_delete: { tgl_peer_id_t chat_id = TGL_MK_CHAT (DS_LVAL (DS_U->chat_id)); tgl_peer_id_t user_id = TGL_MK_USER (DS_LVAL (DS_U->user_id)); int version = DS_LVAL (DS_U->version); tgl_peer_t *C = tgl_peer_get (TLS, chat_id); if (C && (C->flags & TGLPF_CREATED)) { bl_do_chat_del_user (TLS, C->id, version, tgl_get_peer_id (user_id)); } } break; case CODE_update_dc_options: { int i; for (i = 0; i < DS_LVAL (DS_U->dc_options->cnt); i++) { fetch_dc_option (TLS, DS_U->dc_options->data[i]); } } break; case CODE_update_user_blocked: { int blocked = DS_BVAL (DS_U->blocked); tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_U->user_id))); if (P && (P->flags & TGLPF_CREATED)) { int flags = P->flags & 0xffff; if (blocked) { flags |= TGLUF_BLOCKED; } else { flags &= ~TGLUF_BLOCKED; } bl_do_user (TLS, tgl_get_peer_id (P->id), NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL, flags); } } break; case CODE_update_notify_settings: { } break; case CODE_update_service_notification: { vlogprintf (E_ERROR, "Notification %.*s: %.*s\n", DS_RSTR (DS_U->type), DS_RSTR (DS_U->message_text)); if (TLS->callback.notification) { TLS->callback.notification (TLS, DS_U->type->data, DS_U->message_text->data); } } break; case CODE_update_privacy: vlogprintf (E_NOTICE, "privacy change update\n"); break; case CODE_update_user_phone: { tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER (DS_LVAL (DS_U->user_id))); if (U && (U->flags & TGLPF_CREATED)) { bl_do_user (TLS, tgl_get_peer_id (U->id), NULL, NULL, 0, NULL, 0, DS_STR (DS_U->phone), NULL, 0, NULL, NULL, NULL, NULL, NULL, TGL_FLAGS_UNCHANGED); } } break; case CODE_update_read_history_inbox: { tgl_peer_id_t id = tglf_fetch_peer_id (TLS, DS_U->peer); tgl_peer_t *P = tgl_peer_get (TLS, id); if (P && (P->flags & TGLPF_CREATED)) { if (tgl_get_peer_type (P->id) == TGL_PEER_USER) { bl_do_user (TLS, tgl_get_peer_id (P->id), NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, DS_U->max_id, NULL, NULL, TGL_FLAGS_UNCHANGED); } else { bl_do_chat (TLS, tgl_get_peer_id (P->id), NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, DS_U->max_id, NULL, TGL_FLAGS_UNCHANGED); } } } break; case CODE_update_read_history_outbox: { tgl_peer_id_t id = tglf_fetch_peer_id (TLS, DS_U->peer); tgl_peer_t *P = tgl_peer_get (TLS, id); if (P && (P->flags & TGLPF_CREATED)) { if (tgl_get_peer_type (P->id) == TGL_PEER_USER) { bl_do_user (TLS, tgl_get_peer_id (P->id), NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, NULL, DS_U->max_id, NULL, TGL_FLAGS_UNCHANGED); } else { bl_do_chat (TLS, tgl_get_peer_id (P->id), NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, DS_U->max_id, TGL_FLAGS_UNCHANGED); } } } break; case CODE_update_web_page: { } break; /*case CODE_update_msg_update: { struct tgl_message *M = tgl_message_get (TLS, DS_LVAL (DS_U->id)); if (M) { bl_do_msg_update (TLS, M->id); } } break;*/ case CODE_update_read_messages_contents: break; case CODE_update_channel_too_long: { tgl_do_get_channel_difference (TLS, DS_LVAL (DS_U->channel_id), NULL, NULL); } break; case CODE_update_channel: break; case CODE_update_channel_group: break; case CODE_update_new_channel_message: { int new_msg = 0; struct tgl_message *M = tglf_fetch_alloc_message (TLS, DS_U->message, &new_msg); if (M && new_msg) { bl_do_msg_update (TLS, &M->permanent_id); } } break; case CODE_update_read_channel_inbox: break; case CODE_update_delete_channel_messages: break; case CODE_update_channel_message_views: break; case CODE_update_chat_admins: break; case CODE_update_chat_participant_admin: break; case CODE_update_new_sticker_set: break; case CODE_update_sticker_sets_order: break; case CODE_update_sticker_sets: break; case CODE_update_saved_gifs: break; case CODE_update_bot_inline_query: break; default: assert (0); } if (check_only) { return; } if (DS_U->pts) { assert (DS_U->pts_count); bl_do_set_pts (TLS, DS_LVAL (DS_U->pts)); } if (DS_U->qts) { bl_do_set_qts (TLS, DS_LVAL (DS_U->qts)); } if (DS_U->channel_pts) { assert (DS_U->channel_pts_count); int channel_id; if (DS_U->channel_id) { channel_id = DS_LVAL (DS_U->channel_id); } else { assert (DS_U->message); assert (DS_U->message->to_id); assert (DS_U->message->to_id->magic == CODE_peer_channel); channel_id = DS_LVAL (DS_U->message->to_id->channel_id); } bl_do_set_channel_pts (TLS, channel_id, DS_LVAL (DS_U->channel_pts)); } } void tglu_work_updates (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U) { if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { return; } if (!check_only && do_skip_seq (TLS, DS_LVAL (DS_U->seq)) < 0) { return; } int i; if (DS_U->users) { for (i = 0; i < DS_LVAL (DS_U->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_U->users->data[i]); } } if (DS_U->chats) { for (i = 0; i < DS_LVAL (DS_U->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_U->chats->data[i]); } } if (DS_U->updates) { for (i = 0; i < DS_LVAL (DS_U->updates->cnt); i++) { tglu_work_update (TLS, check_only, DS_U->updates->data[i]); } } if (check_only) { return; } bl_do_set_date (TLS, DS_LVAL (DS_U->date)); bl_do_set_seq (TLS, DS_LVAL (DS_U->seq)); } void tglu_work_updates_combined (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U) { if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { return; } if (!check_only && do_skip_seq (TLS, DS_LVAL (DS_U->seq_start)) < 0) { return; } int i; for (i = 0; i < DS_LVAL (DS_U->users->cnt); i++) { tglf_fetch_alloc_user (TLS, DS_U->users->data[i]); } for (i = 0; i < DS_LVAL (DS_U->chats->cnt); i++) { tglf_fetch_alloc_chat (TLS, DS_U->chats->data[i]); } for (i = 0; i < DS_LVAL (DS_U->updates->cnt); i++) { tglu_work_update (TLS, check_only, DS_U->updates->data[i]); } if (check_only) { return; } bl_do_set_date (TLS, DS_LVAL (DS_U->date)); bl_do_set_seq (TLS, DS_LVAL (DS_U->seq)); } void tglu_work_update_short_message (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U) { if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { return; } if (!check_only && tgl_check_pts_diff (TLS, DS_LVAL (DS_U->pts), DS_LVAL (DS_U->pts_count)) <= 0) { return; } if (check_only > 0) { return; } //struct tgl_message *N = tgl_message_get (TLS, DS_LVAL (DS_U->id)); //int new = (!N || !(N->flags & TGLMF_CREATED)); struct tgl_message *M = tglf_fetch_alloc_message_short (TLS, DS_U); if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { return; } assert (M); if (1) { bl_do_msg_update (TLS, &M->permanent_id); } if (check_only) { return; } bl_do_set_pts (TLS, DS_LVAL (DS_U->pts)); } void tglu_work_update_short_chat_message (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U) { if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { return; } if (!check_only && tgl_check_pts_diff (TLS, DS_LVAL (DS_U->pts), DS_LVAL (DS_U->pts_count)) <= 0) { return; } if (check_only > 0) { return; } //struct tgl_message *N = tgl_message_get (TLS, DS_LVAL (DS_U->id)); //int new = (!N || !(N->flags & TGLMF_CREATED)); struct tgl_message *M = tglf_fetch_alloc_message_short_chat (TLS, DS_U); if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { return; } assert (M); if (1) { bl_do_msg_update (TLS, &M->permanent_id); } if (check_only) { return; } bl_do_set_pts (TLS, DS_LVAL (DS_U->pts)); } void tglu_work_updates_too_long (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U) { if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { return; } vlogprintf (E_NOTICE, "updates too long... Getting difference\n"); if (check_only) { return; } tgl_do_get_difference (TLS, 0, 0, 0); } void tglu_work_update_short (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U) { if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { return; } tglu_work_update (TLS, check_only, DS_U->update); } void tglu_work_update_short_sent_message (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U, void *extra) { if (DS_U->pts) { assert (DS_U->pts_count); if (!check_only && tgl_check_pts_diff (TLS, DS_LVAL (DS_U->pts), DS_LVAL (DS_U->pts_count)) <= 0) { return; } } struct tgl_message *M = extra; if (!M) { return; } //long long random_id = M->permanent_id.id; tgl_message_id_t msg_id = M->permanent_id; msg_id.id = DS_LVAL (DS_U->id); bl_do_set_msg_id (TLS, &M->permanent_id, &msg_id); //tgls_insert_random2local (TLS, random_id, &msg_id); int f = DS_LVAL (DS_U->flags); unsigned flags = M->flags; if (f & 1) { flags |= TGLMF_UNREAD; } if (f & 2) { flags |= TGLMF_OUT; } if (f & 16) { flags |= TGLMF_MENTION; } bl_do_edit_message (TLS, &M->permanent_id, NULL, NULL, NULL, NULL, NULL, NULL, 0, DS_U->media, NULL, NULL, NULL, NULL, flags); if (check_only) { return; } bl_do_msg_update (TLS, &M->permanent_id); if (DS_U->pts) { bl_do_set_pts (TLS, DS_LVAL (DS_U->pts)); } } void tglu_work_any_updates (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U, void *extra) { if (check_only > 0 || (TLS->locks & TGL_LOCK_DIFF)) { return; } switch (DS_U->magic) { case CODE_updates_too_long: tglu_work_updates_too_long (TLS, check_only, DS_U); return; case CODE_update_short_message: tglu_work_update_short_message (TLS, check_only, DS_U); return; case CODE_update_short_chat_message: tglu_work_update_short_chat_message (TLS, check_only, DS_U); return; case CODE_update_short: tglu_work_update_short (TLS, check_only, DS_U); return; case CODE_updates_combined: tglu_work_updates_combined (TLS, check_only, DS_U); return; case CODE_updates: tglu_work_updates (TLS, check_only, DS_U); return; case CODE_update_short_sent_message: tglu_work_update_short_sent_message (TLS, check_only, DS_U, extra); return; default: assert (0); } } void tglu_work_any_updates_buf (struct tgl_state *TLS) { struct tl_ds_updates *DS_U = fetch_ds_type_updates (TYPE_TO_PARAM (updates)); assert (DS_U); tglu_work_any_updates (TLS, 1, DS_U, NULL); tglu_work_any_updates (TLS, 0, DS_U, NULL); free_ds_type_updates (DS_U, TYPE_TO_PARAM (updates)); } #define user_cmp(a,b) (tgl_get_peer_id ((a)->id) - tgl_get_peer_id ((b)->id)) DEFINE_TREE(user, struct tgl_user *,user_cmp,0) static void notify_status (struct tgl_user *U, void *ex) { struct tgl_state *TLS = ex; if (TLS->callback.user_status_update) { TLS->callback.user_status_update (TLS, U); } } static void status_notify (struct tgl_state *TLS, void *arg) { tree_act_ex_user (TLS->online_updates, notify_status, TLS); tree_clear_user (TLS->online_updates); TLS->online_updates = NULL; TLS->timer_methods->free (TLS->online_updates_timer); TLS->online_updates_timer = NULL; } void tgl_insert_status_update (struct tgl_state *TLS, struct tgl_user *U) { if (!tree_lookup_user (TLS->online_updates, U)) { TLS->online_updates = tree_insert_user (TLS->online_updates, U, rand ()); } if (!TLS->online_updates_timer) { TLS->online_updates_timer = TLS->timer_methods->alloc (TLS, status_notify, 0); TLS->timer_methods->insert (TLS->online_updates_timer, 0); } } static void user_expire (struct tgl_state *TLS, void *arg) { struct tgl_user *U = arg; TLS->timer_methods->free (U->status.ev); U->status.ev = 0; U->status.online = -1; U->status.when = tglt_get_double_time (); tgl_insert_status_update (TLS, U); } void tgl_insert_status_expire (struct tgl_state *TLS, struct tgl_user *U) { assert (!U->status.ev); U->status.ev = TLS->timer_methods->alloc (TLS, user_expire, U); TLS->timer_methods->insert (U->status.ev, U->status.when - tglt_get_double_time ()); } void tgl_remove_status_expire (struct tgl_state *TLS, struct tgl_user *U) { TLS->timer_methods->free (U->status.ev); U->status.ev = 0; } telegram-purple/tgl/updates.h000066400000000000000000000030471357227200100165720ustar00rootroot00000000000000/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifndef __UPDATES_H__ #define __UPDATES_H__ struct tl_ds_updates; struct tl_ds_update; void tgl_insert_status_update (struct tgl_state *TLS, struct tgl_user *U); void tgl_insert_status_expire (struct tgl_state *TLS, struct tgl_user *U); void tgl_remove_status_expire (struct tgl_state *TLS, struct tgl_user *U); int tgl_check_pts_diff (struct tgl_state *TLS, int pts, int pts_count); void tglu_work_update (struct tgl_state *TLS, int check_only, struct tl_ds_update *DS_U); void tglu_work_updates (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U); void tglu_work_any_updates_buf (struct tgl_state *TLS); void tglu_work_any_updates (struct tgl_state *TLS, int check_only, struct tl_ds_updates *DS_U, void *extra); #endif telegram-purple/commit.h0000664000000000000000000000007400000000000014266 0ustar rootroot#ifndef GIT_COMMIT # define GIT_COMMIT "ca42dcf0e6" #endif