X-Git-Url: http://git.chise.org/gitweb/?p=elisp%2Fmixi.git;a=blobdiff_plain;f=mixi.el;h=9951032dd53441447af8fa9f004cbb87a8ecbf3e;hp=fdd5a1bdb3d6cec9f6f3d020fa348c70aaf25a6c;hb=d4bda9bf34d0cd8b4a323241101dc0b94889a442;hpb=70d0224f944ac380e6a0b49a31d94a5e6fcf2d42 diff --git a/mixi.el b/mixi.el index fdd5a1b..9951032 100644 --- a/mixi.el +++ b/mixi.el @@ -1,6 +1,6 @@ -;; mixi.el --- API library for accessing to mixi +;; mixi.el --- API libraries for accessing to mixi -*- coding: euc-jp -*- -;; Copyright (C) 2005,2006 OHASHI Akira +;; Copyright (C) 2005, 2006, 2007, 2008 OHASHI Akira ;; Author: OHASHI Akira ;; Keywords: hypermedia @@ -18,42 +18,50 @@ ;; 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, you can either send email to this -;; program's maintainer or write to: The Free Software Foundation, -;; Inc.; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Commentary: -;; API for getting contents: +;; APIs for getting contents: ;; ;; * mixi-get-friends ;; * mixi-get-favorites ;; * mixi-get-logs +;; * mixi-get-recommended-friends (indies) ;; * mixi-get-diaries ;; * mixi-get-new-diaries ;; * mixi-search-diaries ;; * mixi-get-communities ;; * mixi-search-communities +;; * mixi-get-recommended-communities (indies) ;; * mixi-get-bbses ;; * mixi-get-new-bbses ;; * mixi-search-bbses ;; * mixi-get-comments ;; * mixi-get-new-comments +;; * mixi-get-new-bbs-comments ;; * mixi-get-messages -;; * mixi-get-introductions +;; * mixi-get-introductions (broken) +;; * mixi-get-news +;; * mixi-get-releases +;; * mixi-get-echoes (limited) +;; * mixi-get-new-echoes (limited) ;; -;; API for posting: +;; APIs for posting: ;; ;; * mixi-post-diary ;; * mixi-post-topic ;; * mixi-post-comment ;; * mixi-post-message +;; * mixi-post-echo (limited) ;; ;; Utilities: ;; -;; * mixi-remove-markup +;; * mixi-remove-markup (half broken) -;; Example: +;; Examples: ;; ;; Display newest 3 diaries like a mail format. ;; @@ -61,16 +69,18 @@ ;; (buffer (get-buffer-create "*temp*")) ;; (format "%Y/%m/%d %H:%M")) ;; (pop-to-buffer buffer) -;; (mapc (lambda (diary) -;; (let ((subject (mixi-diary-title diary)) -;; (from (mixi-friend-nick (mixi-diary-owner diary))) -;; (date (format-time-string format (mixi-diary-time diary))) -;; (body (mixi-remove-markup (mixi-diary-content diary)))) -;; (insert "From: " from "\n" -;; "Subject: " subject "\n" -;; "Date: " date "\n\n" -;; body "\n\n"))) -;; (mixi-get-new-diaries range)) +;; (let ((diaries (mixi-get-new-diaries range))) +;; (while diaries +;; (let* ((diary (car diaries)) +;; (subject (mixi-diary-title diary)) +;; (from (mixi-friend-nick (mixi-diary-owner diary))) +;; (date (format-time-string format (mixi-diary-time diary))) +;; (body (mixi-remove-markup (mixi-diary-content diary)))) +;; (insert "From: " from "\n" +;; "Subject: " subject "\n" +;; "Date: " date "\n\n" +;; body "\n\n")) +;; (setq diaries (cdr diaries)))) ;; (set-buffer-modified-p nil) ;; (setq buffer-read-only t) ;; (goto-char (point-min))) @@ -82,29 +92,31 @@ ;; (buffer (get-buffer-create "*temp*")) ;; (format "%Y/%m/%d %H:%M")) ;; (pop-to-buffer buffer) -;; (mapc (lambda (diary) -;; (let ((subject (mixi-diary-title diary)) -;; (from (mixi-friend-nick (mixi-diary-owner diary))) -;; (date (format-time-string format (mixi-diary-time diary))) -;; (body (mixi-remove-markup (mixi-diary-content diary)))) -;; (insert "From: " from "\n" -;; "Subject: " subject "\n" -;; "Date: " date "\n\n" -;; body "\n\n") -;; (mapc (lambda (comment) -;; (let ((from (mixi-friend-nick -;; (mixi-comment-owner comment))) -;; (subject (concat "Re: " subject)) -;; (date (format-time-string -;; format (mixi-comment-time comment))) -;; (body (mixi-remove-markup -;; (mixi-comment-content comment)))) -;; (insert "From: " from "\n" -;; "Subject: " subject "\n" -;; "Date: " date "\n\n" -;; body "\n\n"))) -;; (mixi-get-comments diary range)))) -;; (mixi-get-new-diaries range)) +;; (let ((diaries (mixi-get-new-diaries range))) +;; (while diaries +;; (let* ((diary (car diaries)) +;; (subject (mixi-diary-title diary)) +;; (from (mixi-friend-nick (mixi-diary-owner diary))) +;; (date (format-time-string format (mixi-diary-time diary))) +;; (body (mixi-remove-markup (mixi-diary-content diary)))) +;; (insert "From: " from "\n" +;; "Subject: " subject "\n" +;; "Date: " date "\n\n" +;; body "\n\n") +;; (let ((comments (mixi-get-comments diary range))) +;; (while comments +;; (let* ((comment (car comments)) +;; (from (mixi-friend-nick (mixi-comment-owner comment))) +;; (subject (concat "Re: " subject)) +;; (date (format-time-string format +;; (mixi-comment-time comment))) +;; (body (mixi-remove-markup (mixi-comment-content comment)))) +;; (insert "From: " from "\n" +;; "Subject: " subject "\n" +;; "Date: " date "\n\n" +;; body "\n\n")) +;; (setq comments (cdr comments))))) +;; (setq diaries (cdr diaries)))) ;; (set-buffer-modified-p nil) ;; (setq buffer-read-only t) ;; (goto-char (point-min))) @@ -118,6 +130,16 @@ (eval-when-compile (require 'cl)) +;; Functions and variables which should be defined in the other module +;; at run-time. +(eval-when-compile + (defvar w3m-use-cookies) + (autoload 'w3m-decode-buffer "w3m") + (autoload 'w3m-retrieve "w3m") + (autoload 'url-retrieve-synchronously "url")) + +(defconst mixi-revision "$Revision: 1.198 $") + (defgroup mixi nil "API library for accessing to mixi." :group 'hypermedia) @@ -171,6 +193,11 @@ (symbol :tag "The other backend")) :group 'mixi) +(defcustom mixi-login-use-ssl nil + "*If non-ni, login using SSL." + :type 'boolean + :group 'mixi) + (defcustom mixi-default-email nil "*Default E-mail address that is used to login automatically." :type '(radio (string :tag "E-mail address") @@ -207,6 +234,7 @@ Increase this value when unexpected error frequently occurs." :type 'boolean :group 'mixi) +(defvar mixi-temp-buffer-name " *mixi temp*") (defvar mixi-me nil) ;; Utilities. @@ -224,14 +252,13 @@ Increase this value when unexpected error frequently occurs." 'error-conditions '(mixi-post-error error)) (defmacro mixi-realization-error (type object) - `(let ((data (if (and (boundp 'buffer) debug-on-error) - (list ,type ,object buffer) + `(let ((data (if debug-on-error + (list ,type ,object (buffer-string)) (list ,type ,object)))) (signal 'mixi-realization-error data))) (defmacro mixi-post-error (type &optional object) - `(let ((data (when (and (boundp 'buffer) debug-on-error) - (list buffer)))) + `(let ((data (when debug-on-error (list (buffer-string))))) (if ,object (setq data (cons ,type (cons ,object data))) (setq data (cons ,type data))) @@ -245,9 +272,7 @@ Increase this value when unexpected error frequently occurs." ¿·¤ÏÀ©¸Â¤µ¤»¤Æ¤¤¤¿¤À¤¤¤Æ¤ª¤ê¤Þ¤¹¡£¤´ÌÂÏǤò¤ª¤«¤±¤¤¤¿¤·¤Þ¤¹¤¬¡¢¤·¤Ð¤é¤¯¤ª
ÂÔ¤Á¤¤¤¿¤À¤¤¤Æ¤«¤éÁàºî¤ò¤ª¤³¤Ê¤Ã¤Æ¤¯¤À¤µ¤¤¡£") (defconst mixi-warning-continuously-accessing - "´Ö³Ö¤ò¶õ¤±¤Ê¤¤Ï¢Â³Åª¤Ê¥Ú¡¼¥¸¤ÎÁ«°Ü¡¦¹¹¿·¤òÉÑÈˤˤª¤³¤Ê¤ï¤ì¤Æ¤¤¤ë¤³¤È¤¬¸«
-¼õ¤±¤é¤ì¤Þ¤·¤¿¤Î¤Ç¡¢°ì»þŪ¤ËÁàºî¤òÄä»ß¤µ¤»¤Æ¤¤¤¿¤À¤­¤Þ¤¹¡£¿½¤·Ìõ¤´¤¶¤¤¤Þ
-¤»¤ó¤¬¡¢¤·¤Ð¤é¤¯¤Î´Ö¤ªÂÔ¤Á¤¯¤À¤µ¤¤¡£") + "´Ö³Ö¤ò¶õ¤±¤Ê¤¤Ï¢Â³Åª¤Ê¥Ú¡¼¥¸¤ÎÁ«°Ü¡¦¹¹¿·¤òÉÑÈˤˤª¤³¤Ê¤ï¤ì¤Æ¤¤¤ë¤³¤È¤¬¸«¼õ¤±¤é¤ì¤Þ¤·¤¿¤Î¤Ç¡¢°ì»þŪ¤ËÁàºî¤òÄä»ß¤µ¤»¤Æ¤¤¤¿¤À¤­¤Þ¤¹¡£¿½¤·Ìõ¤´¤¶¤¤¤Þ¤»¤ó¤¬¡¢¤·¤Ð¤é¤¯¤Î´Ö¤ªÂÔ¤Á¤¯¤À¤µ¤¤¡£") (defmacro mixi-retrieve (url &optional post-data) `(funcall (intern (concat "mixi-" (symbol-name mixi-backend) "-retrieve")) @@ -272,11 +297,11 @@ Increase this value when unexpected error frequently occurs." (mixi-retrieve url post-data))) (defmacro mixi-expand-url (url) - `(if (string-match (concat "^" mixi-url) ,url) + `(if (string-match "^http" ,url) ,url (concat mixi-url ,url))) -;; FIXME: Support file, checkbox and so on. +;; FIXME: Support files. (defun mixi-make-form-data (fields) "Make form data and return (CONTENT-TYPE . FORM-DATA)." (let* ((boundary (apply 'format "--_%d_%d_%d" (current-time))) @@ -298,16 +323,17 @@ Increase this value when unexpected error frequently occurs." (url-request-data post-data) (url-request-extra-headers extra-headers) (url (mixi-expand-url url)) + url-show-status (buffer (url-retrieve-synchronously url)) ret) (unless (bufferp buffer) - (error (mixi-message "Cannot retrieve"))) + (error (mixi-message "Cannot retrieve: " url))) (with-current-buffer buffer (goto-char (point-min)) (while (looking-at "HTTP/[0-9]+\\.[0-9]+ [13][0-9][0-9]") (delete-region (point) (re-search-forward "\r?\n\r?\n"))) (unless (looking-at "HTTP/[0-9]+\\.[0-9]+ 200") - (error (mixi-message "Cannot retrieve"))) + (error (mixi-message "Cannot retrieve: " url))) (delete-region (point) (re-search-forward "\r?\n\r?\n")) (setq ret (decode-coding-string (buffer-string) mixi-coding-system)) (kill-buffer buffer) @@ -323,7 +349,7 @@ Increase this value when unexpected error frequently occurs." (let ((url (mixi-expand-url url))) (with-temp-buffer (if (not (string= (w3m-retrieve url nil nil post-data) "text/html")) - (error (mixi-message "Cannot retrieve")) + (error (mixi-message "Cannot retrieve: " url)) (w3m-decode-buffer url) (let ((ret (buffer-substring-no-properties (point-min) (point-max)))) (mixi-parse-buffer url ret post-data)))))) @@ -332,7 +358,7 @@ Increase this value when unexpected error frequently occurs." (let ((form-data (mixi-make-form-data fields))) (mixi-w3m-retrieve url form-data))) -(defun mixi-curl-retrieve (url &optional post-data) +(defun mixi-curl-retrieve (url &optional post-data form-data) "Retrieve the URL and return gotten strings." (with-temp-buffer (if (fboundp 'set-buffer-multibyte) @@ -348,6 +374,7 @@ Increase this value when unexpected error frequently occurs." (apply #'start-process "curl" (current-buffer) mixi-curl-program (append (if post-data '("-d" "@-")) + form-data (list "-i" "-L" "-s" "-b" mixi-curl-cookie-file "-c" mixi-curl-cookie-file @@ -363,13 +390,24 @@ Increase this value when unexpected error frequently occurs." (while (looking-at "HTTP/[0-9]+\\.[0-9]+ [13][0-9][0-9]") (delete-region (point) (re-search-forward "\r?\n\r?\n"))) (unless (looking-at "HTTP/[0-9]+\\.[0-9]+ 200") - (error (mixi-message "Cannot retrieve"))) + (error (mixi-message "Cannot retrieve: " url))) (delete-region (point) (re-search-forward "\r?\n\r?\n")) (setq ret (decode-coding-string (buffer-string) mixi-coding-system)) (mixi-parse-buffer url ret post-data)))) +(defun mixi-curl-post-form (url fields) + (let (form-data) + (mapcar (lambda (field) + (push "-F" form-data) + (push (concat (car field) "=" + (encode-coding-string (cdr field) + mixi-coding-system)) + form-data)) + fields) + (mixi-curl-retrieve url nil (reverse form-data)))) + (defconst mixi-my-id-regexp - "") + (defmacro with-mixi-retrieve (url &rest body) - `(let (buffer) + `(with-current-buffer (get-buffer-create mixi-temp-buffer-name) (when ,url - (setq buffer (mixi-retrieve ,url)) - (when (string-match "
" - buffer) + (erase-buffer) + (insert (mixi-retrieve ,url)) + (goto-char (point-min)) + (when (search-forward mixi-login-form nil t) (mixi-login) - (setq buffer (mixi-retrieve ,url)))) + (erase-buffer) + (insert (mixi-retrieve ,url)))) + (goto-char (point-min)) ,@body)) (put 'with-mixi-retrieve 'lisp-indent-function 'defun) -(put 'with-mixi-retrieve 'edebug-form-spec '(form body)) +(put 'with-mixi-retrieve 'edebug-form-spec '(body)) (defmacro with-mixi-post-form (url fields &rest body) - `(let (buffer) + `(with-current-buffer (get-buffer-create mixi-temp-buffer-name) (when ,url - (setq buffer (mixi-post-form ,url ,fields)) - (when (string-match "" - buffer) + (erase-buffer) + (insert (mixi-post-form ,url ,fields)) + (goto-char (point-min)) + (when (search-forward mixi-login-form nil t) (mixi-login) - (setq buffer (mixi-post-form ,url ,fields)))) + (erase-buffer) + (insert (mixi-post-form ,url ,fields)))) + (goto-char (point-min)) ,@body)) (put 'with-mixi-post-form 'lisp-indent-function 'defun) -(put 'with-mixi-post-form 'edebug-form-spec '(form body)) +(put 'with-mixi-post-form 'edebug-form-spec '(body)) -(defun mixi-get-matched-items (url regexp &optional range) +(defun mixi-get-matched-items (url regexp &optional range reverse) "Get matched items to REGEXP in URL." (let ((page 1) ids) (catch 'end - (while (or (null range) (< (length ids) range)) - (with-mixi-retrieve (format url page) - (let ((pos 0) + (while (and (or (null range) (< (length ids) range)) + (or (= page 1) (and (stringp url) (string-match "%d" url)))) + (with-mixi-retrieve (when url (format url page)) + (let ((func (if reverse (progn + (goto-char (point-max)) + 're-search-backward) + 're-search-forward)) found) - (while (and (string-match regexp buffer pos) + (while (and (funcall func regexp nil t) (or (null range) (< (length ids) range))) (let ((num 1) list) - (while (match-string num buffer) - (setq list (cons (match-string num buffer) list)) + (while (match-string num) + (setq list (cons (match-string num) list)) (incf num)) (when (not (member (reverse list) ids)) (setq found t) - (setq ids (cons (reverse list) ids))) - (setq pos (match-end (1- num))))) + (setq ids (cons (reverse list) ids))))) (when (not found) (throw 'end ids)))) (incf page))) @@ -465,24 +517,54 @@ Increase this value when unexpected error frequently occurs." (buffer-string))) ;; stolen (and modified) from w3m.el -;; FIXME: Hmm. -(defun mixi-url-encode-and-quote-percent-string (string) +(defconst mixi-entity-alist '(("gt" . ">") + ("lt" . "<") + ("amp" . "&")) + "Alist of html character entities and values.") + +;; stolen (and modified) from w3m.el +(defun mixi-encode-specials-string (str) + "Encode special characters in the string STR." + (let ((pos 0) + (buf)) + (while (string-match "[<>&]" str pos) + (setq buf + (cons ";" + (cons (car (rassoc (match-string 0 str) mixi-entity-alist)) + (cons "&" + (cons (substring str pos (match-beginning 0)) + buf)))) + pos (match-end 0))) + (if buf + (apply 'concat (nreverse (cons (substring str pos) buf))) + str))) + +;; stolen (and modified) from w3m.el +(defun mixi-url-encode-string (string) (apply (function concat) (mapcar (lambda (char) (cond ((eq char ?\n) ; newline - "%%0D%%0A") + "%0D%0A") ((string-match "[-a-zA-Z0-9_:/.]" (char-to-string char)) ; xxx? (char-to-string char)) ; printable ((char-equal char ?\x20) ; space "+") (t - (format "%%%%%02x" char)))) ; escape + (format "%%%02x" char)))) ; escape ;; Coerce a string into a list of chars. (append (encode-coding-string (or string "") mixi-coding-system) nil)))) +(defun mixi-url-encode-and-quote-percent-string (string) + (let ((string (mixi-url-encode-string string)) + (pos 0)) + (while (string-match "%" string pos) + (setq string (replace-match "%%" nil nil string)) + (setq pos (+ (match-end 0) 1))) + string)) + ;; Object. (defconst mixi-object-prefix "mixi-") @@ -579,8 +661,10 @@ Increase this value when unexpected error frequently occurs." "Return a mixi object from URL." (if (string-match mixi-object-url-regexp url) (let ((name (match-string 2 url))) - (when (string= name "bbs") - (setq name "topic")) + (cond ((string= name "bbs") + (setq name "topic")) + ((string= name "profile") + (setq name "friend"))) (let ((func (intern (concat mixi-object-prefix "make-" name "-from-url")))) (funcall func url))) @@ -641,24 +725,24 @@ Increase this value when unexpected error frequently occurs." (unless (file-directory-p cache-directory) (make-directory cache-directory t)) (let ((caches (apropos-internal mixi-cache-regexp 'boundp))) - (mapc (lambda (symbol) - (with-temp-file (expand-file-name - (substring (symbol-name symbol) - (length mixi-object-prefix)) - cache-directory) - (let ((coding-system-for-write mixi-coding-system) - (cache (symbol-value symbol))) - (insert "#s(hash-table size " - (number-to-string (hash-table-count cache)) - " test equal data (\n") - (maphash - (lambda (key value) - (let (print-level print-length) - (insert (prin1-to-string key) " " - (prin1-to-string value) "\n"))) - cache)) - (insert "))"))) - caches)))) + (while caches + (with-temp-file (expand-file-name + (substring (symbol-name (car caches)) + (length mixi-object-prefix)) + cache-directory) + (let ((coding-system-for-write mixi-coding-system) + (cache (symbol-value (car caches)))) + (insert "#s(hash-table size " + (number-to-string (hash-table-count cache)) + " test equal data (\n") + (maphash + (lambda (key value) + (let (print-level print-length) + (insert (prin1-to-string key) " " + (prin1-to-string value) "\n"))) + cache)) + (insert "))")) + (setq caches (cdr caches)))))) ;; stolen (and modified) from lsdb.el (defun mixi-read-cache (&optional marker) @@ -694,17 +778,17 @@ Increase this value when unexpected error frequently occurs." ;; FIXME: Load friend and community first. (let ((files (directory-files cache-directory t mixi-cache-file-regexp))) - (mapc (lambda (file) - (let ((buffer (find-file-noselect file))) - (unwind-protect - (save-excursion - (set-buffer buffer) - (goto-char (point-min)) - (re-search-forward "^#s(") - (goto-char (match-beginning 0)) - (mixi-read-cache (point-marker))) - (kill-buffer buffer)))) - files))))) + (while files + (let ((buffer (find-file-noselect (car files)))) + (unwind-protect + (save-excursion + (set-buffer buffer) + (goto-char (point-min)) + (re-search-forward "^#s(") + (goto-char (match-beginning 0)) + (mixi-read-cache (point-marker))) + (kill-buffer buffer))) + (setq files (cdr files))))))) ;; Friend object. (defvar mixi-friend-cache (make-hash-table :test 'equal)) @@ -722,18 +806,18 @@ Increase this value when unexpected error frequently occurs." "Return a my object." (unless mixi-me (with-mixi-retrieve "/home.pl" - (if (string-match mixi-my-id-regexp buffer) - (setq mixi-me (mixi-make-friend (match-string 1 buffer))) + (if (re-search-forward mixi-my-id-regexp nil t) + (setq mixi-me (mixi-make-friend (match-string 1))) (signal 'error (list 'who-am-i))))) mixi-me) (defconst mixi-friend-url-regexp - "/show_friend\\.pl\\?id=\\([0-9]+\\)") + "/show_\\(friend\\|profile\\)\\.pl\\?id=\\([0-9]+\\)") (defun mixi-make-friend-from-url (url) "Return a friend object from URL." (if (string-match mixi-friend-url-regexp url) - (let ((id (match-string 1 url))) + (let ((id (match-string 2 url))) (mixi-make-friend id)) (when (string-match "/home\\.pl" url) (mixi-make-me)))) @@ -742,83 +826,67 @@ Increase this value when unexpected error frequently occurs." `(eq (mixi-object-class ,friend) 'mixi-friend)) (defmacro mixi-friend-page (friend) - `(concat "/show_friend.pl?id=" (mixi-friend-id ,friend))) + `(concat "/show_profile.pl?id=" (mixi-friend-id ,friend))) (defconst mixi-friend-nick-regexp - "\"\\*\"
? -\\(.*\\)¤µ¤ó([0-9]+)") + "

\\(.*\\)¤µ¤ó([0-9]+)

") (defconst mixi-friend-name-regexp - "̾\\( \\| \\)Á° - -?\\(.+?\\)\\(\\|̾Á°\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-sex-regexp - "À­\\( \\| \\)ÊÌ - -?\\([Ã˽÷]\\)À­\\(\\|À­ÊÌ\n?
\\([Ã˽÷]\\)À­\\(\\)") (defconst mixi-friend-address-regexp - "¸½½»½ê\n\\(.+\\)\\(\n.+\n\\)?") + "
¸½½»½ê
\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-age-regexp - "ǯ\\( \\| \\)Îð\n\\([0-9]+\\)ºÐ\\(\n.+\n\\)?") + "
ǯÎð
\n?
\\([0-9]+\\)ºÐ\\( \\)") (defconst mixi-friend-birthday-regexp - "ÃÂÀ¸Æü\n\\([0-9]+\\)·î\\([0-9]+\\)Æü\\(\n.+\n\\)?") + "
ÃÂÀ¸Æü
\n?
\\([0-9]+\\)·î\\([0-9]+\\)Æü\\(\\)") (defconst mixi-friend-blood-type-regexp - "·ì±Õ·¿\n\\([ABO]B?\\)·¿\\(\n\n\\)?") + "
·ì±Õ·¿
\n?
\\([ABO]B?\\)·¿\\(\\)") (defconst mixi-friend-birthplace-regexp - "½Ð¿ÈÃÏ\n?\n\\(.+\\)\\(\n.+\n\\)?") + "
½Ð¿ÈÃÏ
\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-hobby-regexp - "¼ñ\\( \\| \\)Ì£\n\\(.+?\\)\\(\\|¼ñÌ£\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-job-regexp - "¿¦\\( \\| \\)¶È\n\\(.+\\)\\(\n.+\n\\)?") + "
¿¦¶È
\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-organization-regexp - "½ê\\( \\| \\)°\n]*>\\(.+\\)\\(\n.+\n\\)?") + "
½ê°
\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-profile-regexp - "¼«¸Ê¾Ò²ð\n\\(.+\\)") + "
¼«¸Ê¾Ò²ð
\n?
\\(.+?\\)
") (defun mixi-realize-friend (friend) "Realize a FRIEND." - ;; FIXME: Check a expiration of cache? + ;; FIXME: Check an expiration of cache? (unless (mixi-object-realized-p friend) - (let (buf) - (with-mixi-retrieve (mixi-friend-page friend) - (setq buf buffer)) - (if (string-match mixi-friend-nick-regexp buf) - (mixi-friend-set-nick friend (match-string 1 buf)) - (mixi-realization-error 'cannot-find-nick friend)) - ;; For getting my profile. - (unless (string-match mixi-friend-name-regexp buf) - (with-mixi-retrieve (concat "/show_profile.pl?id=" - (mixi-friend-id friend)) - (setq buf buffer))) - (if (string-match mixi-friend-name-regexp buf) - (mixi-friend-set-name friend (match-string 2 buf)) - (mixi-realization-error 'cannot-find-name friend)) - (if (string-match mixi-friend-sex-regexp buf) - (mixi-friend-set-sex friend - (if (string= (match-string 3 buf) "ÃË") - 'male 'female)) - (mixi-realization-error 'cannot-find-sex friend)) - (when (string-match mixi-friend-address-regexp buf) - (mixi-friend-set-address friend (match-string 1 buf))) - (when (string-match mixi-friend-age-regexp buf) - (mixi-friend-set-age - friend (string-to-number (match-string 2 buf)))) - (when (string-match mixi-friend-birthday-regexp buf) - (mixi-friend-set-birthday - friend (list (string-to-number (match-string 1 buf)) - (string-to-number (match-string 2 buf))))) - (when (string-match mixi-friend-blood-type-regexp buf) - (mixi-friend-set-blood-type friend (intern (match-string 1 buf)))) - (when (string-match mixi-friend-birthplace-regexp buf) - (mixi-friend-set-birthplace friend (match-string 1 buf))) - (when (string-match mixi-friend-hobby-regexp buf) - (mixi-friend-set-hobby - friend (split-string (match-string 2 buf) ", "))) - (when (string-match mixi-friend-job-regexp buf) - (mixi-friend-set-job friend (match-string 2 buf))) - (when (string-match mixi-friend-organization-regexp buf) - (mixi-friend-set-organization friend (match-string 2 buf))) - (when (string-match mixi-friend-profile-regexp buf) - (mixi-friend-set-profile friend (match-string 1 buf)))) + (with-mixi-retrieve (mixi-friend-page friend) + (let ((case-fold-search t)) + (if (re-search-forward mixi-friend-nick-regexp nil t) + (mixi-friend-set-nick friend (match-string 1)) + (mixi-realization-error 'cannot-find-nick friend)) + (when (re-search-forward mixi-friend-name-regexp nil t) + (mixi-friend-set-name friend (match-string 1))) + (when (re-search-forward mixi-friend-sex-regexp nil t) + (mixi-friend-set-sex friend (if (string= (match-string 1) "ÃË") + 'male 'female))) + (when (re-search-forward mixi-friend-address-regexp nil t) + (mixi-friend-set-address friend (match-string 1))) + (when (re-search-forward mixi-friend-age-regexp nil t) + (mixi-friend-set-age friend (string-to-number (match-string 1)))) + (when (re-search-forward mixi-friend-birthday-regexp nil t) + (mixi-friend-set-birthday + friend (list (string-to-number (match-string 1)) + (string-to-number (match-string 2))))) + (when (re-search-forward mixi-friend-blood-type-regexp nil t) + (mixi-friend-set-blood-type friend (intern (match-string 1)))) + (when (re-search-forward mixi-friend-birthplace-regexp nil t) + (mixi-friend-set-birthplace friend (match-string 1))) + (when (re-search-forward mixi-friend-hobby-regexp nil t) + (mixi-friend-set-hobby friend (split-string (match-string 1) ", "))) + (when (re-search-forward mixi-friend-job-regexp nil t) + (mixi-friend-set-job friend (match-string 1))) + (when (re-search-forward mixi-friend-organization-regexp nil t) + (mixi-friend-set-organization friend (match-string 1))) + (when (re-search-forward mixi-friend-profile-regexp nil t) + (mixi-friend-set-profile friend (match-string 1))))) (mixi-object-touch friend))) (defun mixi-friend-id (friend) @@ -906,7 +974,7 @@ Increase this value when unexpected error frequently occurs." (aref (cdr friend) 12)) (defun mixi-friend-profile (friend) - "Return the pforile of FRIEND." + "Return the profile of FRIEND." (unless (mixi-friend-p friend) (signal 'wrong-type-argument (list 'mixi-friend-p friend))) (mixi-realize-friend friend) @@ -984,15 +1052,20 @@ Increase this value when unexpected error frequently occurs." (signal 'wrong-type-argument (list 'mixi-friend-p friend))) (aset (cdr friend) 13 profile)) -(defmacro mixi-friend-list-page (&optional friend) - `(concat "/list_friend.pl?page=%d" - (when ,friend (concat "&id=" (mixi-friend-id ,friend))))) +(defun mixi-my-friend-list-page (&optional dummy) + (concat "/list_friend_simple.pl?page=%d")) + +(defun mixi-friend-list-page (friend) + (concat "/list_friend.pl?page=%d&id=" (mixi-friend-id friend))) (defconst mixi-friend-list-id-regexp - "
\\(.+\\)([0-9]+)

") (defconst mixi-friend-list-nick-regexp - "\\(.+\\)¤µ¤ó([0-9]+)
") + "\\(.+\\)¤µ¤ó([0-9]+)") +;;;###autoload (defun mixi-get-friends (&rest friend-or-range) "Get friends of FRIEND." (when (> (length friend-or-range) 2) @@ -1005,45 +1078,43 @@ Increase this value when unexpected error frequently occurs." (setq range (nth 0 friend-or-range))) (unless (or (null friend) (mixi-friend-p friend)) (signal 'wrong-type-argument (list 'mixi-friend-p friend))) - (let ((ids (mixi-get-matched-items (mixi-friend-list-page friend) - mixi-friend-list-id-regexp - range)) - (nicks (mixi-get-matched-items (mixi-friend-list-page friend) - mixi-friend-list-nick-regexp - range))) - (let ((index 0) - ret) - (while (< index (length ids)) - (setq ret (cons (mixi-make-friend (nth 0 (nth index ids)) - (nth 0 (nth index nicks))) ret)) - (incf index)) - (reverse ret))))) + (let (list-page list-nick-regexp) + (if (or (null friend) (equal friend mixi-me)) + (setq list-page 'mixi-my-friend-list-page + list-nick-regexp mixi-my-friend-list-nick-regexp) + (setq list-page 'mixi-friend-list-page + list-nick-regexp mixi-friend-list-nick-regexp)) + (let ((ids (mixi-get-matched-items (funcall list-page friend) + mixi-friend-list-id-regexp + range)) + (nicks (mixi-get-matched-items (funcall list-page friend) + list-nick-regexp + range))) + (let ((index 0) + ret) + (while (< index (length ids)) + (setq ret (cons (mixi-make-friend (nth 0 (nth index ids)) + (nth 0 (nth index nicks))) ret)) + (incf index)) + (reverse ret)))))) ;; Favorite. (defmacro mixi-favorite-list-page () `(concat "/list_bookmark.pl?page=%d")) -(defconst mixi-favorite-list-id-regexp - "
") -(defconst mixi-favorite-list-nick-regexp - "̾  Á° -\\(.+\\)") +(defconst mixi-favorite-list-regexp + "̾Á° +\\(.*\\)") +;;;###autoload (defun mixi-get-favorites (&optional range) "Get favorites." - (let ((ids (mixi-get-matched-items (mixi-favorite-list-page) - mixi-favorite-list-id-regexp - range)) - (nicks (mixi-get-matched-items (mixi-favorite-list-page) - mixi-favorite-list-nick-regexp + (let ((items (mixi-get-matched-items (mixi-favorite-list-page) + mixi-favorite-list-regexp range))) - (let ((index 0) - ret) - (while (< index (length ids)) - (setq ret (cons (mixi-make-friend (nth 0 (nth index ids)) - (nth 0 (nth index nicks))) ret)) - (incf index)) - (reverse ret)))) + (mapcar (lambda (item) + (mixi-make-friend (nth 0 item) (nth 1 item))) + items))) ;; Log object. (defun mixi-make-log (friend time) @@ -1069,8 +1140,9 @@ Increase this value when unexpected error frequently occurs." `(concat "/show_log.pl")) (defconst mixi-log-list-regexp - "\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\) \\(.*\\)") + "\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\) \\(.*?\\)") +;;;###autoload (defun mixi-get-logs (&optional range) "Get logs." (let ((items (mixi-get-matched-items (mixi-log-list-page) @@ -1086,25 +1158,43 @@ Increase this value when unexpected error frequently occurs." (string-to-number (nth 0 item))))) items))) +;; Recommended friend. +(defmacro mixi-recommended-friend-list-page () + `(concat "http://indies.mixi.jp/recommend.pl")) + +(defconst mixi-recommended-friend-list-regexp + "\\(.+?\\)¤µ¤ó([0-9]+)") + +;;;###autoload +(defun mixi-get-recommended-friends (&optional range) + "Get recommended friends." + (let ((items (mixi-get-matched-items (mixi-recommended-friend-list-page) + mixi-recommended-friend-list-regexp + range))) + (mapcar (lambda (item) + (mixi-make-friend (nth 0 item) (nth 1 item))) + items))) + ;; Diary object. (defvar mixi-diary-cache (make-hash-table :test 'equal)) -(defun mixi-make-diary (owner id &optional time title content) +(defun mixi-make-diary (owner id &optional comment-count time title content) "Return a diary object." (let ((owner (or owner (mixi-make-me)))) (mixi-make-cache (list (mixi-friend-id owner) id) - (cons 'mixi-diary (vector nil owner id time title - content)) + (cons 'mixi-diary (vector nil owner id comment-count time + title content)) mixi-diary-cache))) (defconst mixi-diary-url-regexp - "/view_diary\\.pl\\?id=\\([0-9]+\\)&owner_id=\\([0-9]+\\)") + "/view_diary\\.pl\\?id=\\([0-9]+\\)&owner_id=\\([0-9]+\\)\\(&comment_count=\\([0-9]+\\)\\)?") (defun mixi-make-diary-from-url (url) "Return a diary object from URL." (when (string-match mixi-diary-url-regexp url) (let ((id (match-string 1 url)) - (owner-id (match-string 2 url))) - (mixi-make-diary (mixi-make-friend owner-id) id)))) + (owner-id (match-string 2 url)) + (comment-count (match-string 4 url))) + (mixi-make-diary (mixi-make-friend owner-id) id comment-count)))) (defmacro mixi-diary-p (diary) `(eq (mixi-object-class ,diary) 'mixi-diary)) @@ -1114,40 +1204,46 @@ Increase this value when unexpected error frequently occurs." "&owner_id=" (mixi-friend-id (mixi-diary-owner ,diary)))) (defconst mixi-diary-closed-regexp - "ͧ¿Í\\(¤Îͧ¿Í\\)?¤Þ¤Ç¸ø³«¤Î¤¿¤áÆɤळ¤È¤¬½ÐÍè¤Þ¤»¤ó¡£") + "¤³¤ÎÆüµ­¤Ë¥¢¥¯¥»¥¹¤Ç¤­¤Þ¤»¤ó¡£°Ê²¼¤Î²ÄǽÀ­¤¬¹Í¤¨¤é¤ì¤Þ¤¹¡£
") (defconst mixi-diary-owner-nick-regexp - "\\(.+?\\)\\(¤µ¤ó\\)?¤ÎÆüµ­") -(defconst mixi-diary-time-regexp - "\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü\\(
\\|
\\)\\([0-9]+\\):\\([0-9]+\\)") + "
+

