Skip to content
imap for emacs - wip
Emacs Lisp
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
LICENSE
README
eimap-auth.el
eimap-connection.el
eimap-dispatch.el
eimap-generate.el
eimap-parse.el
eimap.el
sample.txt

README

;;; -*- 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
You can’t perform that action at this time.