-
Notifications
You must be signed in to change notification settings - Fork 1
imap for emacs - wip
License
corecode/eimap
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
;;; -*- mode: emacs-lisp; -*-
;;; WHAT IS THIS?
; eimap is an experiment to approach IMAP processing from a new angle.
;
; the protocol parser and generator are both formally generated from
; grammars.
;
; instead of using a request-reply approach (which does not work well
; with IMAP), eimap uses a streaming data model:
;
; data from the server is automatically parsed into usable lisp data
; structures and directly handed to a handler for the incoming data
; (not shown in the sample code below).
;
; if the application requires other data that has not been streamed in
; yet, it can request the server to send this data, using the
; `eimap-request' method (see example below).
;;; USING THE APPLICATION
; (add-to-list 'load-path default-directory)
;
; (require 'eimap)
;
; (eimap
; "0x2c.org" :user "2"
; ;; default is IMAP+STARTTLS.
; ;; pass :port "imaps" for SSL connection to port 993
; )
;
;;; USING THE BACKEND LIBRARY
(add-to-list 'load-path default-directory)
(require 'eimap)
;; this table will dispatch all the incoming messages
;;
(eimap-declare-dispatch-table eimap-README)
;; upcalls are passed the `upcall-data' supplied to `eimap-open' and a
;; plist from the parsed message. `eimap-parse.el' contains the
;; formal grammar and self-documents the fields of each message.
;;
;; the upcall is called with the eimap connection buffer active
;;
(eimap-define-method eimap-README connection-state (upcall-data state-data)
;; connection-state is issued when the state changes. Possible
;; `:state's are `connecting', `connected', `authenticating',
;; `authenticated', and `closed'.
(when (eq 'authenticated (plist-get state-data :state))
;; `eimap-request' has to be called with the eimap connection
;; buffer active. use `eimap-request*' to pass the connection
;; object explicitly.
;;
;; `eimap-request' takes a request element; see
;; `eimap-generate.el' for the self-documenting formal grammar.
;;
;; it also takes a `:cbdata' callback data argument that will be
;; passed to the `:barrier' and `:done' callbacks. There is no
;; data callback, because replies generally can not be associated
;; with the originating requests. The presence of a `:barrier'
;; also drains the request stream before the request is issued.
(eimap-request
'(:method SELECT :mailbox "INBOX")
:cbdata upcall-data
:done (lambda (respdata cbdata)
;; now that the SELECT is done, we can
;; sequence the FETCH. Maybe there should
;; be a way to add a tail barrier?
(eimap-request '(:method FETCH
;; `:to' can be a
;; number or `*'.
:ids (:from 1 :to *)
:attr (FLAGS UID)))))))
;; Depending on the server, there will be more or less unsolicited
;; data. EXISTS is a mandatory response to SELECT.
(eimap-define-method eimap-README EXISTS (upcall-data imap-data)
(message "This mailbox has %d messages" (plist-get imap-data :exists)))
;; The server may also send status responses. All status responses
;; (`resp-text-code') are converted to their own upcalls.
(eimap-define-method eimap-README UIDVALIDITY (upcall-data imap-data)
;; in reality, we'd have to empty caches if the UIDVALIDITY changed.
(message "This mailbox UID validity is %d" (plist-get imap-data :uidvalidity)))
;; this upcall will be issued for every FETCH response
;;
;; let's assume we're building something like offlineIMAP, just to
;; illustrate how async requests would work with overlapping requests.
;;
;; for a real application, you'd collect uids first and issue several
;; per request to reduce the protocol overhead.
(eimap-define-method eimap-README FETCH (upcall-data imap-data)
;; usually, you'd update local state with this information and then
;; issue new requests based on local state.
(when (plist-get imap-data :flags)
(message "flags for uid %d (msgid %d) are %s"
(plist-get imap-data :uid)
(plist-get imap-data :msgid)
(pp-to-string (plist-get imap-data :flags))))
;; now, say we decide that this message is new and its body needs
;; to be fetched. for ease of demonstration, we'll just fetch the
;; bodystructure instead.
(if (plist-get imap-data :bodystructure)
;; jolly good, we already got the data.
(message "message uid %d has structure %s"
(plist-get imap-data :uid)
(pp-to-string (plist-get imap-data :bodystructure)))
;; no bodystructure present, let's fetch it.
;; this just simulates us picking some messages
(when (eq 1 (% (plist-get imap-data :msgid) 30))
(eimap-request `(:method FETCH
:uid t
:ids ,(plist-get imap-data :uid)
:attr (UID BODYSTRUCTURE))))))
(eimap-open
"0x2c.org" :user "2"
;; `:upcall' is where it's at. All incoming data (and connection
;; state change) are communicated via `:upcall'. If you want to use
;; the automatic dispatch, just use `eimap-create-dispatch' to do the
;; work for you.
;;
;; Otherwise, pass a function that takes (upcall-data method data) as
;; arguments. `upcall-data' is what you pass in `:upcall-data';
;; `method' is the IMAP response `:method' (see `eimap-parse.el'),
;; and `data' is the corresponding response data. For example,
;; `:upcall' might be called with:
;;
;; ("o hi" 'FETCH (:msgid 3 :flags ("\\seen" "\\answered") :uid 667))
:upcall (eimap-create-dispatch eimap-README)
:upcall-data "o hi")
;; check out (switch-to-buffer-other-window "*Messages*")
;; that's where all the parsed data arrived
About
imap for emacs - wip
Resources
License
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published