From 958d17b29fad1deedf747be664f73c26d6742ada Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Fri, 29 Sep 2017 23:43:25 +0300 Subject: [PATCH 01/25] Create mail directory --- idec.el | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/idec.el b/idec.el index d63e275..9d891df 100644 --- a/idec.el +++ b/idec.el @@ -96,6 +96,15 @@ ;; FUNCTIONS ;; ;;;;;;;;; +(defun create-echo-mail-dir (echo) + "Create ECHO directory inside `idec-mail-dir'." + (if (file-exists-p idec-mail-dir) + (message idec-mail-dir) + (mkdir idec-mail-dir)) + (if (file-exists-p (concat idec-mail-dir (concat "/" echo))) + (message (concat idec-mail-dir (concat "/" echo))) + (mkdir (concat idec-mail-dir (concat "/" echo))))) + (defun idec-load-new-messages () "Load new messages from IDEC nodes Not implemented.") From 20f8ab5c6988fb5676d945565dfac51f90f3ce09 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Fri, 29 Sep 2017 23:56:09 +0300 Subject: [PATCH 02/25] Doc --- idec.el | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/idec.el b/idec.el index 9d891df..8732894 100644 --- a/idec.el +++ b/idec.el @@ -106,13 +106,15 @@ (mkdir (concat idec-mail-dir (concat "/" echo))))) (defun idec-load-new-messages () - "Load new messages from IDEC nodes Not implemented.") + "Load new messages from IDEC nodes Not implemented." + ) ;; ECHOES FUNCTIONS ;; ;;;;;;;;;;;;;;;; (defun make-echo-url (echoes) - "Make ECHOES url to retreive messages." + "Make ECHOES url to retreive messages from `idec-primary-node'; +with `idec-download-offset' and `idec-download-limit'." ;; Check ECHOES is list (if (listp echoes) ;; Required GNU Emacs >= 25.3 @@ -120,6 +122,15 @@ (string-join echoes "/") "/" idec-download-offset ":" idec-download-limit)) (message (concat idec-primary-node "u/e/" echoes "/" idec-download-offset ":" idec-download-limit)))) +(defun download-subscriptions () + "Download messages from echoes defined in `idec-echo-subscriptions' from `idec-primary-node'." + (with-current-buffer + (url-retrieve-synchronously (make-echo-url (split-string idec-echo-subscriptions ","))) + (goto-char (point-min)) + (re-search-forward "^$") + (delete-region (point) (point-min)) + (display-echo-messages (buffer-string)))) + (defun display-echo-messages (messages) "Display downloaded MESSAGES from echo." (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: browse echo*")) From 44ca1a94b20dc8ab219c01c4e5d6a7579a97637f Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Sun, 1 Oct 2017 01:35:29 +0300 Subject: [PATCH 03/25] Load new messages: In progress --- idec.el | 99 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 26 deletions(-) diff --git a/idec.el b/idec.el index 8732894..11130c9 100644 --- a/idec.el +++ b/idec.el @@ -51,13 +51,21 @@ "Use /list.txt extension." :group 'idec) +(defcustom idec-smart-fetch nil + "Enable smat fetching; +Download only new messages; Traffic saving; Not implemented." + :type 'boolean + :group 'idec) + (defcustom idec-download-limit "50" - "Limit of download messages." + "Limit of download messages; +Not used if `idec-smart-fetching' is not nil." :type 'string :group 'idec) (defcustom idec-download-offset "-50" - "Offset of download messages." + "Offset of download messages; +Not used if `idec-smart-fetching' is not nil." :type 'string :group 'idec) @@ -93,6 +101,18 @@ ;; END OF CUSTOMIZATION ;; ;;;;;;;;;;;;;;;;;;;; +;; VARIABLES +;; ;;;;;;;;; + +(defvar smart-download-limit nil + "Used with `idec-smart-fetch'.") + +(defvar smart-download-offset nil + "Used with `idec-smart-fetch'.") + +;; END OF VARIABLES +;; ;;;;;;;;;;;;;;;; + ;; FUNCTIONS ;; ;;;;;;;;; @@ -105,9 +125,48 @@ (message (concat idec-mail-dir (concat "/" echo))) (mkdir (concat idec-mail-dir (concat "/" echo))))) +(defun get-echo-dir (echo) + "Get ECHO dir from `idec-mail-dir'." + (concat idec-mail-dir (concat "/" echo))) + +(defun check-for-echo () + "Check LINE and create dir." + (with-current-buffer + (if (string-match-p "^.*\..*$") + "" + nil))) + +(defun check-message-in-echo (msg echo) + "Check if exists message MSG in ECHO `idec-mail-dir'." + (if (file-exists-p (concat (get-echo-dir echo) (concat "/" msg))) + nil)) + +(defun get-url-content (url) + "Get URL content and return it without headers." + (with-current-buffer + (url-retrieve-synchronously url) + (goto-char (point-min)) + (re-search-forward "^$") + (forward-line) + (delete-region (point) (point-min)) + (buffer-string))) + (defun idec-load-new-messages () - "Load new messages from IDEC nodes Not implemented." - ) + "Load new messages from IDEC `idec-primary-node'; +Not implemented." + (interactive) + (defvar current-echo nil) + (dolist (line (split-string (download-subscriptions) "\n")) + (message (concat "Working for " line)) + (if (string-match "^.*\..*$" line) + (setq current-echo line) + (proccess-echo-message line current-echo)) + )) + +(defun download-subscriptions () + "Download messages from echoes defined in `idec-echo-subscriptions' from `idec-primary-node'." + (get-url-content + (make-echo-url (split-string idec-echo-subscriptions ",")))) ;; ECHOES FUNCTIONS ;; ;;;;;;;;;;;;;;;; @@ -122,15 +181,6 @@ with `idec-download-offset' and `idec-download-limit'." (string-join echoes "/") "/" idec-download-offset ":" idec-download-limit)) (message (concat idec-primary-node "u/e/" echoes "/" idec-download-offset ":" idec-download-limit)))) -(defun download-subscriptions () - "Download messages from echoes defined in `idec-echo-subscriptions' from `idec-primary-node'." - (with-current-buffer - (url-retrieve-synchronously (make-echo-url (split-string idec-echo-subscriptions ","))) - (goto-char (point-min)) - (re-search-forward "^$") - (delete-region (point) (point-min)) - (display-echo-messages (buffer-string)))) - (defun display-echo-messages (messages) "Display downloaded MESSAGES from echo." (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: browse echo*")) @@ -139,12 +189,14 @@ with `idec-download-offset' and `idec-download-limit'." (defun load-echo-messages (echo) "Load messages from ECHO." - (with-current-buffer - (url-retrieve-synchronously (make-echo-url echo)) - (goto-char (point-min)) - (re-search-forward "^$") - (delete-region (point) (point-min)) - (display-echo-messages (buffer-string)))) + (display-echo-messages (get-url-content (make-echo-url echo)))) + +(defun proccess-echo-message (msg echo) + "Download new message MSG in ECHO." + (with-output-to-temp-buffer (get-buffer-create "*IDEC: DEBUG*") + (switch-to-buffer "*IDEC: DEBUG*") + (print msg) + (print echo))) (defun proccess-echo-list (raw-list) "Parse RAW-LIST from HTTP response." @@ -167,15 +219,10 @@ with `idec-download-offset' and `idec-download-limit'." (defun idec-fetch-echo-list (nodeurl) "Fetch echoes list from remote NODEURL." - (with-current-buffer - (url-retrieve-synchronously nodeurl) - (goto-char (point-min)) - (re-search-forward "^$") - (delete-region (point) (point-min)) - (proccess-echo-list (buffer-string)))) + (proccess-echo-list (get-url-content nodeurl))) (defun idec-load-echoes () - "Load echoes list from node." + "Load echoes list.txt from node `idec-primary-node'." (interactive) (idec-fetch-echo-list (concat idec-primary-node "list.txt"))) From e87191d004f10d175f213947fd60dbc0d2e37591 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Sun, 1 Oct 2017 13:20:44 +0300 Subject: [PATCH 04/25] Download messages to idec-mail-dir --- idec.el | 64 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/idec.el b/idec.el index 11130c9..cd0f156 100644 --- a/idec.el +++ b/idec.el @@ -121,25 +121,30 @@ Not used if `idec-smart-fetching' is not nil." (if (file-exists-p idec-mail-dir) (message idec-mail-dir) (mkdir idec-mail-dir)) - (if (file-exists-p (concat idec-mail-dir (concat "/" echo))) - (message (concat idec-mail-dir (concat "/" echo))) - (mkdir (concat idec-mail-dir (concat "/" echo))))) + (if (file-exists-p (concat idec-mail-dir "/" echo)) + (message (concat idec-mail-dir "/" echo)) + (mkdir (concat idec-mail-dir "/" echo)))) (defun get-echo-dir (echo) "Get ECHO dir from `idec-mail-dir'." (concat idec-mail-dir (concat "/" echo))) -(defun check-for-echo () - "Check LINE and create dir." - (with-current-buffer - (if (string-match-p "^.*\..*$") - "" - nil))) +(defun filename-to-store (content id) + "Make filename from CONTENT unixtime and ID." + (concat (nth 2 (split-string content)) "-" id)) + +(defun get-message-file (echo id content) + "Get ECHO message filename by ID and CONTENT unixtime." + (concat (get-echo-dir echo) "/" (filename-to-store content id))) + +(defun store-message (content echo id) + "Store CONTENT from ECHO message in `idec-mail-dir' with it ID." + (create-echo-mail-dir echo) + (write-region content nil (get-message-file echo id content) nil nil nil t)) (defun check-message-in-echo (msg echo) "Check if exists message MSG in ECHO `idec-mail-dir'." - (if (file-exists-p (concat (get-echo-dir echo) (concat "/" msg))) - nil)) + (file-exists-p (concat (get-echo-dir echo) (concat "/" msg)))) (defun get-url-content (url) "Get URL content and return it without headers." @@ -156,12 +161,26 @@ Not used if `idec-smart-fetching' is not nil." Not implemented." (interactive) (defvar current-echo nil) + (defvar new-messages '()) (dolist (line (split-string (download-subscriptions) "\n")) - (message (concat "Working for " line)) - (if (string-match "^.*\..*$" line) - (setq current-echo line) - (proccess-echo-message line current-echo)) - )) + (if (string-match "\\." line) + (and (setq current-echo line) + (message current-echo)) + (if (not (check-message-in-echo current-echo line)) + (download-message current-echo line))))) + +(defun get-message-content (echo msg) + "Get ECHO MSG content from `idec-primary-node'." + (decode-coding-string + (base64-decode-string + (nth 1 (split-string (get-url-content (make-messages-url msg)) ":"))) + 'utf-8)) + +(defun download-message (echo msg) + "Download ECHO message MSG to `idec-mail-dir'." + (message (concat "Download message " msg " to " echo)) + (if (not (string-match "^$" msg)) + (store-message (get-message-content echo msg) echo msg))) (defun download-subscriptions () "Download messages from echoes defined in `idec-echo-subscriptions' from `idec-primary-node'." @@ -181,6 +200,15 @@ with `idec-download-offset' and `idec-download-limit'." (string-join echoes "/") "/" idec-download-offset ":" idec-download-limit)) (message (concat idec-primary-node "u/e/" echoes "/" idec-download-offset ":" idec-download-limit)))) +(defun make-messages-url (messages) + "Make MESSAGES url to retreive messages from `idec-primary-node'." + ;; Check ECHOES is list + (if (listp messages) + ;; Required GNU Emacs >= 25.3 + (message (concat idec-primary-node "u/m/" + (string-join messages "/"))) + (message (concat idec-primary-node "u/m/" messages)))) + (defun display-echo-messages (messages) "Display downloaded MESSAGES from echo." (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: browse echo*")) @@ -195,8 +223,8 @@ with `idec-download-offset' and `idec-download-limit'." "Download new message MSG in ECHO." (with-output-to-temp-buffer (get-buffer-create "*IDEC: DEBUG*") (switch-to-buffer "*IDEC: DEBUG*") - (print msg) - (print echo))) + (princ msg) + (princ echo))) (defun proccess-echo-list (raw-list) "Parse RAW-LIST from HTTP response." From bfb9c756191ad9d760fe39b14ad95999ed78eaa6 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Sun, 1 Oct 2017 14:28:02 +0300 Subject: [PATCH 05/25] Download only new messages Write messages counter --- idec.el | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/idec.el b/idec.el index cd0f156..204366b 100644 --- a/idec.el +++ b/idec.el @@ -133,18 +133,27 @@ Not used if `idec-smart-fetching' is not nil." "Make filename from CONTENT unixtime and ID." (concat (nth 2 (split-string content)) "-" id)) -(defun get-message-file (echo id content) - "Get ECHO message filename by ID and CONTENT unixtime." - (concat (get-echo-dir echo) "/" (filename-to-store content id))) +(defun get-message-file (echo id) + "Get ECHO message filename by ID." + (concat (get-echo-dir echo) "/" id)) + +(defun get-counter-file (echo) + "Get ECHO counter filename." + (concat (get-echo-dir echo) "/counter")) (defun store-message (content echo id) "Store CONTENT from ECHO message in `idec-mail-dir' with it ID." (create-echo-mail-dir echo) - (write-region content nil (get-message-file echo id content) nil nil nil t)) + (write-region content nil (get-message-file echo id))) + +(defun store-echo-counter (echo) + "Store count messages in ECHO." + (create-echo-mail-dir echo) + (write-region (echo-messages-count echo) nil (get-counter-file echo))) (defun check-message-in-echo (msg echo) "Check if exists message MSG in ECHO `idec-mail-dir'." - (file-exists-p (concat (get-echo-dir echo) (concat "/" msg)))) + (file-exists-p (get-message-file echo msg))) (defun get-url-content (url) "Get URL content and return it without headers." @@ -165,9 +174,8 @@ Not implemented." (dolist (line (split-string (download-subscriptions) "\n")) (if (string-match "\\." line) (and (setq current-echo line) - (message current-echo)) - (if (not (check-message-in-echo current-echo line)) - (download-message current-echo line))))) + (store-echo-counter line)) + (download-message current-echo line)))) (defun get-message-content (echo msg) "Get ECHO MSG content from `idec-primary-node'." @@ -180,7 +188,9 @@ Not implemented." "Download ECHO message MSG to `idec-mail-dir'." (message (concat "Download message " msg " to " echo)) (if (not (string-match "^$" msg)) - (store-message (get-message-content echo msg) echo msg))) + (if (not + (check-message-in-echo msg echo)) + (store-message (get-message-content echo msg) echo msg)))) (defun download-subscriptions () "Download messages from echoes defined in `idec-echo-subscriptions' from `idec-primary-node'." @@ -209,6 +219,15 @@ with `idec-download-offset' and `idec-download-limit'." (string-join messages "/"))) (message (concat idec-primary-node "u/m/" messages)))) +(defun make-count-url (echo) + "Return messages count url in `idec-primary-node' from ECHO." + (concat idec-primary-node "/x/c/" echo)) + +(defun echo-messages-count (echo) + "Get messages count in ECHO." + (nth 1 (split-string + (get-url-content (make-count-url echo)) ":"))) + (defun display-echo-messages (messages) "Display downloaded MESSAGES from echo." (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: browse echo*")) @@ -217,6 +236,7 @@ with `idec-download-offset' and `idec-download-limit'." (defun load-echo-messages (echo) "Load messages from ECHO." + (store-echo-counter echo) (display-echo-messages (get-url-content (make-echo-url echo)))) (defun proccess-echo-message (msg echo) From f46fbbeebd184b253474f3cd2278ea7d808e47be Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Sun, 1 Oct 2017 22:05:40 +0300 Subject: [PATCH 06/25] New messages buffer --- idec.el | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/idec.el b/idec.el index 204366b..0a4dafb 100644 --- a/idec.el +++ b/idec.el @@ -110,6 +110,9 @@ Not used if `idec-smart-fetching' is not nil." (defvar smart-download-offset nil "Used with `idec-smart-fetch'.") +(defvar new-messages-list '() + "New messages for display.") + ;; END OF VARIABLES ;; ;;;;;;;;;;;;;;;; @@ -153,7 +156,7 @@ Not used if `idec-smart-fetching' is not nil." (defun check-message-in-echo (msg echo) "Check if exists message MSG in ECHO `idec-mail-dir'." - (file-exists-p (get-message-file echo msg))) + (not (file-exists-p (get-message-file echo msg)))) (defun get-url-content (url) "Get URL content and return it without headers." @@ -166,8 +169,7 @@ Not used if `idec-smart-fetching' is not nil." (buffer-string))) (defun idec-load-new-messages () - "Load new messages from IDEC `idec-primary-node'; -Not implemented." + "Load new messages from IDEC `idec-primary-node'." (interactive) (defvar current-echo nil) (defvar new-messages '()) @@ -175,7 +177,26 @@ Not implemented." (if (string-match "\\." line) (and (setq current-echo line) (store-echo-counter line)) - (download-message current-echo line)))) + (when (and (check-message-in-echo line current-echo) + (> (length line) 1)) + (download-message current-echo line)))) + (display-new-messages)) + +(defun display-new-messages () + "Display new fetched messages from `new-messages-list'." + (with-output-to-temp-buffer (get-buffer-create "*IDEC: New messages*") + (switch-to-buffer "*IDEC: New messages*") + (dolist (msg new-messages-list) + ;; Write message subj + (insert-text-button (nth 6 (split-string msg "\n")) + 'help-echo (concat "Read message")) + ;; Write message time and echo + (princ (format "\t\t\t%s\t%s\t\t" (nth 1 (split-string msg "\n")) + (current-time-string + (car (read-from-string (nth 2 (split-string msg "\n"))))) + )) + (princ "\n") + (add-to-invisibility-spec '(msg . t))))) (defun get-message-content (echo msg) "Get ECHO MSG content from `idec-primary-node'." @@ -187,10 +208,14 @@ Not implemented." (defun download-message (echo msg) "Download ECHO message MSG to `idec-mail-dir'." (message (concat "Download message " msg " to " echo)) - (if (not (string-match "^$" msg)) - (if (not - (check-message-in-echo msg echo)) - (store-message (get-message-content echo msg) echo msg)))) + (defvar message-content) + (if (string= "" msg) + (message "Nil message") + (when (and (not (string= "" msg)) + (check-message-in-echo msg echo)) + (setq message-content (get-message-content echo msg)) + (store-message message-content echo msg) + (setq new-messages-list (push message-content new-messages-list))))) (defun download-subscriptions () "Download messages from echoes defined in `idec-echo-subscriptions' from `idec-primary-node'." @@ -284,3 +309,4 @@ with `idec-download-offset' and `idec-download-limit'." (provide 'idec) ;;; idec.el ends here + From 4a521999699784253858ff262c309be20070789f Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Mon, 2 Oct 2017 13:47:14 +0300 Subject: [PATCH 07/25] Display message in new buffer Parse message text --- idec.el | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/idec.el b/idec.el index 0a4dafb..00fabc2 100644 --- a/idec.el +++ b/idec.el @@ -158,6 +158,56 @@ Not used if `idec-smart-fetching' is not nil." "Check if exists message MSG in ECHO `idec-mail-dir'." (not (file-exists-p (get-message-file echo msg)))) +;; Message fields pasing +(defun get-message-tags (msg) + "Get MSG tags." + (nth 0 (split-string msg "\n"))) + +(defun get-message-echo (msg) + "Get MSG echo." + (nth 1 (split-string msg "\n"))) + +(defun get-message-time (msg) + "Get MSG time." + (current-time-string + (car (read-from-string (nth 2 (split-string msg "\n")))))) + +(defun get-message-author (msg) + "Get MSG author." + (nth 3 (split-string msg "\n"))) + +(defun get-message-address (msg) + "Get MSG address." + (nth 4 (split-string msg "\n"))) + +(defun get-message-recipient (msg) + "Get MSG recipient." + (nth 5 (split-string msg "\n"))) + +(defun get-message-subg (msg) + "Get MSG recipient." + (nth 6 (split-string msg "\n"))) + +(defun get-message-body (msg) + "Get MSG body text." + (s-join "\n" (last (split-string msg "\n") 6))) + +(defun get-message-field (msg field) + "Get message MSG FIELD." + (defvar fields-hash (make-hash-table :test 'equal) + "Hashtable with MSG parsing functions.") + + ;; Define hashtable first + (puthash "tags" (get-message-tags msg) fields-hash) + (puthash "echo" (get-message-echo msg) fields-hash) + (puthash "time" (get-message-time msg) fields-hash) + (puthash "author" (get-message-author msg) fields-hash) + (puthash "address" (get-message-address msg) fields-hash) + (puthash "recipient" (get-message-recipient msg) fields-hash) + (puthash "subg" (get-message-subg msg) fields-hash) + (puthash "body" (get-message-body msg) fields-hash) + (gethash field fields-hash)) + (defun get-url-content (url) "Get URL content and return it without headers." (with-current-buffer @@ -182,20 +232,33 @@ Not used if `idec-smart-fetching' is not nil." (download-message current-echo line)))) (display-new-messages)) +(defun display-message (msg) + "Display message MSG in new buffer in idec-mode." + (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: view " (get-message-field msg "subg") "*")) + (switch-to-buffer (concat "*IDEC: view " (get-message-field msg "subg") "*")) + (princ (concat "From: \t" (get-message-field msg "author") "\n")) + (princ (concat "To: " (get-message-field msg "recipient") "\n")) + (princ (concat "Echo: " (get-message-field msg "subg") "\n")) + (princ (concat "At: " (get-message-field msg "time") "\n")) + (princ (concat "Subject: " (get-message-field msg "subg") "\n")) + (princ (get-message-field msg "body")))) + (defun display-new-messages () "Display new fetched messages from `new-messages-list'." (with-output-to-temp-buffer (get-buffer-create "*IDEC: New messages*") (switch-to-buffer "*IDEC: New messages*") (dolist (msg new-messages-list) ;; Write message subj - (insert-text-button (nth 6 (split-string msg "\n")) - 'help-echo (concat "Read message")) + (insert-text-button (get-message-field msg "subg") + 'help-echo "Read message" + 'plain-msg msg + 'action (lambda (x) (display-message (button-get x 'plain-msg)))) ;; Write message time and echo - (princ (format "\t\t\t%s\t%s\t\t" (nth 1 (split-string msg "\n")) - (current-time-string - (car (read-from-string (nth 2 (split-string msg "\n"))))) - )) - (princ "\n") + (princ (format "\t\t\t%s\t%s(%s)\t%s\t\t\n" + (get-message-field msg "author") + (get-message-field msg "echo") + (get-message-field msg "address") + (get-message-field msg "time"))) (add-to-invisibility-spec '(msg . t))))) (defun get-message-content (echo msg) @@ -232,7 +295,7 @@ with `idec-download-offset' and `idec-download-limit'." (if (listp echoes) ;; Required GNU Emacs >= 25.3 (message (concat idec-primary-node "u/e/" - (string-join echoes "/") "/" idec-download-offset ":" idec-download-limit)) + (s-join "/" echoes) "/" idec-download-offset ":" idec-download-limit)) (message (concat idec-primary-node "u/e/" echoes "/" idec-download-offset ":" idec-download-limit)))) (defun make-messages-url (messages) @@ -241,7 +304,7 @@ with `idec-download-offset' and `idec-download-limit'." (if (listp messages) ;; Required GNU Emacs >= 25.3 (message (concat idec-primary-node "u/m/" - (string-join messages "/"))) + (s-join "/" messages))) (message (concat idec-primary-node "u/m/" messages)))) (defun make-count-url (echo) @@ -309,4 +372,3 @@ with `idec-download-offset' and `idec-download-limit'." (provide 'idec) ;;; idec.el ends here - From 611ab2c2443de1501712c6afe4af1a38564b04f8 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Mon, 2 Oct 2017 14:27:19 +0300 Subject: [PATCH 08/25] Some formating changes --- idec.el | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/idec.el b/idec.el index 00fabc2..720f103 100644 --- a/idec.el +++ b/idec.el @@ -184,7 +184,7 @@ Not used if `idec-smart-fetching' is not nil." "Get MSG recipient." (nth 5 (split-string msg "\n"))) -(defun get-message-subg (msg) +(defun get-message-subj (msg) "Get MSG recipient." (nth 6 (split-string msg "\n"))) @@ -204,7 +204,7 @@ Not used if `idec-smart-fetching' is not nil." (puthash "author" (get-message-author msg) fields-hash) (puthash "address" (get-message-address msg) fields-hash) (puthash "recipient" (get-message-recipient msg) fields-hash) - (puthash "subg" (get-message-subg msg) fields-hash) + (puthash "subj" (get-message-subj msg) fields-hash) (puthash "body" (get-message-body msg) fields-hash) (gethash field fields-hash)) @@ -234,14 +234,15 @@ Not used if `idec-smart-fetching' is not nil." (defun display-message (msg) "Display message MSG in new buffer in idec-mode." - (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: view " (get-message-field msg "subg") "*")) - (switch-to-buffer (concat "*IDEC: view " (get-message-field msg "subg") "*")) - (princ (concat "From: \t" (get-message-field msg "author") "\n")) + (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: view " (get-message-field msg "subj") "*")) + (switch-to-buffer (concat "*IDEC: view " (get-message-field msg "subj") "*")) + (princ (concat "From: " (get-message-field msg "author") "(" (get-message-field msg "address") ")" "\n")) (princ (concat "To: " (get-message-field msg "recipient") "\n")) - (princ (concat "Echo: " (get-message-field msg "subg") "\n")) + (princ (concat "Echo: " (get-message-field msg "echo") "\n")) (princ (concat "At: " (get-message-field msg "time") "\n")) - (princ (concat "Subject: " (get-message-field msg "subg") "\n")) - (princ (get-message-field msg "body")))) + (princ (concat "Subject: " (get-message-field msg "subj") "\n")) + (princ (concat "_______________________________\n\n" + (get-message-field msg "body"))))) (defun display-new-messages () "Display new fetched messages from `new-messages-list'." @@ -249,15 +250,15 @@ Not used if `idec-smart-fetching' is not nil." (switch-to-buffer "*IDEC: New messages*") (dolist (msg new-messages-list) ;; Write message subj - (insert-text-button (get-message-field msg "subg") + (insert-text-button (get-message-field msg "subj") 'help-echo "Read message" 'plain-msg msg 'action (lambda (x) (display-message (button-get x 'plain-msg)))) ;; Write message time and echo - (princ (format "\t\t\t%s\t%s(%s)\t%s\t\t\n" + (princ (format "\t\t\t%s(%s)\t%s\t%s\t\t\n" (get-message-field msg "author") - (get-message-field msg "echo") (get-message-field msg "address") + (get-message-field msg "echo") (get-message-field msg "time"))) (add-to-invisibility-spec '(msg . t))))) @@ -357,7 +358,7 @@ with `idec-download-offset' and `idec-download-limit'." "Fetch echoes list from remote NODEURL." (proccess-echo-list (get-url-content nodeurl))) -(defun idec-load-echoes () +(defun idec-online-browse () "Load echoes list.txt from node `idec-primary-node'." (interactive) (idec-fetch-echo-list (concat idec-primary-node "list.txt"))) From b07dc2b68ec9443cf7c362f9069888d75c7b48ad Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Mon, 2 Oct 2017 17:56:07 +0300 Subject: [PATCH 09/25] idec-mode initial --- idec.el | 97 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 15 deletions(-) diff --git a/idec.el b/idec.el index 720f103..b82857d 100644 --- a/idec.el +++ b/idec.el @@ -51,9 +51,9 @@ "Use /list.txt extension." :group 'idec) -(defcustom idec-smart-fetch nil +(defcustom idec-smart-fetch t "Enable smat fetching; -Download only new messages; Traffic saving; Not implemented." +Download only new messages; Not implemented." :type 'boolean :group 'idec) @@ -116,6 +116,34 @@ Not used if `idec-smart-fetching' is not nil." ;; END OF VARIABLES ;; ;;;;;;;;;;;;;;;; +;; MODE +;; ;;;; + +(defun idec-close-message-buffer () + "Close buffer with message." + (kill-buffer (current-buffer))) + +(defvar idec-mode-map nil + "Keymapping for IDEC mode.") + +(unless idec-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c ." 'idec-close-message-buffer) + (setq idec-mode-map map))) + +(define-derived-mode idec-mode + text-mode "[idec]" + "Major mode for view and editing IDEC messages." + (kill-all-local-variables) + ;; Mode definition + (setq major-mode 'idec-mode) + (setq mode-name "[idec]") + (use-local-map idec-mode-map) + (setq imenu-generic-expression "*IDEC")) + +;; END OF MODE +;; ;;;;;;;;;;; + ;; FUNCTIONS ;; ;;;;;;;;; @@ -159,39 +187,60 @@ Not used if `idec-smart-fetching' is not nil." (not (file-exists-p (get-message-file echo msg)))) ;; Message fields pasing +(defun trim-string (string) + "Remove white spaces in beginning and ending of STRING; +White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." +(replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string))) + (defun get-message-tags (msg) "Get MSG tags." - (nth 0 (split-string msg "\n"))) + (trim-string (nth 0 (split-string msg "\n")))) (defun get-message-echo (msg) "Get MSG echo." - (nth 1 (split-string msg "\n"))) + (trim-string (nth 1 (split-string msg "\n")))) (defun get-message-time (msg) "Get MSG time." - (current-time-string - (car (read-from-string (nth 2 (split-string msg "\n")))))) + (trim-string (current-time-string + (car (read-from-string (nth 2 (split-string msg "\n"))))))) (defun get-message-author (msg) "Get MSG author." - (nth 3 (split-string msg "\n"))) + (trim-string (nth 3 (split-string msg "\n")))) (defun get-message-address (msg) "Get MSG address." - (nth 4 (split-string msg "\n"))) + (trim-string (nth 4 (split-string msg "\n")))) (defun get-message-recipient (msg) "Get MSG recipient." - (nth 5 (split-string msg "\n"))) + (trim-string (nth 5 (split-string msg "\n")))) (defun get-message-subj (msg) "Get MSG recipient." - (nth 6 (split-string msg "\n"))) + (trim-string (nth 6 (split-string msg "\n")))) (defun get-message-body (msg) "Get MSG body text." (s-join "\n" (last (split-string msg "\n") 6))) +(defun get-longest-field (field msg-list) + "Return longest FIELD in MSG-LIST." + (defvar field-legth '()) + (defvar field-max nil) + (setq field-max 0) + (dolist (msg msg-list) + (when (> (length (get-message-field msg field)) + field-max) + (setq field-max (length (get-message-field msg field))))) + field-max + ;; Populate list + ;; (dolist (msg msg-list) + ;; (setq field-legth (append field-legth (length (get-message-field msg field))))) + ;; (last (sort field-legth '<)) + ) + (defun get-message-field (msg field) "Get message MSG FIELD." (defvar fields-hash (make-hash-table :test 'equal) @@ -235,14 +284,17 @@ Not used if `idec-smart-fetching' is not nil." (defun display-message (msg) "Display message MSG in new buffer in idec-mode." (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: view " (get-message-field msg "subj") "*")) + ;; Run in IDEC mode (switch-to-buffer (concat "*IDEC: view " (get-message-field msg "subj") "*")) (princ (concat "From: " (get-message-field msg "author") "(" (get-message-field msg "address") ")" "\n")) (princ (concat "To: " (get-message-field msg "recipient") "\n")) (princ (concat "Echo: " (get-message-field msg "echo") "\n")) (princ (concat "At: " (get-message-field msg "time") "\n")) (princ (concat "Subject: " (get-message-field msg "subj") "\n")) - (princ (concat "_______________________________\n\n" - (get-message-field msg "body"))))) + (princ (concat "__________________________________\n\n" + (get-message-field msg "body"))) + (add-text-properties (point-min) (point-max) 'read-only)) + (idec-mode)) (defun display-new-messages () "Display new fetched messages from `new-messages-list'." @@ -250,14 +302,28 @@ Not used if `idec-smart-fetching' is not nil." (switch-to-buffer "*IDEC: New messages*") (dolist (msg new-messages-list) ;; Write message subj - (insert-text-button (get-message-field msg "subj") + (insert-text-button (concat (get-message-field msg "subj") + (make-string + (- (get-longest-field "subj" new-messages-list) + (length (get-message-field msg "subj"))) + ? )) 'help-echo "Read message" 'plain-msg msg 'action (lambda (x) (display-message (button-get x 'plain-msg)))) ;; Write message time and echo - (princ (format "\t\t\t%s(%s)\t%s\t%s\t\t\n" + (princ (format " %s(%s)%s%s\t%s\n" (get-message-field msg "author") (get-message-field msg "address") + (make-string (- + (+ + (get-longest-field "author" new-messages-list) + (get-longest-field "address" new-messages-list) + 1) + (+ + (length (get-message-field msg "author")) + (length (get-message-field msg "address"))) + ) + ? ) (get-message-field msg "echo") (get-message-field msg "time"))) (add-to-invisibility-spec '(msg . t))))) @@ -352,7 +418,8 @@ with `idec-download-offset' and `idec-download-limit'." (princ (format "\t\t||%s\t\t%s\n" (nth 2 (split-string line ":")) (nth 1 (split-string line ":"))))) - ))) + )) + (idec-mode)) (defun idec-fetch-echo-list (nodeurl) "Fetch echoes list from remote NODEURL." From 7e1ed72435670d8a4c3514b3574bdafa16fa9962 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Mon, 2 Oct 2017 18:01:25 +0300 Subject: [PATCH 10/25] Todo --- todo.org | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 todo.org diff --git a/todo.org b/todo.org new file mode 100644 index 0000000..ae145a5 --- /dev/null +++ b/todo.org @@ -0,0 +1,4 @@ +* TODO idec-mode +* TODO Formating with highlighting header +* TODO Read local mail instead of downloading into RAM +* TODO Use smart-fetching From 27987cb894762440391d0e427cca67bc472aba5b Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Tue, 3 Oct 2017 10:46:43 +0300 Subject: [PATCH 11/25] Download message only if it not in local mail --- idec.el | 58 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/idec.el b/idec.el index b82857d..3c6d0b5 100644 --- a/idec.el +++ b/idec.el @@ -184,7 +184,7 @@ Not used if `idec-smart-fetching' is not nil." (defun check-message-in-echo (msg echo) "Check if exists message MSG in ECHO `idec-mail-dir'." - (not (file-exists-p (get-message-file echo msg)))) + (not (f-file? (get-message-file echo msg)))) ;; Message fields pasing (defun trim-string (string) @@ -300,33 +300,35 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." "Display new fetched messages from `new-messages-list'." (with-output-to-temp-buffer (get-buffer-create "*IDEC: New messages*") (switch-to-buffer "*IDEC: New messages*") - (dolist (msg new-messages-list) - ;; Write message subj - (insert-text-button (concat (get-message-field msg "subj") - (make-string - (- (get-longest-field "subj" new-messages-list) - (length (get-message-field msg "subj"))) - ? )) - 'help-echo "Read message" - 'plain-msg msg - 'action (lambda (x) (display-message (button-get x 'plain-msg)))) - ;; Write message time and echo - (princ (format " %s(%s)%s%s\t%s\n" - (get-message-field msg "author") - (get-message-field msg "address") - (make-string (- - (+ - (get-longest-field "author" new-messages-list) - (get-longest-field "address" new-messages-list) - 1) - (+ - (length (get-message-field msg "author")) - (length (get-message-field msg "address"))) - ) - ? ) - (get-message-field msg "echo") - (get-message-field msg "time"))) - (add-to-invisibility-spec '(msg . t))))) + (if (= (length new-messages-list) 0) + (princ "No new messages.") + (dolist (msg new-messages-list) + ;; Write message subj + (insert-text-button (concat (get-message-field msg "subj") + (make-string + (- (get-longest-field "subj" new-messages-list) + (length (get-message-field msg "subj"))) + ? )) + 'help-echo "Read message" + 'plain-msg msg + 'action (lambda (x) (display-message (button-get x 'plain-msg)))) + ;; Write message time and echo + (princ (format " %s(%s)%s%s\t%s\n" + (get-message-field msg "author") + (get-message-field msg "address") + (make-string (- + (+ + (get-longest-field "author" new-messages-list) + (get-longest-field "address" new-messages-list) + 1) + (+ + (length (get-message-field msg "author")) + (length (get-message-field msg "address"))) + ) + ? ) + (get-message-field msg "echo") + (get-message-field msg "time"))) + (add-to-invisibility-spec '(msg . t)))))) (defun get-message-content (echo msg) "Get ECHO MSG content from `idec-primary-node'." From eb06c3e0daf88d3d03e56f73d74c61b9ad69f272 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Tue, 3 Oct 2017 14:35:58 +0300 Subject: [PATCH 12/25] Mode and body parsing --- idec.el | 89 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 16 deletions(-) diff --git a/idec.el b/idec.el index 3c6d0b5..d35e48d 100644 --- a/idec.el +++ b/idec.el @@ -71,7 +71,7 @@ Not used if `idec-smart-fetching' is not nil." (defcustom idec-echo-subscriptions nil "List of subribes echoes." - :type 'list + :type 'string :group 'idec) (defcustom idec-mail-dir "~/.emacs.d/idec-mail" @@ -123,23 +123,54 @@ Not used if `idec-smart-fetching' is not nil." "Close buffer with message." (kill-buffer (current-buffer))) -(defvar idec-mode-map nil +(defvar idec-mode-hook nil) + +(defvar idec-mode-map + (let ((map (make-keymap))) + (define-key map "\C-c \C-c" 'kill-this-buffer) + map) "Keymapping for IDEC mode.") -(unless idec-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "\C-c ." 'idec-close-message-buffer) - (setq idec-mode-map map))) +(defconst idec-font-lock-keywords-1 + (list + '("\\<\\(\\(?:Echo\\|From\\|Subj\\|T\\(?:ime\\|o\\)\\):\\)\\>" . font-lock-variable-name-face) + '("\\('\\w*'\\)" . font-lock-variable-name-face)) + "Minimal highlighting expressions for IDEC mode.") -(define-derived-mode idec-mode - text-mode "[idec]" +(defconst idec-font-lock-keywords-2 + (append idec-font-lock-keywords-1 (list + '("\\<\\(>>?.*\\)\s\\>" . font-lock-comment-face) + '("\\('\\w*'\\)" . font-lock-variable-name-face))) + "Quotes highligting for IDEC mode.") + +(defvar idec-font-lock-keywords idec-font-lock-keywords-2 + "Default highlighting expressions for WPDL mode.") + +(defvar idec-mode-syntax-table + (let ((st (make-syntax-table))))) + +(defun idec-mode () "Major mode for view and editing IDEC messages." + (interactive) (kill-all-local-variables) ;; Mode definition - (setq major-mode 'idec-mode) - (setq mode-name "[idec]") + ;; (set-syntax-table idec-mode-syntax-table) (use-local-map idec-mode-map) - (setq imenu-generic-expression "*IDEC")) + (set (make-local-variable 'font-lock-defaults) '(idec-font-lock-keywords)) + (setq major-mode 'idec-mode) + (setq mode-name "[IDEC]") + (setq imenu-generic-expression "*IDEC") + (run-hooks 'idec-mode-hook)) + +;; (define-derived-mode idec-mode +;; text-mode "[idec]" +;; "Major mode for view and editing IDEC messages." +;; (kill-all-local-variables) +;; ;; Mode definition +;; (setq major-mode 'idec-mode) +;; (setq mode-name "[idec]") +;; (use-local-map idec-mode-map) +;; (setq imenu-generic-expression "*IDEC")) ;; END OF MODE ;; ;;;;;;;;;;; @@ -218,12 +249,25 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." (trim-string (nth 5 (split-string msg "\n")))) (defun get-message-subj (msg) - "Get MSG recipient." + "Get MSG subject." (trim-string (nth 6 (split-string msg "\n")))) (defun get-message-body (msg) "Get MSG body text." - (s-join "\n" (last (split-string msg "\n") 6))) + (goto-char (point-min)) + (forward-line 8) + (substring msg (point) (point-max))) + ;; (s-join "\n" (last (split-string msg "\n") 7))) + ;; (defvar msg-counter 1) + ;; (defvar msg-body '()) + ;; (defvar msg-list (split-string msg "\n")) + ;; (dolist (line msg-list) + ;; (if (not (= msg-counter 7)) + ;; (setq msg-counter (1+ msg-counter)) + ;; (setq msg-body (append msg-body '(line))))) + ;; (dolist (b msg-body) + ;; (message b)) + ;; (s-join "\n" msg-body)) (defun get-longest-field (field msg-list) "Return longest FIELD in MSG-LIST." @@ -283,9 +327,12 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." (defun display-message (msg) "Display message MSG in new buffer in idec-mode." - (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: view " (get-message-field msg "subj") "*")) + (with-output-to-temp-buffer (get-buffer-create (concat + "*IDEC: " + (decode-coding-string (get-message-field msg "subj") 'utf-8) + "*")) ;; Run in IDEC mode - (switch-to-buffer (concat "*IDEC: view " (get-message-field msg "subj") "*")) + (switch-to-buffer (concat "*IDEC: " (decode-coding-string (get-message-field msg "subj") 'utf-8) "*")) (princ (concat "From: " (get-message-field msg "author") "(" (get-message-field msg "address") ")" "\n")) (princ (concat "To: " (get-message-field msg "recipient") "\n")) (princ (concat "Echo: " (get-message-field msg "echo") "\n")) @@ -293,7 +340,16 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." (princ (concat "Subject: " (get-message-field msg "subj") "\n")) (princ (concat "__________________________________\n\n" (get-message-field msg "body"))) + (princ "\n__________________________________\n") + (princ "[") + (insert-button "Answer" + 'action (lambda (x) (message "OK"))) + (princ "]") + (princ "\t[") + (insert-button "Answer with quote") + (princ "]") (add-text-properties (point-min) (point-max) 'read-only)) + (point-max) (idec-mode)) (defun display-new-messages () @@ -328,7 +384,8 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." ? ) (get-message-field msg "echo") (get-message-field msg "time"))) - (add-to-invisibility-spec '(msg . t)))))) + (add-to-invisibility-spec '(msg . t))))) + (idec-mode)) (defun get-message-content (echo msg) "Get ECHO MSG content from `idec-primary-node'." From e00a8c65d0e21350c006cb81cdd34ffa89369232 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Tue, 3 Oct 2017 16:27:14 +0300 Subject: [PATCH 13/25] Navigation over new messages --- idec.el | 78 +++++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/idec.el b/idec.el index d35e48d..2b66446 100644 --- a/idec.el +++ b/idec.el @@ -121,13 +121,15 @@ Not used if `idec-smart-fetching' is not nil." (defun idec-close-message-buffer () "Close buffer with message." - (kill-buffer (current-buffer))) + (kill-this-buffer)) (defvar idec-mode-hook nil) (defvar idec-mode-map (let ((map (make-keymap))) (define-key map "\C-c \C-c" 'kill-this-buffer) + (define-key map "\C-c \C-n" 'idec-next-message) + (define-key map "\C-c \C-b" 'idec-previous-message) map) "Keymapping for IDEC mode.") @@ -144,7 +146,7 @@ Not used if `idec-smart-fetching' is not nil." "Quotes highligting for IDEC mode.") (defvar idec-font-lock-keywords idec-font-lock-keywords-2 - "Default highlighting expressions for WPDL mode.") + "Default highlighting expressions for IDEC mode.") (defvar idec-mode-syntax-table (let ((st (make-syntax-table))))) @@ -154,7 +156,7 @@ Not used if `idec-smart-fetching' is not nil." (interactive) (kill-all-local-variables) ;; Mode definition - ;; (set-syntax-table idec-mode-syntax-table) + (set-syntax-table idec-mode-syntax-table) (use-local-map idec-mode-map) (set (make-local-variable 'font-lock-defaults) '(idec-font-lock-keywords)) (setq major-mode 'idec-mode) @@ -162,15 +164,25 @@ Not used if `idec-smart-fetching' is not nil." (setq imenu-generic-expression "*IDEC") (run-hooks 'idec-mode-hook)) -;; (define-derived-mode idec-mode -;; text-mode "[idec]" -;; "Major mode for view and editing IDEC messages." -;; (kill-all-local-variables) -;; ;; Mode definition -;; (setq major-mode 'idec-mode) -;; (setq mode-name "[idec]") -;; (use-local-map idec-mode-map) -;; (setq imenu-generic-expression "*IDEC")) +;; NAVIGATION FUNCTIONS +;; ;;;;;;;;;;;;;;;;;;;; + +(defun idec-next-message () + "Show next message." + (interactive) + (kill-this-buffer) + (forward-button 1) + (push-button)) + +(defun idec-previous-message () + "Show next message." + (interactive) + (kill-this-buffer) + (backward-button 1) + (push-button)) + +;; END OF NAVIGATION FUNCTIONS +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; END OF MODE ;; ;;;;;;;;;;; @@ -253,21 +265,9 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." (trim-string (nth 6 (split-string msg "\n")))) (defun get-message-body (msg) - "Get MSG body text." - (goto-char (point-min)) - (forward-line 8) - (substring msg (point) (point-max))) - ;; (s-join "\n" (last (split-string msg "\n") 7))) - ;; (defvar msg-counter 1) - ;; (defvar msg-body '()) - ;; (defvar msg-list (split-string msg "\n")) - ;; (dolist (line msg-list) - ;; (if (not (= msg-counter 7)) - ;; (setq msg-counter (1+ msg-counter)) - ;; (setq msg-body (append msg-body '(line))))) - ;; (dolist (b msg-body) - ;; (message b)) - ;; (s-join "\n" msg-body)) + "Get MSG body text. +Return list with body content." + (-drop 8 (split-string msg "\n"))) (defun get-longest-field (field msg-list) "Return longest FIELD in MSG-LIST." @@ -278,12 +278,7 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." (when (> (length (get-message-field msg field)) field-max) (setq field-max (length (get-message-field msg field))))) - field-max - ;; Populate list - ;; (dolist (msg msg-list) - ;; (setq field-legth (append field-legth (length (get-message-field msg field))))) - ;; (last (sort field-legth '<)) - ) + field-max) (defun get-message-field (msg field) "Get message MSG FIELD." @@ -316,13 +311,14 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." (interactive) (defvar current-echo nil) (defvar new-messages '()) - (dolist (line (split-string (download-subscriptions) "\n")) - (if (string-match "\\." line) - (and (setq current-echo line) - (store-echo-counter line)) - (when (and (check-message-in-echo line current-echo) - (> (length line) 1)) - (download-message current-echo line)))) + (let (new-messages-list) + (dolist (line (split-string (download-subscriptions) "\n")) + (if (string-match "\\." line) + (and (setq current-echo line) + (store-echo-counter line)) + (when (and (check-message-in-echo line current-echo) + (> (length line) 1)) + (download-message current-echo line))))) (display-new-messages)) (defun display-message (msg) @@ -339,7 +335,7 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." (princ (concat "At: " (get-message-field msg "time") "\n")) (princ (concat "Subject: " (get-message-field msg "subj") "\n")) (princ (concat "__________________________________\n\n" - (get-message-field msg "body"))) + (s-join "\n" (get-message-field msg "body")))) (princ "\n__________________________________\n") (princ "[") (insert-button "Answer" From 84060a9e35339d8cc4bb224eeab2419fc1ca21ae Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Tue, 3 Oct 2017 18:16:46 +0300 Subject: [PATCH 14/25] Assoc lists --- idec.el | 81 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/idec.el b/idec.el index 2b66446..52f63db 100644 --- a/idec.el +++ b/idec.el @@ -110,7 +110,7 @@ Not used if `idec-smart-fetching' is not nil." (defvar smart-download-offset nil "Used with `idec-smart-fetch'.") -(defvar new-messages-list '() +(defvar new-messages-list nil "New messages for display.") ;; END OF VARIABLES @@ -156,7 +156,7 @@ Not used if `idec-smart-fetching' is not nil." (interactive) (kill-all-local-variables) ;; Mode definition - (set-syntax-table idec-mode-syntax-table) + ;; (set-syntax-table idec-mode-syntax-table) (use-local-map idec-mode-map) (set (make-local-variable 'font-lock-defaults) '(idec-font-lock-keywords)) (setq major-mode 'idec-mode) @@ -275,9 +275,9 @@ Return list with body content." (defvar field-max nil) (setq field-max 0) (dolist (msg msg-list) - (when (> (length (get-message-field msg field)) + (when (> (length (get-message-field (cdr (assoc 'content msg)) field)) field-max) - (setq field-max (length (get-message-field msg field))))) + (setq field-max (length (get-message-field (cdr (assoc 'content msg)) field))))) field-max) (defun get-message-field (msg field) @@ -311,31 +311,38 @@ Return list with body content." (interactive) (defvar current-echo nil) (defvar new-messages '()) - (let (new-messages-list) - (dolist (line (split-string (download-subscriptions) "\n")) - (if (string-match "\\." line) - (and (setq current-echo line) - (store-echo-counter line)) - (when (and (check-message-in-echo line current-echo) - (> (length line) 1)) - (download-message current-echo line))))) + (dolist (line (split-string (download-subscriptions) "\n")) + (if (string-match "\\." line) + (and (setq current-echo line) + (store-echo-counter line)) + (when (and (check-message-in-echo line current-echo) + (> (length line) 1)) + (download-message current-echo line)))) (display-new-messages)) +(defun answer-message (msg) + "Make answer to message MSG." + (get-buffer-create (concat "*IDEC: Answer to " (cdr (assoc 'id msg)))) + (switch-to-buffer (concat "*IDEC: Answer to " (cdr (assoc 'id msg))))) + (defun display-message (msg) "Display message MSG in new buffer in idec-mode." (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: " - (decode-coding-string (get-message-field msg "subj") 'utf-8) + (decode-coding-string + (get-message-field + (cdr (assoc 'content msg)) "subj") + 'utf-8) "*")) ;; Run in IDEC mode - (switch-to-buffer (concat "*IDEC: " (decode-coding-string (get-message-field msg "subj") 'utf-8) "*")) - (princ (concat "From: " (get-message-field msg "author") "(" (get-message-field msg "address") ")" "\n")) - (princ (concat "To: " (get-message-field msg "recipient") "\n")) - (princ (concat "Echo: " (get-message-field msg "echo") "\n")) - (princ (concat "At: " (get-message-field msg "time") "\n")) - (princ (concat "Subject: " (get-message-field msg "subj") "\n")) + (switch-to-buffer (concat "*IDEC: " (decode-coding-string (get-message-field (cdr (assoc 'content msg)) "subj") 'utf-8) "*")) + (princ (concat "From: " (get-message-field (cdr (assoc 'content msg)) "author") "(" (get-message-field (cdr (assoc 'content msg)) "address") ")" "\n")) + (princ (concat "To: " (get-message-field (cdr (assoc 'content msg)) "recipient") "\n")) + (princ (concat "Echo: " (get-message-field (cdr (assoc 'content msg)) "echo") "\n")) + (princ (concat "At: " (get-message-field (cdr (assoc 'content msg)) "time") "\n")) + (princ (concat "Subject: " (get-message-field (cdr (assoc 'content msg)) "subj") "\n")) (princ (concat "__________________________________\n\n" - (s-join "\n" (get-message-field msg "body")))) + (s-join "\n" (get-message-field (assoc 'content msg) "body")))) (princ "\n__________________________________\n") (princ "[") (insert-button "Answer" @@ -354,33 +361,34 @@ Return list with body content." (switch-to-buffer "*IDEC: New messages*") (if (= (length new-messages-list) 0) (princ "No new messages.") - (dolist (msg new-messages-list) + (dolist (msg (reverse new-messages-list)) ;; Write message subj - (insert-text-button (concat (get-message-field msg "subj") + (insert-text-button (concat (get-message-field (cdr (assoc 'content msg)) "subj") (make-string (- (get-longest-field "subj" new-messages-list) - (length (get-message-field msg "subj"))) + (length (get-message-field (cdr (assoc 'content msg)) "subj"))) ? )) 'help-echo "Read message" - 'plain-msg msg - 'action (lambda (x) (display-message (button-get x 'plain-msg)))) + ;; 'plain-msg msg + 'action (lambda (x) (display-message msg;; (button-get x 'plain-msg) + ))) ;; Write message time and echo (princ (format " %s(%s)%s%s\t%s\n" - (get-message-field msg "author") - (get-message-field msg "address") + (get-message-field (cdr (assoc 'content msg)) "author") + (get-message-field (cdr (assoc 'content msg)) "address") (make-string (- (+ (get-longest-field "author" new-messages-list) (get-longest-field "address" new-messages-list) 1) (+ - (length (get-message-field msg "author")) - (length (get-message-field msg "address"))) + (length (get-message-field (cdr (assoc 'content msg)) "author")) + (length (get-message-field (cdr (assoc 'content msg)) "address"))) ) ? ) - (get-message-field msg "echo") - (get-message-field msg "time"))) - (add-to-invisibility-spec '(msg . t))))) + (get-message-field (cdr (assoc 'content msg)) "echo") + (get-message-field (cdr (assoc 'content msg)) "time"))) + (add-to-invisibility-spec '((cdr (assoc 'content msg)) . t))))) (idec-mode)) (defun get-message-content (echo msg) @@ -400,7 +408,12 @@ Return list with body content." (check-message-in-echo msg echo)) (setq message-content (get-message-content echo msg)) (store-message message-content echo msg) - (setq new-messages-list (push message-content new-messages-list))))) + (setq new-messages-list (-concat + 'new-messages-list + '( + (content . message-content) + (id . msg)) + ))))) (defun download-subscriptions () "Download messages from echoes defined in `idec-echo-subscriptions' from `idec-primary-node'." @@ -464,7 +477,7 @@ with `idec-download-offset' and `idec-download-limit'." (when (not (equal line "")) ;; Defind echo (defvar current-echo nil) - (setq current-echo (nth 0 (split-string line ":"))) + (setq current-echo (assoc 'content (split-string line ":"))) ;; Create clickable button (insert-text-button current-echo 'action (lambda (x) (load-echo-messages (button-get x 'echo))) From 6c5d82ac9630db7768f4ee2786d4c1de2ab386b1 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Wed, 4 Oct 2017 00:37:20 +0300 Subject: [PATCH 15/25] new messages put to hash table --- idec.el | 52 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/idec.el b/idec.el index 52f63db..27078e8 100644 --- a/idec.el +++ b/idec.el @@ -274,10 +274,11 @@ Return list with body content." (defvar field-legth '()) (defvar field-max nil) (setq field-max 0) - (dolist (msg msg-list) - (when (> (length (get-message-field (cdr (assoc 'content msg)) field)) + (maphash (lambda (id msg) + (when (> (length (get-message-field msg field)) field-max) - (setq field-max (length (get-message-field (cdr (assoc 'content msg)) field))))) + (setq field-max (length (get-message-field msg field))))) + msg-list) field-max) (defun get-message-field (msg field) @@ -311,6 +312,7 @@ Return list with body content." (interactive) (defvar current-echo nil) (defvar new-messages '()) + (setq new-messages-list (make-hash-table :test 'equal)) (dolist (line (split-string (download-subscriptions) "\n")) (if (string-match "\\." line) (and (setq current-echo line) @@ -318,7 +320,10 @@ Return list with body content." (when (and (check-message-in-echo line current-echo) (> (length line) 1)) (download-message current-echo line)))) - (display-new-messages)) + ;; (print (hash-table-count new-messages-list)) + ;; (message (gethash "id" (nth 0 new-messages-list))) + (display-new-messages) + ) (defun answer-message (msg) "Make answer to message MSG." @@ -359,36 +364,36 @@ Return list with body content." "Display new fetched messages from `new-messages-list'." (with-output-to-temp-buffer (get-buffer-create "*IDEC: New messages*") (switch-to-buffer "*IDEC: New messages*") - (if (= (length new-messages-list) 0) + (if (= (hash-table-count new-messages-list) 0) (princ "No new messages.") - (dolist (msg (reverse new-messages-list)) + (maphash (lambda (id msg) ;; Write message subj - (insert-text-button (concat (get-message-field (cdr (assoc 'content msg)) "subj") + (insert-text-button (concat (get-message-field msg "subj") (make-string (- (get-longest-field "subj" new-messages-list) - (length (get-message-field (cdr (assoc 'content msg)) "subj"))) + (length (get-message-field msg "subj"))) ? )) 'help-echo "Read message" - ;; 'plain-msg msg + 'plain-msg msg 'action (lambda (x) (display-message msg;; (button-get x 'plain-msg) ))) ;; Write message time and echo (princ (format " %s(%s)%s%s\t%s\n" - (get-message-field (cdr (assoc 'content msg)) "author") - (get-message-field (cdr (assoc 'content msg)) "address") + (get-message-field msg "author") + (get-message-field msg "address") (make-string (- (+ (get-longest-field "author" new-messages-list) (get-longest-field "address" new-messages-list) 1) (+ - (length (get-message-field (cdr (assoc 'content msg)) "author")) - (length (get-message-field (cdr (assoc 'content msg)) "address"))) + (length (get-message-field msg "author")) + (length (get-message-field msg "address"))) ) ? ) - (get-message-field (cdr (assoc 'content msg)) "echo") - (get-message-field (cdr (assoc 'content msg)) "time"))) - (add-to-invisibility-spec '((cdr (assoc 'content msg)) . t))))) + (get-message-field msg "echo") + (get-message-field msg "time")))) + new-messages-list))) (idec-mode)) (defun get-message-content (echo msg) @@ -408,12 +413,15 @@ Return list with body content." (check-message-in-echo msg echo)) (setq message-content (get-message-content echo msg)) (store-message message-content echo msg) - (setq new-messages-list (-concat - 'new-messages-list - '( - (content . message-content) - (id . msg)) - ))))) + + (puthash msg message-content new-messages-list) + ;; (setq new-messages-list (-concat + ;; 'new-messages-list + ;; '( + ;; (content . message-content) + ;; (id . msg)) + ;; )) + ))) (defun download-subscriptions () "Download messages from echoes defined in `idec-echo-subscriptions' from `idec-primary-node'." From 0e57b3505d1194fd60e9876c93a777f70fcecdce Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Wed, 4 Oct 2017 17:35:24 +0300 Subject: [PATCH 16/25] Download all images --- idec.el | 178 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 102 insertions(+), 76 deletions(-) diff --git a/idec.el b/idec.el index 27078e8..6e21189 100644 --- a/idec.el +++ b/idec.el @@ -134,10 +134,10 @@ Not used if `idec-smart-fetching' is not nil." "Keymapping for IDEC mode.") (defconst idec-font-lock-keywords-1 - (list - '("\\<\\(\\(?:Echo\\|From\\|Subj\\|T\\(?:ime\\|o\\)\\):\\)\\>" . font-lock-variable-name-face) - '("\\('\\w*'\\)" . font-lock-variable-name-face)) - "Minimal highlighting expressions for IDEC mode.") + (list + '("\\(ID:.*\\)" . font-lock-function-name-face) + '("\\<\\(\\(?:Echo\\|From\\|Subj\\|T\\(?:ime\\|o\\)\\):\\)\\>" . font-lock-function-name-face)) + "Minimal highlighting expressions for IDEC mode.") (defconst idec-font-lock-keywords-2 (append idec-font-lock-keywords-1 (list @@ -149,7 +149,7 @@ Not used if `idec-smart-fetching' is not nil." "Default highlighting expressions for IDEC mode.") (defvar idec-mode-syntax-table - (let ((st (make-syntax-table))))) + (make-syntax-table text-mode-syntax-table)) (defun idec-mode () "Major mode for view and editing IDEC messages." @@ -158,6 +158,7 @@ Not used if `idec-smart-fetching' is not nil." ;; Mode definition ;; (set-syntax-table idec-mode-syntax-table) (use-local-map idec-mode-map) + (font-lock-add-keywords 'idec-mode '(idec-font-lock-keywords)) (set (make-local-variable 'font-lock-defaults) '(idec-font-lock-keywords)) (setq major-mode 'idec-mode) (setq mode-name "[IDEC]") @@ -311,15 +312,18 @@ Return list with body content." "Load new messages from IDEC `idec-primary-node'." (interactive) (defvar current-echo nil) - (defvar new-messages '()) (setq new-messages-list (make-hash-table :test 'equal)) - (dolist (line (split-string (download-subscriptions) "\n")) - (if (string-match "\\." line) - (and (setq current-echo line) - (store-echo-counter line)) - (when (and (check-message-in-echo line current-echo) - (> (length line) 1)) - (download-message current-echo line)))) + (let (msgid-for-download) + (setq msgid-for-download (make-hash-table :test 'equal)) + (dolist (line (split-string (download-subscriptions) "\n")) + (if (string-match "\\." line) + (and (setq current-echo line) + (store-echo-counter line)) + (when (and (check-message-in-echo line current-echo) + (> (length line) 1)) + (when (not (string= "" line)) + (puthash line current-echo msgid-for-download))))) + (download-message msgid-for-download)) ;; (print (hash-table-count new-messages-list)) ;; (message (gethash "id" (nth 0 new-messages-list))) (display-new-messages) @@ -332,22 +336,26 @@ Return list with body content." (defun display-message (msg) "Display message MSG in new buffer in idec-mode." - (with-output-to-temp-buffer (get-buffer-create (concat - "*IDEC: " + (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: " (decode-coding-string (get-message-field - (cdr (assoc 'content msg)) "subj") + (gethash "msg" msg) "subj") 'utf-8) "*")) ;; Run in IDEC mode - (switch-to-buffer (concat "*IDEC: " (decode-coding-string (get-message-field (cdr (assoc 'content msg)) "subj") 'utf-8) "*")) - (princ (concat "From: " (get-message-field (cdr (assoc 'content msg)) "author") "(" (get-message-field (cdr (assoc 'content msg)) "address") ")" "\n")) - (princ (concat "To: " (get-message-field (cdr (assoc 'content msg)) "recipient") "\n")) - (princ (concat "Echo: " (get-message-field (cdr (assoc 'content msg)) "echo") "\n")) - (princ (concat "At: " (get-message-field (cdr (assoc 'content msg)) "time") "\n")) - (princ (concat "Subject: " (get-message-field (cdr (assoc 'content msg)) "subj") "\n")) + (switch-to-buffer (concat "*IDEC: " (decode-coding-string (get-message-field + (gethash "msg" msg) "subj") + 'utf-8) + "*")) + (princ (concat "ID: " (gethash "id" msg) "\n")) + (princ (concat "From: " (get-message-field (gethash "msg" msg) "author") "(" + (get-message-field (gethash "msg" msg) "address") ")" "\n")) + (princ (concat "To: " (get-message-field (gethash "msg" msg) "recipient") "\n")) + (princ (concat "Echo: " (get-message-field (gethash "msg" msg) "echo") "\n")) + (princ (concat "At: " (get-message-field (gethash "msg" msg) "time") "\n")) + (princ (concat "Subject: " (get-message-field (gethash "msg" msg) "subj") "\n")) (princ (concat "__________________________________\n\n" - (s-join "\n" (get-message-field (assoc 'content msg) "body")))) + (s-join "\n" (get-message-field (gethash "msg" msg) "body")))) (princ "\n__________________________________\n") (princ "[") (insert-button "Answer" @@ -367,64 +375,77 @@ Return list with body content." (if (= (hash-table-count new-messages-list) 0) (princ "No new messages.") (maphash (lambda (id msg) - ;; Write message subj - (insert-text-button (concat (get-message-field msg "subj") - (make-string - (- (get-longest-field "subj" new-messages-list) - (length (get-message-field msg "subj"))) - ? )) - 'help-echo "Read message" - 'plain-msg msg - 'action (lambda (x) (display-message msg;; (button-get x 'plain-msg) - ))) - ;; Write message time and echo - (princ (format " %s(%s)%s%s\t%s\n" - (get-message-field msg "author") - (get-message-field msg "address") - (make-string (- - (+ - (get-longest-field "author" new-messages-list) - (get-longest-field "address" new-messages-list) - 1) - (+ - (length (get-message-field msg "author")) - (length (get-message-field msg "address"))) - ) - ? ) - (get-message-field msg "echo") - (get-message-field msg "time")))) + (let (m) + (setq m (make-hash-table :test 'equal)) + (puthash "id" id m) + (puthash "msg" msg m) + ;; Write message subj + (insert-text-button (concat (get-message-field msg "subj") + (make-string + (- (get-longest-field "subj" new-messages-list) + (length (get-message-field msg "subj"))) + ? )) + 'help-echo "Read message" + 'msg-hash m + 'action (lambda (x) (display-message (button-get x 'msg-hash))))) + ;; Write message time and echo + (princ (format " %s(%s)%s%s\t%s\n" + (get-message-field msg "author") + (get-message-field msg "address") + (make-string (- + (+ + (get-longest-field "author" new-messages-list) + (get-longest-field "address" new-messages-list) + 1) + (+ + (length (get-message-field msg "author")) + (length (get-message-field msg "address"))) + ) + ? ) + (get-message-field msg "echo") + (get-message-field msg "time")))) new-messages-list))) (idec-mode)) -(defun get-message-content (echo msg) - "Get ECHO MSG content from `idec-primary-node'." - (decode-coding-string - (base64-decode-string - (nth 1 (split-string (get-url-content (make-messages-url msg)) ":"))) - 'utf-8)) +(defun get-messages-content (messages) + "Get MESSAGES content from `idec-primary-node'." + (defvar msg-ids '()) + (let (new-hash) + (setq new-hash (make-hash-table :test 'equal)) + (maphash (lambda (msgid echo) + (add-to-list 'msg-ids msgid) + (message (concat "Download message " msgid " to " echo))) + messages) + (message (make-messages-url msg-ids)) + (dolist (line (split-string (get-url-content (make-messages-url msg-ids)) "\n")) + (when (not (string= "" line)) + (let (msgid content mes) + (setq mes (make-hash-table :test 'equal)) + (setq msgid (nth 0 (split-string line ":"))) + (setq content + (decode-coding-string + (base64-decode-string + (nth 1 (split-string line ":"))) + 'utf-8)) + ;; Populate message hash: {"echo": "echo name", "content": "message content"} + (puthash "echo" (get-message-field content "echo") mes) + (puthash "content" content mes) + (puthash msgid mes new-hash)))) + new-hash)) -(defun download-message (echo msg) - "Download ECHO message MSG to `idec-mail-dir'." - (message (concat "Download message " msg " to " echo)) - (defvar message-content) - (if (string= "" msg) - (message "Nil message") - (when (and (not (string= "" msg)) - (check-message-in-echo msg echo)) - (setq message-content (get-message-content echo msg)) - (store-message message-content echo msg) - - (puthash msg message-content new-messages-list) - ;; (setq new-messages-list (-concat - ;; 'new-messages-list - ;; '( - ;; (content . message-content) - ;; (id . msg)) - ;; )) - ))) +(defun download-message (ids) + "Download messages with IDS to `idec-mail-dir'." + (if (= (hash-table-count ids) 0) + nil + (maphash (lambda (id msg) + (store-message (gethash "content" msg) (gethash "echo" msg) id) + (puthash id (gethash "content" msg) new-messages-list)) + (get-messages-content ids)))) (defun download-subscriptions () "Download messages from echoes defined in `idec-echo-subscriptions' from `idec-primary-node'." + (message (make-echo-url (split-string idec-echo-subscriptions ","))) + (message idec-echo-subscriptions) (get-url-content (make-echo-url (split-string idec-echo-subscriptions ",")))) @@ -446,8 +467,13 @@ with `idec-download-offset' and `idec-download-limit'." ;; Check ECHOES is list (if (listp messages) ;; Required GNU Emacs >= 25.3 - (message (concat idec-primary-node "u/m/" - (s-join "/" messages))) + (let (msgs) + (dolist (msg messages) + (setq msgs (concat msgs "/" msg))) + (message msgs) + (concat idec-primary-node "u/m/" msgs + ;; (s-join "/" messages) + )) (message (concat idec-primary-node "u/m/" messages)))) (defun make-count-url (echo) From 723da9ecb4dd5c9057370c1c8261eae70f6a165a Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Wed, 4 Oct 2017 17:58:27 +0300 Subject: [PATCH 17/25] Cosmetic --- idec.el | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/idec.el b/idec.el index 6e21189..e5007ef 100644 --- a/idec.el +++ b/idec.el @@ -370,10 +370,11 @@ Return list with body content." (defun display-new-messages () "Display new fetched messages from `new-messages-list'." - (with-output-to-temp-buffer (get-buffer-create "*IDEC: New messages*") - (switch-to-buffer "*IDEC: New messages*") - (if (= (hash-table-count new-messages-list) 0) - (princ "No new messages.") + (if (= (hash-table-count new-messages-list) 0) + (message "IDEC: No new messages.") + (with-output-to-temp-buffer (get-buffer-create "*IDEC: New messages*") + (switch-to-buffer "*IDEC: New messages*") + (maphash (lambda (id msg) (let (m) (setq m (make-hash-table :test 'equal)) @@ -404,8 +405,8 @@ Return list with body content." ? ) (get-message-field msg "echo") (get-message-field msg "time")))) - new-messages-list))) - (idec-mode)) + new-messages-list)) + (idec-mode))) (defun get-messages-content (messages) "Get MESSAGES content from `idec-primary-node'." @@ -464,7 +465,7 @@ with `idec-download-offset' and `idec-download-limit'." (defun make-messages-url (messages) "Make MESSAGES url to retreive messages from `idec-primary-node'." - ;; Check ECHOES is list + ;; Check MESSAGES is list (if (listp messages) ;; Required GNU Emacs >= 25.3 (let (msgs) From c48e6d48c0fa6a559e075f51d17415123d63f9d5 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Thu, 5 Oct 2017 16:22:35 +0300 Subject: [PATCH 18/25] some changes --- idec.el | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/idec.el b/idec.el index e5007ef..1fa59dc 100644 --- a/idec.el +++ b/idec.el @@ -234,7 +234,7 @@ Not used if `idec-smart-fetching' is not nil." (defun trim-string (string) "Remove white spaces in beginning and ending of STRING; White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." -(replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string))) + (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string))) (defun get-message-tags (msg) "Get MSG tags." @@ -308,6 +308,20 @@ Return list with body content." (delete-region (point) (point-min)) (buffer-string))) +;; LOCAL MAIL FUNCTIONS +;; ;;;;;;;;;;;;;;;;;;;; + +(defun get-local-echoes () + "Get local downloaded echoes from `idec-mail-dir'." + (delete '".." (delete '"." (directory-files idec-mail-dir nil "\\w*\\.\\w*")))) + +(defun idec-browse-local-mail () + "Browse local mail from `idec-mail-dir'." + (message (s-join " " (get-local-echoes)))) + +;; END OF LOCAL MAIL FUNCTIONS +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defun idec-load-new-messages () "Load new messages from IDEC `idec-primary-node'." (interactive) @@ -361,7 +375,7 @@ Return list with body content." (insert-button "Answer" 'action (lambda (x) (message "OK"))) (princ "]") - (princ "\t[") + (princ "\t [") (insert-button "Answer with quote") (princ "]") (add-text-properties (point-min) (point-max) 'read-only)) @@ -417,7 +431,6 @@ Return list with body content." (add-to-list 'msg-ids msgid) (message (concat "Download message " msgid " to " echo))) messages) - (message (make-messages-url msg-ids)) (dolist (line (split-string (get-url-content (make-messages-url msg-ids)) "\n")) (when (not (string= "" line)) (let (msgid content mes) @@ -512,7 +525,7 @@ with `idec-download-offset' and `idec-download-limit'." (when (not (equal line "")) ;; Defind echo (defvar current-echo nil) - (setq current-echo (assoc 'content (split-string line ":"))) + (setq current-echo (nth 0 (split-string line ":"))) ;; Create clickable button (insert-text-button current-echo 'action (lambda (x) (load-echo-messages (button-get x 'echo))) From 14c197ac54355eb201def95017d718168495da6c Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Mon, 16 Oct 2017 11:52:32 +0300 Subject: [PATCH 19/25] Online browsing and customizations move to separate file --- idec-customize.el | 121 +++++++++++++++++++++++++++++++++++++++ idec.el | 141 ++++++++++++++-------------------------------- 2 files changed, 164 insertions(+), 98 deletions(-) create mode 100644 idec-customize.el diff --git a/idec-customize.el b/idec-customize.el new file mode 100644 index 0000000..d94bd75 --- /dev/null +++ b/idec-customize.el @@ -0,0 +1,121 @@ +;;; idec-customize.el --- GNU Emacs client for IDEC network + +;; Copyright (c) 2017 Denis Zheleztsov + +;; Author: Denis Zheleztsov +;; Keywords: lisp,network,IDEC +;; Version: 0.1 + +;; 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 3 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 . + +;;; Commentary: + +;; In active developent. +;; Fetched node must be support modern IDEC extensions like /list.txt, /x/c, etc. + +;;; Code: + +;; CUSTOMIZATION +;; ;;;;;;;;;;;;; + +(defgroup idec nil + "IDEC configuration." + :group 'network) + +;; Not used +(defcustom idec-nodes-list + '("http://idec.spline-online.tk/" + "https://ii-net.tk/ii/ii-point.php?q=/") + "List of IDEC nodes." + :type 'alist + :group 'idec) + +(defcustom idec-primary-node nil + "Primary node to send messages." + :type 'string + :group 'idec) + +;; Never used at this time. +(defcustom idec-use-list-txt t + "Use /list.txt extension." + :group 'idec) + +(defcustom idec-smart-fetch t + "Enable smat fetching; +Download only new messages; Not implemented." + :type 'boolean + :group 'idec) + +(defcustom idec-download-limit "50" + "Limit of download messages; +Not used if `idec-smart-fetching' is not nil." + :type 'string + :group 'idec) + +(defcustom idec-download-offset "-50" + "Offset of download messages; +Not used if `idec-smart-fetching' is not nil." + :type 'string + :group 'idec) + +(defcustom idec-echo-subscriptions nil + "List of subribes echoes." + :type 'string + :group 'idec) + +(defcustom idec-mail-dir "~/.emacs.d/idec-mail" + "Directory to store mail." + :type 'string + :group 'idec) + +(defgroup idec-accounts nil + "IDEC accounts settings." + :group 'idec) + +(defcustom idec-account-nick nil + "Account nickname." + :type 'string + :group 'idec-accounts) + +(defcustom idec-account-node nil + "Node to send messages." + :type 'string + :group 'idec-accounts) + +(defcustom idec-account-auth nil + "Account authstring." + :type 'string + :group 'idec-accounts) + +;; END OF CUSTOMIZATION +;; ;;;;;;;;;;;;;;;;;;;; + +;; VARIABLES +;; ;;;;;;;;; + +(defvar smart-download-limit nil + "Used with `idec-smart-fetch'.") + +(defvar smart-download-offset nil + "Used with `idec-smart-fetch'.") + +(defvar new-messages-list nil + "New messages for display.") + +;; END OF VARIABLES +;; ;;;;;;;;;;;;;;;; + +(provide 'idec-customize) + +;;; idec-customize ends here diff --git a/idec.el b/idec.el index 1fa59dc..a55f97b 100644 --- a/idec.el +++ b/idec.el @@ -26,95 +26,7 @@ ;;; Code: -;; CUSTOMIZATION -;; ;;;;;;;;;;;;; - -(defgroup idec nil - "IDEC configuration." - :group 'network) - -;; Not used -(defcustom idec-nodes-list - '("http://idec.spline-online.tk/" - "https://ii-net.tk/ii/ii-point.php?q=/") - "List of IDEC nodes." - :type 'alist - :group 'idec) - -(defcustom idec-primary-node nil - "Primary node to send messages." - :type 'string - :group 'idec) - -;; Never used at this time. -(defcustom idec-use-list-txt t - "Use /list.txt extension." - :group 'idec) - -(defcustom idec-smart-fetch t - "Enable smat fetching; -Download only new messages; Not implemented." - :type 'boolean - :group 'idec) - -(defcustom idec-download-limit "50" - "Limit of download messages; -Not used if `idec-smart-fetching' is not nil." - :type 'string - :group 'idec) - -(defcustom idec-download-offset "-50" - "Offset of download messages; -Not used if `idec-smart-fetching' is not nil." - :type 'string - :group 'idec) - -(defcustom idec-echo-subscriptions nil - "List of subribes echoes." - :type 'string - :group 'idec) - -(defcustom idec-mail-dir "~/.emacs.d/idec-mail" - "Directory to store mail." - :type 'string - :group 'idec) - -(defgroup idec-accounts nil - "IDEC accounts settings." - :group 'idec) - -(defcustom idec-account-nick nil - "Account nickname." - :type 'string - :group 'idec-accounts) - -(defcustom idec-account-node nil - "Node to send messages." - :type 'string - :group 'idec-accounts) - -(defcustom idec-account-auth nil - "Account authstring." - :type 'string - :group 'idec-accounts) - -;; END OF CUSTOMIZATION -;; ;;;;;;;;;;;;;;;;;;;; - -;; VARIABLES -;; ;;;;;;;;; - -(defvar smart-download-limit nil - "Used with `idec-smart-fetch'.") - -(defvar smart-download-offset nil - "Used with `idec-smart-fetch'.") - -(defvar new-messages-list nil - "New messages for display.") - -;; END OF VARIABLES -;; ;;;;;;;;;;;;;;;; +(require 'idec-customize) ;; MODE ;; ;;;; @@ -141,8 +53,7 @@ Not used if `idec-smart-fetching' is not nil." (defconst idec-font-lock-keywords-2 (append idec-font-lock-keywords-1 (list - '("\\<\\(>>?.*\\)\s\\>" . font-lock-comment-face) - '("\\('\\w*'\\)" . font-lock-variable-name-face))) + '("\\<\\(>>?.*\\)\s\\>" . font-lock-comment-face))) "Quotes highligting for IDEC mode.") (defvar idec-font-lock-keywords idec-font-lock-keywords-2 @@ -151,6 +62,7 @@ Not used if `idec-smart-fetching' is not nil." (defvar idec-mode-syntax-table (make-syntax-table text-mode-syntax-table)) +;; Mode function (defun idec-mode () "Major mode for view and editing IDEC messages." (interactive) @@ -422,6 +334,44 @@ Return list with body content." new-messages-list)) (idec-mode))) +;; Online reading +(defun display-echo-messages (messages) + "Display downloaded MESSAGES from echo." + (message messages) + (let (msgs echo) + (defvar echo-msg-hash (make-hash-table :test 'equal) + "Hashtable with MSG parsing functions.") + (setq echo (nth 0 (split-string messages "\n"))) + (setq msgs (delete (nth 0 (split-string messages "\n")) (split-string messages "\n"))) + (dolist (id msgs) + (puthash id echo echo-msg-hash)) + (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: online browse " echo "*" )) + (switch-to-buffer (concat "*IDEC: online browse " echo "*")) + (maphash (lambda (id msg-hash) + (princ "__________________________________\n") + (princ (concat "ID: " id "\n")) + (princ (concat "From: " (get-message-field (gethash "content" msg-hash) "author") "(" + (get-message-field (gethash "content" msg-hash) "address") ")" "\n")) + (princ (concat "To: " (get-message-field (gethash "content" msg-hash) "recipient") "\n")) + (princ (concat "Echo: " (get-message-field (gethash "content" msg-hash) "echo") "\n")) + (princ (concat "At: " (get-message-field (gethash "content" msg-hash) "time") "\n")) + (princ (concat "Subject: " (get-message-field (gethash "content" msg-hash) "subj") "\n")) + (princ (concat "__________________________________\n\n" + (s-join "\n" (get-message-field (gethash "content" msg-hash) "body")))) + (princ "\n__________________________________\n") + (princ "[") + (insert-button "Answer" + 'action (lambda (x) (message "OK"))) + (princ "]") + (princ "\t [") + (insert-button "Answer with quote") + (princ "]\n\n")) + ;; Plain messages hash proccesing + (get-messages-content echo-msg-hash)) + (add-text-properties (point-min) (point-max) 'read-only) + (idec-mode)) + )) + (defun get-messages-content (messages) "Get MESSAGES content from `idec-primary-node'." (defvar msg-ids '()) @@ -488,7 +438,7 @@ with `idec-download-offset' and `idec-download-limit'." (concat idec-primary-node "u/m/" msgs ;; (s-join "/" messages) )) - (message (concat idec-primary-node "u/m/" messages)))) + (concat idec-primary-node "u/m/" messages))) (defun make-count-url (echo) "Return messages count url in `idec-primary-node' from ECHO." @@ -499,14 +449,9 @@ with `idec-download-offset' and `idec-download-limit'." (nth 1 (split-string (get-url-content (make-count-url echo)) ":"))) -(defun display-echo-messages (messages) - "Display downloaded MESSAGES from echo." - (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: browse echo*")) - (switch-to-buffer "*IDEC: browse echo*") - (princ messages))) - (defun load-echo-messages (echo) "Load messages from ECHO." + (message (concat "DEBUG: " echo)) (store-echo-counter echo) (display-echo-messages (get-url-content (make-echo-url echo)))) From 2d676bd853718afbaf21b5b0dc85be12c559e480 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Mon, 16 Oct 2017 17:38:35 +0300 Subject: [PATCH 20/25] Fixed online reading --- idec.el | 195 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 154 insertions(+), 41 deletions(-) diff --git a/idec.el b/idec.el index a55f97b..4714af2 100644 --- a/idec.el +++ b/idec.el @@ -70,8 +70,8 @@ ;; Mode definition ;; (set-syntax-table idec-mode-syntax-table) (use-local-map idec-mode-map) - (font-lock-add-keywords 'idec-mode '(idec-font-lock-keywords)) - (set (make-local-variable 'font-lock-defaults) '(idec-font-lock-keywords)) + ;; (font-lock-add-keywords 'idec-mode '(idec-font-lock-keywords)) + ;; (set (make-local-variable 'font-lock-defaults) '(idec-font-lock-keywords)) (setq major-mode 'idec-mode) (setq mode-name "[IDEC]") (setq imenu-generic-expression "*IDEC") @@ -150,32 +150,39 @@ White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." (defun get-message-tags (msg) "Get MSG tags." - (trim-string (nth 0 (split-string msg "\n")))) + ;; (trim-string + (nth 0 (split-string msg "\n"))) (defun get-message-echo (msg) "Get MSG echo." - (trim-string (nth 1 (split-string msg "\n")))) + ;; (trim-string + (nth 1 (split-string msg "\n"))) (defun get-message-time (msg) "Get MSG time." - (trim-string (current-time-string - (car (read-from-string (nth 2 (split-string msg "\n"))))))) + ;; ;; (trim-string + (current-time-string + (car (read-from-string (nth 2 (split-string msg "\n")))))) (defun get-message-author (msg) "Get MSG author." - (trim-string (nth 3 (split-string msg "\n")))) + ;; ;; (trim-string + (nth 3 (split-string msg "\n"))) (defun get-message-address (msg) "Get MSG address." - (trim-string (nth 4 (split-string msg "\n")))) + ;; (trim-string + (nth 4 (split-string msg "\n"))) (defun get-message-recipient (msg) "Get MSG recipient." - (trim-string (nth 5 (split-string msg "\n")))) + ;; (trim-string + (nth 5 (split-string msg "\n"))) (defun get-message-subj (msg) "Get MSG subject." - (trim-string (nth 6 (split-string msg "\n")))) + ;; (trim-string + (nth 6 (split-string msg "\n"))) (defun get-message-body (msg) "Get MSG body text. @@ -255,11 +262,6 @@ Return list with body content." (display-new-messages) ) -(defun answer-message (msg) - "Make answer to message MSG." - (get-buffer-create (concat "*IDEC: Answer to " (cdr (assoc 'id msg)))) - (switch-to-buffer (concat "*IDEC: Answer to " (cdr (assoc 'id msg))))) - (defun display-message (msg) "Display message MSG in new buffer in idec-mode." (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: " @@ -336,18 +338,21 @@ Return list with body content." ;; Online reading (defun display-echo-messages (messages) - "Display downloaded MESSAGES from echo." - (message messages) - (let (msgs echo) - (defvar echo-msg-hash (make-hash-table :test 'equal) - "Hashtable with MSG parsing functions.") + "Display downloaded MESSAGES from 2echo." + (message (concat "RECEIVED MESSAGES: " messages)) + (let (msgs echo echo-msg-hash) + (setq echo-msg-hash (make-hash-table :test 'equal)) (setq echo (nth 0 (split-string messages "\n"))) - (setq msgs (delete (nth 0 (split-string messages "\n")) (split-string messages "\n"))) + (setq msgs (split-string messages "\n")) (dolist (id msgs) - (puthash id echo echo-msg-hash)) + (when (not (or + (string-match "\\." id) + (string= "" id))) + (puthash id echo echo-msg-hash))) (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: online browse " echo "*" )) (switch-to-buffer (concat "*IDEC: online browse " echo "*")) (maphash (lambda (id msg-hash) + (when (equal (get-message-field (gethash "content" msg-hash) "echo") echo) (princ "__________________________________\n") (princ (concat "ID: " id "\n")) (princ (concat "From: " (get-message-field (gethash "content" msg-hash) "author") "(" @@ -361,27 +366,139 @@ Return list with body content." (princ "\n__________________________________\n") (princ "[") (insert-button "Answer" - 'action (lambda (x) (message "OK"))) + 'action (lambda (x) (edit-answer-without-quote (button-get x 'id) (button-get x 'msg-hash))) + 'id id + 'msg-hash msg-hash) (princ "]") (princ "\t [") (insert-button "Answer with quote") - (princ "]\n\n")) + (princ "]\n\n"))) ;; Plain messages hash proccesing (get-messages-content echo-msg-hash)) - (add-text-properties (point-min) (point-max) 'read-only) - (idec-mode)) - )) + (idec-mode))) + (add-text-properties (point-min) (point-max) 'read-only)) + +;; ANSWERS +(defun make-answer-header (id msg-hash) + "Make header with reto to ID from MSG-HASH." + (let (answer-hash subj p) + (setq answer-hash (make-hash-table :test 'equal)) + (puthash "id" id answer-hash) + (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) + (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) + (puthash "time" (get-message-field (gethash "content" msg-hash) "time") answer-hash) + + (setq subj (get-message-field (gethash "content" msg-hash) "subj")) + + ;; Make `Re:' in subj if it not present. + (if (not (string-match "Re:" subj)) + (puthash "subj" (concat "Re: " subj) answer-hash) + (puthash "subj" subj answer-hash)) + + (concat + (concat "Answer to " id " in " (gethash "echo" answer-hash) "\n") + (concat "Author: " + (gethash "author" answer-hash) + (concat " at " (gethash "time" answer-hash)) + "\n") + (concat "Subj: " (gethash "subj" answer-hash) "\n") + "------- YOU MESSAGE BELLOW -------\n"))) + +(defun edit-answer-without-quote (id msg-hash) + "Answer to message with ID MSG-HASH." + (let (answer-hash subj p) + (setq answer-hash (make-hash-table :test 'equal)) + (puthash "id" id answer-hash) + (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) + (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) + + (setq subj (get-message-field (gethash "content" msg-hash) "subj")) + + ;; Make `Re:' in subj if it not present. + (if (not (string-match "Re:" subj)) + (puthash "subj" (concat "Re: " subj) answer-hash) + (puthash "subj" subj answer-hash)) + + (switch-to-buffer (get-buffer-create (concat "*IDEC: answer to " id "*"))) + + (insert (make-answer-header id msg-hash)) + (forward-line) + (add-text-properties (point-min) (point) 'read-only) + + (forward-line) + (setq p (point)) + + (point-max) + (insert "\n") + (insert-text-button "[Send]" + 'action (lambda (x) (message "Send..."))) + (goto-char p) + ) + (idec-mode)) + +(defun edit-answer-without-quote (id msg-hash) + "Answer to message with ID MSG-HASH." + (let (answer-hash subj p) + (setq answer-hash (make-hash-table :test 'equal)) + (puthash "id" id answer-hash) + (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) + (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) + + (setq subj (get-message-field (gethash "content" msg-hash) "subj")) + + ;; Make `Re:' in subj if it not present. + (if (not (string-match "Re:" subj)) + (puthash "subj" (concat "Re: " subj) answer-hash) + (puthash "subj" subj answer-hash)) + + (switch-to-buffer (get-buffer-create (concat "*IDEC: answer to " id "*"))) + + (insert (concat "Answer to " id " in " (gethash "echo" answer-hash))) + ;; Write header + ;; (princ (concat "Answer to " id " in " (gethash "echo" answer-hash))) + + ;; Make it readonly + ;; (add-text-properties (point) (point-min) 'read-only) + + ;; Write author + (forward-line) + (insert (concat "\nAuthor: " (gethash "author" answer-hash) "\n")) + (add-text-properties (point-min) (point) 'read-only) + + ;; Write subj + (point-max) + (forward-line) + (insert (concat "Subj: "(gethash "subj" answer-hash))) + (forward-line) + + ;; Body + (insert "\n------- YOU MESSAGE BELLOW -------\n") + ;; (add-text-properties (beginning-of-line) (end-of-line) 'read-only) + (forward-line) + (setq p (point)) + + (point-max) + (insert "\n") + (insert-text-button "[Send]" + 'action (lambda (x) (message "Send..."))) + (goto-char p) + ) + (idec-mode)) + +;; END OF ANSWERS + +(defun hash-table-keys (hash-table) + "Get list of keys from HASH-TABLE." + (let ((keys ())) + (maphash (lambda (k v) (push k keys)) hash-table) + keys)) (defun get-messages-content (messages) "Get MESSAGES content from `idec-primary-node'." - (defvar msg-ids '()) (let (new-hash) (setq new-hash (make-hash-table :test 'equal)) - (maphash (lambda (msgid echo) - (add-to-list 'msg-ids msgid) - (message (concat "Download message " msgid " to " echo))) - messages) - (dolist (line (split-string (get-url-content (make-messages-url msg-ids)) "\n")) + ;; (message (get-url-content (make-messages-url (hash-table-keys messages)))) + (dolist (line (split-string (get-url-content (make-messages-url (hash-table-keys messages))) "\n")) (when (not (string= "" line)) (let (msgid content mes) (setq mes (make-hash-table :test 'equal)) @@ -431,13 +548,7 @@ with `idec-download-offset' and `idec-download-limit'." ;; Check MESSAGES is list (if (listp messages) ;; Required GNU Emacs >= 25.3 - (let (msgs) - (dolist (msg messages) - (setq msgs (concat msgs "/" msg))) - (message msgs) - (concat idec-primary-node "u/m/" msgs - ;; (s-join "/" messages) - )) + (concat idec-primary-node "u/m/" (s-join "/" messages)) (concat idec-primary-node "u/m/" messages))) (defun make-count-url (echo) @@ -452,7 +563,9 @@ with `idec-download-offset' and `idec-download-limit'." (defun load-echo-messages (echo) "Load messages from ECHO." (message (concat "DEBUG: " echo)) - (store-echo-counter echo) + (message (concat "URL: " (make-echo-url echo))) + (message (concat "CONTENT: " (get-url-content (make-echo-url echo)))) + ;; (store-echo-counter echo) (display-echo-messages (get-url-content (make-echo-url echo)))) (defun proccess-echo-message (msg echo) From 223d83169b7437fde3b3480319d8cd03ff8c147b Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Mon, 16 Oct 2017 17:52:01 +0300 Subject: [PATCH 21/25] Use `idec-online-download-limit/offset' --- idec-customize.el | 12 ++++++++++++ idec.el | 34 ++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/idec-customize.el b/idec-customize.el index d94bd75..a2f316f 100644 --- a/idec-customize.el +++ b/idec-customize.el @@ -79,6 +79,18 @@ Not used if `idec-smart-fetching' is not nil." :type 'string :group 'idec) +(defcustom idec-online-download-limit idec-dowload-limit + "Download limit on online browsing; +Default to `idec-download-lmit'" + :type 'string + :group 'idec) + +(defcustom idec-online-download-offset idec-dowload-offset + "Download limit on online browsing; +Default to `idec-download-offset'" + :type 'string + :group 'idec) + (defgroup idec-accounts nil "IDEC accounts settings." :group 'idec) diff --git a/idec.el b/idec.el index 4714af2..506dbbb 100644 --- a/idec.el +++ b/idec.el @@ -533,15 +533,22 @@ Return list with body content." ;; ECHOES FUNCTIONS ;; ;;;;;;;;;;;;;;;; -(defun make-echo-url (echoes) +(defun make-echo-url (echoes &optional online) "Make ECHOES url to retreive messages from `idec-primary-node'; -with `idec-download-offset' and `idec-download-limit'." +with `idec-download-offset' and `idec-download-limit'; +If ONLINE is t uses `idec-online-download-limit' and `idec-online-download-offset'." ;; Check ECHOES is list - (if (listp echoes) - ;; Required GNU Emacs >= 25.3 - (message (concat idec-primary-node "u/e/" - (s-join "/" echoes) "/" idec-download-offset ":" idec-download-limit)) - (message (concat idec-primary-node "u/e/" echoes "/" idec-download-offset ":" idec-download-limit)))) + (let (limit offset) + (if online + (and (setq limit idec-online-download-limit) + (setq offset idec-online-download-offset)) + (and (setq limit idec-download-limit) + (setq offset idec-download-offset))) + (if (listp echoes) + ;; Required GNU Emacs >= 25.3 + (message (concat idec-primary-node "u/e/" + (s-join "/" echoes) "/" offset ":" limit)) + (message (concat idec-primary-node "u/e/" echoes "/" offset ":" limit))))) (defun make-messages-url (messages) "Make MESSAGES url to retreive messages from `idec-primary-node'." @@ -560,12 +567,11 @@ with `idec-download-offset' and `idec-download-limit'." (nth 1 (split-string (get-url-content (make-count-url echo)) ":"))) -(defun load-echo-messages (echo) - "Load messages from ECHO." - (message (concat "DEBUG: " echo)) - (message (concat "URL: " (make-echo-url echo))) - (message (concat "CONTENT: " (get-url-content (make-echo-url echo)))) - ;; (store-echo-counter echo) +(defun load-echo-messages (echo &optional online) + "Load messages from ECHO with ONLINE selector." + (when (not online) + (message (concat "Update counter of " echo)) + (store-echo-counter echo)) (display-echo-messages (get-url-content (make-echo-url echo)))) (defun proccess-echo-message (msg echo) @@ -586,7 +592,7 @@ with `idec-download-offset' and `idec-download-limit'." (setq current-echo (nth 0 (split-string line ":"))) ;; Create clickable button (insert-text-button current-echo - 'action (lambda (x) (load-echo-messages (button-get x 'echo))) + 'action (lambda (x) (load-echo-messages (button-get x 'echo) t)) 'help-echo (concat "Go to echo " current-echo) 'echo current-echo) (princ (format "\t\t||%s\t\t%s\n" From b9ee92e20d0dfa1dfce0c09dd60f40f91bcdb948 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Tue, 17 Oct 2017 10:34:56 +0300 Subject: [PATCH 22/25] Initial refactoring --- idec-answers.el | 142 +++++++++++++++++ idec-mode.el | 80 ++++++++++ idec-online.el | 119 ++++++++++++++ idec-parser.el | 106 +++++++++++++ idec.el | 405 ++++++++++++------------------------------------ 5 files changed, 544 insertions(+), 308 deletions(-) create mode 100644 idec-answers.el create mode 100644 idec-mode.el create mode 100644 idec-online.el create mode 100644 idec-parser.el diff --git a/idec-answers.el b/idec-answers.el new file mode 100644 index 0000000..36f5a72 --- /dev/null +++ b/idec-answers.el @@ -0,0 +1,142 @@ +;;; idec-answers.el --- This file part of GNU Emacs client for IDEC network + +;; Copyright (c) 2017 Denis Zheleztsov + +;; Author: Denis Zheleztsov +;; Keywords: lisp,network,IDEC +;; Version: 0.1 + +;; 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 3 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 . + +;;; Commentary: + +;; In active developent. +;; Fetched node must be support modern IDEC extensions like /list.txt, /x/c, etc. + +;;; Code: + +(require 'idec-mode) + +;; ANSWERS +(defun make-answer-header (id msg-hash) + "Make header with reto to ID from MSG-HASH." + (let (answer-hash subj p) + (setq answer-hash (make-hash-table :test 'equal)) + (puthash "id" id answer-hash) + (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) + (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) + (puthash "time" (get-message-field (gethash "content" msg-hash) "time") answer-hash) + + (setq subj (get-message-field (gethash "content" msg-hash) "subj")) + + ;; Make `Re:' in subj if it not present. + (if (not (string-match "Re:" subj)) + (puthash "subj" (concat "Re: " subj) answer-hash) + (puthash "subj" subj answer-hash)) + + (concat + (concat "Answer to " id " in " (gethash "echo" answer-hash) "\n") + (concat "Author: " + (gethash "author" answer-hash) + (concat " at " (gethash "time" answer-hash)) + "\n") + (concat "Subj: " (gethash "subj" answer-hash) "\n") + "------- YOU MESSAGE BELLOW -------\n"))) + +(defun edit-answer-without-quote (id msg-hash) + "Answer to message with ID MSG-HASH." + (let (answer-hash subj p) + (setq answer-hash (make-hash-table :test 'equal)) + (puthash "id" id answer-hash) + (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) + (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) + + (setq subj (get-message-field (gethash "content" msg-hash) "subj")) + + ;; Make `Re:' in subj if it not present. + (if (not (string-match "Re:" subj)) + (puthash "subj" (concat "Re: " subj) answer-hash) + (puthash "subj" subj answer-hash)) + + (switch-to-buffer (get-buffer-create (concat "*IDEC: answer to " id "*"))) + + (insert (make-answer-header id msg-hash)) + (forward-line) + (add-text-properties (point-min) (point) 'read-only) + + (forward-line) + (setq p (point)) + + (point-max) + (insert "\n") + (insert-text-button "[Send]" + 'action (lambda (x) (message "Send..."))) + (goto-char p) + ) + (idec-mode)) + +(defun edit-answer-without-quote (id msg-hash) + "Answer to message with ID MSG-HASH." + (let (answer-hash subj p) + (setq answer-hash (make-hash-table :test 'equal)) + (puthash "id" id answer-hash) + (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) + (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) + + (setq subj (get-message-field (gethash "content" msg-hash) "subj")) + + ;; Make `Re:' in subj if it not present. + (if (not (string-match "Re:" subj)) + (puthash "subj" (concat "Re: " subj) answer-hash) + (puthash "subj" subj answer-hash)) + + (switch-to-buffer (get-buffer-create (concat "*IDEC: answer to " id "*"))) + + (insert (concat "Answer to " id " in " (gethash "echo" answer-hash))) + ;; Write header + ;; (princ (concat "Answer to " id " in " (gethash "echo" answer-hash))) + + ;; Make it readonly + ;; (add-text-properties (point) (point-min) 'read-only) + + ;; Write author + (forward-line) + (insert (concat "\nAuthor: " (gethash "author" answer-hash) "\n")) + (add-text-properties (point-min) (point) 'read-only) + + ;; Write subj + (point-max) + (forward-line) + (insert (concat "Subj: "(gethash "subj" answer-hash))) + (forward-line) + + ;; Body + (insert "\n------- YOU MESSAGE BELLOW -------\n") + ;; (add-text-properties (beginning-of-line) (end-of-line) 'read-only) + (forward-line) + (setq p (point)) + + (point-max) + (insert "\n") + (insert-text-button "[Send]" + 'action (lambda (x) (message "Send..."))) + (goto-char p) + ) + (idec-mode)) + +;; END OF ANSWERS + +(provide 'idec-answers) + +;;; idec-answers.el ends here diff --git a/idec-mode.el b/idec-mode.el new file mode 100644 index 0000000..1345b5f --- /dev/null +++ b/idec-mode.el @@ -0,0 +1,80 @@ +;;; idec-mode.el --- This file part of GNU Emacs client for IDEC network + +;; Copyright (c) 2017 Denis Zheleztsov + +;; Author: Denis Zheleztsov +;; Keywords: lisp,network,IDEC +;; Version: 0.1 + +;; 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 3 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 . + +;;; Commentary: + +;; In active developent. +;; Fetched node must be support modern IDEC extensions like /list.txt, /x/c, etc. + +;;; Code: + +;; MODE +;; ;;;; + +(defun idec-close-message-buffer () + "Close buffer with message." + (kill-this-buffer)) + +(defvar idec-mode-hook nil) + +(defvar idec-mode-map + (let ((map (make-keymap))) + (define-key map "\C-c \C-c" 'kill-this-buffer) + (define-key map "\C-c \C-n" 'idec-next-message) + (define-key map "\C-c \C-b" 'idec-previous-message) + map) + "Keymapping for IDEC mode.") + +(defconst idec-font-lock-keywords-1 + (list + '("\\(ID:.*\\)" . font-lock-function-name-face) + '("\\<\\(\\(?:Echo\\|From\\|Subj\\|T\\(?:ime\\|o\\)\\):\\)\\>" . font-lock-function-name-face)) + "Minimal highlighting expressions for IDEC mode.") + +(defconst idec-font-lock-keywords-2 + (append idec-font-lock-keywords-1 (list + '("\\<\\(>>?.*\\)\s\\>" . font-lock-comment-face))) + "Quotes highligting for IDEC mode.") + +(defvar idec-font-lock-keywords idec-font-lock-keywords-2 + "Default highlighting expressions for IDEC mode.") + +(defvar idec-mode-syntax-table + (make-syntax-table text-mode-syntax-table)) + +;; Mode function +(defun idec-mode () + "Major mode for view and editing IDEC messages." + (interactive) + (kill-all-local-variables) + ;; Mode definition + ;; (set-syntax-table idec-mode-syntax-table) + (use-local-map idec-mode-map) + ;; (font-lock-add-keywords 'idec-mode '(idec-font-lock-keywords)) + ;; (set (make-local-variable 'font-lock-defaults) '(idec-font-lock-keywords)) + (setq major-mode 'idec-mode) + (setq mode-name "[IDEC]") + (setq imenu-generic-expression "*IDEC") + (run-hooks 'idec-mode-hook)) + +(provide 'idec-mode) + +;;; idec-mode.el ends here diff --git a/idec-online.el b/idec-online.el new file mode 100644 index 0000000..6333f69 --- /dev/null +++ b/idec-online.el @@ -0,0 +1,119 @@ +;;; idec-online.el --- This file part of GNU Emacs client for IDEC network + +;; Copyright (c) 2017 Denis Zheleztsov + +;; Author: Denis Zheleztsov +;; Keywords: lisp,network,IDEC +;; Version: 0.1 + +;; 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 3 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 . + +;;; Commentary: + +;; In active developent. +;; Fetched node must be support modern IDEC extensions like /list.txt, /x/c, etc. + +;;; Code: + +(require 'idec-mode) +(require 'idec-answers) + +(defun display-echo-messages (messages) + "Display downloaded MESSAGES from echo." + (message (concat "RECEIVED MESSAGES: " messages)) + (let (msgs echo echo-msg-hash) + (setq echo-msg-hash (make-hash-table :test 'equal)) + (setq echo (nth 0 (split-string messages "\n"))) + (setq msgs (split-string messages "\n")) + (dolist (id msgs) + (when (not (or + (string-match "\\." id) + (string= "" id))) + (puthash id echo echo-msg-hash))) + (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: online browse " echo "*" )) + (switch-to-buffer (concat "*IDEC: online browse " echo "*")) + (maphash (lambda (id msg-hash) + (when (equal (get-message-field (gethash "content" msg-hash) "echo") echo) + (princ "__________________________________\n") + (princ (concat "ID: " id "\n")) + (princ (concat "From: " (get-message-field (gethash "content" msg-hash) "author") "(" + (get-message-field (gethash "content" msg-hash) "address") ")" "\n")) + (princ (concat "To: " (get-message-field (gethash "content" msg-hash) "recipient") "\n")) + (princ (concat "Echo: " (get-message-field (gethash "content" msg-hash) "echo") "\n")) + (princ (concat "At: " (get-message-field (gethash "content" msg-hash) "time") "\n")) + (princ (concat "Subject: " (get-message-field (gethash "content" msg-hash) "subj") "\n")) + (princ (concat "__________________________________\n\n" + (s-join "\n" (get-message-field (gethash "content" msg-hash) "body")))) + (princ "\n__________________________________\n") + (princ "[") + (insert-button "Answer" + 'action (lambda (x) (edit-answer-without-quote (button-get x 'id) (button-get x 'msg-hash))) + 'id id + 'msg-hash msg-hash) + (princ "]") + (princ "\t [") + (insert-button "Answer with quote") + (princ "]\n\n"))) + ;; Plain messages hash proccesing + (get-messages-content echo-msg-hash)) + (idec-mode))) + (add-text-properties (point-min) (point-max) 'read-only)) + + +(defun load-echo-messages (echo &optional online) + "Load messages from ECHO with ONLINE selector." + (when (not online) + (message (concat "Update counter of " echo)) + (store-echo-counter echo)) + (display-echo-messages (get-url-content (make-echo-url echo)))) + +(defun proccess-echo-message (msg echo) + "Download new message MSG in ECHO." + (with-output-to-temp-buffer (get-buffer-create "*IDEC: DEBUG*") + (switch-to-buffer "*IDEC: DEBUG*") + (princ msg) + (princ echo))) + +(defun proccess-echo-list (raw-list) + "Parse RAW-LIST from HTTP response." + (with-output-to-temp-buffer (get-buffer-create "*IDEC: list.txt*") + (switch-to-buffer "*IDEC: list.txt*") + (dolist (line (split-string (decode-coding-string raw-list 'utf-8) "\n")) + (when (not (equal line "")) + ;; Defind echo + (defvar current-echo nil) + (setq current-echo (nth 0 (split-string line ":"))) + ;; Create clickable button + (insert-text-button current-echo + 'action (lambda (x) (load-echo-messages (button-get x 'echo) t)) + 'help-echo (concat "Go to echo " current-echo) + 'echo current-echo) + (princ (format "\t\t||%s\t\t%s\n" + (nth 2 (split-string line ":")) + (nth 1 (split-string line ":"))))) + )) + (idec-mode)) + +(defun idec-fetch-echo-list (nodeurl) + "Fetch echoes list from remote NODEURL." + (proccess-echo-list (get-url-content nodeurl))) + +(defun idec-online-browse () + "Load echoes list.txt from node `idec-primary-node'." + (interactive) + (idec-fetch-echo-list (concat idec-primary-node "list.txt"))) + +(provide 'idec-online) + +;;; idec-online.el ends here diff --git a/idec-parser.el b/idec-parser.el new file mode 100644 index 0000000..1497f5c --- /dev/null +++ b/idec-parser.el @@ -0,0 +1,106 @@ +;;; idec-parser.el --- This file part of GNU Emacs client for IDEC network + +;; Copyright (c) 2017 Denis Zheleztsov + +;; Author: Denis Zheleztsov +;; Keywords: lisp,network,IDEC +;; Version: 0.1 + +;; 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 3 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 . + +;;; Commentary: + +;; In active developent. +;; Fetched node must be support modern IDEC extensions like /list.txt, /x/c, etc. + +;;; Code: + +;; Message fields pasing +(defun trim-string (string) + "Remove white spaces in beginning and ending of STRING; +White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." + (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string))) + +(defun get-message-tags (msg) + "Get MSG tags." + ;; (trim-string + (nth 0 (split-string msg "\n"))) + +(defun get-message-echo (msg) + "Get MSG echo." + ;; (trim-string + (nth 1 (split-string msg "\n"))) + +(defun get-message-time (msg) + "Get MSG time." + ;; ;; (trim-string + (current-time-string + (car (read-from-string (nth 2 (split-string msg "\n")))))) + +(defun get-message-author (msg) + "Get MSG author." + ;; ;; (trim-string + (nth 3 (split-string msg "\n"))) + +(defun get-message-address (msg) + "Get MSG address." + ;; (trim-string + (nth 4 (split-string msg "\n"))) + +(defun get-message-recipient (msg) + "Get MSG recipient." + ;; (trim-string + (nth 5 (split-string msg "\n"))) + +(defun get-message-subj (msg) + "Get MSG subject." + ;; (trim-string + (nth 6 (split-string msg "\n"))) + +(defun get-message-body (msg) + "Get MSG body text. +Return list with body content." + (-drop 8 (split-string msg "\n"))) + +(defun get-longest-field (field msg-list) + "Return longest FIELD in MSG-LIST." + (defvar field-legth '()) + (defvar field-max nil) + (setq field-max 0) + (maphash (lambda (id msg) + (when (> (length (get-message-field msg field)) + field-max) + (setq field-max (length (get-message-field msg field))))) + msg-list) + field-max) + +(defun get-message-field (msg field) + "Get message MSG FIELD." + (defvar fields-hash (make-hash-table :test 'equal) + "Hashtable with MSG parsing functions.") + + ;; Define hashtable first + (puthash "tags" (get-message-tags msg) fields-hash) + (puthash "echo" (get-message-echo msg) fields-hash) + (puthash "time" (get-message-time msg) fields-hash) + (puthash "author" (get-message-author msg) fields-hash) + (puthash "address" (get-message-address msg) fields-hash) + (puthash "recipient" (get-message-recipient msg) fields-hash) + (puthash "subj" (get-message-subj msg) fields-hash) + (puthash "body" (get-message-body msg) fields-hash) + (gethash field fields-hash)) + +(provide 'idec-parser) + +;;; idec-parser.el ends here diff --git a/idec.el b/idec.el index 506dbbb..259a2ea 100644 --- a/idec.el +++ b/idec.el @@ -26,56 +26,112 @@ ;;; Code: -(require 'idec-customize) +(require 'idec-mode) +;; (require 'idec-answers) +(require 'idec-parser) +(require 'idec-online) -;; MODE -;; ;;;; +(defgroup idec nil + "IDEC configuration." + :group 'network) -(defun idec-close-message-buffer () - "Close buffer with message." - (kill-this-buffer)) +;; Not used +(defcustom idec-nodes-list + '("http://idec.spline-online.tk/" + "https://ii-net.tk/ii/ii-point.php?q=/") + "List of IDEC nodes." + :type 'alist + :group 'idec) -(defvar idec-mode-hook nil) +(defcustom idec-primary-node nil + "Primary node to send messages." + :type 'string + :group 'idec) -(defvar idec-mode-map - (let ((map (make-keymap))) - (define-key map "\C-c \C-c" 'kill-this-buffer) - (define-key map "\C-c \C-n" 'idec-next-message) - (define-key map "\C-c \C-b" 'idec-previous-message) - map) - "Keymapping for IDEC mode.") +;; Never used at this time. +(defcustom idec-use-list-txt t + "Use /list.txt extension." + :group 'idec) -(defconst idec-font-lock-keywords-1 - (list - '("\\(ID:.*\\)" . font-lock-function-name-face) - '("\\<\\(\\(?:Echo\\|From\\|Subj\\|T\\(?:ime\\|o\\)\\):\\)\\>" . font-lock-function-name-face)) - "Minimal highlighting expressions for IDEC mode.") +(defcustom idec-smart-fetch t + "Enable smat fetching; +Download only new messages; Not implemented." + :type 'boolean + :group 'idec) -(defconst idec-font-lock-keywords-2 - (append idec-font-lock-keywords-1 (list - '("\\<\\(>>?.*\\)\s\\>" . font-lock-comment-face))) - "Quotes highligting for IDEC mode.") +(defcustom idec-download-limit "50" + "Limit of download messages; +Not used if `idec-smart-fetching' is not nil." + :type 'string + :group 'idec) -(defvar idec-font-lock-keywords idec-font-lock-keywords-2 - "Default highlighting expressions for IDEC mode.") +(defcustom idec-download-offset "-50" + "Offset of download messages; +Not used if `idec-smart-fetching' is not nil." + :type 'string + :group 'idec) -(defvar idec-mode-syntax-table - (make-syntax-table text-mode-syntax-table)) +(defcustom idec-echo-subscriptions nil + "List of subribes echoes." + :type 'string + :group 'idec) -;; Mode function -(defun idec-mode () - "Major mode for view and editing IDEC messages." - (interactive) - (kill-all-local-variables) - ;; Mode definition - ;; (set-syntax-table idec-mode-syntax-table) - (use-local-map idec-mode-map) - ;; (font-lock-add-keywords 'idec-mode '(idec-font-lock-keywords)) - ;; (set (make-local-variable 'font-lock-defaults) '(idec-font-lock-keywords)) - (setq major-mode 'idec-mode) - (setq mode-name "[IDEC]") - (setq imenu-generic-expression "*IDEC") - (run-hooks 'idec-mode-hook)) +(defcustom idec-mail-dir "~/.emacs.d/idec-mail" + "Directory to store mail." + :type 'string + :group 'idec) + +(defcustom idec-online-download-limit "0" + "Download limit on online browsing; +Default to `idec-download-lmit'" + :type 'string + :group 'idec) + +(defcustom idec-online-download-offset "0" + "Download limit on online browsing; +Default to `idec-download-offset'" + :type 'string + :group 'idec) + +(defgroup idec-accounts nil + "IDEC accounts settings." + :group 'idec) + +(defcustom idec-account-nick nil + "Account nickname." + :type 'string + :group 'idec-accounts) + +(defcustom idec-account-node nil + "Node to send messages." + :type 'string + :group 'idec-accounts) + +(defcustom idec-account-auth nil + "Account authstring." + :type 'string + :group 'idec-accounts) + +;; END OF CUSTOMIZATION +;; ;;;;;;;;;;;;;;;;;;;; + +;; VARIABLES +;; ;;;;;;;;; + +(defvar smart-download-limit nil + "Used with `idec-smart-fetch'.") + +(defvar smart-download-offset nil + "Used with `idec-smart-fetch'.") + +(defvar new-messages-list nil + "New messages for display.") + +(setq idec-online-download-limit idec-download-limit) +(setq idec-online-download-offset idec-download-offset) + +;; END OF VARIABLES +;; ;;;;;;;;;;;;;;;; ;; NAVIGATION FUNCTIONS ;; ;;;;;;;;;;;;;;;;;;;; @@ -142,80 +198,6 @@ "Check if exists message MSG in ECHO `idec-mail-dir'." (not (f-file? (get-message-file echo msg)))) -;; Message fields pasing -(defun trim-string (string) - "Remove white spaces in beginning and ending of STRING; -White space here is any of: space, tab, Emacs newline (line feed, ASCII 10)." - (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string))) - -(defun get-message-tags (msg) - "Get MSG tags." - ;; (trim-string - (nth 0 (split-string msg "\n"))) - -(defun get-message-echo (msg) - "Get MSG echo." - ;; (trim-string - (nth 1 (split-string msg "\n"))) - -(defun get-message-time (msg) - "Get MSG time." - ;; ;; (trim-string - (current-time-string - (car (read-from-string (nth 2 (split-string msg "\n")))))) - -(defun get-message-author (msg) - "Get MSG author." - ;; ;; (trim-string - (nth 3 (split-string msg "\n"))) - -(defun get-message-address (msg) - "Get MSG address." - ;; (trim-string - (nth 4 (split-string msg "\n"))) - -(defun get-message-recipient (msg) - "Get MSG recipient." - ;; (trim-string - (nth 5 (split-string msg "\n"))) - -(defun get-message-subj (msg) - "Get MSG subject." - ;; (trim-string - (nth 6 (split-string msg "\n"))) - -(defun get-message-body (msg) - "Get MSG body text. -Return list with body content." - (-drop 8 (split-string msg "\n"))) - -(defun get-longest-field (field msg-list) - "Return longest FIELD in MSG-LIST." - (defvar field-legth '()) - (defvar field-max nil) - (setq field-max 0) - (maphash (lambda (id msg) - (when (> (length (get-message-field msg field)) - field-max) - (setq field-max (length (get-message-field msg field))))) - msg-list) - field-max) - -(defun get-message-field (msg field) - "Get message MSG FIELD." - (defvar fields-hash (make-hash-table :test 'equal) - "Hashtable with MSG parsing functions.") - - ;; Define hashtable first - (puthash "tags" (get-message-tags msg) fields-hash) - (puthash "echo" (get-message-echo msg) fields-hash) - (puthash "time" (get-message-time msg) fields-hash) - (puthash "author" (get-message-author msg) fields-hash) - (puthash "address" (get-message-address msg) fields-hash) - (puthash "recipient" (get-message-recipient msg) fields-hash) - (puthash "subj" (get-message-subj msg) fields-hash) - (puthash "body" (get-message-body msg) fields-hash) - (gethash field fields-hash)) (defun get-url-content (url) "Get URL content and return it without headers." @@ -336,157 +318,6 @@ Return list with body content." new-messages-list)) (idec-mode))) -;; Online reading -(defun display-echo-messages (messages) - "Display downloaded MESSAGES from 2echo." - (message (concat "RECEIVED MESSAGES: " messages)) - (let (msgs echo echo-msg-hash) - (setq echo-msg-hash (make-hash-table :test 'equal)) - (setq echo (nth 0 (split-string messages "\n"))) - (setq msgs (split-string messages "\n")) - (dolist (id msgs) - (when (not (or - (string-match "\\." id) - (string= "" id))) - (puthash id echo echo-msg-hash))) - (with-output-to-temp-buffer (get-buffer-create (concat "*IDEC: online browse " echo "*" )) - (switch-to-buffer (concat "*IDEC: online browse " echo "*")) - (maphash (lambda (id msg-hash) - (when (equal (get-message-field (gethash "content" msg-hash) "echo") echo) - (princ "__________________________________\n") - (princ (concat "ID: " id "\n")) - (princ (concat "From: " (get-message-field (gethash "content" msg-hash) "author") "(" - (get-message-field (gethash "content" msg-hash) "address") ")" "\n")) - (princ (concat "To: " (get-message-field (gethash "content" msg-hash) "recipient") "\n")) - (princ (concat "Echo: " (get-message-field (gethash "content" msg-hash) "echo") "\n")) - (princ (concat "At: " (get-message-field (gethash "content" msg-hash) "time") "\n")) - (princ (concat "Subject: " (get-message-field (gethash "content" msg-hash) "subj") "\n")) - (princ (concat "__________________________________\n\n" - (s-join "\n" (get-message-field (gethash "content" msg-hash) "body")))) - (princ "\n__________________________________\n") - (princ "[") - (insert-button "Answer" - 'action (lambda (x) (edit-answer-without-quote (button-get x 'id) (button-get x 'msg-hash))) - 'id id - 'msg-hash msg-hash) - (princ "]") - (princ "\t [") - (insert-button "Answer with quote") - (princ "]\n\n"))) - ;; Plain messages hash proccesing - (get-messages-content echo-msg-hash)) - (idec-mode))) - (add-text-properties (point-min) (point-max) 'read-only)) - -;; ANSWERS -(defun make-answer-header (id msg-hash) - "Make header with reto to ID from MSG-HASH." - (let (answer-hash subj p) - (setq answer-hash (make-hash-table :test 'equal)) - (puthash "id" id answer-hash) - (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) - (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) - (puthash "time" (get-message-field (gethash "content" msg-hash) "time") answer-hash) - - (setq subj (get-message-field (gethash "content" msg-hash) "subj")) - - ;; Make `Re:' in subj if it not present. - (if (not (string-match "Re:" subj)) - (puthash "subj" (concat "Re: " subj) answer-hash) - (puthash "subj" subj answer-hash)) - - (concat - (concat "Answer to " id " in " (gethash "echo" answer-hash) "\n") - (concat "Author: " - (gethash "author" answer-hash) - (concat " at " (gethash "time" answer-hash)) - "\n") - (concat "Subj: " (gethash "subj" answer-hash) "\n") - "------- YOU MESSAGE BELLOW -------\n"))) - -(defun edit-answer-without-quote (id msg-hash) - "Answer to message with ID MSG-HASH." - (let (answer-hash subj p) - (setq answer-hash (make-hash-table :test 'equal)) - (puthash "id" id answer-hash) - (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) - (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) - - (setq subj (get-message-field (gethash "content" msg-hash) "subj")) - - ;; Make `Re:' in subj if it not present. - (if (not (string-match "Re:" subj)) - (puthash "subj" (concat "Re: " subj) answer-hash) - (puthash "subj" subj answer-hash)) - - (switch-to-buffer (get-buffer-create (concat "*IDEC: answer to " id "*"))) - - (insert (make-answer-header id msg-hash)) - (forward-line) - (add-text-properties (point-min) (point) 'read-only) - - (forward-line) - (setq p (point)) - - (point-max) - (insert "\n") - (insert-text-button "[Send]" - 'action (lambda (x) (message "Send..."))) - (goto-char p) - ) - (idec-mode)) - -(defun edit-answer-without-quote (id msg-hash) - "Answer to message with ID MSG-HASH." - (let (answer-hash subj p) - (setq answer-hash (make-hash-table :test 'equal)) - (puthash "id" id answer-hash) - (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) - (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) - - (setq subj (get-message-field (gethash "content" msg-hash) "subj")) - - ;; Make `Re:' in subj if it not present. - (if (not (string-match "Re:" subj)) - (puthash "subj" (concat "Re: " subj) answer-hash) - (puthash "subj" subj answer-hash)) - - (switch-to-buffer (get-buffer-create (concat "*IDEC: answer to " id "*"))) - - (insert (concat "Answer to " id " in " (gethash "echo" answer-hash))) - ;; Write header - ;; (princ (concat "Answer to " id " in " (gethash "echo" answer-hash))) - - ;; Make it readonly - ;; (add-text-properties (point) (point-min) 'read-only) - - ;; Write author - (forward-line) - (insert (concat "\nAuthor: " (gethash "author" answer-hash) "\n")) - (add-text-properties (point-min) (point) 'read-only) - - ;; Write subj - (point-max) - (forward-line) - (insert (concat "Subj: "(gethash "subj" answer-hash))) - (forward-line) - - ;; Body - (insert "\n------- YOU MESSAGE BELLOW -------\n") - ;; (add-text-properties (beginning-of-line) (end-of-line) 'read-only) - (forward-line) - (setq p (point)) - - (point-max) - (insert "\n") - (insert-text-button "[Send]" - 'action (lambda (x) (message "Send..."))) - (goto-char p) - ) - (idec-mode)) - -;; END OF ANSWERS - (defun hash-table-keys (hash-table) "Get list of keys from HASH-TABLE." (let ((keys ())) @@ -567,48 +398,6 @@ If ONLINE is t uses `idec-online-download-limit' and `idec-online-download-offse (nth 1 (split-string (get-url-content (make-count-url echo)) ":"))) -(defun load-echo-messages (echo &optional online) - "Load messages from ECHO with ONLINE selector." - (when (not online) - (message (concat "Update counter of " echo)) - (store-echo-counter echo)) - (display-echo-messages (get-url-content (make-echo-url echo)))) - -(defun proccess-echo-message (msg echo) - "Download new message MSG in ECHO." - (with-output-to-temp-buffer (get-buffer-create "*IDEC: DEBUG*") - (switch-to-buffer "*IDEC: DEBUG*") - (princ msg) - (princ echo))) - -(defun proccess-echo-list (raw-list) - "Parse RAW-LIST from HTTP response." - (with-output-to-temp-buffer (get-buffer-create "*IDEC: list.txt*") - (switch-to-buffer "*IDEC: list.txt*") - (dolist (line (split-string (decode-coding-string raw-list 'utf-8) "\n")) - (when (not (equal line "")) - ;; Defind echo - (defvar current-echo nil) - (setq current-echo (nth 0 (split-string line ":"))) - ;; Create clickable button - (insert-text-button current-echo - 'action (lambda (x) (load-echo-messages (button-get x 'echo) t)) - 'help-echo (concat "Go to echo " current-echo) - 'echo current-echo) - (princ (format "\t\t||%s\t\t%s\n" - (nth 2 (split-string line ":")) - (nth 1 (split-string line ":"))))) - )) - (idec-mode)) - -(defun idec-fetch-echo-list (nodeurl) - "Fetch echoes list from remote NODEURL." - (proccess-echo-list (get-url-content nodeurl))) - -(defun idec-online-browse () - "Load echoes list.txt from node `idec-primary-node'." - (interactive) - (idec-fetch-echo-list (concat idec-primary-node "list.txt"))) ;; END OF ECHOES FUNCTIONS ;; ;;;;;;;;;;;;;;;;;;;;;;; From 8da6c4615f68a2988724e63386a79d60f4ae8a0c Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Tue, 17 Oct 2017 14:09:25 +0300 Subject: [PATCH 23/25] Working answer post --- idec-answers.el | 137 ++++++++++++++++++++++------------------------ idec-customize.el | 2 +- idec-online.el | 5 ++ idec.el | 6 +- 4 files changed, 73 insertions(+), 77 deletions(-) diff --git a/idec-answers.el b/idec-answers.el index 36f5a72..fe22b46 100644 --- a/idec-answers.el +++ b/idec-answers.el @@ -27,11 +27,59 @@ ;;; Code: (require 'idec-mode) +(require 'web) -;; ANSWERS -(defun make-answer-header (id msg-hash) - "Make header with reto to ID from MSG-HASH." - (let (answer-hash subj p) +(defun point-url () + "Return url with `idec-primary-node' to send messages." + (concat idec-primary-node "u/point")) + +(defun request-is-done (result) + "Show message with RESULT code." + (message "IDEC: Sended. Result: %S" result)) + +(defun do-post-request (url data) + "Make POST request to URL with DATA." + (web-http-post + (lambda (con header data) + (request-is-done data)) + :url url + :data data)) + +(defun post-message (encoded-message) + "Do POST request to `idec-primary-node' with Base64 ENCODED-MESSAGE." + (let (json) + (setq json (make-hash-table :test 'equal)) + (puthash "pauth" idec-account-auth json) + (puthash "tmsg" encoded-message json) + (do-post-request (point-url) json)) + (message "Message sended")) + +(defun do-send-reply-post-request (message) + "Make IDEC compatible point MESSAGE and send it to `idec-primary-node'." + (message (gethash "body" message)) + (let (point-message) + (setq point-message (list + (gethash "echo" message) + (gethash "author" message) + (gethash "subj" message) + "" + (concat "@repto:" (gethash "id" message)) + (gethash "body" message))) + ;; Encode message in Base64 + (post-message (base64-encode-string (encode-coding-string (s-join "\n" point-message) 'utf-8))))) + +(defun send-message (msg) + "Send message MSG to `idec-primary-node'." + (switch-to-buffer (concat "*IDEC: answer to " (gethash "id" msg) "*")) + (puthash "body" + (s-join "\n" (-drop-last 1 (-drop 4 (split-string (buffer-string) "\n")))) + msg) + (message (gethash "body" msg)) + (do-send-reply-post-request msg)) + +(defun get-answers-hash (id msg-hash) + "Make answers hashtable from ID and MSG-HASH." + (let (answer-hash) (setq answer-hash (make-hash-table :test 'equal)) (puthash "id" id answer-hash) (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) @@ -44,6 +92,12 @@ (if (not (string-match "Re:" subj)) (puthash "subj" (concat "Re: " subj) answer-hash) (puthash "subj" subj answer-hash)) + answer-hash)) + +(defun make-answer-header (id msg-hash) + "Make header with reto to ID from MSG-HASH." + (let (answer-hash subj p) + (setq answer-hash (get-answers-hash id msg-hash)) (concat (concat "Answer to " id " in " (gethash "echo" answer-hash) "\n") @@ -56,84 +110,21 @@ (defun edit-answer-without-quote (id msg-hash) "Answer to message with ID MSG-HASH." - (let (answer-hash subj p) - (setq answer-hash (make-hash-table :test 'equal)) - (puthash "id" id answer-hash) - (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) - (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) - - (setq subj (get-message-field (gethash "content" msg-hash) "subj")) - - ;; Make `Re:' in subj if it not present. - (if (not (string-match "Re:" subj)) - (puthash "subj" (concat "Re: " subj) answer-hash) - (puthash "subj" subj answer-hash)) - + (let (answer-hash p) + (setq answer-hash (get-answers-hash id msg-hash)) (switch-to-buffer (get-buffer-create (concat "*IDEC: answer to " id "*"))) (insert (make-answer-header id msg-hash)) (forward-line) - (add-text-properties (point-min) (point) 'read-only) - - (forward-line) + (add-text-properties (point) (point-min) 'read-only) (setq p (point)) - (point-max) (insert "\n") (insert-text-button "[Send]" - 'action (lambda (x) (message "Send..."))) + 'action (lambda (x) (send-message (button-get x 'msg))) + 'msg answer-hash) (goto-char p) - ) - (idec-mode)) - -(defun edit-answer-without-quote (id msg-hash) - "Answer to message with ID MSG-HASH." - (let (answer-hash subj p) - (setq answer-hash (make-hash-table :test 'equal)) - (puthash "id" id answer-hash) - (puthash "echo" (get-message-field (gethash "content" msg-hash) "echo") answer-hash) - (puthash "author" (get-message-field (gethash "content" msg-hash) "author") answer-hash) - - (setq subj (get-message-field (gethash "content" msg-hash) "subj")) - - ;; Make `Re:' in subj if it not present. - (if (not (string-match "Re:" subj)) - (puthash "subj" (concat "Re: " subj) answer-hash) - (puthash "subj" subj answer-hash)) - - (switch-to-buffer (get-buffer-create (concat "*IDEC: answer to " id "*"))) - - (insert (concat "Answer to " id " in " (gethash "echo" answer-hash))) - ;; Write header - ;; (princ (concat "Answer to " id " in " (gethash "echo" answer-hash))) - - ;; Make it readonly - ;; (add-text-properties (point) (point-min) 'read-only) - - ;; Write author - (forward-line) - (insert (concat "\nAuthor: " (gethash "author" answer-hash) "\n")) - (add-text-properties (point-min) (point) 'read-only) - - ;; Write subj - (point-max) - (forward-line) - (insert (concat "Subj: "(gethash "subj" answer-hash))) - (forward-line) - - ;; Body - (insert "\n------- YOU MESSAGE BELLOW -------\n") - ;; (add-text-properties (beginning-of-line) (end-of-line) 'read-only) - (forward-line) - (setq p (point)) - - (point-max) - (insert "\n") - (insert-text-button "[Send]" - 'action (lambda (x) (message "Send..."))) - (goto-char p) - ) - (idec-mode)) + (idec-mode))) ;; END OF ANSWERS diff --git a/idec-customize.el b/idec-customize.el index a2f316f..0ca09d4 100644 --- a/idec-customize.el +++ b/idec-customize.el @@ -1,4 +1,4 @@ -;;; idec-customize.el --- GNU Emacs client for IDEC network +;;; idec-customize.el --- This file part of GNU Emacs client for IDEC network ;; Copyright (c) 2017 Denis Zheleztsov diff --git a/idec-online.el b/idec-online.el index 6333f69..7284ffe 100644 --- a/idec-online.el +++ b/idec-online.el @@ -114,6 +114,11 @@ (interactive) (idec-fetch-echo-list (concat idec-primary-node "list.txt"))) +(defun idec-online-browse-hidden () + "Browse hidden echo." + (interactive) + (load-echo-messages (read-string "Enter echo name: ") t)) + (provide 'idec-online) ;;; idec-online.el ends here diff --git a/idec.el b/idec.el index 259a2ea..a91bedf 100644 --- a/idec.el +++ b/idec.el @@ -97,17 +97,17 @@ Default to `idec-download-offset'" "IDEC accounts settings." :group 'idec) -(defcustom idec-account-nick nil +(defcustom idec-account-nick "" "Account nickname." :type 'string :group 'idec-accounts) -(defcustom idec-account-node nil +(defcustom idec-account-node "" "Node to send messages." :type 'string :group 'idec-accounts) -(defcustom idec-account-auth nil +(defcustom idec-account-auth "" "Account authstring." :type 'string :group 'idec-accounts) From 13d3fbb921c15abf3d00643792e12cf749a22c79 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Wed, 18 Oct 2017 14:14:33 +0300 Subject: [PATCH 24/25] Working answers and new messages --- idec-answers.el | 115 ++++++++++++++++++++++++++++++++++++++++++++---- idec-db.el | 75 +++++++++++++++++++++++++++++++ idec-mode.el | 7 ++- idec.el | 56 ++++++----------------- 4 files changed, 201 insertions(+), 52 deletions(-) create mode 100644 idec-db.el diff --git a/idec-answers.el b/idec-answers.el index fe22b46..fcfb16d 100644 --- a/idec-answers.el +++ b/idec-answers.el @@ -29,6 +29,37 @@ (require 'idec-mode) (require 'web) +(defun replace-in-string (what with str) + "Replace WHAT WITH in STR." + (replace-regexp-in-string (regexp-quote what) with str nil 'literal)) + +(defun base64-to-base64url (str) + "Make url safe base64 string STR." + (when (string-match (regexp-quote "=") str) + (and (base64-to-base64url (replace-regexp-in-string "=+$" "" str)))) + (when (string-match (regexp-quote "+") str) + (and (base64-to-base64url (replace-in-string "+" "-" str)))) + (when (string-match (regexp-quote "/") str) + (and (base64-to-base64url (replace-in-string "/" "_" str)))) + str) + +(defun base64url-to-base64 (str) + "Make base64 from urlsafe STR." + (when (string-match (regexp-quote "-") str) + (and (base64url-to-base64 (replace-in-string "-" "+" str)))) + (when (string-match (regexp-quote "_") str) + (and (base64url-to-base64 (replace-in-string "_" "/" str)))) + str) + +(defun base64url-encode-string (str) + "Decode base64 urlsafe string STR." + (message (concat "Base64url: " (base64-to-base64url (base64-encode-string str t)))) + (base64-to-base64url (base64-encode-string str t))) + +(defun base64url-decode-string (str) + "Encode base64 urlsafe string STR." + (base64-decode-string (base64url-to-base64 str))) + (defun point-url () "Return url with `idec-primary-node' to send messages." (concat idec-primary-node "u/point")) @@ -37,23 +68,65 @@ "Show message with RESULT code." (message "IDEC: Sended. Result: %S" result)) -(defun do-post-request (url data) - "Make POST request to URL with DATA." +(defun do-post-request (url msg) + "Make POST request to URL with data MSG." + (message (gethash 'tmsg msg)) (web-http-post (lambda (con header data) (request-is-done data)) :url url - :data data)) + :data msg + ) + ;; (request + ;; url + ;; :type "POST" + ;; :data '(("pauth" . (gethash "path" msg)) ("tmsg" . (gethash "tmsg" msg))) + ;; ;; :headers '(("Content-Type" . "application/json")) + ;; ;; :parser 'json-read + ;; :success (function* + ;; (lambda (&key data &allow-other-keys) + ;; (message "I sent: %S" (assoc-default 'json data))))) + ) (defun post-message (encoded-message) "Do POST request to `idec-primary-node' with Base64 ENCODED-MESSAGE." + (message (base64url-decode-string encoded-message)) (let (json) (setq json (make-hash-table :test 'equal)) - (puthash "pauth" idec-account-auth json) - (puthash "tmsg" encoded-message json) + (puthash 'pauth idec-account-auth json) + (puthash 'tmsg encoded-message json) (do-post-request (point-url) json)) + ;; (message (base64url-decode-string encoded-message)) (message "Message sended")) +(defun send-new-message (echo) + "Send new message to ECHO." + (switch-to-buffer (concat "*IDEC: New message to echo " echo "*")) + (let ((msg (make-hash-table :test 'equal))) + (puthash "body" + (encode-coding-string (s-join "\n" (-drop-last 1 (-drop 4 (split-string (buffer-string) "\n")))) + 'utf-8) + msg) + (puthash "subj" + (encode-coding-string (nth 1 (split-string (nth 2 (split-string (buffer-string) "\n")) "bj: ")) + 'utf-8) + msg) + (puthash "echo" echo msg) + + (do-send-new-post-request msg))) + +(defun do-send-new-post-request (msg) + "Make IDEC compatible point message MSG and send it to `idec-primary-node'." + (let (point-message) + (setq point-message (list + (gethash "echo" msg) + "All" + (gethash "subj" msg) + "" + (gethash "body" msg))) + ;; Encode message in Base64 + (post-message (base64url-encode-string (s-join "\n" point-message))))) + (defun do-send-reply-post-request (message) "Make IDEC compatible point MESSAGE and send it to `idec-primary-node'." (message (gethash "body" message)) @@ -66,9 +139,10 @@ (concat "@repto:" (gethash "id" message)) (gethash "body" message))) ;; Encode message in Base64 - (post-message (base64-encode-string (encode-coding-string (s-join "\n" point-message) 'utf-8))))) + (post-message (base64url-encode-string (encode-coding-string (s-join "\n" point-message) 'utf-8))) + (kill-buffer (concat "*IDEC: answer to " (gethash "id" message) "*")))) -(defun send-message (msg) +(defun send-reply-message (msg) "Send message MSG to `idec-primary-node'." (switch-to-buffer (concat "*IDEC: answer to " (gethash "id" msg) "*")) (puthash "body" @@ -121,13 +195,38 @@ (insert "\n") (insert-text-button "[Send]" - 'action (lambda (x) (send-message (button-get x 'msg))) + 'action (lambda (x) (send-reply-message (button-get x 'msg))) 'msg answer-hash) (goto-char p) (idec-mode))) ;; END OF ANSWERS +;; NEW MESSAGE +(defun make-new-message-header (echo) + "Return header for new message with filled ECHO field." + (concat + (concat "New message to echo " echo "\n") + "\n" + "Subj: \n" + "------- YOU MESSAGE BELLOW -------\n") + ) + +(defun edit-new-message (echo) + "Edit new message to ECHO." + (switch-to-buffer (get-buffer-create (concat "*IDEC: New message to echo " echo "*"))) + (insert (make-new-message-header echo)) + (forward-line) + + (let (p) + (setq p (point)) + (insert "\n") + (insert-text-button "[Send]" + 'action (lambda (x) (send-new-message (button-get x 'msg-echo))) + 'msg-echo echo) + (goto-char p)) + (idec-mode)) + (provide 'idec-answers) ;;; idec-answers.el ends here diff --git a/idec-db.el b/idec-db.el new file mode 100644 index 0000000..ac16d67 --- /dev/null +++ b/idec-db.el @@ -0,0 +1,75 @@ +;;; idec-db.el --- This file is a part of GNU Emacs client for IDEC network + +;; Copyright (c) 2017 Denis Zheleztsov + +;; Author: Denis Zheleztsov +;; Keywords: lisp,network,IDEC +;; Version: 0.1 + +;; 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 3 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 . + +;;; Commentary: + +;; In active developent. +;; Fetched node must be support modern IDEC extensions like /list.txt, /x/c, etc. + +;;; Code: +(require 'emacsql) +(require 'idec-parser) + +(defun create-echo-mail-dir (echo) + "Create ECHO directory inside `idec-mail-dir'." + (if (file-exists-p idec-mail-dir) + (message idec-mail-dir) + (mkdir idec-mail-dir)) + (if (file-exists-p (concat idec-mail-dir "/" echo)) + (message (concat idec-mail-dir "/" echo)) + (mkdir (concat idec-mail-dir "/" echo)))) + +(defun get-echo-dir (echo) + "Get ECHO dir from `idec-mail-dir'." + (concat idec-mail-dir (concat "/" echo))) + +(defun filename-to-store (content id) + "Make filename from CONTENT unixtime and ID." + (concat (nth 2 (split-string content)) "-" id)) + +(defun get-message-file (echo id) + "Get ECHO message filename by ID." + (concat (get-echo-dir echo) "/" id)) + +(defun get-counter-file (echo) + "Get ECHO counter filename." + (concat (get-echo-dir echo) "/counter")) + +(defun store-message (content echo id) + "Store CONTENT from ECHO message in `idec-mail-dir' with it ID." + (create-echo-mail-dir echo) + (write-region content nil (get-message-file echo id))) + +(defun store-echo-counter (echo) + "Store count messages in ECHO." + (create-echo-mail-dir echo) + (write-region (echo-messages-count echo) nil (get-counter-file echo))) + +(defun check-message-in-echo (msg echo) + "Check if exists message MSG in ECHO `idec-mail-dir'." + (not (f-file? (get-message-file echo msg)))) + +(defun open-echo-db (echo) + "Create or open sqlite database inside ECHO `idec-mail-dir'.") + +(provide 'idec-db) + +;;; idec-db.el ends here diff --git a/idec-mode.el b/idec-mode.el index 1345b5f..0cfce60 100644 --- a/idec-mode.el +++ b/idec-mode.el @@ -58,7 +58,10 @@ "Default highlighting expressions for IDEC mode.") (defvar idec-mode-syntax-table - (make-syntax-table text-mode-syntax-table)) + (let ((st (make-syntax-table))) + (modify-syntax-entry ?_ "w" st) + (modify-syntax-entry ?/ ". 2b" st) + st)) ;; Mode function (defun idec-mode () @@ -66,7 +69,7 @@ (interactive) (kill-all-local-variables) ;; Mode definition - ;; (set-syntax-table idec-mode-syntax-table) + (set-syntax-table idec-mode-syntax-table) (use-local-map idec-mode-map) ;; (font-lock-add-keywords 'idec-mode '(idec-font-lock-keywords)) ;; (set (make-local-variable 'font-lock-defaults) '(idec-font-lock-keywords)) diff --git a/idec.el b/idec.el index a91bedf..8f9510c 100644 --- a/idec.el +++ b/idec.el @@ -30,6 +30,7 @@ ;; (require 'idec-answers) (require 'idec-parser) (require 'idec-online) +(require 'idec-db) (defgroup idec nil "IDEC configuration." @@ -159,45 +160,6 @@ Default to `idec-download-offset'" ;; FUNCTIONS ;; ;;;;;;;;; -(defun create-echo-mail-dir (echo) - "Create ECHO directory inside `idec-mail-dir'." - (if (file-exists-p idec-mail-dir) - (message idec-mail-dir) - (mkdir idec-mail-dir)) - (if (file-exists-p (concat idec-mail-dir "/" echo)) - (message (concat idec-mail-dir "/" echo)) - (mkdir (concat idec-mail-dir "/" echo)))) - -(defun get-echo-dir (echo) - "Get ECHO dir from `idec-mail-dir'." - (concat idec-mail-dir (concat "/" echo))) - -(defun filename-to-store (content id) - "Make filename from CONTENT unixtime and ID." - (concat (nth 2 (split-string content)) "-" id)) - -(defun get-message-file (echo id) - "Get ECHO message filename by ID." - (concat (get-echo-dir echo) "/" id)) - -(defun get-counter-file (echo) - "Get ECHO counter filename." - (concat (get-echo-dir echo) "/counter")) - -(defun store-message (content echo id) - "Store CONTENT from ECHO message in `idec-mail-dir' with it ID." - (create-echo-mail-dir echo) - (write-region content nil (get-message-file echo id))) - -(defun store-echo-counter (echo) - "Store count messages in ECHO." - (create-echo-mail-dir echo) - (write-region (echo-messages-count echo) nil (get-counter-file echo))) - -(defun check-message-in-echo (msg echo) - "Check if exists message MSG in ECHO `idec-mail-dir'." - (not (f-file? (get-message-file echo msg)))) - (defun get-url-content (url) "Get URL content and return it without headers." @@ -268,11 +230,16 @@ Default to `idec-download-offset'" (s-join "\n" (get-message-field (gethash "msg" msg) "body")))) (princ "\n__________________________________\n") (princ "[") - (insert-button "Answer" - 'action (lambda (x) (message "OK"))) + (let (answer-hash) + (setq answer-hash (make-hash-table :test 'equal)) + (puthash "content" (gethash "msg" msg) answer-hash) + (insert-button "Answer" + 'action (lambda (x) (edit-answer-without-quote (button-get x 'id) (button-get x 'msg-hash))) + 'id (gethash "id" msg) + 'msg-hash answer-hash)) (princ "]") (princ "\t [") - (insert-button "Answer with quote") + (insert-button "Quote answer") (princ "]") (add-text-properties (point-min) (point-max) 'read-only)) (point-max) @@ -402,6 +369,11 @@ If ONLINE is t uses `idec-online-download-limit' and `idec-online-download-offse ;; END OF ECHOES FUNCTIONS ;; ;;;;;;;;;;;;;;;;;;;;;;; +(defun idec-new-message () + "Make new message." + (interactive) + (edit-new-message (read-string "Echo: "))) + ;; END OF FUNCTIONS ;; ;;;;;;;;;;;;;;;; From 287a1dfad57a9ef468748825c3c3afd40c599b40 Mon Sep 17 00:00:00 2001 From: Denis Zheleztsov Date: Wed, 18 Oct 2017 16:16:43 +0300 Subject: [PATCH 25/25] db initial --- idec-db.el | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/idec-db.el b/idec-db.el index ac16d67..feca0d4 100644 --- a/idec-db.el +++ b/idec-db.el @@ -26,6 +26,7 @@ ;;; Code: (require 'emacsql) +(require 'emacsql-sqlite) (require 'idec-parser) (defun create-echo-mail-dir (echo) @@ -68,7 +69,59 @@ (not (f-file? (get-message-file echo msg)))) (defun open-echo-db (echo) - "Create or open sqlite database inside ECHO `idec-mail-dir'.") + "Create or open sqlite database inside ECHO `idec-mail-dir'." + (emacsql-sqlite (concat (get-echo-dir echo) "/db.sqlite3"))) + +(defun create-db-schema (echo) + "Create db schema for ECHO." + (emacsql (open-echo-db echo) + [:create-table messages + ([(id :primary-key) + tags + author + to + echo + subj + (time :timestamp) + (body :text) + (unread integer :default 1)]) + ]) + t) + +(defun init-echo-db (echo) + "Initialize new database for ECHO." + (when (check-message-in-echo "db.sqlite3" echo) + (and + (create-db-schema echo) + (message (concat "IDEC: Database for " echo " initialized."))))) + +(defun insert-message-to-db (msg id &optional mark-read) + "Insert MSG ID to echo db; +unread by default, but you can MARK-READ it." + (if (not (emacsql (open-echo-db (get-message-field msg "echo")) + [:insert :into messages + :values ([$s1 $s2 $s3 $s4 $s5 $s6 $s7 $s8 $s9])] + id + (get-message-field msg "tags") + (get-message-field msg "author") + (get-message-field msg "recipient") + (get-message-field msg "echo") + (get-message-field msg "subj") + (get-message-field msg "time") + (s-join "\n" (get-message-field msg "body")) + mark-read)) + (message (concat "IDEC: Message " id " stored in db")) + (message (concat "IDEC: Problem to store message " id)))) + +(defun check-message-in-db (msgid echo) + "Check message MSGID in ECHO database." + (if (not (emacsql (open-echo-db echo) + [:select [id] + :from messages + :where (= id $s1)] + msgid)) + t + nil)) (provide 'idec-db)