1 ;; hatena-diary-mode.el --- major mode for Hatena::Diary (http://d.hatena.ne.jp)
3 ;; Created: Thu Jun 17 2004
4 ;; Keywords: blog emacs
5 ;; author: hikigaeru <http://d.hatena.ne.jp/hikigaeru/>
6 ;; hirosandesu <http://d.hatena.ne.jp/suttanipaata/>
8 ;; ¸ø³«¥Ú¡¼¥¸: http://sourceforge.jp/projects/hatena-diary-el/
10 ;; http://d.hatena.ne.jp/hikigaeru/20040617
11 ;; http://d.hatena.ne.jp/dev-null
14 ;; This program supports the update of your Hatena-Diary.
15 ;; This program is Elisp program that operates by Emacs.
16 ;; Copyright (C) 2010 hirosandesu
18 ;; This program is free software; you can redistribute it and/or modify
19 ;; it under the terms of the GNU General Public License as published
20 ;; by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
22 ;; This program is distributed in the hope that it will be useful,
23 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
24 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
26 ;; You should have received a copy of the GNU General Public License along with this program.
27 ;; If not, see <http://www.gnu.org/licenses/>.
30 (defconst hatena-version "2.2.0" "Version number of hatena.el")
33 ;; 1) ŬÅö¤Ê¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤³¤Î¥Õ¥¡¥¤¥ë¤ò¤ª¤¯.
34 ;; (~/elisp/ Æâ¤Ë¤ª¤¤¤¿¤È¤¹¤ë).
36 ;; 2) .emacs ¤Ë¼¡¤Î 4 ¹Ô¤òÄɲ乤ë.
37 ;; (setq load-path (cons (expand-file-name "~/elisp") load-path))
38 ;; (load "hatena-diary-mode")
39 ;; (setq hatena-usrid "your username on Hatena::Diary")
40 ;; (setq hatena-plugin-directory "~/elisp")
41 ;; `hatena-use-file' ¤ò non-nil ¤Ë¤¹¤ë¤È¥Ñ¥¹¥ï¡¼¥É¤ò base64 ¤Ç
42 ;; °Å¹æ²½¤·¤Æ¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Þ¤¹¤¬¡¢"¿Í´Ö¤¬¸«¤Æ¤¹¤°¤ï¤«¤é¤Ê¤¤"¤°¤é¤¤¤Î
43 ;; °ÕÌ£¤·¤«¤Ê¤¤¤Î¤ÇÃí°Õ¤·¤Æ²¼¤µ¤¤¡£
48 ;; `M-x hatena' ¤Çº£Æü¤ÎÆüµ¤¬³«¤¤Þ¤¹. ¤¿¤À¤Î¥Æ¥¥¹¥È¥Õ¥¡¥¤¥ë¤Ç¤¹¡£
49 ;; ¥¿¥¤¥È¥ë ¤òÉÕ¤±¤¿¤¤¾ì¹ç¤Ï¡¢°ì¹ÔÌÜ¤Ë "title" ¤È½ñ¤¤¤Æ¡¢¤½¤Î¸å¤Ë¥Æ¥¥¹¥È¤ò
53 ;; Æüµ¤ò½ñ¤¤¤¿¤é, \C-c\C-p ¤Ç send ¤Ç¤¤Þ¤¹.
54 ;; ¥Þ¡¼¥¯¥¢¥Ã¥×¤Ï¡¢¤Ï¤Æ¤Ê¤ÎµË¡¤Ë½¾¤¤¤Þ¤¹¡£
55 ;; \C-ct ¤Ç¡Ö¹¹¿·¡×¤È¡Ö¤Á¤ç¤Ã¤È¤·¤¿¹¹¿·¡×¤òÀڤ꤫¤¨¤Þ¤¹¡£
59 ;; `hatena-change-trivial' "¤Á¤ç¤Ã¤È¤·¤¿¹¹¿·"¤«¤É¤¦¤«¤ò digit ¤ËÊѤ¨¤Þ¤¹¡£
60 ;; `hatena-entry-type' ¥¨¥ó¥È¥ê¤Î "*" ¤ÎÆ°ºî¤òÀڤ꤫¤¨¤Þ¤¹¡£
61 ;; 0 ¤Ç *pn* ¤Ë¡¢1 ¤Ç *t* (¥¿¥¤¥à¥¹¥¿¥ó¥×)¤Ë¤Ê¤ê¤Þ¤¹¡£
63 ;; `hatena-submit' (\C-c\C-p) Æüµ¤ò¤Ï¤Æ¤Ê¤Ë¥Ý¥¹¥È¤·¤Þ¤¹
64 ;; `hatena-delete-diary' ¤½¤ÎÆü¤ÎÆüµ¤ò web ¤«¤éºï½ü.
65 ;; `hatena-find-previous' (\C-c\C-b)
66 ;; `hatena-find-followings' (\C-c\C-f). ¤½¤ì¤¾¤ì¡¢Á°¤ÎÆü¤È¼¡¤ÎÆü¤Î
67 ;; Æüµ¥Õ¥¡¥¤¥ë¤ò³«¤¯¡£°ú¿ô¤òÍ¿¤¨¤ë¤È¤½¤ÎÆü¿ô¤À¤±¥¸¥ã¥ó¥×¡£
68 ;; ( Îã \C 1 2 \C-c\C-b ¤Ç12ÆüÁ° )
69 ;; `hatena-exit' Æüµ buffer ¤ò save ¤·¤Æ ¤¹¤Ù¤Æ kill
70 ;; `hatena-browser-function' ¤Ë 'browse-url ¤È¤«¤ä¤ë¤ÈÆüµ¤ò¥Ý¥¹¥È
71 ;; ¤·¤¿¸å¤½¤ÎÆü url ¤ò°ú¿ô¤È¤·¤Æ¥Ö¥é¥¦¥¶¤ò¸Æ¤Ó¤Þ¤¹.
72 ;; `hatena-insert-webdiary' ¤Ï¤Æ¤Ê¥Ð¥Ã¥Õ¥¡¤Ç¼Â¹Ô¤¹¤ë¤È¡¢¸½ºß web ¤Ë
73 ;; ¥¢¥Ã¥×¤µ¤ì¤Æ¤¤¤ë¥Õ¥¡¥¤¥ë¤ò¼è¤Ã¤Æ¤¯¤ë¡£ o
74 ;; `hatena-twitter' Æüµ¹¹¿·»þ¤ËTwitter¤ËÄÌÃΤ¹¤ë¤«¤É¤¦¤«¤òÊѤ¨¤Þ¤¹¡£
75 ;;¡¡¡¡`hatena-image-insert' ¤Ï¤Æ¤Ê¥Õ¥©¥È¥é¥¤¥Õ¤Ë²èÁü¤ò¥¢¥Ã¥×¥í¡¼¥É¤·
76 ;; ¥¨¥ó¥È¥ê¤Ë²èÁüɽ¼¨ÍѤΥ¿¥°¤òÁÞÆþ¤·¤Þ¤¹¡£
77 ;; `hatena-get-webdiary' http://d.hatena.ne.jp/usrid/export ¤ò
78 ;; ¼è¤Ã¤Æ¤¤ÆÊÑ´¹¡£Â¤ê¤Ê¤¤ÆüµÊ¬¤ò¥Õ¥¡¥¤¥ë¤Ë¤¹¡£
81 ;; hatena-diary-mode ¤Ï¥Ç¥Õ¥©¥ë¥È¤Ç html-mode ¤ËÈ碌¤Æ¤¤¤Þ¤¹¡£¤³¤ì¤ò
82 ;; html-helper-mode ¤Ë¤·¤¿¤±¤ì¤Ð¡¢
84 ;; -(define-derived-mode hatena-diary-mode html-mode "Hatena"
85 ;; +(define-derived-mode hatena-diary-mode html-helper-mode "Hatena"
87 ;; ¤È¤·¤Æ `eval-buffer' ¤·¤Æ²¼¤µ¤¤¡£
90 ;; hook ¤È¤Ï¥é¥¤¥Ö¥é¥ê¤òÆɹþ¤ó¤À»þ¡¢½é´ü²½¤¹¤ë»þ¤Ê¤É¡¢ÆÃÄê¤Î¥¿¥¤¥ß
91 ;; ¥ó¥°¤Ç¸Æ¤Ó½Ð¤·¤¿¤¤´Ø¿ô¤òÊÝ»ý¤¹¤ëÊÑ¿ô¤Ç¤¹¡£hatena-diary-mode ¤Ë¤Ï°Ê²¼¤Î
94 ;; `hatena-diary-mode-hooks' Hatena mode ¤Ë¤·¤¿»þ¤Ë¸Æ¤Ð¤ì¤ë hook .
96 ;; (add-hook 'hatena-diary-mode-hooks
98 ;; (setq line-spacing 8) ;;¹Ô¤¬µÍ¤Þ¤Ã¤Æ¤ë¤È¥¤¥ä¡¢
101 ;; `hatena-diary-mode-submit-hook' Æüµ¤ò¥Ý¥¹¥È`hatena-submit' ¤¹¤ëľÁ°¤Ë
102 ;; ¸Æ¤Ó½Ð¤¹´Ø¿ô¤Ç¤¹¡£Î㤨¤Ð¡¢Ï¢Â³¤·¤Ê¤¤²þ¹Ô¤ò¤¹¤Ù¤Æ½ü¤¯¡¢¤Ê¤É¤Î½èÍý¤¬¹Í¤¨¤é¤ì¤Þ¤¹¡£
104 ;; (add-hook 'hatena-diary-mode-submit-hook
106 ;; (goto-char (point-min))
107 ;; (replace-regexp "\\([^\n]\\)\n\\([^\n]\\)" "\\1\\2")))
109 ;; `hatena-diary-mode-before-submit-hook' Æüµ¤ò¥Ý¥¹¥È `hatena-submit' ¤¹¤ë
110 ;; ľÁ°¤Ë¸Æ¤Ó½Ð¤¹´Ø¿ô¤Ç¤¹¡£`hatena-diary-mode-submit-hook' ¤È¤Ï°ã¤¤¡¢
111 ;; ¤³¤Î¥Õ¥Ã¥¯¤Ç²Ã¤¨¤é¤ì¤¿Êѹ¹¤Ï¼ê¸µ¤Î¥Õ¥¡¥¤¥ë¤Ë¤â»Ä¤ê¤Þ¤¹¡£
114 (require 'hatena-vars)
119 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
122 (if hatena-diary-mode-map
124 (setq hatena-diary-mode-map (make-keymap))
125 (define-key hatena-diary-mode-map "\C-c\C-p" 'hatena-submit)
126 (define-key hatena-diary-mode-map "\C-c\C-b" 'hatena-find-previous)
127 (define-key hatena-diary-mode-map "\C-c\C-f" 'hatena-find-following)
128 (define-key hatena-diary-mode-map "\C-ct" 'hatena-change-trivial)
129 (define-key hatena-diary-mode-map "\C-c\C-i" 'hatena-image-insert)
130 (define-key help-map "4" 'hatena-help-syntax1)
131 (define-key help-map "5" 'hatena-help-syntax2)
132 (define-key help-map "6" 'hatena-help-syntax3)
133 (define-key help-map "7" 'hatena-help-syntax4)
134 (define-key help-map "8" 'hatena-help-syntax5))
136 (defconst hatena-today-buffer nil)
137 (defun hatena (&optional date)
138 "Hatena::Diary ¥Ú¡¼¥¸¤ò³«¤¯. "
140 (unless (file-exists-p hatena-directory)
141 (make-directory hatena-directory t))
144 ;;º£Æü¤ÎÆüµ¤Î¥Ð¥Ã¥Õ¥¡¤ò³Îǧ(cookie ¤Î´ÉÍý¤Î¤¿¤á)
145 ;;¸ºß¤·¤Ê¤±¤ì¤Ð¡¢¥¯¥Ã¥¡¼¤ò¼èÆÀ¤¹¤ë¡£
146 (let ((buffer-new-p t)
148 (if (memq hatena-today-buffer (buffer-list))
149 (setq buffer-new-p nil)
151 (setq hatena-today-buffer
153 (concat hatena-directory (hatena-today-date))))
154 ;;¥Õ¥¡¥¤¥ë¡¢¥Ð¥Ã¥Õ¥¡¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð¡¢web¤ÎÆüµ¤ò¥Á¥§¥Ã¥¯
155 (if (file-exists-p (concat hatena-directory (hatena-today-date)))
156 (setq file-new-p nil))
157 (if (and file-new-p buffer-new-p)
159 (message "Æüµ¥Õ¥¡¥¤¥ë¤â¥Ð¥Ã¥Õ¥¡¤â¤¢¤ê¤Þ¤»¤ó¡£Web¤ò¥Á¥§¥Ã¥¯¤·¤Þ¤¹")
160 (hatena-insert-webdiary)))
163 (if (string-match hatena-fname-regexp date)
164 (find-file (concat hatena-directory date))
174 (define-derived-mode hatena-diary-mode html-mode "Hatena"
176 (font-lock-add-keywords 'hatena-diary-mode
178 (list "^\\(Title\\) \\(.*\\)$"
179 '(1 hatena-header-face t)
180 '(2 hatena-title-face t))
182 (list "\\(<[^\n/].*>\\)\\([^<>\n]*\\)\\(</.*>\\)"
183 '(1 hatena-html-face t)
184 '(2 hatena-link-face t)
185 '(3 hatena-html-face t))
187 (list "^\\(\\*[^\n ]*\\) \\(.*\\)$"
188 '(1 hatena-markup-face t)
189 '(2 hatena-html-face t))
191 (list "\\(\\[?\\(a:id\\|f:id\\|i:id\\|r:id\\|map:id\\|graph:id\\|g.hatena:id\\|b:id:\\|id\\|google\\|isbn\\|asin\\|http\\|http\\|ftp\\|mailto\\|search\\|amazon\\|rakuten\\|jan\\|ean\\|question\\|tex\\):\\(\\([^\n]*\\]\\)\\|[^ ¡¡\n]*\\)\\)"
192 '(1 hatena-markup-face t))
193 (list "^:\\([^:\n]+\\):"
194 '(0 hatena-markup-face t)
195 '(1 hatena-link-face t))
197 '(1 hatena-markup-face t))
198 (list "\\(((\\).*\\())\\)"
199 '(1 hatena-markup-face t)
200 '(2 hatena-markup-Face T))
201 (list "^\\(>>\\|<<\\|><!--\\|--><\\|>\\(|.+\\)?|?|\\||?|<\\)"
202 '(1 hatena-markup-face t))
203 (list "\\(s?https?://\[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#\]+\\)"
204 '(1 hatena-html-face t))))
206 (set-buffer-modified-p nil)
207 (run-hooks 'hatena-diary-mode-hook))
209 ;;hatena-diary-mode ¥È¥°¥ë
210 (setq auto-mode-alist
213 (cons (concat hatena-directory hatena-fname-regexp) 'hatena-diary-mode))
217 (defun hatena-today-date(&optional offset date)
218 ;; date ¤ÏǤ°Õ¤ÎÆüÉÕ¡¢offset ¤ÏǤ°Õ¤Î»þ´Ö¡¢-24 ¤Ç°ìÆü¿Ê¤à
221 (string-match "\\([0-9][0-9][0-9][0-9]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)" date)
223 (string-to-int (match-string 3 date))
224 (string-to-int (match-string 2 date))
225 (string-to-int (match-string 1 date)) 0 nil 32400))
226 (decode-time (current-time))) ))
229 (- (nth 2 lst) (if offset offset hatena-change-day-offset)))
230 (format-time-string "%Y%m%d"
231 (apply 'encode-time lst ))))
233 (defun hatena-w3c-dtf-time-zone-designator (&optional time universal)
235 (let ((time (or time (current-time))))
236 (let ((tzd (format-time-string "%z" time universal)))
239 (if (string-match "\\`\\([-+][0-9][0-9]\\)\\([0-9][0-9]\\)\\'"
241 (concat (match-string-no-properties 1 tzd) ":"
242 (match-string-no-properties 2 tzd))
243 (error (concat "Unexpected return value of "
244 "(format-time-string \"%%z\" time universal): %s")
245 (prin1-to-string tzd))))))))
247 (defun hatena-w3c-dtf-string (&optional time universal)
248 ;; ref. "Date and Time Formats" <http://www.w3.org/TR/NOTE-datetime>.
249 (let ((time (or time (current-time))))
250 (concat (format-time-string "%Y-%m-%dT%T" time universal)
251 (hatena-w3c-dtf-time-zone-designator time universal))))
253 (defun hatena-set-datetime-attribute-to-ins-and-del-elements ()
254 "¥Ð¥Ã¥Õ¥¡Æâ¤Î¤¹¤Ù¤Æ¤ÎINSÍ×ÁÇ¡¦DELÍ×ÁǤ˸½ºß»þ¹ï¤ÎDATETIME°À¤ò
255 ¥»¥Ã¥È¤¹¤ë¡£´û¤ËDATETIME°À¤¬¥»¥Ã¥È¤µ¤ì¤Æ¤¤¤ëÍ×ÁǤÏÊѹ¹¤·¤Ê¤¤¡£"
260 (goto-char (point-min))
261 (while (re-search-forward
262 "<\\(ins\\|del\\)\\([ \t\r\n]*\\|[ \t\r\n]+[^>]+?\\)>" nil t)
265 (string-match "[ \t\r\n]datetime[ \t\r\n]*=[ \t\r\n]*['\"]"
269 (match-string 1) ;"ins" or "del"
270 " datetime=\"" (hatena-w3c-dtf-string) "\""
271 (match-string 2) ;attributes
274 (defun hatena-submit (&optional file userid)
275 "¤Ï¤Æ¤ÊÆüµ http://d.hatena.ne.jp/ ¤Ë post ¥á¥½¥Ã¥É¤ÇÆüµ¤òÁ÷¤ë. curl ¤ò»È¤¦. "
279 (setq file buffer-file-name)
281 (run-hooks 'hatena-diary-mode-before-submit-hook)
282 ;;"*t*" ¤Ë¤¹¤ë¤« "*pn*" ¤Ë¤¹¤ë¤«
283 (cond ( (= hatena-entry-type 0)
287 (goto-char (point-min))
288 (while (re-search-forward "^\\*p\\([0-9]\\)\\*" nil t)
289 (if (< i (setq j (string-to-int (match-string 1))))
291 (goto-char (point-min))
292 (while (re-search-forward "^\\(\\*\\)\\([[ ]\\)" nil t)
294 (concat "*p" (format "%d" (setq i (1+ i))) "*\\2")
296 ( (= hatena-entry-type 1)
298 (goto-char (point-min))
299 (while (re-search-forward "^\\(\\*\\)\\([[ ]\\)" nil t)
305 ;;¥¿¥¤¥È¥ë¤Î*t*¤ò»þ´Ö¤ËÃÖ¤¤«¤¨¤ë
306 (goto-char (point-min))
308 (while (re-search-forward "^\\*t\\*" nil t)
310 (concat "*" (hatena-current-second i) "*")
313 ;; INSÍ×ÁÇ¡¦DELÍ×ÁǤ˸½ºß»þ¹ï¤ÎDATETIME°À¤ò¥»¥Ã¥È¤¹¤ë¡£
314 (hatena-set-datetime-attribute-to-ins-and-del-elements))
318 (setq userid hatena-usrid))
320 (let ((filename (file-name-nondirectory file)))
321 (if (string-match hatena-fname-regexp filename)
323 ((year (match-string 1 filename))
324 (month (match-string 2 filename))
325 (day (match-string 3 filename))
326 (date (concat year month day))
327 ;;¤Ï¤Æ¤Ê¤ËÄÌÃΤ¹¤ë¥¿¥¤¥à¥¹¥¿¥ó¥×
329 (format-time-string "%Y%m%d%H%m%S" (current-time)))
331 (baseurl (concat "http://d.hatena.ne.jp/" userid "/"))
332 (referer (concat baseurl "edit?date=" date))
333 (nexturl (concat baseurl (concat year month day)))
334 (url (concat baseurl "edit"))
340 (insert-file-contents send-file)
341 ;; ¥Ð¥Ã¥Õ¥¡¤òÁ÷¤ëÁ°¤Ë¸Æ¤Ð¤ì¤ë hooks
342 (run-hooks 'hatena-diary-mode-submit-hook)
343 (cond ( (string-match "\\`title[ ¡¡]*\\(.*\\)?\n" (buffer-string))
345 (setq title (match-string 1 (buffer-string)))
346 (substring (buffer-string)
347 (length (match-string 0 (buffer-string))))
350 ( (string-match hatena-header-regexp (buffer-string))
352 (setq title (match-string 1 (buffer-string)))
353 (substring (buffer-string)
354 (1+ (length (match-string 0 (buffer-string)))))) )
355 (t (buffer-string)))))
356 (body (hatena-url-encode-string full-body hatena-default-coding-system))
357 (trivial (if hatena-trivial "1" "0"))
358 (twit (hatena-url-encode-string hatena-twitter-prefix hatena-default-coding-system))
368 "&twitter_notification_enabled=" (if hatena-twitter-flag "1" "")
369 "&twitter_notification_prefix=" twit
370 ;; session ID for POST to hatena
371 ;; this is a scheme of ensuring security in Hatena::Diary
373 (let* ((md5sum (md5 (with-temp-buffer
374 (insert-file-contents hatena-cookie)
375 (re-search-forward "rk\\s \\([0-9a-zA-Z]+\\)")
376 (concat (buffer-substring
378 (match-end 1)))) nil nil 'utf-8))
381 (while (> (length md5sum) p)
385 (char-to-string (string-to-number
386 (substring md5sum p (+ p 2)) 16))))
388 (substring (base64-encode-string temp) 0 22)))
389 ;; if "date" element exists ,
390 ;; command can't create the new page at hatena
391 (if (hatena-check-newpage referer)
392 (concat "&date=" date))
393 "×tamp=" timestamp )))
395 (with-temp-file hatena-tmpfile
398 (message "%s => %s" filename referer)
399 (call-process hatena-curl-command nil nil nil
402 "--data" (concat "@" hatena-tmpfile)
406 (and (functionp hatena-browser-function)
407 (funcall hatena-browser-function nexturl))
409 (error "Not Hatena file: %s" file)))
410 (setq hatena-twitter-prefix nil))
412 (defun hatena-login ()
414 (if (file-exists-p hatena-cookie)
415 (delete-file hatena-cookie))
416 (message (concat "logging in to \"" hatena-url "\" as \"" hatena-usrid "\""))
417 (let ((password (hatena-ask-password)))
419 (call-process hatena-curl-command nil nil nil
420 "-k" "-c" hatena-cookie
422 "-d" (concat "name=" (hatena-url-encode-string hatena-usrid))
423 "-d" (concat "password=" (hatena-url-encode-string password))
424 "-d" (concat "autologin=1")
425 "-d" (concat "mode=enter")
426 "https://www.hatena.ne.jp/login"))
427 (message "Say HAPPY! to Hatena::Diary"))
430 (defun hatena-check-newpage (urldate)
431 "¥Ú¡¼¥¸¤¬ºîÀ®ºÑ¤ß¤«¤É¤¦¤«¥Á¥§¥Ã¥¯"
432 (message "checking diary ....")
433 (call-process hatena-curl-command nil nil nil
438 (find-file hatena-tmpfile2)
440 (string-match "name=\"date\""
444 (message "modify diary")
446 (message "make new diary") nil))
448 (defun hatena-diary-file-p(file)
449 (let ((fname (file-name-nondirectory file)))
450 (if (string-match hatena-fname-regexp fname) t nil)))
452 (defun hatena-get-diary-string(&optional date)
453 "¤Ï¤Æ¤Ê¤Ë¤¢¤ëÆüµ¥Õ¥¡¥¤¥ë¤ò¼è¤ê¡¢¤½¤Îʸ»úÎó¤òÊÖ¤¹¡£
454 ¥í¥°¥¤¥ó¤·¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£"
455 (if (not date) (error "not date"))
456 (message "checking diary of %s ...." date)
457 (let ((urldate (concat "http://d.hatena.ne.jp/"
461 (call-process hatena-curl-command nil nil nil
467 (insert-file-contents hatena-tmpfile)
469 (goto-char (point-min))(while (replace-string """ "\""))
470 (goto-char (point-min))(while (replace-string "&" "&"))
471 (goto-char (point-min))(while (replace-string ">" ">"))
472 (goto-char (point-min))(while (replace-string "<" "<"))
473 (goto-char (point-min))(while (replace-string "'" "'"))
475 (if (string-match "<textarea[^>\n]*>\\(\\(\n\\|.\\)*?\\)</textarea>"
477 (match-string 1 (buffer-string)) nil)))
479 (defun hatena-insert-webdiary(&optional date)
480 "web ¤ÎÆüµ¤òÁÞÆþ¤¹¤ë¡£"
483 (setq date (file-name-nondirectory buffer-file-name)))
484 (if (string-match hatena-fname-regexp date)
485 (insert (hatena-get-diary-string date))
486 (error "not date or hatena file")))
488 (defun hatena-delete-diary(&optional file userid)
489 "Æüµ¤òºï½ü¤¹¤ë¡£¥í¡¼¥«¥ë¤Ïºï½ü¤·¤Ê¤¤¡£"
491 ;;¥Ð¥Ã¥Õ¥¡¤«¤éÆɤà¤ÈÁ÷¿®»þ´Ö¤Î¤È¤³¤í¤Ë"deleted"
493 (setq file buffer-file-name))
495 (setq userid hatena-usrid))
496 (let ((filename (file-name-nondirectory file)))
497 (if (string-match hatena-fname-regexp filename)
499 ((year (match-string 1 filename))
500 (month (match-string 2 filename))
501 (day (match-string 3 filename))
502 (date (concat year month day))
503 (baseurl (concat "http://d.hatena.ne.jp/" userid "/"))
504 (referer (concat baseurl "edit?date=" date))
505 (url (concat baseurl "edit"))
507 (edit (hatena-url-encode-string "¤³¤ÎÆü¤òºï½ü"))
515 (insert-file-contents hatena-cookie)
516 (re-search-forward "rk\\s \\([0-9a-zA-Z]+\\)")
517 (concat (buffer-substring
519 (match-end 1)))) nil nil 'utf-8))
522 (while (> (length md5sum) p)
526 (char-to-string (string-to-number
527 (substring md5sum p (+ p 2)) 16))))
529 (substring (base64-encode-string temp) 0 22)))
531 (message "deleting %s" referer)
532 (with-temp-file hatena-tmpfile (insert post-data))
534 (call-process hatena-curl-command nil nil nil
537 "--data" (concat "@" hatena-tmpfile)
541 (error "Not Hatena file: %s" file))))
543 (defun hatena-logout()
545 (call-process hatena-curl-command nil nil nil
548 "http://d.hatena.ne.jp/logout")
549 (message "logged out from d.hatena.ne.jp"))
551 (defun hatena-ask-password()
553 (if (null hatena-use-file)
554 (setq pass (read-passwd "password ? : "))
555 ;;¥Õ¥¡¥¤¥ë¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ïºî¤ë¡£
556 (if (not (file-exists-p hatena-password-file))
557 (append-to-file (point) (point) hatena-password-file))
558 (setq str (with-temp-buffer nil
559 (insert-file-contents hatena-password-file)
561 (if (string-match "[^ ]+" str)
562 (setq pass (base64-decode-string (match-string 0 str)))
563 (setq pass (read-passwd "password ? : "))
564 (with-temp-file hatena-password-file
565 (insert (base64-encode-string
566 (format "%s" pass)))))
570 "hatena-fname-regexp¤Ë¥Þ¥Ã¥Á¤¹¤ë¥Ð¥Ã¥Õ¥¡¤ò¤¹¤Ù¤ÆÊݸ¤·¤Æ¾Ãµî"
572 (if (yes-or-no-p "save all diaries and kill buffer ?")
574 (let ((buflist (buffer-list))
576 (while (< i (length buflist))
577 (let ((bufname (buffer-name (nth i (buffer-list)))))
578 (if (string-match hatena-fname-regexp bufname)
580 (if (buffer-modified-p (nth i (buffer-list)))
581 (save-buffer (nth i (buffer-list))))
582 (kill-buffer (nth i (buffer-list)))))
583 (setq i (1+ i))))))))
585 (defun hatena-find-previous (&optional count file)
586 "count ÆüÁ°¤ÎÆüµ¤ò³«¤¯ count ¤¬ nil ¤Ê¤é°ìÆü¤À¤±Ìá¤ë"
588 (hatena-find-pf (if count (- count) -1) (buffer-name)))
590 (defun hatena-find-following (&optional count file)
591 "count Æü¸å¤ÎÆüµ¤ò³«¤¯ count ¤¬ nil ¤Ê¤é°ìÆü¤À¤±¤¹¤¹¤à"
593 (hatena-find-pf (if count count 1) (buffer-name)))
595 (defun hatena-find-pf(count &optional file)
596 (if (equal major-mode 'hatena-diary-mode)
598 (setq file (buffer-name)))
599 (error "not hatena mode"))
601 (lambda (element count lst)
602 (let* ((sublst (member element lst))
603 (result (+ (- (length lst) (length sublst))
605 (if (or (null sublst)
610 (funcall find-previous
611 (file-name-nondirectory file)
612 (if (not count) 1 count)
615 nil hatena-fname-regexp)))
616 (if previous (find-file (concat (file-name-directory file) previous))
617 ;;¸«¤Ä¤«¤é¤Ê¤¤»þ¤Ï¡¢Ì¤Íè¤ÎÆüÉÕ¤ò¿Ò¤Í¤ë¡£
618 (let ((filename (read-string "ºîÀ®¤·¤¿¤¤ÆüÉÕ¤òÆþÎÏ: "
619 (hatena-today-date (* -24 count) (buffer-name)) nil)))
620 (if (string-match hatena-fname-regexp filename)
624 (error "ÆüÉÕ¥Õ¥¡¥¤¥ë¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó!!"))))))
626 (defun hatena-get-webdiary ()
627 "http://d.hatena.ne.jp/usrid/export ¤ò¼è¤Ã¤Æ¤¤ÆÊÑ´¹¡£Â¤ê¤Ê¤¤ÆüµÊ¬¤ò¥Õ¥¡¥¤¥ë¤Ë¤¹¡£"
630 (call-process hatena-curl-command nil nil nil
633 (concat "http://d.hatena.ne.jp/" hatena-usrid "/export" ))
635 ;;export ¤Ï utf-8 ¤Ê¤Î¤Ç¡¢hatena-default-coding-system ¤Ëľ¤¹¡£
636 (let ((filelst (directory-files
638 nil hatena-fname-regexp))
639 (title-regexp "<day date=\"\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)\" title=\"\\(.*\\)\">\n<body>\n")
640 pt-start pt-end day title body)
643 (insert-file-contents hatena-tmpfile)
644 (set-buffer-file-coding-system hatena-default-coding-system)
645 (hatena-translate-reverse-region (point-min) (point-max))
647 (while (re-search-forward title-regexp nil t)
648 (setq day (concat (match-string 1) (match-string 2) (match-string 3)))
649 (setq title (match-string 4))
650 (setq pt-start (match-end 0))
651 (re-search-forward "</body>\n" nil t)
652 (setq pt-end (match-beginning 0))
653 (setq body (buffer-substring pt-start pt-end))
655 (if (null (member day filelst))
658 (set-buffer-file-coding-system hatena-default-coding-system)
659 (message "creatig %s" day)
662 (kill-buffer (current-buffer))))))
663 (message "finished"))))
667 (defun hatena-url-encode-string (str &optional coding)
668 "w3m-url-encode-string ¤«¤é¥³¥Ô¡¼"
669 (apply (function concat)
673 ((eq ch ?\n) ; newline
675 ((string-match "[-a-zA-Z0-9_:/.]" (char-to-string ch)) ; xxx?
676 (char-to-string ch)) ; printable
677 ((char-equal ch ?\x20) ; space
680 (format "%%%02x" ch)))) ; escape
681 ;; Coerce a string to a list of chars.
682 (append (encode-coding-string (or str "")
684 buffer-file-coding-system
688 (defun hatena-twitter-prefix-input (ts)
689 "Æüµ¹¹¿·»þ¤ÎÆâÍÆÆþÎÏ"
690 (interactive "sTwitter prefix:")
691 (setq hatena-twitter-prefix ts))
693 ;----------------Æüìʸ»ú¤ÎÊÑ´¹----------------
695 (defvar hatena-entity-reference-chars-alist
696 '((?> . "gt") (?< . "lt") (?& . "amp") (?\" . "quot"))
697 "translation table from character to entity reference")
698 (defvar hatena-entity-reference-chars-regexp "[><&\\]")
699 (defvar hatena-entity-reference-chars-reverse-regexp "&\\(gt\\|lt\\|amp\\|quot\\);")
701 (defun hatena-translate-region (beg end)
702 "Translate inhibited literals."
706 (narrow-to-region beg end)
707 (let ((ct hatena-entity-reference-chars-alist))
709 (while (re-search-forward hatena-entity-reference-chars-regexp nil t)
711 (concat "&" (cdr (assoc (preceding-char) ct)) ";")))))))
713 (defun hatena-translate-reverse-region (beg end)
714 "Translate entity references to literals."
718 (narrow-to-region beg end)
719 (let ((ct hatena-entity-reference-chars-alist))
721 (while (re-search-forward
722 hatena-entity-reference-chars-reverse-regexp nil t)
723 ;(setq c (preceding-char))
726 (rassoc (match-string 1)
729 (defun hatena-change-trivial ()
731 (if (not hatena-trivial)
733 (message "¤Á¤ç¤Ã¤È¤·¤¿¹¹¿·¥â¡¼¥É")
734 (setq hatena-trivial t))
735 (setq hatena-trivial nil)
736 (message "¹¹¿·¥â¡¼¥É")))
738 (defun hatena-twitter ()
740 (if (not hatena-twitter-flag)
742 (message "twitter¤ËÄÌÃÎ")
743 (setq hatena-twitter-flag t))
744 (setq hatena-twitter-flag nil)
745 (message "twitter¤Ë¤ÏÄÌÃΤ·¤Ê¤¤")))
747 (defun hatena-current-second(number)
748 "¸½ºß¤Þ¤Ç¤ÎÉÿô¤òÊÖ¤¹¡£emacs ¤Ç¤ÏÀ°¿ô¤¬¥±¥¿°î¤ì¤¹¤ë¤Î¤Ç¡¢ÉâÆ°¾®¿ôÅÀ¤Ç"
749 (let* ((ct (current-time))
750 (high (float (car ct)))
751 (low (float (car (cdr ct))))
753 (setq str (format "%f"(+
754 (+ (* high (lsh 2 15)) low)
756 (substring str 0 10) ;;
760 ;-------------------------------------------
762 (defun hatena-help-syntax1 ()
763 "¤Ï¤Æ¤ÊµË¡ ¥Ø¥ë¥×Ìܼ¡¤òɽ¼¨¤¹¤ë"
765 (describe-variable 'hatena-help-syntax-index))
767 (defun hatena-help-syntax2 ()
768 "¤Ï¤Æ¤ÊµË¡ ÆþÎϻٱçµË¡¤Î¥Ø¥ë¥×¤òɽ¼¨¤¹¤ë"
770 (describe-variable 'hatena-help-syntax-input))
772 (defun hatena-help-syntax3 ()
773 "¤Ï¤Æ¤ÊµË¡ ¼«Æ°¥ê¥ó¥¯¤Î¥Ø¥ë¥×¤òɽ¼¨¤¹¤ë"
775 (describe-variable 'hatena-help-syntax-autolink))
777 (defun hatena-help-syntax4 ()
778 "¤Ï¤Æ¤ÊµË¡ ¤Ï¤Æ¤ÊÆ⼫ư¥ê¥ó¥¯¤Î¥Ø¥ë¥×¤òɽ¼¨¤¹¤ë"
780 (describe-variable 'hatena-help-syntax-hatena-autolink))
782 (defun hatena-help-syntax5 ()
783 "¤Ï¤Æ¤ÊµË¡ ÆþÎϻٱ絡ǽ¤Î¥Ø¥ë¥×¤òɽ¼¨¤¹¤ë"
785 (describe-variable 'hatena-help-syntax-other))
788 (defun hatena-image-insert (filename filesize)
789 "²èÁü¤ò¤Ï¤Æ¤Ê¥Õ¥©¥È¥é¥¤¥Õ¤Ë¥¢¥Ã¥×¥í¡¼¥É¤·¡¢Æüµ¤ËÁÞÆþ¤¹¤ë"
790 (interactive "fImage File:\nsFile Size:")
792 ((extension (upcase (substring filename (- (length filename) 3))))
793 (baseurl (concat "http://f.hatena.ne.jp/" hatena-usrid "/"))
794 (url (concat baseurl "up"))
796 (let* ((md5sum (md5 (with-temp-buffer
797 (insert-file-contents hatena-cookie)
798 (re-search-forward "rk\\s \\([0-9a-zA-Z]+\\)")
799 (concat (buffer-substring
801 (match-end 1)))) nil nil 'utf-8))
804 (while (> (length md5sum) p)
808 (char-to-string (string-to-number
809 (substring md5sum p (+ p 2)) 16))))
811 (substring (base64-encode-string temp) 0 22))))
813 ((or (string= extension "JPG") (string= extension "GIF") (string= extension "PNG"))
815 (call-process hatena-curl-command nil t nil
819 "-F" (concat "rkm=" rkm)
822 "-F" (concat "size=" filesize)
824 "-F" (concat "image1=@" (expand-file-name filename))
826 (goto-char (point-min))
827 (re-search-forward "check-\\([0-9]+\\)")
828 (setq hatena-photo (concat "[f:id:" hatena-usrid ":" (buffer-substring
832 (insert hatena-photo)
834 (insert-image (create-image (expand-file-name filename)))
838 (provide 'hatena-diary-mode)