;ELC ;;; Compiled ;;; in Emacs version 28.0.50 ;;; with all optimizations. (byte-code "\300\301!\210\300\302!\210\300\303!\210\300\304!\210\300\305!\210\300\306!\210\300\307!\207" [require symon cl-lib url parse-time timezone json button] 2) (defconst symon-lingr-version "0.1.1") (byte-code "\300\301\302\303\304\305%\210\300\306\302\307\304\301%\210\310\311\302\312\304\301%\210\310\313\302\314\304\301%\210\310\315\302\316\304\301%\210\310\317\320\321\304\301%\210\310\322\302\323\304\301%\210\310\324\302\325\304\301%\210\310\326\327\330\304\306%\210\331\332\333\334\304\306%\210\331\335\336\337\304\306%\210\331\340\341\342\304\306%\210\331\343\344\345\304\306%\207" [custom-declare-group symon-lingr nil "A notification-based Lingr client." :group symon symon-lingr-timeline "Timeline settings for symon-lingr.el." custom-declare-variable symon-lingr-user-name "User name to login to Lingr." symon-lingr-password "Password to login to Lingr." symon-lingr-muted-rooms "List of room names not to subscribe." symon-lingr-enable-notification t "When non-nil, echo new messages in the minibuffer." symon-lingr-log-file "File to save `symon-lingr' logs in." symon-lingr-app-key "App key to access Lingr API (optional for now)." symon-lingr-link-regexp (concat "\\<\\(" (mapconcat 'regexp-quote '("http" "https" "ftp" "mailto" "file" "news" "shell" "elisp" "doi" "message" "file+sys" "file+emacs" "bbdb" "bibtex" "docview" "gnus" "info" "irc" "mew" "mhe" "rmail" "vm" "vm-imap" "wl") "\\|") "\\):\\([^ \n()<>]+\\(?:([[:word:]0-9_]+)\\|\\([^[:punct:] \n]\\|/\\)\\)\\)") "A regexp that recognizes an url." custom-declare-face symon-lingr-user-id-face ((((background light)) (:foreground "#7e7765" :bold t)) (t (:foreground "#faf5ee" :bold t))) "Face used to highlight user IDs in Lingr timelines." symon-lingr-nickname-face ((((background light)) (:foreground "#aea89a")) (t (:foreground "#e2c69f"))) "Face used to highlight nicknames in Lingr timelines." symon-lingr-time-face ((((background light)) (:foreground "#aea89a")) (t (:foreground "#e2c69f"))) "Face used to highlight timestamps in Lingr timelines." symon-lingr-room-header-face ((((background light)) (:background "#e4e3de" :foreground "#d48e2d")) (t (:background "#4c4c4c" :foreground "#d48e2d"))) "Face used to highlight room header in Lingr timelines."] 6) (defalias 'symon-lingr--assoc-ref #[(k lst) "\302 \"A\207" [k lst assoc] 3]) #@57 Convert (K1 V1 K2 V2 ...) to ((K1 . V1) (K2 . V2) ...). (defalias 'symon-lingr--plist-to-alist #[(plst) "\205@A@B\301AA!B\207" [plst symon-lingr--plist-to-alist] 3 (#$ . 2409)]) #@99 Make a string button and return it. This is NOT a destructive function unlike `make-text-button'. (defalias 'symon-lingr--make-button #[(str action &rest props) "\303!\304\305\306\301 \n&\210)\207" [str action props copy-sequence apply make-text-button 0] 7 (#$ . 2599)]) (byte-code "\300\301\302\303#\300\207" [function-put symon-lingr--make-button lisp-indent-function 1] 4) #@29 Linkify URLs in the region. (defalias 'symon-lingr--linkify-urls #[(beg end) "b\210\303 \n\304#\205\305\306\224\306\225\307\310\311\312\306!&\210\202\207" [beg symon-lingr-link-regexp end search-forward-regexp t make-text-button 0 action #[(b) "\301\302\303\"!\207" [b browse-url button-get url] 4] url match-string] 8 (#$ . 2987)]) #@45 Parse and encode Lingr messages' timestamp. (defalias 'symon-lingr--parse-time-string #[(str) "\301\302\303\304!!\"\207" [str apply encode-time parse-time-string timezone-make-date-arpa-standard] 5 (#$ . 3333)]) (byte-code "\300\301\302\303#\210\300\301\304\305#\207" [put lingr-error error-conditions (error lingr-error) error-message "Lingr error"] 4) #@66 Read current response buffer as JSON. Return nil on parse error. (defalias 'symon-lingr--parse-response #[nil "\212\301b\210\302\303\304\305#\205!\3061\307\310\311`d{\312\"!)0\202!\210\304)\207" [json-array-type 0 search-forward "\n\n" nil t (error) list json-read-from-string decode-coding-string utf-8] 4 (#$ . 3694)]) #@729 Call Lingr-API API with PARAMS, and return the parsed response on success, or nil iff Lingr did not return a JSON. This function may raise an error on connection failure, or signal `lingr-error' if lingr returned an error status. When ASYNC-CALLBACK is non-nil, this function immediately returns with the process buffer and ASYNC-CALLBACK is called with the response later. ASYNC-CALLBACK can also be a pair of two functions of the form (CALLBACK . ERRORBACK). That case, ERRORBACK is called with a signal, which is a list of the form (ERROR-SYMBOL DATA ...), on failure. If ERRORBACK is omitted, errors are demoted to a simple message and never raised. PARAMS must be a plist of the form ("KEY" "VALUE" "KEY" "VALUE" ...). (defalias 'symon-lingr--call-api #[(api &optional async-callback &rest params) "\203\n\306 BB \204\307\nP\202\307\n\310\311\312\313 !\314#R\315 !\203) \202+ @\315 !\2035\316\2027 A \204gr\317!q\210\320 )\321\322\"\323\230\203a\324\325\321\326\"C\"\202c)\202~\3271w\330\331 \fD#0\202~\f!)+\207" [symon-lingr-app-key params api async-callback errorback callback "app_key" "http://lingr.com/api/" "?" mapconcat #[(p) "\301\302@A#\207" [p format "%s=%s"] 4] symon-lingr--plist-to-alist "&" functionp #[(e) "\301\302\303!\"\207" [e message "%s" error-message-string] 4] url-retrieve-synchronously symon-lingr--parse-response symon-lingr--assoc-ref status "error" signal lingr-error detail (error) url-retrieve #[(s cb eb) "\204 \304 \305\306 \"\307\230\203\n\310\305\311 \"D!\202 !)\207@@\312=\203/\n@A@!\207\n\313!\207" [s res eb cb symon-lingr--parse-response symon-lingr--assoc-ref status "error" lingr-error detail :error (error "Lingr: Unexpected redirection.")] 5] url res err] 7 (#$ . 4027)]) #@17 The session ID. (defvar symon-lingr--session-id nil (#$ . 5808)) #@29 Nickname of the login user. (defvar symon-lingr--nickname nil (#$ . 5879)) #@55 List of room names which the login user is attending. (defvar symon-lingr--rooms nil (#$ . 5960)) #@55 The latest `counter' value returned by the Lingr API. (defvar symon-lingr--counter nil (#$ . 6064)) #@220 Login to Lingr asynchronously. If CONT is non-nil, it must be a 0-ary function and is called after successfully logging in to Lingr. [This function calls `session/create', `user/get_rooms', `room/subscribe' once each.] (defalias 'symon-lingr--login #[(&optional cont) "\206\305\306!\n\206\307\310!\f\206\311\312\313!\210\314\315\316\317\320\314\321\316\322\323\314\324\316\325\326\312\327\330 DE\331\330\fDD\257\332BBBF\333BBBF\334 \335 &+\207" [symon-lingr-user-name user symon-lingr-password password cont read-from-minibuffer "Username: " read-passwd "Password: " #[nil "\300\207" [nil] 1] message "Lingr: Logging in to Lingr ..." symon-lingr--call-api "session/create" lambda (json) (setq symon-lingr--session-id (symon-lingr--assoc-ref 'session json) symon-lingr--nickname (symon-lingr--assoc-ref 'nickname json)) "user/get_rooms" (json) (setq symon-lingr--rooms (cl-remove-if (lambda (r) (member r symon-lingr-muted-rooms)) (symon-lingr--assoc-ref 'rooms json))) "room/subscribe" (json) (setq symon-lingr--counter (symon-lingr--assoc-ref 'counter json)) "Lingr: Successfully logged in as %s." quote funcall ("rooms" (mapconcat 'identity symon-lingr--rooms ",") "session" symon-lingr--session-id) ("session" symon-lingr--session-id) "user" "password"] 19 (#$ . 6171)]) #@80 Logout from Lingr synchronously. [This function calls `session/destroy' once.] (defalias 'symon-lingr--logout #[nil "\204\301\302!\207\303\304\305\306$\210\305\301\307!\207" [symon-lingr--session-id message "Lingr: Not logged in to Lingr." symon-lingr--call-api "session/destroy" nil "session" "Lingr: Successfully logged out from Lingr."] 5 (#$ . 7463)]) #@35 Read a room name with minibuffer. (defalias 'symon-lingr--choose-room #[nil "\204\302\303!\207 \204\302\304!\207 A\204 @\207\305\306 \"\207" [symon-lingr--session-id symon-lingr--rooms error "Not logged in to Lingr." "No rooms available." completing-read "Room: "] 3 (#$ . 7830)]) #@83 Submit message STR to ROOM asynchronously. [This function calls `room/say' once.] (defalias 'symon-lingr-say #[(&optional str room) "\206\304 \305\306\307\"!\310\311\312\313\n\314 \315\316 &\n*\207" [room str symon-lingr--session-id symon-lingr--nickname symon-lingr--choose-room read-from-minibuffer format "Say in %s: " symon-lingr--call-api "room/say" (lambda (_) (message "Lingr: Successfully posted a message.")) "session" "nickname" "room" "text"] 11 (#$ . 8124) nil]) #@261 Return recent messages posted in ROOM before UNTIL-MESSAGE (if specified). When ASYNC-CALLBACK is non-nil, this function returns immediately and call ASYNC-CALLBACK with the messages later. [This function calls either `room/show' or `room/get_archives' once.] (defalias 'symon-lingr--room-archive #[(room &optional until-message async-callback) "\306\307\"\310\311\n\"\210 \203) \203)\312\313\314\315\316\317 D\320BBE\321\f\322\n\323 &\202g \203B\312\324\314\325\316\317 D\326BBE\321\f\327\n&\202g \203T\312\313\330\321\f\322\n\323 &\202a\306\331\312\324\330\321\f\327\n&\"@\306\332 \"))\207" [until-message until-id room async-callback symon-lingr--session-id res symon-lingr--assoc-ref id message "Lingr: Requesting archive of room %s ..." symon-lingr--call-api "room/get_archives" lambda (s) funcall quote ((symon-lingr--assoc-ref 'messages s)) "session" "room" "before" "room/show" (s) ((symon-lingr--assoc-ref 'messages (car (symon-lingr--assoc-ref 'rooms s)))) "rooms" nil rooms messages] 9 (#$ . 8613)]) #@213 Open a Comet stream. When a new message is arrived to the stream, CONSUMER-FN is called with the message. -SILENT is an internal variable and should not be used. [This function calls `event/observe' repeatedly.] (defalias 'symon-lingr--open-stream #[(consumer-fn &optional errback -silent) "\204\306\307!\210\310\311\312\313\314\315\316\317\320 D\321BBF\322\320 D\320\nD\323BBBF\312\324\n\205.\325\n\326BBEB\327 \330\f&\331\332 !\333\")\207" [-silent consumer-fn errback symon-lingr--session-id symon-lingr--counter buf message "Lingr: Opening a comet stream ..." symon-lingr--call-api "event/observe" lambda (json) let ((counter (symon-lingr--assoc-ref 'counter json)) (events (symon-lingr--assoc-ref 'events json))) (when counter (setq symon-lingr--counter counter)) mapcar quote (events) symon-lingr--open-stream (t) (status) funcall (status) "session" "counter" set-process-query-on-exit-flag get-buffer-process nil] 10 (#$ . 9645)]) #@63 Convert ISO8601 TIMESTAMP to an user-friendly representation. (defalias 'symon-lingr--format-timestamp #[(timestamp) "\306!\307\310 \"\211@\311_\nA@\\\211\312V\203\335\313 !\211AAAA\203-\f\211A\242\2024\314\315\316\fGD\"\f\211A\2421\f\211A\2422\f\211A\2423\f\211A\2424\3173!\3204\321=\203a\322\202\3274\323=\203l\324\202\3274\325=\203w\326\202\3274\327=\203\202\330\202\3274\331=\203\215\332\202\3274\333=\203\230\334\202\3274\335=\203\243\336\202\3274\337=\203\256\340\202\3274\341=\203\271\342\202\3274\343=\203\304\344\202\3274\345=\203\317\346\202\3274\347=\205\327\350Q.\202  \351V\203\356\352\353\354 \355\211#\"\202  \355V\203\375\352\356 \355\245\"\202  \321V\203\n\352\357 \"\202 \360+\207" [timestamp created-time diff secs ____ _ symon-lingr--parse-time-string time-subtract current-time 65536.0 86400 decode-time signal wrong-number-of-arguments (_ __ ___ d m . ____) int-to-string " " 1 "Jan" 4 "Apr" 7 "Jul" 10 "Oct" 2 "Feb" 5 "May" 8 "Aug" 11 "Nov" 3 "Mar" 6 "Jun" 9 "Sep" 12 "Dec" 3600 format "%dh" / 60 "%dm" "%ds" "now" __ ___ d m] 7 (#$ . 10595)]) #@37 Format and insert MESSAGE at point. (defalias 'symon-lingr--insert-message #[(message) "\306\301\"\306\307\"\310\306\303\"!\f GZ\311\312\313\" r q\210\314\216\306\315\"c\210\316ed\"\210eb\210\317c\210\320y\321U\2041\322ed\"\210\323 + \324\n\325\326#\324\327\330 \"\325\331#\332\324\317\333\334\335 E#\324 \325\336#\337 \337\261-\207" [message nickname id timestamp fill-column align symon-lingr--assoc-ref speaker_id symon-lingr--format-timestamp generate-new-buffer " *temp*" t #[nil "\301!\205 \302!\207" [#1=#:temp-buffer buffer-name kill-buffer] 2] text fill-region " " 1 0 symon-lingr--linkify-urls buffer-string propertize face symon-lingr-user-id-face format " (%s)" symon-lingr-nickname-face " :" display space :align-to symon-lingr-time-face "\n" #1#] 9 (#$ . 11731)]) (defvar symon-lingr--last-read-message nil) (defvar symon-lingr--unread-messages-count 0) (defvar symon-lingr--unread-messages (make-hash-table :test 'equal)) #@25 Mark MESSAGE as unread. (defalias 'symon-lingr--push-unread-message #[(message) "\305\301\"\306 \n\"\307 @\206\310T ABB\n#\210\fT\211*\207" [message room symon-lingr--unread-messages oldval symon-lingr--unread-messages-count symon-lingr--assoc-ref gethash puthash 0] 5 (#$ . 12691)]) #@48 Unmark and return all unread messages in ROOM. (defalias 'symon-lingr--pop-unread-messages #[(room) "\305 \"\211A@\203 \203\306 \nA@\"\203\nA@\307\310 #\210\f\n@\206)\311Z\nA\237)\207" [room symon-lingr--unread-messages oldval symon-lingr--last-read-message symon-lingr--unread-messages-count gethash symon-lingr--message< puthash nil 0] 5 (#$ . 12989)]) #@41 Return non-nil iff M1 is older than M2. (defalias 'symon-lingr--message< #[(m1 m2) "\302\303\304\"!\302\303\304 \"!W\207" [m1 m2 string-to-number symon-lingr--assoc-ref id] 5 (#$ . 13362)]) (defalias 'symon-lingr--load-log-file #[nil "\205\"\303!\205\"\304\305\306\"r q\210\307\216\310!\210eb\210\311p!\211+\207" [symon-lingr-log-file #1=#:temp-buffer symon-lingr--last-read-message file-exists-p generate-new-buffer " *temp*" t #[nil "\301!\205 \302!\207" [#1# buffer-name kill-buffer] 2] insert-file-contents read] 3]) (defalias 'symon-lingr--save-log-file #[nil "\205\303\304\305\"r q\210\306\216\307\np\"\210\310ed#+\207" [symon-lingr-log-file #1=#:temp-buffer symon-lingr--last-read-message generate-new-buffer " *temp*" t #[nil "\301!\205 \302!\207" [#1# buffer-name kill-buffer] 2] prin1 write-region] 4]) (defalias 'symon-lingr--fetch-first-messages #[(rooms &optional cont) "\204 \205 \207\302@\303\304\305\306\307\310AD\310 DEF#\207" [rooms cont symon-lingr--room-archive nil lambda (messages) (dolist (message messages) (when (or (null symon-lingr--last-read-message) (symon-lingr--message< symon-lingr--last-read-message message)) (symon-lingr--push-unread-message message))) symon-lingr--fetch-first-messages quote] 10]) (defalias 'symon-lingr--initialize #[nil "\300 \210\301\302!\207" [symon-lingr--load-log-file symon-lingr--login #[nil "\302\303 \304\"\207" [symon-lingr--unread-messages-count symon-lingr--rooms 0 symon-lingr--fetch-first-messages #[nil "\300\301\302\"\207" [symon-lingr--open-stream #[(s) "\303\301\"\211\205\n\203\301\304\303\305 \"\303\306 \"#\210\307 !)\207" [s message symon-lingr-enable-notification symon-lingr--assoc-ref "New Lingr message in `%s': %s" room text symon-lingr--push-unread-message] 7] #[(s) "\301\211\207" [symon-lingr--session-id nil] 2]] 3]] 3]] 2]) (defalias 'symon-lingr--cleanup #[nil "\301 \210\3021 \303 0\207\304\305\"\210)\306\207" [#1=#:err symon-lingr--save-log-file (debug error) symon-lingr--logout message "Error: %S" nil] 3]) #@26 Display unread messages. (defalias 'symon-lingr-display #[nil "\306\307!\310r q\210\311 \210\n\312\211\203W\f@\313 !\314\315 \316Q\317\320#\316\321\322\303 \323 @&\316\261\210 \312\211\203O\f@\324!\210\316c\210\fA\211\204<+\fA\211\204*\325\326 !!+\207" [action buf symon-lingr--rooms room --dolist-tail-- messages get-buffer-create "*symon-lingr*" #[(b) "\306\301\"\306\302\"\307 \n\"\211\203=\310\302 @#\210\311!b\210 \312\211\2059 @\313c\210\314\f!\210 A\211\204'\312*\202L\315!b\210\315!\311!|\210\316c+\207" [b room until messages message --dolist-tail-- button-get symon-lingr--room-archive button-put button-end nil "\n" symon-lingr--insert-message button-start "(No more messages.)\n"] 5] erase-buffer nil symon-lingr--pop-unread-messages propertize " " "\n" face symon-lingr-room-header-face symon-lingr--make-button "[Fetch older messages]\n" until symon-lingr--insert-message select-window display-buffer message] 10 (#$ . 15405) nil]) (byte-code "\300\301\302\303\304\305\306##\210\307\310!\207" [put symon-lingr-monitor symon-monitor vector #[nil "\303\304\305 I\210\303\306\307\304\310#I\210\311 \210\312\313 \205\n\"\207" [symon-refresh-rate symon-lingr--session-id symon-lingr--unread-messages-count [nil nil] 0 symon--make-history-ring 1 run-with-timer #[nil "\302\303\205 \"\207" [symon-lingr--session-id symon-lingr--unread-messages-count ring-insert nil] 3] symon-lingr--initialize ring-insert nil] 6] #[nil "\300\301!\210\302 \207" [cancel-timer nil symon-lingr--cleanup] 2] #[nil "\302\303!\211@\304 \247\204\305\202\306\307 \310#\303PP*\207" [lst val ring-elements nil "Lingr-Unread:" "N/A " format "%d%s " ""] 6] provide symon-lingr] 7)