\\(.+?\\)\\(¤µ¤ó\\)?¤ÎÆüµ­

") (defconst mixi-diary-title-regexp - " \\([^<]+\\)") + "
+
+
\\([^<\n]+\\)\\(\\)?") +(defconst mixi-diary-time-regexp + "
\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü\\([0-9]+\\):\\([0-9]+\\)
") (defconst mixi-diary-content-regexp - "\\(.*\\)") + "
+\\(\\(.\\|\r?\n\\)*?\\) +
") -(defun mixi-realize-diary (diary) +(defun mixi-realize-diary (diary &optional page) "Realize a DIARY." - ;; FIXME: Check a expiration of cache? + ;; FIXME: Check an expiration of cache? (unless (mixi-object-realized-p diary) - (with-mixi-retrieve (mixi-diary-page diary) - (unless (string-match mixi-diary-closed-regexp buffer) - (if (string-match mixi-diary-owner-nick-regexp buffer) - (mixi-friend-set-nick (mixi-diary-owner diary) - (match-string 1 buffer)) - (mixi-realization-error 'cannot-find-owner-nick diary)) - (if (string-match mixi-diary-time-regexp buffer) - (mixi-diary-set-time - diary (encode-time 0 (string-to-number (match-string 10 buffer)) - (string-to-number (match-string 9 buffer)) - (string-to-number (match-string 7 buffer)) - (string-to-number (match-string 6 buffer)) - (string-to-number (match-string 5 buffer)))) - (mixi-realization-error 'cannot-find-time diary)) - (if (string-match mixi-diary-title-regexp buffer) - (mixi-diary-set-title diary (match-string 2 buffer)) - (mixi-realization-error 'cannot-find-title diary)) - (if (string-match mixi-diary-content-regexp buffer) - (mixi-diary-set-content diary (match-string 2 buffer)) - (mixi-realization-error 'cannot-find-content diary)))) + (with-mixi-retrieve (or page (mixi-diary-page diary)) + (let ((case-fold-search t)) + (unless (re-search-forward mixi-diary-closed-regexp nil t) + (if (re-search-forward mixi-diary-owner-nick-regexp nil t) + (mixi-friend-set-nick (mixi-diary-owner diary) + (match-string 2)) + (mixi-realization-error 'cannot-find-owner-nick diary)) + (if (re-search-forward mixi-diary-title-regexp nil t) + (mixi-diary-set-title diary (match-string 1)) + (mixi-realization-error 'cannot-find-title diary)) + (if (re-search-forward mixi-diary-time-regexp nil t) + (mixi-diary-set-time + diary (encode-time 0 (string-to-number (match-string 5)) + (string-to-number (match-string 4)) + (string-to-number (match-string 3)) + (string-to-number (match-string 2)) + (string-to-number (match-string 1)))) + (mixi-realization-error 'cannot-find-time diary)) + (if (re-search-forward mixi-diary-content-regexp nil t) + (mixi-diary-set-content diary (match-string 1)) + (mixi-realization-error 'cannot-find-content diary))))) (mixi-object-touch diary))) (defun mixi-diary-owner (diary) @@ -1162,13 +1258,19 @@ Increase this value when unexpected error frequently occurs." (signal 'wrong-type-argument (list 'mixi-diary-p diary))) (aref (cdr diary) 2)) +(defun mixi-diary-comment-count (diary) + "Return the comment-count of DIARY." + (unless (mixi-diary-p diary) + (signal 'wrong-type-argument (list 'mixi-diary-p diary))) + (aref (cdr diary) 3)) + (defun mixi-diary-time (diary) "Return the time of DIARY." (unless (mixi-diary-p diary) (signal 'wrong-type-argument (list 'mixi-diary-p diary))) (unless (aref (cdr diary) 3) (mixi-realize-diary diary)) - (aref (cdr diary) 3)) + (aref (cdr diary) 4)) (defun mixi-diary-title (diary) "Return the title of DIARY." @@ -1176,56 +1278,49 @@ Increase this value when unexpected error frequently occurs." (signal 'wrong-type-argument (list 'mixi-diary-p diary))) (unless (aref (cdr diary) 4) (mixi-realize-diary diary)) - (aref (cdr diary) 4)) + (aref (cdr diary) 5)) (defun mixi-diary-content (diary) "Return the content of DIARY." (unless (mixi-diary-p diary) (signal 'wrong-type-argument (list 'mixi-diary-p diary))) (mixi-realize-diary diary) - (aref (cdr diary) 5)) + (aref (cdr diary) 6)) + +(defun mixi-diary-set-comment-count (diary comment-count) + "Set the comment-count of DIARY." + (unless (mixi-diary-p diary) + (signal 'wrong-type-argument (list 'mixi-diary-p diary))) + (aset (cdr diary) 3 comment-count)) (defun mixi-diary-set-time (diary time) "Set the time of DIARY." (unless (mixi-diary-p diary) (signal 'wrong-type-argument (list 'mixi-diary-p diary))) - (aset (cdr diary) 3 time)) + (aset (cdr diary) 4 time)) (defun mixi-diary-set-title (diary title) "Set the title of DIARY." (unless (mixi-diary-p diary) (signal 'wrong-type-argument (list 'mixi-diary-p diary))) - (aset (cdr diary) 4 title)) + (aset (cdr diary) 5 title)) (defun mixi-diary-set-content (diary content) "Set the content of DIARY." (unless (mixi-diary-p diary) (signal 'wrong-type-argument (list 'mixi-diary-p diary))) - (aset (cdr diary) 5 content)) + (aset (cdr diary) 6 content)) (defmacro mixi-diary-list-page (&optional friend) `(concat "/list_diary.pl?page=%d" (when ,friend (concat "&id=" (mixi-friend-id ,friend))))) (defconst mixi-diary-list-regexp - " -\\([0-9]+\\)·î\\([0-9]+\\)Æü
\\([0-9]+\\):\\([0-9]+\\)
\\(
\\|\\) - \\(.*\\) - - - - - - -
- -\\(.*\\) - -?
- -
-") + "
\\(\\|\\)\\(.*\\)\\(ÊÔ½¸¤¹¤ë\\|\\)
+
\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü\n?\\([0-9]+\\):\\([0-9]+\\)
+
") +;;;###autoload (defun mixi-get-diaries (&rest friend-or-range) "Get diaries of FRIEND." (when (> (length friend-or-range) 2) @@ -1240,73 +1335,75 @@ Increase this value when unexpected error frequently occurs." (signal 'wrong-type-argument (list 'mixi-friend-p friend))) (let ((items (mixi-get-matched-items (mixi-diary-list-page friend) mixi-diary-list-regexp - range)) - (year (nth 5 (decode-time (current-time)))) - (month (nth 4 (decode-time (current-time))))) + range))) (mapcar (lambda (item) - (let ((month-of-item (string-to-number (nth 0 item)))) - (when (> month-of-item month) - (decf year)) - (setq month month-of-item) - (mixi-make-diary friend (nth 5 item) - (encode-time - 0 (string-to-number (nth 3 item)) - (string-to-number (nth 2 item)) - (string-to-number (nth 1 item)) - month year) - (nth 6 item) (nth 7 item)))) + (mixi-make-diary friend (nth 1 item) nil + (encode-time + 0 (string-to-number (nth 8 item)) + (string-to-number (nth 7 item)) + (string-to-number (nth 6 item)) + (string-to-number (nth 5 item)) + (string-to-number (nth 4 item))) + (nth 2 item))) items)))) (defmacro mixi-new-diary-list-page () `(concat "/new_friend_diary.pl?page=%d")) (defconst mixi-new-diary-list-regexp - "\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\) -\\(.+\\) (\\(.*\\)) ") + "
\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\)
+
\\(.+\\) (\\(.*\\))
̾  Á° -\\(.*\\) - - - - -¥¿¥¤¥È¥ë -\\(.+\\) - - -ËÜ  Ê¸ -\\(.*\\) - - - -ºîÀ®Æü»þ -\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\) -¾ÜºÙ¤ò¸«¤ë - -") - + "
  • + +
    +
    \\(.+\\)\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\)
    +

    \\(.*\\) +

    +
  • ") + +;;;###autoload (defun mixi-search-diaries (keyword &optional range) (let ((items (mixi-get-matched-items (mixi-search-diary-list-page keyword) mixi-search-diary-list-regexp @@ -1314,30 +1411,32 @@ Increase this value when unexpected error frequently occurs." (year (nth 5 (decode-time (current-time)))) (month (nth 4 (decode-time (current-time))))) (mapcar (lambda (item) - (let ((month-of-item (string-to-number (nth 3 item)))) + (let ((month-of-item (string-to-number (nth 4 item)))) (when (> month-of-item month) (decf year)) (setq month month-of-item) - (mixi-make-diary (mixi-make-friend (nth 8 item) (nth 0 item)) - (nth 7 item) + (mixi-make-diary (mixi-make-friend (nth 1 item) (nth 2 item)) + (nth 0 item) + nil (encode-time - 0 (string-to-number (nth 6 item)) + 0 (string-to-number (nth 7 item)) + (string-to-number (nth 6 item)) (string-to-number (nth 5 item)) - (string-to-number (nth 4 item)) month year) - (nth 1 item) - (nth 2 item)))) + (nth 3 item) + (nth 8 item)))) items))) (defmacro mixi-post-diary-page () `(concat "/add_diary.pl")) (defconst mixi-post-key-regexp - "") + "\\(ºîÀ®\\|½ñ¤­¹þ¤ß\\)¤¬´°Î»¤·¤Þ¤·¤¿¡£È¿±Ç¤Ë»þ´Ö¤¬¤«¤«¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¤Î¤Ç¡¢É½¼¨¤µ¤ì¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ï¾¯¡¹¤ªÂÔ¤Á¤¯¤À¤µ¤¤¡£") + "\\(ºîÀ®\\|½ñ¤­¹þ¤ß\\)¤¬´°Î»¤·¤Þ¤·¤¿¡£È¿±Ç¤Ë»þ´Ö¤¬¤«¤«¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£

    ") ;; FIXME: Support photos. +;;;###autoload (defun mixi-post-diary (title content) "Post a diary." (unless (stringp title) @@ -1350,8 +1449,8 @@ Increase this value when unexpected error frequently occurs." ("submit" . "main"))) post-key) (with-mixi-post-form (mixi-post-diary-page) fields - (if (string-match mixi-post-key-regexp buffer) - (setq post-key (match-string 1 buffer)) + (if (re-search-forward mixi-post-key-regexp nil t) + (setq post-key (match-string 1)) (mixi-post-error 'cannot-find-key))) (setq fields `(("post_key" . ,post-key) ("id" . ,(mixi-friend-id (mixi-make-me))) @@ -1359,7 +1458,7 @@ Increase this value when unexpected error frequently occurs." ("diary_body" . ,content) ("submit" . "confirm"))) (with-mixi-post-form (mixi-post-diary-page) fields - (unless (string-match mixi-post-succeed-regexp buffer) + (unless (re-search-forward mixi-post-succeed-regexp nil t) (mixi-post-error 'cannot-find-succeed))))) ;; Community object. @@ -1392,72 +1491,78 @@ Increase this value when unexpected error frequently occurs." (defconst mixi-community-nodata-regexp "^¥Ç¡¼¥¿¤¬¤¢¤ê¤Þ¤»¤ó") (defconst mixi-community-name-regexp - "\\(.*\\)") + "
    +

    \\(.*\\)

    ") (defconst mixi-community-birthday-regexp - "³«ÀßÆü -\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü") + "
    ³«ÀßÆü
    +
    \\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü
    ") ;; FIXME: Care when the owner has seceded. (defconst mixi-community-owner-regexp - "´ÉÍý¿Í - - -") + "
    ¥«¥Æ¥´¥ê
    +
    \\(.+\\)
    ") (defconst mixi-community-members-regexp - " -") + "
    ¥á¥ó¥Ð¡¼¿ô
    +
    \\([0-9]+\\)¿Í
    ") (defconst mixi-community-open-level-regexp - " -") + "
    »²²Ã¾ò·ï¤È
    ¸ø³«¥ì¥Ù¥ë
    +
    \\(.+\\)
    ") (defconst mixi-community-authority-regexp - " -") + "
    ¥È¥Ô¥Ã¥¯¤Î
    ºîÀ®¸¢¸Â
    +
    +\\(.+\\) + + +
    ") (defconst mixi-community-description-regexp - "") + "
    +

    \\(.+\\)

    ") (defun mixi-realize-community (community) "Realize a COMMUNITY." - ;; FIXME: Check a expiration of cache? + ;; FIXME: Check an expiration of cache? (unless (mixi-object-realized-p community) (with-mixi-retrieve (mixi-community-page community) - (if (string-match mixi-community-nodata-regexp buffer) - ;; FIXME: Set all members? - (mixi-community-set-name community "¥Ç¡¼¥¿¤¬¤¢¤ê¤Þ¤»¤ó") - (if (string-match mixi-community-name-regexp buffer) - (mixi-community-set-name community (match-string 1 buffer)) - (mixi-realization-error 'cannot-find-name community)) - (if (string-match mixi-community-birthday-regexp buffer) - (mixi-community-set-birthday - community - (encode-time 0 0 0 (string-to-number (match-string 3 buffer)) - (string-to-number (match-string 2 buffer)) - (string-to-number (match-string 1 buffer)))) - (mixi-realization-error 'cannot-find-birthday community)) - (if (string-match mixi-community-owner-regexp buffer) - (if (string= (match-string 1 buffer) "home.pl") - (mixi-community-set-owner community (mixi-make-me)) - (mixi-community-set-owner - community (mixi-make-friend (match-string 2 buffer) - (match-string 3 buffer)))) - (mixi-realization-error 'cannot-find-owner community)) - (if (string-match mixi-community-category-regexp buffer) - (mixi-community-set-category community (match-string 1 buffer)) - (mixi-realization-error 'cannot-find-category community)) - (if (string-match mixi-community-members-regexp buffer) - (mixi-community-set-members - community (string-to-number (match-string 1 buffer))) - (mixi-realization-error 'cannot-find-members community)) - (if (string-match mixi-community-open-level-regexp buffer) - (mixi-community-set-open-level community (match-string 1 buffer)) - (mixi-realization-error 'cannot-find-open-level community)) - (if (string-match mixi-community-authority-regexp buffer) - (mixi-community-set-authority community (match-string 1 buffer)) - (mixi-realization-error 'cannot-find-authority community)) - (if (string-match mixi-community-description-regexp buffer) - (mixi-community-set-description community (match-string 1 buffer)) - (mixi-realization-error 'cannot-find-description community)))) + (let ((case-fold-search t)) + (if (re-search-forward mixi-community-nodata-regexp nil t) + ;; FIXME: Set all members? + (mixi-community-set-name community "¥Ç¡¼¥¿¤¬¤¢¤ê¤Þ¤»¤ó") + (if (re-search-forward mixi-community-name-regexp nil t) + (mixi-community-set-name community (match-string 1)) + (mixi-realization-error 'cannot-find-name community)) + (if (re-search-forward mixi-community-birthday-regexp nil t) + (mixi-community-set-birthday + community (encode-time 0 0 0 + (string-to-number (match-string 3)) + (string-to-number (match-string 2)) + (string-to-number (match-string 1)))) + (mixi-realization-error 'cannot-find-birthday community)) + (if (re-search-forward mixi-community-owner-regexp nil t) + (if (string= (match-string 1) "home.pl") + (mixi-community-set-owner community (mixi-make-me)) + (mixi-community-set-owner community (mixi-make-friend + (match-string 2) + (match-string 3)))) + (mixi-realization-error 'cannot-find-owner community)) + (if (re-search-forward mixi-community-category-regexp nil t) + (mixi-community-set-category community (match-string 1)) + (mixi-realization-error 'cannot-find-category community)) + (if (re-search-forward mixi-community-members-regexp nil t) + (mixi-community-set-members community + (string-to-number (match-string 1))) + (mixi-realization-error 'cannot-find-members community)) + (if (re-search-forward mixi-community-open-level-regexp nil t) + (mixi-community-set-open-level community (match-string 1)) + (mixi-realization-error 'cannot-find-open-level community)) + (if (re-search-forward mixi-community-authority-regexp nil t) + (mixi-community-set-authority community (match-string 1)) + (mixi-realization-error 'cannot-find-authority community)) + (if (re-search-forward mixi-community-description-regexp nil t) + (mixi-community-set-description community (match-string 1)) + (mixi-realization-error 'cannot-find-description community))))) (mixi-object-touch community))) (defun mixi-community-id (community) @@ -1578,10 +1683,11 @@ Increase this value when unexpected error frequently occurs." (when ,friend (concat "&id=" (mixi-friend-id ,friend))))) (defconst mixi-community-list-id-regexp - "\\(.+\\)([0-9]+)") + "\\(.+\\)([0-9]+)") +;;;###autoload (defun mixi-get-communities (&rest friend-or-range) "Get communities of FRIEND." (when (> (length friend-or-range) 2) @@ -1614,11 +1720,10 @@ Increase this value when unexpected error frequently occurs." "&category_id=0")) (defconst mixi-search-community-list-regexp - "
    - -") + "
    \\(.+\\) ([0-9]+)") ;; FIXME: Support category. +;;;###autoload (defun mixi-search-communities (keyword &optional range) (let ((items (mixi-get-matched-items (mixi-search-community-list-page keyword) @@ -1628,24 +1733,43 @@ Increase this value when unexpected error frequently occurs." (mixi-make-community (nth 0 item) (nth 1 item))) items))) +;; Recommended community. +(defalias 'mixi-recommended-community-list-page + 'mixi-recommended-friend-list-page) + +(defconst mixi-recommended-community-list-regexp + "\\(.+\\)([0-9]+)") + +;;;###autoload +(defun mixi-get-recommended-communities (&optional range) + "Get recommended communities." + (let ((items (mixi-get-matched-items (mixi-recommended-community-list-page) + mixi-recommended-community-list-regexp + range))) + (mapcar (lambda (item) + (mixi-make-community (nth 0 item) (nth 1 item))) + items))) + ;; Topic object. (defvar mixi-topic-cache (make-hash-table :test 'equal)) -(defun mixi-make-topic (community id &optional time title owner content) +(defun mixi-make-topic (community id &optional comment-count time title owner + content) "Return a topic object." (mixi-make-cache (list (mixi-community-id community) id) - (cons 'mixi-topic (vector nil community id time title owner - content)) + (cons 'mixi-topic (vector nil community id comment-count + time title owner content)) mixi-topic-cache)) (defconst mixi-topic-url-regexp - "/view_bbs\\.pl\\?id=\\([0-9]+\\)\\(&comment_count=[0-9]+\\)?&comm_id=\\([0-9]+\\)") + "/view_bbs\\.pl\\?id=\\([0-9]+\\)\\(&comment_count=\\([0-9]+\\)\\)?&comm_id=\\([0-9]+\\)") (defun mixi-make-topic-from-url (url) "Return a topic object from URL." (when (string-match mixi-topic-url-regexp url) (let ((id (match-string 1 url)) - (community-id (match-string 3 url))) - (mixi-make-topic (mixi-make-community community-id) id)))) + (comment-count (match-string 3 url)) + (community-id (match-string 4 url))) + (mixi-make-topic (mixi-make-community community-id) id comment-count)))) (defmacro mixi-topic-p (topic) `(eq (mixi-object-class ,topic) 'mixi-topic)) @@ -1655,43 +1779,43 @@ Increase this value when unexpected error frequently occurs." "&comm_id=" (mixi-community-id (mixi-topic-community ,topic)))) (defconst mixi-topic-community-regexp - "
    ") -(defconst mixi-topic-time-regexp - "") + "
    +

    \\(.+\\) ¥È¥Ô¥Ã¥¯

    ") (defconst mixi-topic-title-regexp - "
    ") + "\\([^<]+\\)") +(defconst mixi-topic-time-regexp + "\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\)") (defconst mixi-topic-owner-regexp - "") -(defconst mixi-event-time-regexp - "") + "
    +

    \\(.+\\) ¥¤¥Ù¥ó¥È

    ") (defconst mixi-event-title-regexp - "
    ") -(defconst mixi-event-owner-regexp - " -") + "
    ³«ºÅÆü»þ
    +
    \\(.+\\)
    ") (defconst mixi-event-place-regexp - " -") + "
    ³«ºÅ¾ì½ê
    +
    \\(.+\\)
    ") +(defconst mixi-event-owner-regexp + "
    \\((mixi Âà²ñºÑ)\\|\\(.*\\)\\)
    ") +(defconst mixi-event-owner-seceded-regexp + "(mixi Âà²ñºÑ)") (defconst mixi-event-detail-regexp - " -") + "
    \\(\\(.\\|\r?\n\\)*?\\)
    +") (defconst mixi-event-limit-regexp - " -?") + "
    Ê罸´ü¸Â
    +
    \\(.+\\)
    ") (defconst mixi-event-members-regexp - " - + +
    + "
    ´ÉÍý¿Í
    +
    \\(.*\\)") (defconst mixi-community-category-regexp - "
    ¥«¥Æ¥´¥ê\\([^<]+\\)¥á¥ó¥Ð¡¼¿ô\\([0-9]+\\)¿Í
    »²²Ã¾ò·ï¤È
    ¸ø³«¥ì¥Ù¥ë
    \\(.+\\)
    ¥È¥Ô¥Ã¥¯ºîÀ®¤Î¸¢¸Â\\(.+\\)
    \\(.+\\)¥³¥ß¥å¥Ë¥Æ¥£Ì¾\\([^<]+\\)
    \\[\\(.+\\)\\] ¥È¥Ô¥Ã¥¯\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü
    \\([0-9]+\\):\\([0-9]+\\)
     \\([^<]+\\)  \\(.*?\\)\\(¤µ¤ó\\)?") + "
    \\(.*?\\)\\(¤µ¤ó\\)?") (defconst mixi-topic-content-regexp - "
    \\(\n\\)*
    \\(.+\\)
    ") + "
    \\(\\(.\\|\r?\n\\)*?\\)
    ") -(defun mixi-realize-topic (topic) +(defun mixi-realize-topic (topic &optional page) "Realize a TOPIC." - ;; FIXME: Check a expiration of cache? + ;; FIXME: Check an expiration of cache? (unless (mixi-object-realized-p topic) - (with-mixi-retrieve (mixi-topic-page topic) - (if (string-match mixi-topic-community-regexp buffer) + (with-mixi-retrieve (or page (mixi-topic-page topic)) + (if (re-search-forward mixi-topic-community-regexp nil t) (mixi-community-set-name (mixi-topic-community topic) - (match-string 1 buffer)) + (match-string 1)) (mixi-realization-error 'cannot-find-community topic)) - (if (string-match mixi-topic-time-regexp buffer) + (if (re-search-forward mixi-topic-title-regexp nil t) + (mixi-topic-set-title topic (match-string 1)) + (mixi-realization-error 'cannot-find-title topic)) + (if (re-search-forward mixi-topic-time-regexp nil t) (mixi-topic-set-time - topic (encode-time 0 (string-to-number (match-string 5 buffer)) - (string-to-number (match-string 4 buffer)) - (string-to-number (match-string 3 buffer)) - (string-to-number (match-string 2 buffer)) - (string-to-number (match-string 1 buffer)))) + topic (encode-time 0 (string-to-number (match-string 5)) + (string-to-number (match-string 4)) + (string-to-number (match-string 3)) + (string-to-number (match-string 2)) + (string-to-number (match-string 1)))) (mixi-realization-error 'cannot-find-time topic)) - (if (string-match mixi-topic-title-regexp buffer) - (mixi-topic-set-title topic (match-string 1 buffer)) - (mixi-realization-error 'cannot-find-title topic)) - (if (string-match mixi-topic-owner-regexp buffer) - (mixi-topic-set-owner topic - (mixi-make-friend (match-string 1 buffer) - (match-string 2 buffer))) + (if (re-search-forward mixi-topic-owner-regexp nil t) + (mixi-topic-set-owner topic (mixi-make-friend (match-string 1) + (match-string 2))) (mixi-realization-error 'cannot-find-owner topic)) - (if (string-match mixi-topic-content-regexp buffer) - (mixi-topic-set-content topic (match-string 2 buffer)) + (if (re-search-forward mixi-topic-content-regexp nil t) + (mixi-topic-set-content topic (match-string 1)) (mixi-realization-error 'cannot-find-content topic))) (mixi-object-touch topic))) @@ -1707,45 +1831,57 @@ Increase this value when unexpected error frequently occurs." (signal 'wrong-type-argument (list 'mixi-topic-p topic))) (aref (cdr topic) 2)) +(defun mixi-topic-comment-count (topic) + "Return the comment-count of TOPIC." + (unless (mixi-topic-p topic) + (signal 'wrong-type-argument (list 'mixi-topic-p topic))) + (aref (cdr topic) 3)) + (defun mixi-topic-time (topic) "Return the time of TOPIC." (unless (mixi-topic-p topic) (signal 'wrong-type-argument (list 'mixi-topic-p topic))) (mixi-realize-topic topic) - (aref (cdr topic) 3)) + (aref (cdr topic) 4)) (defun mixi-topic-title (topic) "Return the title of TOPIC." (unless (mixi-topic-p topic) (signal 'wrong-type-argument (list 'mixi-topic-p topic))) (mixi-realize-topic topic) - (aref (cdr topic) 4)) + (aref (cdr topic) 5)) (defun mixi-topic-owner (topic) "Return the owner of TOPIC." (unless (mixi-topic-p topic) (signal 'wrong-type-argument (list 'mixi-topic-p topic))) (mixi-realize-topic topic) - (aref (cdr topic) 5)) + (aref (cdr topic) 6)) (defun mixi-topic-content (topic) "Return the content of TOPIC." (unless (mixi-topic-p topic) (signal 'wrong-type-argument (list 'mixi-topic-p topic))) (mixi-realize-topic topic) - (aref (cdr topic) 6)) + (aref (cdr topic) 7)) + +(defun mixi-topic-set-comment-count (topic comment-count) + "Set the comment-count of TOPIC." + (unless (mixi-topic-p topic) + (signal 'wrong-type-argument (list 'mixi-topic-p topic))) + (aset (cdr topic) 3 comment-count)) (defun mixi-topic-set-time (topic time) "Set the time of TOPIC." (unless (mixi-topic-p topic) (signal 'wrong-type-argument (list 'mixi-topic-p topic))) - (aset (cdr topic) 3 time)) + (aset (cdr topic) 4 time)) (defun mixi-topic-set-title (topic title) "Set the title of TOPIC." (unless (mixi-topic-p topic) (signal 'wrong-type-argument (list 'mixi-topic-p topic))) - (aset (cdr topic) 4 title)) + (aset (cdr topic) 5 title)) (defun mixi-topic-set-owner (topic owner) "Set the owner of TOPIC." @@ -1753,18 +1889,19 @@ Increase this value when unexpected error frequently occurs." (signal 'wrong-type-argument (list 'mixi-topic-p topic))) (unless (mixi-friend-p owner) (signal 'wrong-type-argument (list 'mixi-friend-p owner))) - (aset (cdr topic) 5 owner)) + (aset (cdr topic) 6 owner)) (defun mixi-topic-set-content (topic content) "Set the content of TOPIC." (unless (mixi-topic-p topic) (signal 'wrong-type-argument (list 'mixi-topic-p topic))) - (aset (cdr topic) 6 content)) + (aset (cdr topic) 7 content)) (defmacro mixi-post-topic-page (community) `(concat "/add_bbs.pl?id=" (mixi-community-id community))) ;; FIXME: Support photos. +;;;###autoload (defun mixi-post-topic (community title content) "Post a topic to COMMUNITY." (unless (mixi-community-p community) @@ -1778,36 +1915,38 @@ Increase this value when unexpected error frequently occurs." ("submit" . "main"))) post-key) (with-mixi-post-form (mixi-post-topic-page community) fields - (if (string-match mixi-post-key-regexp buffer) - (setq post-key (match-string 1 buffer)) + (if (re-search-forward mixi-post-key-regexp nil t) + (setq post-key (match-string 1)) (mixi-post-error 'cannot-find-key community))) (setq fields `(("post_key" . ,post-key) ("bbs_title" . ,title) ("bbs_body" . ,content) ("submit" . "confirm"))) (with-mixi-post-form (mixi-post-topic-page community) fields - (unless (string-match mixi-post-succeed-regexp buffer) + (unless (re-search-forward mixi-post-succeed-regexp nil t) (mixi-post-error 'cannot-find-succeed community))))) ;; Event object. (defvar mixi-event-cache (make-hash-table :test 'equal)) -(defun mixi-make-event (community id &optional time title owner date place - detail limit members) +(defun mixi-make-event (community id &optional comment-count time title owner + date place detail limit members) "Return a event object." (mixi-make-cache (list (mixi-community-id community) id) - (cons 'mixi-event (vector nil community id time title owner - date place detail limit members)) + (cons 'mixi-event (vector nil community id comment-count + time title owner date place + detail limit members)) mixi-event-cache)) (defconst mixi-event-url-regexp - "/view_event\\.pl\\?id=\\([0-9]+\\)\\(&comment_count=[0-9]+\\)?&comm_id=\\([0-9]+\\)") + "/view_event\\.pl\\?id=\\([0-9]+\\)\\(&comment_count=\\([0-9]+\\)\\)?&comm_id=\\([0-9]+\\)") (defun mixi-make-event-from-url (url) "Return a event object from URL." (when (string-match mixi-event-url-regexp url) (let ((id (match-string 1 url)) - (community-id (match-string 3 url))) - (mixi-make-event (mixi-make-community community-id) id)))) + (comment-count (match-string 3 url)) + (community-id (match-string 4 url))) + (mixi-make-event (mixi-make-community community-id) id comment-count)))) (defmacro mixi-event-p (event) `(eq (mixi-object-class ,event) 'mixi-event)) @@ -1817,89 +1956,77 @@ Increase this value when unexpected error frequently occurs." "&comm_id=" (mixi-community-id (mixi-event-community ,event)))) (defconst mixi-event-community-regexp - "
    \\[\\(.+\\)\\] ¥¤¥Ù¥ó¥È -?\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü
    -?\\([0-9]+\\):\\([0-9]+\\)
     \\([^<]+\\) \\(.*\\)") -(defconst mixi-event-owner-seceded-regexp - " \\((mixi Âà²ñºÑ)\\)") + "\\([^<]+\\)") +(defconst mixi-event-time-regexp + "\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\)") (defconst mixi-event-date-regexp - "³«ºÅÆü»þ - \\(.+\\) -³«ºÅ¾ì½ê - \\(.+\\) -¾ÜºÙ
    \\(.+\\)
    Ê罸´ü¸Â \\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü»²²Ã¼Ô - -? -? - + "
    »²²Ã¼Ô
    +
    \\(.+\\)
    ") -?") - -(defun mixi-realize-event (event) +(defun mixi-realize-event (event &optional page) "Realize a EVENT." - ;; FIXME: Check a expiration of cache? + ;; FIXME: Check an expiration of cache? (unless (mixi-object-realized-p event) - (with-mixi-retrieve (mixi-event-page event) - (if (string-match mixi-event-community-regexp buffer) - (mixi-community-set-name (mixi-event-community event) - (match-string 1 buffer)) - (mixi-realization-error 'cannot-find-community event)) - (if (string-match mixi-event-time-regexp buffer) - (mixi-event-set-time - event (encode-time 0 (string-to-number (match-string 8 buffer)) - (string-to-number (match-string 7 buffer)) - (string-to-number (match-string 6 buffer)) - (string-to-number (match-string 5 buffer)) - (string-to-number (match-string 4 buffer)))) - (mixi-realization-error 'cannot-find-time event)) - (if (string-match mixi-event-title-regexp buffer) - (mixi-event-set-title event (match-string 2 buffer)) - (mixi-realization-error 'cannot-find-title event)) - (if (string-match mixi-event-owner-regexp buffer) - (mixi-event-set-owner event - (mixi-make-friend (match-string 2 buffer) - (match-string 3 buffer))) - (if (string-match mixi-event-owner-seceded-regexp buffer) - (mixi-event-set-owner event - (mixi-make-friend nil - (match-string 2 buffer))) - (mixi-realization-error 'cannot-find-owner event))) - (if (string-match mixi-event-date-regexp buffer) - (mixi-event-set-date event (match-string 6 buffer)) - (mixi-realization-error 'cannot-find-date event)) - (if (string-match mixi-event-place-regexp buffer) - (mixi-event-set-place event (match-string 6 buffer)) - (mixi-realization-error 'cannot-find-place event)) - (if (string-match mixi-event-detail-regexp buffer) - (mixi-event-set-detail event (match-string 6 buffer)) - (mixi-realization-error 'cannot-find-detail event)) - (when (string-match mixi-event-limit-regexp buffer) - (mixi-event-set-limit - event (encode-time 0 0 0 (string-to-number (match-string 8 buffer)) - (string-to-number (match-string 7 buffer)) - (string-to-number (match-string 6 buffer))))) - (if (string-match mixi-event-members-regexp buffer) - (mixi-event-set-members event (match-string 6 buffer)) - (mixi-realization-error 'cannot-find-members event))) + (with-mixi-retrieve (or page (mixi-event-page event)) + (let ((case-fold-search t)) + (if (re-search-forward mixi-event-community-regexp nil t) + (mixi-community-set-name (mixi-event-community event) + (match-string 1)) + (mixi-realization-error 'cannot-find-community event)) + (if (re-search-forward mixi-event-title-regexp nil t) + (mixi-event-set-title event (match-string 1)) + (mixi-realization-error 'cannot-find-title event)) + (if (re-search-forward mixi-event-time-regexp nil t) + (mixi-event-set-time + event (encode-time 0 (string-to-number (match-string 5)) + (string-to-number (match-string 4)) + (string-to-number (match-string 3)) + (string-to-number (match-string 2)) + (string-to-number (match-string 1)))) + (mixi-realization-error 'cannot-find-time event)) + (if (re-search-forward mixi-event-date-regexp nil t) + (mixi-event-set-date event (match-string 1)) + (mixi-realization-error 'cannot-find-date event)) + (if (re-search-forward mixi-event-place-regexp nil t) + (mixi-event-set-place event (match-string 1)) + (mixi-realization-error 'cannot-find-place event)) + (if (re-search-forward mixi-event-owner-regexp nil t) + (let ((seceded-or-not (match-string 1)) + (id (match-string 2)) + (nick (match-string 3))) + (if (string= mixi-event-owner-seceded-regexp seceded-or-not) + (mixi-event-set-owner event + (mixi-make-friend nil seceded-or-not)) + (mixi-event-set-owner event (mixi-make-friend id nick)))) + (mixi-realization-error 'cannot-find-owner event)) + (if (re-search-forward mixi-event-detail-regexp nil t) + (mixi-event-set-detail event (match-string 1)) + (mixi-realization-error 'cannot-find-detail event)) + (if (re-search-forward mixi-event-limit-regexp nil t) + (mixi-event-set-limit event (match-string 1)) + (mixi-realization-error 'cannot-find-limit event)) + (if (re-search-forward mixi-event-members-regexp nil t) + (mixi-event-set-members event (match-string 1)) + (mixi-realization-error 'cannot-find-members event)))) (mixi-object-touch event))) (defun mixi-event-community (event) @@ -1914,73 +2041,85 @@ Increase this value when unexpected error frequently occurs." (signal 'wrong-type-argument (list 'mixi-event-p event))) (aref (cdr event) 2)) +(defun mixi-event-comment-count (event) + "Return the comment-count of EVENT." + (unless (mixi-event-p event) + (signal 'wrong-type-argument (list 'mixi-event-p event))) + (aref (cdr event) 3)) + (defun mixi-event-time (event) "Return the time of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) (mixi-realize-event event) - (aref (cdr event) 3)) + (aref (cdr event) 4)) (defun mixi-event-title (event) "Return the title of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) (mixi-realize-event event) - (aref (cdr event) 4)) + (aref (cdr event) 5)) (defun mixi-event-owner (event) "Return the owner of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) (mixi-realize-event event) - (aref (cdr event) 5)) + (aref (cdr event) 6)) (defun mixi-event-date (event) "Return the date of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) (mixi-realize-event event) - (aref (cdr event) 6)) + (aref (cdr event) 7)) (defun mixi-event-place (event) "Return the place of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) (mixi-realize-event event) - (aref (cdr event) 7)) + (aref (cdr event) 8)) (defun mixi-event-detail (event) "Return the detail of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) (mixi-realize-event event) - (aref (cdr event) 8)) + (aref (cdr event) 9)) (defun mixi-event-limit (event) "Return the limit of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) (mixi-realize-event event) - (aref (cdr event) 9)) + (aref (cdr event) 10)) (defun mixi-event-members (event) "Return the members of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) (mixi-realize-event event) - (aref (cdr event) 10)) + (aref (cdr event) 11)) + +(defun mixi-event-set-comment-count (event comment-count) + "Set the comment-count of EVENT." + (unless (mixi-event-p event) + (signal 'wrong-type-argument (list 'mixi-event-p event))) + (aset (cdr event) 3 comment-count)) (defun mixi-event-set-time (event time) "Set the time of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) - (aset (cdr event) 3 time)) + (aset (cdr event) 4 time)) (defun mixi-event-set-title (event title) "Set the title of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) - (aset (cdr event) 4 title)) + (aset (cdr event) 5 title)) (defun mixi-event-set-owner (event owner) "Set the owner of EVENT." @@ -1988,52 +2127,67 @@ Increase this value when unexpected error frequently occurs." (signal 'wrong-type-argument (list 'mixi-event-p event))) (unless (mixi-friend-p owner) (signal 'wrong-type-argument (list 'mixi-friend-p owner))) - (aset (cdr event) 5 owner)) + (aset (cdr event) 6 owner)) (defun mixi-event-set-date (event date) "Set the date of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) - (aset (cdr event) 6 date)) + (aset (cdr event) 7 date)) (defun mixi-event-set-place (event place) "Set the place of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) - (aset (cdr event) 7 place)) + (aset (cdr event) 8 place)) (defun mixi-event-set-detail (event detail) "Set the detail of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) - (aset (cdr event) 8 detail)) + (aset (cdr event) 9 detail)) (defun mixi-event-set-limit (event limit) "Set the limit of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) - (aset (cdr event) 9 limit)) + (aset (cdr event) 10 limit)) (defun mixi-event-set-members (event members) "Set the members of EVENT." (unless (mixi-event-p event) (signal 'wrong-type-argument (list 'mixi-event-p event))) - (aset (cdr event) 10 members)) + (aset (cdr event) 11 members)) -;; Bbs object. +;; BBS object. (defconst mixi-bbs-list '(mixi-topic mixi-event)) -(defmacro mixi-bbs-p (object) - `(when (memq (mixi-object-class ,object) mixi-bbs-list) - t)) +(defmacro mixi-bbs-p (bbs) + `(memq (mixi-object-class ,bbs) mixi-bbs-list)) -(defun mixi-bbs-community (object) - "Return the community of OBJECT." - (unless (mixi-bbs-p object) - (signal 'wrong-type-argument (list 'mixi-bbs-p object))) +(defun mixi-bbs-community (bbs) + "Return the community of BBS." + (unless (mixi-bbs-p bbs) + (signal 'wrong-type-argument (list 'mixi-bbs-p bbs))) (let ((func (intern (concat mixi-object-prefix - (mixi-object-name object) "-community")))) - (funcall func object))) + (mixi-object-name bbs) "-community")))) + (funcall func bbs))) + +(defun mixi-bbs-comment-count (bbs) + "Return the comment-count of BBS." + (unless (mixi-bbs-p bbs) + (signal 'wrong-type-argument (list 'mixi-bbs-p bbs))) + (let ((func (intern (concat mixi-object-prefix + (mixi-object-name bbs) "-comment-count")))) + (funcall func bbs))) + +(defun mixi-bbs-set-comment-count (bbs count) + "Set the comment-count of BBS." + (unless (mixi-bbs-p bbs) + (signal 'wrong-type-argument (list 'mixi-bbs-p bbs))) + (let ((func (intern (concat mixi-object-prefix + (mixi-object-name bbs) "-set-comment-count")))) + (funcall func bbs count))) (defalias 'mixi-bbs-id 'mixi-object-id) (defalias 'mixi-bbs-time 'mixi-object-time) @@ -2046,10 +2200,11 @@ Increase this value when unexpected error frequently occurs." "&id=" (mixi-community-id ,community))) (defconst mixi-bbs-list-regexp - "") + "
    ") +;;;###autoload (defun mixi-get-new-bbses (&optional range) "Get new topics." (let ((items (mixi-get-matched-items (mixi-new-bbs-list-page) mixi-new-bbs-list-regexp range))) - (mapcar (lambda (item) - (let ((name (nth 0 item))) - (when (string= name "bbs") - (setq name "topic")) - (let ((func (intern (concat "mixi-make-" name)))) - (funcall func (mixi-make-community (nth 2 item)) - (nth 1 item))))) - items))) - + (delq nil + (mapcar (lambda (item) + (let ((name (nth 0 item))) + (when (string= name "bbs") + (setq name "topic")) + (let* ((func (intern (concat "mixi-make-" name))) + (bbs (funcall func + (mixi-make-community (nth 3 item)) + (nth 1 item))) + (comment-count (mixi-bbs-comment-count bbs)) + (count (string-to-number (nth 2 item)))) + (when (or (null comment-count) + (< comment-count count)) + (mixi-bbs-set-comment-count bbs count) + bbs)))) + items)))) + (defmacro mixi-search-bbs-list-page (keyword) `(concat "/search_topic.pl?page=%d&type=top&submit=search" "&keyword=" (mixi-url-encode-and-quote-percent-string ,keyword) "&community_id=0&category_id=0")) (defconst mixi-search-bbs-list-regexp - "¾ÜºÙ¤ò¸«¤ë") + "") ;; FIXME: Support community and category. +;;;###autoload (defun mixi-search-bbses (keyword &optional range) (let ((items (mixi-get-matched-items (mixi-search-bbs-list-page keyword) mixi-search-bbs-list-regexp @@ -2105,10 +2270,23 @@ Increase this value when unexpected error frequently occurs." (nth 1 item))))) items))) +;; Parent object. +(defmacro mixi-parent-p (object) + `(or (eq (mixi-object-class ,object) 'mixi-diary) + (mixi-bbs-p ,object))) + +(defun mixi-realize-parent (parent &optional page) + "Realize a PARENT." + (unless (mixi-parent-p parent) + (signal 'wrong-type-argument (list 'mixi-parent-p parent))) + (let ((func (intern (concat mixi-object-prefix "realize-" + (mixi-object-name parent))))) + (funcall func parent page))) + ;; Comment object. -(defun mixi-make-comment (parent owner time content) +(defun mixi-make-comment (parent owner time content &optional count) "Return a comment object." - (cons 'mixi-comment (vector parent owner time content))) + (cons 'mixi-comment (vector parent owner time content count))) (defmacro mixi-comment-p (comment) `(eq (mixi-object-class ,comment) 'mixi-comment)) @@ -2137,6 +2315,12 @@ Increase this value when unexpected error frequently occurs." (signal 'wrong-type-argument (list 'mixi-comment-p comment))) (aref (cdr comment) 3)) +(defun mixi-comment-count (comment) + "Return the count of COMMENT." + (unless (mixi-comment-p comment) + (signal 'wrong-type-argument (list 'mixi-comment-p comment))) + (aref (cdr comment) 4)) + (defun mixi-diary-comment-list-page (diary) (concat "/view_diary.pl?full=1" "&id=" (mixi-diary-id diary) @@ -2144,32 +2328,20 @@ Increase this value when unexpected error frequently occurs." ;; FIXME: Split regexp to time, owner(id and nick) and contents. (defconst mixi-diary-comment-list-regexp -"
    - - - - - - - - - - -") + "
    \\(¼«Ê¬¤Î¥³¥á¥ó¥È¤òºï½ü¤¹¤ë\\|\\|\\) +\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\)
    +
    +
    +
    \\(.*\\)
    +
    +\\(\\(.\\|\r?\n\\)*?\\) +
    ") (defun mixi-event-comment-list-page (event) (concat "/view_event.pl?page=all" @@ -2214,75 +2366,122 @@ Increase this value when unexpected error frequently occurs." ;; FIXME: Split regexp to time, owner(id and nick) and contents. (defconst mixi-event-comment-list-regexp - "
    -\\) -\\( - - - -") - + "
    \\(\\|\\) +\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\)
    +
    +
    +
    \\(.*\\)
    +
    +\\(\\(.\\|\r?\n\\)*?\\) +
    ") + +;;;###autoload (defun mixi-get-comments (parent &optional range) "Get comments of PARENT." - (unless (mixi-object-p parent) - (signal 'wrong-type-argument (list 'mixi-object-p parent))) + (unless (mixi-parent-p parent) + (signal 'wrong-type-argument (list 'mixi-parent-p parent))) (let* ((name (mixi-object-name parent)) (list-page (intern (concat mixi-object-prefix name "-comment-list-page"))) (regexp (eval (intern (concat mixi-object-prefix name - "-comment-list-regexp"))))) - (let ((items (mixi-get-matched-items - (funcall list-page parent) regexp))) - (let (list) - (catch 'stop - (mapc (lambda (item) - (when (and (numberp range) - (>= (length list) range)) - (throw 'stop nil)) - (setq list (cons item list))) - (reverse items))) - (setq items (reverse list))) + "-comment-list-regexp")))) + (page (funcall list-page parent))) + (unless (mixi-object-realized-p parent) + (mixi-realize-parent parent page) + (setq page nil)) + (let ((items (mixi-get-matched-items page regexp range t))) (mapcar (lambda (item) - (mixi-make-comment parent (mixi-make-friend - (nth 7 item) (nth 8 item)) - (encode-time - 0 - (string-to-number (nth 4 item)) - (string-to-number (nth 3 item)) - (string-to-number (nth 2 item)) - (string-to-number (nth 1 item)) - (string-to-number (nth 0 item))) - (nth 10 item))) + (let (owner-id owner-nick year month day hour minute content + count) + (if (eq (mixi-object-class parent) 'mixi-diary) + (progn + (setq owner-id (nth 1 item)) + (setq owner-nick (nth 2 item)) + (setq year (nth 4 item)) + (setq month (nth 5 item)) + (setq day (nth 6 item)) + (setq hour (nth 7 item)) + (setq minute (nth 8 item)) + (setq content (nth 9 item))) + (setq owner-id (nth 8 item)) + (setq owner-nick (nth 9 item)) + (setq year (nth 3 item)) + (setq month (nth 4 item)) + (setq day (nth 5 item)) + (setq hour (nth 6 item)) + (setq minute (nth 7 item)) + (setq content (nth 10 item)) + (setq count (nth 1 item))) + (mixi-make-comment parent (mixi-make-friend owner-id + owner-nick) + (encode-time + 0 + (string-to-number minute) + (string-to-number hour) + (string-to-number day) + (string-to-number month) + (string-to-number year)) + content count))) items)))) (defmacro mixi-new-comment-list-page () `(concat "/new_comment.pl?page=%d")) (defconst mixi-new-comment-list-regexp - "") + "") +;;;###autoload (defun mixi-get-new-comments (&optional range) "Get new comments." (let ((items (mixi-get-matched-items (mixi-new-comment-list-page) mixi-new-comment-list-regexp range))) - (mapcar (lambda (item) - (mixi-make-diary (mixi-make-friend (nth 1 item)) (nth 0 item))) - items))) + (delq nil + (mapcar (lambda (item) + (let* ((diary (mixi-make-diary + (mixi-make-friend (nth 1 item)) + (nth 0 item))) + (comment-count (mixi-diary-comment-count diary)) + (count (string-to-number (nth 2 item)))) + (when (or (null comment-count) + (< comment-count count)) + (mixi-diary-set-comment-count diary count) + diary))) + items)))) + +(defmacro mixi-new-bbs-comment-list-page () + `(concat "/new_bbs_comment.pl?page=%d")) + +(defconst mixi-new-bbs-comment-list-regexp + "") + +;;;###autoload +(defun mixi-get-new-bbs-comments (&optional range) + "Get new BBS comments." + (let ((items (mixi-get-matched-items (mixi-new-bbs-comment-list-page) + mixi-new-bbs-comment-list-regexp + range))) + (delq nil + (mapcar (lambda (item) + (let ((name (nth 0 item))) + (when (string= name "bbs") + (setq name "topic")) + (let ((make-func (intern (concat "mixi-make-" name))) + (comment-count-func + (intern (concat "mixi-" name "-comment-count"))) + (set-comment-count-func + (intern (concat "mixi-" name + "-set-comment-count")))) + (let* ((bbs (funcall make-func + (mixi-make-community (nth 3 item)) + (nth 1 item))) + (comment-count (funcall comment-count-func bbs)) + (count (string-to-number (nth 2 item)))) + (when (or (null comment-count) + (< comment-count count)) + (funcall set-comment-count-func bbs count) + bbs))))) + items)))) (defun mixi-post-diary-comment-page (diary) (concat "/add_comment.pl?&diary_id=" (mixi-diary-id diary))) @@ -2296,6 +2495,7 @@ Increase this value when unexpected error frequently occurs." "&comm_id=" (mixi-community-id (mixi-event-community event)))) ;; FIXME: Support photos. +;;;###autoload (defun mixi-post-comment (parent content) "Post a comment to PARENT." (unless (mixi-object-p parent) @@ -2312,8 +2512,8 @@ Increase this value when unexpected error frequently occurs." ("comment_body" . ,content))) (setq fields `(("comment" . ,content)))) (with-mixi-post-form (funcall page parent) fields - (if (string-match mixi-post-key-regexp buffer) - (setq post-key (match-string 1 buffer)) + (if (re-search-forward mixi-post-key-regexp nil t) + (setq post-key (match-string 1)) (mixi-post-error 'cannot-find-key parent))) (if (mixi-diary-p parent) (setq fields @@ -2325,15 +2525,14 @@ Increase this value when unexpected error frequently occurs." ("comment" . ,content) ("submit" . "confirm")))) (with-mixi-post-form (funcall page parent) fields - (unless (string-match mixi-post-succeed-regexp buffer) + (unless (re-search-forward mixi-post-succeed-regexp nil t) (mixi-post-error 'cannot-find-succeed parent))))) ;; Message object. (defconst mixi-message-box-list '(inbox outbox savebox thrash)) ; thrash? (defmacro mixi-message-box-p (box) - `(when (memq ,box mixi-message-box-list) - t)) + `(memq ,box mixi-message-box-list)) (defun mixi-message-box-name (box) "Return the name of BOX." @@ -2368,35 +2567,35 @@ Increase this value when unexpected error frequently occurs." (defconst mixi-message-owner-regexp "\\(º¹½Ð¿Í\\|°¸ Àè\\) : \\(.*\\)\\(\\|\\)") -(defconst mixi-message-title-regexp -"·ï\\(¡¡\\| \\)̾ : \\(.+\\)\n?") (defconst mixi-message-time-regexp "Æü\\(¡¡\\| \\)ÉÕ : \\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\)»þ\\([0-9]+\\)ʬ  ") +(defconst mixi-message-title-regexp +"·ï\\(¡¡\\| \\)̾ : \\(.*\\)\n?") (defconst mixi-message-content-regexp - "
    ") + "") (defun mixi-realize-message (message) "Realize a MESSAGE." (unless (mixi-object-realized-p message) (with-mixi-retrieve (mixi-message-page message) - (if (string-match mixi-message-owner-regexp buffer) + (if (re-search-forward mixi-message-owner-regexp nil t) (mixi-message-set-owner message - (mixi-make-friend (match-string 2 buffer) - (match-string 3 buffer))) + (mixi-make-friend (match-string 2) + (match-string 3))) (mixi-realization-error 'cannot-find-owner message)) - (if (string-match mixi-message-title-regexp buffer) - (mixi-message-set-title message (match-string 2 buffer)) - (mixi-realization-error 'cannot-find-title message)) - (if (string-match mixi-message-time-regexp buffer) + (if (re-search-forward mixi-message-time-regexp nil t) (mixi-message-set-time - message (encode-time 0 (string-to-number (match-string 6 buffer)) - (string-to-number (match-string 5 buffer)) - (string-to-number (match-string 4 buffer)) - (string-to-number (match-string 3 buffer)) - (string-to-number (match-string 2 buffer)))) + message (encode-time 0 (string-to-number (match-string 6)) + (string-to-number (match-string 5)) + (string-to-number (match-string 4)) + (string-to-number (match-string 3)) + (string-to-number (match-string 2)))) (mixi-realization-error 'cannot-find-time message)) - (if (string-match mixi-message-content-regexp buffer) - (mixi-message-set-content message (match-string 1 buffer)) + (if (re-search-forward mixi-message-title-regexp nil t) + (mixi-message-set-title message (match-string 2)) + (mixi-realization-error 'cannot-find-title message)) + (if (re-search-forward mixi-message-content-regexp nil t) + (mixi-message-set-content message (match-string 1)) (mixi-realization-error 'cannot-find-content message))) (mixi-object-touch message))) @@ -2471,6 +2670,7 @@ Increase this value when unexpected error frequently occurs." (defconst mixi-message-list-regexp "") +;;;###autoload (defun mixi-get-introductions (&rest friend-or-range) "Get introductions of FRIEND." (when (> (length friend-or-range) 2) @@ -2620,6 +2822,415 @@ Increase this value when unexpected error frequently occurs." (nth 2 item))) items)))) +;; News object. +(defvar mixi-news-cache (make-hash-table :test 'equal)) +(defun mixi-make-news (media-id id &optional media time title content) + "Return a news object." + (mixi-make-cache (list media-id id) + (cons 'mixi-news (vector nil media-id id media time title + content)) + mixi-news-cache)) + +(defconst mixi-news-url-regexp + "/view_news\\.pl\\?\\(id=\\([0-9]+\\)&media_id=\\([0-9]+\\)\\|media_id=\\([0-9]+\\)&id=\\([0-9]+\\)\\)") + +(defun mixi-make-news-from-url (url) + "Return a news object from URL." + (when (string-match mixi-news-url-regexp url) + (let ((id (or (match-string 2 url) (match-string 5 url))) + (media-id (or (match-string 3 url) (match-string 4 url)))) + (mixi-make-news media-id id)))) + +(defmacro mixi-news-p (news) + `(eq (mixi-object-class ,news) 'mixi-news)) + +(defmacro mixi-news-page (news) + `(concat "http://news.mixi.jp/view_news.pl?id=" (mixi-news-id ,news) + "&media_id=" (mixi-news-media-id ,news))) + +(defconst mixi-news-finished-regexp + "

    ¢¨¿½¤·Ìõ¤¢¤ê¤Þ¤»¤ó¤¬¡¢¤³¤Î¥Ë¥å¡¼¥¹¤Ï·ÇºÜ´ü´Ö¤¬½ªÎ»¤·¤¿¤«¡¢URL¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤¿¤á¤´Í÷¤¤¤¿¤À¤±¤Þ¤»¤ó¡£¾Ü¤·¤¯¤Ï¤³¤Á¤é¤ò¤´Í÷¤¯¤À¤µ¤¤¡£

    ") +(defconst mixi-news-title-regexp + "
    +

    \\(.+\\)

    ") +(defconst mixi-news-media-time-regexp + "

    ¡Ê\\(.+\\) - \\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\)¡Ë

    ") +(defconst mixi-news-content-regexp + "
    +\\(.+\\) ++ +\\(
    +
    \\|
    \\)") + +(defun mixi-realize-news (news) + "Realize a NEWS." + ;; FIXME: Check an expiration of cache? + (unless (mixi-object-realized-p news) + (with-mixi-retrieve (mixi-news-page news) + (if (re-search-forward mixi-news-finished-regexp nil t) + (mixi-news-set-content news (match-string 0)) + (if (re-search-forward mixi-news-title-regexp nil t) + (mixi-news-set-title news (match-string 1)) + (mixi-realization-error 'cannot-find-title news)) + (if (re-search-forward mixi-news-media-time-regexp nil t) + (progn + (mixi-news-set-media news (match-string 1)) + (let ((year (nth 5 (decode-time (current-time)))) + (month (nth 4 (decode-time (current-time)))) + (month-of-item (string-to-number (match-string 2)))) + (when (> month-of-item month) + (decf year)) + (mixi-news-set-time + news (encode-time 0 (string-to-number (match-string 5)) + (string-to-number (match-string 4)) + (string-to-number (match-string 3)) + month year)))) + (mixi-realization-error 'cannot-find-media-time news)) + (if (re-search-forward mixi-news-content-regexp nil t) + (mixi-news-set-content news (match-string 1)) + (mixi-realization-error 'cannot-find-content news)))) + (mixi-object-touch news))) + +(defun mixi-news-media-id (news) + "Return the media-id of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (aref (cdr news) 1)) + +(defun mixi-news-id (news) + "Return the id of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (aref (cdr news) 2)) + +(defun mixi-news-media (news) + "Return the media of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (unless (aref (cdr news) 3) + (mixi-realize-news news)) + (aref (cdr news) 3)) + +(defun mixi-news-time (news) + "Return the time of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (unless (aref (cdr news) 4) + (mixi-realize-news news)) + (aref (cdr news) 4)) + +(defun mixi-news-title (news) + "Return the title of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (unless (aref (cdr news) 5) + (mixi-realize-news news)) + (aref (cdr news) 5)) + +(defun mixi-news-content (news) + "Return the content of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (mixi-realize-news news) + (aref (cdr news) 6)) + +(defun mixi-news-set-media (news media) + "Set the media of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (aset (cdr news) 3 media)) + +(defun mixi-news-set-time (news time) + "Set the time of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (aset (cdr news) 4 time)) + +(defun mixi-news-set-title (news title) + "Set the title of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (aset (cdr news) 5 title)) + +(defun mixi-news-set-content (news content) + "Set the content of NEWS." + (unless (mixi-news-p news) + (signal 'wrong-type-argument (list 'mixi-news-p news))) + (aset (cdr news) 6 content)) + +(defconst mixi-news-category-list '(domestic politics economy area abroad + sports entertainment IT game-anime + column)) + +(defmacro mixi-news-category-p (category) + `(memq ,category mixi-news-category-list)) + +(defun mixi-news-category-id (category) + "Return the id of CATEGORY." + (unless (mixi-news-category-p category) + (signal 'wrong-type-argument (list 'mixi-news-category-p category))) + (number-to-string + (1+ (- (length mixi-news-category-list) + (length (memq category mixi-news-category-list)))))) + +(defconst mixi-news-sort-list '(newest pickup)) + +(defmacro mixi-news-sort-p (sort) + `(memq ,sort mixi-news-sort-list)) + +(defun mixi-news-sort-id (sort) + "Return the id of SORT." + (unless (mixi-news-sort-p sort) + (signal 'wrong-type-argument (list 'mixi-news-sort-p sort))) + (number-to-string + (- (length mixi-news-sort-list) + (length (memq sort mixi-news-sort-list))))) + +(defmacro mixi-news-list-page (category sort) + `(concat "http://news.mixi.jp/list_news_category.pl?page=%d" + "&sort=" (mixi-news-sort-id ,sort) + "&id=" (mixi-news-category-id ,category) + "&type=bn")) + +(defconst mixi-news-list-regexp + "
    + +") + +;;;###autoload +(defun mixi-get-news (category sort &optional range) + "Get news of CATEGORY and SORT." + (unless (mixi-news-category-p category) + (signal 'wrong-type-argument (list 'mixi-news-category-p category))) + (unless (mixi-news-sort-p sort) + (signal 'wrong-type-argument (list 'mixi-news-sort-p sort))) + (let ((items (mixi-get-matched-items (mixi-news-list-page category sort) + mixi-news-list-regexp + range)) + (year (nth 5 (decode-time (current-time)))) + (month (nth 4 (decode-time (current-time))))) + (mapcar (lambda (item) + (let ((month-of-item (string-to-number (nth 4 item)))) + (when (> month-of-item month) + (decf year)) + (setq month month-of-item) + (mixi-make-news (nth 1 item) (nth 0 item) (nth 3 item) + (encode-time + 0 (string-to-number (nth 7 item)) + (string-to-number (nth 6 item)) + (string-to-number (nth 5 item)) + month year) + (nth 2 item)))) + items))) + +;; Release object. +(defun mixi-make-release (title time content) + "Return a release object." + (cons 'mixi-release (vector title time content))) + +(defmacro mixi-release-p (release) + `(eq (mixi-object-class ,release) 'mixi-release)) + +(defun mixi-release-title (release) + "Return the title of RELEASE." + (unless (mixi-release-p release) + (signal 'wrong-type-argument (list 'mixi-release-p release))) + (aref (cdr release) 0)) + +(defun mixi-release-time (release) + "Return the time of RELEASE." + (unless (mixi-release-p release) + (signal 'wrong-type-argument (list 'mixi-release-p release))) + (aref (cdr release) 1)) + +(defun mixi-release-content (release) + "Return the content of RELEASE." + (unless (mixi-release-p release) + (signal 'wrong-type-argument (list 'mixi-release-p release))) + (aref (cdr release) 2)) + +(defmacro mixi-release-list-page () + `(concat "/release_info.pl?page=%d")) + +(defconst mixi-release-list-regexp + " + + +
     \\(.+\\) -\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü
    \\([0-9]+\\):\\([0-9]+\\)\\(
    - -\\|\\) -
    - - -\\( - -
    \\) -\\(.*\\) - -\\(| ]+>ºï½ü - -\\|\\)
    -
    - - -
    -\\(.+\\) -
    ") + "\\( +\\|\\)\\(.*\\) +\\( +| ¼«Ê¬¤Î¥³¥á¥ó¥È¤òºï½ü¤¹¤ë +\\|\\) +* +\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\) + +* +
    +\\(\\(.\\|\r?\n\\)*?\\) +
    + +") (defun mixi-topic-comment-list-page (topic) (concat "/view_bbs.pl?page=all" @@ -2178,34 +2350,14 @@ Increase this value when unexpected error frequently occurs." ;; FIXME: Split regexp to time, owner(id and nick) and contents. (defconst mixi-topic-comment-list-regexp - "
    -\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü
    -\\([0-9]+\\):\\([0-9]+\\)
    -\\( -\\|\\)
      -[^<]+:  -\\( -\\|\\) *\\(.*\\) - -?\\( - -\\|ºï½ü -\\|\\)
    - - - - -
    - -\\(.+\\) -
    -
    -\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü
    -\\([0-9]+\\):\\([0-9]+\\)
    -\\(
    \\) -[^<]+ : -\\(.*\\) - -\\(| -ºï½ü - -\\|\\)
    - - -
    \\(.+\\)
    -
    \\(.+\\)
    \\(.*\\)
    ") +;;;###autoload (defun mixi-get-messages (&rest box-or-range) "Get messages of BOX." (when (> (length box-or-range) 2) @@ -2500,6 +2700,7 @@ Increase this value when unexpected error frequently occurs." (defconst mixi-post-message-succeed-regexp "Á÷¿®´°Î»¤·¤Þ¤·¤¿¡£") +;;;###autoload (defun mixi-post-message (friend title content) "Post a message to FRIEND." (unless (mixi-friend-p friend) @@ -2513,8 +2714,8 @@ Increase this value when unexpected error frequently occurs." ("submit" . "main"))) post-key) (with-mixi-post-form (mixi-post-message-page friend) fields - (if (string-match mixi-post-message-key-regexp buffer) - (setq post-key (match-string 1 buffer)) + (if (re-search-forward mixi-post-message-key-regexp nil t) + (setq post-key (match-string 1)) (mixi-post-error 'cannot-find-key friend))) (setq fields `(("post_key" . ,post-key) ("subject" . ,title) @@ -2522,7 +2723,7 @@ Increase this value when unexpected error frequently occurs." ("yes" . "¡¡Á÷¡¡¿®¡¡") ("submit" . "confirm"))) (with-mixi-post-form (mixi-post-message-page friend) fields - (unless (string-match mixi-post-message-succeed-regexp buffer) + (unless (re-search-forward mixi-post-message-succeed-regexp nil t) (mixi-post-error 'cannot-find-succeed friend))))) ;; Introduction object. @@ -2596,6 +2797,7 @@ Increase this value when unexpected error frequently occurs."

    ¡¦ \\(.+\\)\"\"

    \\(.+\\)\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\) ¢£ \\(.+\\)\\([1-9][0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)
    +
    + +
    + + + + + +
    +\\(.+\\) +
    ") + +;;;###autoload +(defun mixi-get-releases (&optional range) + "Get releases." + (let ((items (mixi-get-matched-items (mixi-release-list-page) + mixi-release-list-regexp + range))) + (mapcar (lambda (item) + (mixi-make-release (nth 0 item) + (encode-time 0 0 0 + (string-to-number (nth 3 item)) + (string-to-number (nth 2 item)) + (string-to-number (nth 1 item))) + (nth 4 item))) + items))) + +;; Echo object. +(defvar mixi-echo-cache (make-hash-table :test 'equal)) +;; FIXME: Support parent. +(defun mixi-make-echo (owner post-time &optional content) + "Return an echo object." + (let ((owner (or owner (mixi-make-me)))) + (mixi-make-cache (list (mixi-friend-id owner) post-time) + (cons 'mixi-echo (vector nil owner post-time content)) + mixi-echo-cache))) + +(defconst mixi-echo-url-regexp + "view_echo\\.pl\\?id=\\([0-9]+\\)&post_time=\\([0-9]+\\)") + +(defun mixi-make-echo-from-url (url) + "Return an echo object from URL." + (when (string-match mixi-echo-url-regexp url) + (let ((owner-id (match-string 1 url)) + (post-time (match-string 2 url))) + (mixi-make-echo (mixi-make-friend owner-id) post-time)))) + +(defmacro mixi-echo-p (echo) + `(eq (mixi-object-class ,echo) 'mixi-echo)) + +(defmacro mixi-echo-page (echo) + `(concat "/view_echo.pl?id=" (mixi-friend-id (mixi-echo-owner ,echo)) + "&post_time=" (mixi-echo-post-time ,echo))) + +(defconst mixi-echo-owner-nick-regexp + "
    \\(.*\\)
    ") +(defconst mixi-echo-content-regexp + "
    \\(.+\\)
    ") + +(defun mixi-realize-echo (echo) + "Realize an ECHO." + ;; FIXME: Check an expiration of cache? + (unless (mixi-object-realized-p echo) + (with-mixi-retrieve (mixi-echo-page echo) + (let ((case-fold-search t)) + (if (re-search-forward mixi-echo-owner-nick-regexp nil t) + (mixi-friend-set-nick (mixi-echo-owner echo) + (match-string 1)) + (mixi-realization-error 'cannot-find-owner-nick echo)) + (if (re-search-forward mixi-echo-content-regexp nil t) + (mixi-echo-set-content echo (match-string 1)) + (mixi-realization-error 'cannot-find-owner-nick echo)))) + (mixi-object-touch echo))) + +(defun mixi-echo-owner (echo) + "Return the owner of ECHO." + (unless (mixi-echo-p echo) + (signal 'wrong-type-argument (list 'mixi-echo-p echo))) + (aref (cdr echo) 1)) + +(defun mixi-echo-post-time (echo) + "Return the post-time of ECHO." + (unless (mixi-echo-p echo) + (signal 'wrong-type-argument (list 'mixi-echo-p echo))) + (aref (cdr echo) 2)) + +(defun mixi-echo-content (echo) + "Return the content of ECHO." + (unless (mixi-echo-p echo) + (signal 'wrong-type-argument (list 'mixi-echo-p echo))) + (mixi-realize-echo echo) + (aref (cdr echo) 3)) + +(defun mixi-echo-set-content (echo content) + "Set the content of ECHO." + (unless (mixi-echo-p echo) + (signal 'wrong-type-argument (list 'mixi-echo-p echo))) + (aset (cdr echo) 3 content)) + +(defmacro mixi-echo-list-page (&optional friend) + `(concat "/list_echo.pl?page=%d" + (when ,friend (concat "&id=" (mixi-friend-id ,friend))))) + +(defconst mixi-echo-list-regexp + "") + +;;;###autoload +(defun mixi-get-echoes (&rest friend-or-range) + "Get echoes of FRIEND." + (when (> (length friend-or-range) 2) + (signal 'wrong-number-of-arguments + (list 'mixi-get-echoes (length friend-or-range)))) + (let ((friend (nth 0 friend-or-range)) + (range (nth 1 friend-or-range))) + (when (or (not (mixi-friend-p friend)) (mixi-friend-p range)) + (setq friend (nth 1 friend-or-range)) + (setq range (nth 0 friend-or-range))) + (unless (or (null friend) (mixi-friend-p friend)) + (signal 'wrong-type-argument (list 'mixi-friend-p friend))) + (let ((items (mixi-get-matched-items (mixi-echo-list-page friend) + mixi-echo-list-regexp + range))) + (mapcar (lambda (item) + (mixi-make-echo friend (nth 1 item))) + items)))) + +(defmacro mixi-new-echo-list-page () + `(concat "/recent_echo.pl?page=%d")) + +(defconst mixi-new-echo-list-regexp + "") + +;;;###autoload +(defun mixi-get-new-echoes (&optional range) + "Get new echoes." + (let ((items (mixi-get-matched-items (mixi-new-echo-list-page) + mixi-new-echo-list-regexp + range))) + (mapcar (lambda (item) + (mixi-make-echo (mixi-make-friend (nth 0 item)) (nth 1 item))) + items))) + +(defmacro mixi-post-echo-page () + `(concat "/add_echo.pl")) + +(defconst mixi-echo-post-succeed-regexp mixi-my-id-regexp) + +;;;###autoload +(defun mixi-post-echo (content &optional parent) + "Post an echo." + (unless (stringp content) + (signal 'wrong-type-argument (list 'stringp content))) + (unless (or (null parent) (mixi-echo-p parent)) + (signal 'wrong-type-argument (list 'mixi-echo-p parent))) + (let (fields post-key) + (with-mixi-retrieve (mixi-post-echo-page) + (if (re-search-forward mixi-post-key-regexp nil t) + (setq post-key (match-string 1)) + (mixi-post-error 'cannot-find-key))) + (setq fields `(("post_key" . ,post-key) + ("redirect" . "home") + ("body" . ,content))) + (when (mixi-echo-p parent) + (setq fields (cons `("parent_member_id" . ,(mixi-friend-id + (mixi-echo-owner parent))) + fields)) + (setq fields (cons `("parent_post_time" . ,(mixi-echo-post-time parent)) + fields))) + (with-mixi-post-form (mixi-post-echo-page) fields + (unless (re-search-forward mixi-echo-post-succeed-regexp nil t) + (mixi-post-error 'cannot-find-succeed))))) + (provide 'mixi) ;;; mixi.el ends here