Установка g-client в emacs под Windows
Для чтения новостной ленты Google Reader в emacs есть специальный плагин g-client. Кроме Google Reader g-client поддерживает и другие сервисы Google – Calendar, Blogger. Рассмотрим как настроить и использовать greader.
G-client входит в состав проекта Emacspeak. Проект Emacspeak разрабатывает T.V. Raman из Корнелльского университета. Raman активно работает над проектом Emacspeak, но g-client не обновлялся с марта 2007.
G-client использует аутентификацию на Google Reader через токен SID. Весной 2010 аутентификация по токену SID в Google API была отключена. Сейчас не-web приложения должны аутентифицироваться через токен Auth. Следовательно, если сейчас просто установить g-client, то он не будет работать. До внесения в механизм аутентификации g-client curl, запущенный из консоли cygwin bash, с теми же параметрами, которые ему передает g-client, у меня возвращал следующее:
| Error | |
Forbidden
Your client does not have permission to get URL/reader/api/0/tokenfrom this server.
- для компиляции исходников g-client на ELisp потребуется утилита make;
- для работы g-client с HTTP используется утилита curl;
- для осуществления XSLT-преобразования полученного XML от Google Reader используется утилита xsltproc.
Утилита xsltproc присутствует в cygwin в составе пакета libxslt в категории Libs.
Для просмотра результирующей HTML-страницы я использовал emacs браузер emacs-w3m. Разумеется, может быть использован любой другой браузер. Но тогда какой смысл разбираться с g-client под emacs если для просмотра будет использоваться сторонний браузер. Хотя, emacs-w3m имеет свои недостатки, но об этом после. Emacs-w3m – это набор скриптов на ELisp, которые реализуют интерфейс в emacs к консольному браузеру w3m. Соответственно, в cygwin я устанавливал ещё и w3m. Но установка и настройка emacs-w3m – это отдельная песня. Не будет отвлекаться.
Вообще говоря, после того, как вы разместили el-скрипты в какой-либо подходящей директории (например, C:\Documents and Settings\<username>\Application Data\.emacs.d\g-client) их необходимо скомпилировать. скомпилированные el-файлы имеют расширение elc. Для компиляции el-файлов необходимо в emacs выполнить команду “M-x byte-recompile-directory” для компиляции всех файлов в директории или “M-x byte-compile-file” для компиляции конкретного файла. Перекомпиляцию скриптов потребуется делать ещё и далее после внесения изменений в файлы.
При компиляции файлов g-client постоянно возникают предупреждения “cl package required at runtime”. Эти предупреждения можно просто игнорировать.
Если в процессе работы с emacs у вас будет возникать ошибка “Symbol’s function definition is void: <function_name>” и если вы уверены. что эта функция должна быть видима попробуйте перекомпилировать модуль с этой функцией командой “M-x byte-compile-file”. Команда “M-x byte-recompile-directory” в таких случаях мне не помогала.
В файл .emacs необходимо внести следующие строки:
(add-to-list 'load-path "~/.emacs.d/g-client")
(load-library "g-loaddefs")
(setq g-user-email "your_email@gmail.com")
(setq g-html-handler 'w3m-buffer)
(autoload 'w3m-buffer "w3m")
(setq max-lisp-eval-depth 1000)
Строка “(setq g-html-handler ‘w3m-buffer)” определяет, что просмотр результирующей html-страницы будет осуществляться браузером emacs-w3m. Последующие две строки – “(autoload ‘w3m-buffer “w3m”)” и “(setq max-lisp-eval-depth 1000)” необходимы для корректной работы браузера emacs-w3m с g-client.
Функция w3m-buffer используется для рендеринга текущего буфера. Она была добавлена в в emacs-w3m в модуль w3m.el 2006-10-02.
Параметр max-lisp-eval-depth по умолчанию у меня был равна 800. При этом в процессе рендеринга результирующей html-страницы браузером emacs-w3m возникало сообщение ”with-current-buffer: Lisp nesting exceeds `max-lisp-eval-depth’”. При увеличении значения этой переменной до 1000 такая ошибка больше не возникала.
Теперь перейдем к исправлению механизма аутентификации в модуле greader.el. Google Reader больше не поддерживает аутентификацию по токену SID (proof link), которая используется в модуле greader.el. Надо использовать аутентификацию по токену Auth.
1. В модуле g-auth.el:
1.1. в структуре g-auth удалим (или безопаснее закомментировать) поле “session-id” за ненадобностью
(defstruct g-auth
(username (user-login-name))
email
password
token
;session-id ;gsession-id
cookie-alist
service
(lifetime g-auth-lifetime)
timestamp
post-auth-action)
1.2. в функции g-authenticate при вызове shell-command-on-region добавил параметр g-curl-common-options после g-curl-program. Соответственно в строку функции format необходимо добавить “%s” в соответствующую позицию. В параметр g-curl-common-options в конце добавил ключ “–insecure”. Этот ключ необходим для того, чтобы пока не заморачиваться с настройкой SSL-сертификатов для curl при взаимодействии с Google API. Установить значение параметра g-curl-common-options можно или через setq в файле .emacs или можно использовать команду “M-x customize-option”. Параметр g-curl-common options у меня в итоге равен “–compressed –silent –location –location-trusted –insecure”. Если SSL для curl + g-client не настроить, то может возникать сообщение “cURL ERROR: 60: SSL certificate problem”.
(format "%s %s %s -X POST --data-binary @- %s 2>/dev/null"
g-curl-program g-curl-common-options g-cookie-options
(g-auth-url (g-auth-service auth-handle)))
2. В модуле greader.el:
2.1. В функции greader-post-authenticate-function оставим только проверку auth handle, так как токен был уже установлен в функции g-authenticate в модуле g-auth.el:
(unless (greader-p (g-auth-service auth-handle))
(error "This auth handle is not for Google Reader.")))
Функция greader-post-authenticate-function у меня в итоге выглядит так:
(defun greader-post-authenticate-function (auth-handle)
"Run Googlre Reader post-auth steps."
(unless (greader-p (g-auth-service auth-handle))
(error "This auth handle is not for Google Reader.")))
2.2. В функции greader-preferences при обращении к функции g-json-get-result в строке format вместо “–cookie SID=’%s’” необходимо оставить просто “%s”. А в значениях параметров вместо “(g-cookie “SID” greader-auth-handle)” указать “(g-authorization greader-auth-handle)”. Этот параметр задаёт header с токеном Auth для нового вида авторизации. Аналогичные исправления необходимо сделать во всех остальных местах – в функциях greader-feed-list, greader-tag-list, greader-tagged-reading-list, greader-update-subscription, greader-add-label, greader-star. То есть, фрагмент кода выглядел так:
(format
"%s %s --cookie SID='%s' %s 2>/dev/null"
g-curl-program g-curl-common-options
(g-cookie "SID" greader-auth-handle)
А исправленный вариант выглядит так:
(format
"%s %s %s %s 2>/dev/null"
g-curl-program g-curl-common-options
(g-authorization greader-auth-handle)
Теперь необходимо изменить кодировку в файле atom-view.xsl – “iso8859-15″ на “utf-8″. Это необходимо для корректного преобразования кириллицы в процессе XSLT-преобразования.
В общем-то это всё. Теперь можно перекомпилировать измененные файлы и запускать команду “M-x greader-reading-list”. Если все будет успешно, то запросится пароль Google, а затем отобразится html-страница с новостями Google Reader.
Если возникает сообщение “Error=BadAuthentication”, значит некорректно настроена аутентификация curl. Используйте отладку. Я для отладки curl собирал результирующую командную строку curl и запускал её в cygwin bash. А вообще, в процессе решения этой проблемы с g-client мне пришлось разобраться в основах языка ELisp, его компиляции и в механизмах его отладки в emacs (директива debug и интерактивный отладчик edebug). Но отладка Lisp – это отдельная большая тема. Которая, к тому же хорошо освещена в документации. Интерактивный отладчик edebug сильно помогает, но почему-то у меня не получилось с помощью edebug отлаживать функцию, которая вызывается не непосредственно, а через цепочку вызовов из других функций. В случае таких цепочек вызовов приходилось включать edebug для всей цепочки. И еще одно неудобство – нельзя посмотреть (или я просто пока не нашел как) для каких функций включен edebug.
Долгое время у меня после выполнения команды “M-x greader-reading-list” и ввода пароля в буфере “g scratch” возникала следующая ошибка: “warning: failed to load external entity “c:/Documents” cannot parse c:/Documents”. Проблема решилась перекомпиляцией некоторых модулей emacs-w3m командой “M-x byte-compile-file”.
У меня браузер emacs-w3m отображает результирующую html-страницу отвратительно. Зачем-то добавляет в тэги a параметр HSEQ (см. приведенные ниже скриншоты). Многие гиперссылки не отображает как гиперссылки. Но это проблемы emacs-w3m, а не g-client. Тот же самый html-файл прекрасно отображается в Google Chrome.
После всех настроек после запуска функции g-display-result (она вызывается из функции greader-reading-list) у меня html-страница отображается, но возникает сообщение “edebug-after: Wrong type argument: char-or-string-p, #”. Эта ошибка возникает из-за передачи имени буфера без кавычек в emacs-w3m:
w3m-string-match-url-components-1(#)
(condition-case nil (string-match w3m-url-components-regexp string) (error (w3m-string-match-url-components-1 string)))
(let ((string base)) (condition-case nil (string-match w3m-url-components-regexp string) (error ...)))
(w3m-string-match-url-components base)
У меня стояла достаточно новая, но не самая последняя версия emacs-w3m – от 30 июля 2010. Поставил самую последную девелоперсую версию emacs-w3m от 2 сентября.
Я использовал самую последнюю девелоперскую версию emacs-w3m.
Вот скриншоты того, что у нас получилось:
Настройка SSL
Для того, чтобы curl смог работать с сертификатами SSL ему необходимо сообщить где лежат файлы сертификатов. Опция –cacert позволяет задать SSL-сертификат (CA certificate to verify peer against (SSL)). Файл сертификата для curl должен быть в PEM-формате (Privacy Enhanced Mail). Если вы уже пользовались какими-либо сервисами Google, то сертификат у вас скорее всего уже есть. Но браузеры хранят SSL-сертификаты в своем внутреннем формате. Для примера рассмотрим как экспортировать SSl-сертификат из Firefox в pem-формат.
Зайдите на какой-нибудь сервис Google, требующий авторизации (например, на GMail) через Firefox. Будет установлено HTTPS-соединение и строка адреса станет желтой. Кликните на значок замка в строке статуса браузера. Нажмите на кнопку “Посмотреть сертификат” и перейдите на вкладку “Подробности”. С помощью кнопки “Экспортировать” можно экспортировать данный сертификат в файл. Теперь надо выбрать формат файла. Как вы видите в списке есть два формата PEM – “Сертификат X.509 в формате PEM” и “Цепочка сертификатов X.509 в формате PEM” надо выбирать цепочку сертификатов, ввести имя файла и указать расширение “.pem”. Файл сертификата можно положить, например, в директорию /usr/ssl/certs.
Если бы вы выбрали формат “Сертификат X.509 в формате PEM”, то curl возвращал бы ошибку
curl: (60) SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Теперь надо указать curl использовать данный сертификат. Для этого выполним в emacs команду “M-x customize-option” и введём “g-curl-common-options”. Добавим параметр cacert. В итоге значение переменной g-curl-common-options должно выглядеть так:
--compressed --silent --location --location-trusted --cacert /usr/ssl/certs/mail.google.com.chain.pem
Всё. Сохраняем значение параметра и можем наслаждаться работой greader через SSL.
Заключение
В ходе разбирательств с g-client я много искал в Интернет по этой теме. Информации мало. Есть пост Raman’а от 02.03. 2007 в блоге Emacspeak. Есть Google группа emacs-g-client (организованная также Раманом), но практически неактивная. Есть пост Билла Клементсона (Bill Clemenston) от 6.03.2007, в котором он подробно описывает процесс установки. Я написал Биллу письмо и он ответил следующее: “At some point, the g-client code changed and no longer worked with the code in my blog post. However, at that stage, I had already stopped using both w3m and g-client so I never bothered trying to debug the issues.”
Что ещё осталось сделать:
1. Проверить и при необходимости исправить время жизни токена в соответствии с настройками сервисов Google “Typically, tokens remain valid for 2 weeks”.
Эту задачу я оставляю как домашнее упражнение заинтересовавшимся читателям.


osya









