X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=mixi.el;h=a9e04ffdb40a027feda6f6e9f9dd00d1871c30ed;hb=6760587c1526fcfbb1f165c4d7152f13903141d6;hp=6799c43d71bf873a6dd872fda3c075f4c3851722;hpb=d37088b102a3c0ad0487925ca437a2732a5a415d;p=elisp%2Fmixi.git diff --git a/mixi.el b/mixi.el index 6799c43..a9e04ff 100644 --- a/mixi.el +++ b/mixi.el @@ -1,6 +1,6 @@ ;; 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,9 +18,9 @@ ;; 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: @@ -29,19 +29,25 @@ ;; * 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) ;; ;; APIs for posting: ;; @@ -49,10 +55,11 @@ ;; * mixi-post-topic ;; * mixi-post-comment ;; * mixi-post-message +;; * mixi-post-echo (limited) ;; ;; Utilities: ;; -;; * mixi-remove-markup +;; * mixi-remove-markup (half broken) ;; Examples: ;; @@ -135,6 +142,8 @@ (autoload 'w3m-retrieve "w3m") (autoload 'url-retrieve-synchronously "url")) +(defconst mixi-revision "$Revision: 1.192 $") + (defgroup mixi nil "API library for accessing to mixi." :group 'hypermedia) @@ -324,13 +333,13 @@ Increase this value when unexpected error frequently occurs." (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) @@ -346,7 +355,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)))))) @@ -387,7 +396,7 @@ 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)))) @@ -433,14 +442,15 @@ Increase this value when unexpected error frequently occurs." (defun mixi-logout () (mixi-retrieve "/logout.pl")) +(defconst mixi-login-form "
") + (defmacro with-mixi-retrieve (url &rest body) `(with-current-buffer (get-buffer-create mixi-temp-buffer-name) (when ,url (erase-buffer) (insert (mixi-retrieve ,url)) (goto-char (point-min)) - (when (search-forward - "" nil t) + (when (search-forward mixi-login-form nil t) (mixi-login) (erase-buffer) (insert (mixi-retrieve ,url)))) @@ -455,8 +465,7 @@ Increase this value when unexpected error frequently occurs." (erase-buffer) (insert (mixi-post-form ,url ,fields)) (goto-char (point-min)) - (when (search-forward - "" nil t) + (when (search-forward mixi-login-form nil t) (mixi-login) (erase-buffer) (insert (mixi-post-form ,url ,fields)))) @@ -470,7 +479,8 @@ Increase this value when unexpected error frequently occurs." (let ((page 1) ids) (catch 'end - (while (or (null range) (< (length ids) range)) + (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)) @@ -513,6 +523,29 @@ Increase this value when unexpected error frequently occurs." (buffer-string))) ;; stolen (and modified) from w3m.el +(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 @@ -802,55 +835,48 @@ Increase this value when unexpected error frequently occurs." `(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?
\\(.+?\\)\\(\\)") (defconst mixi-friend-age-regexp - "ǯ\\( \\| \\)Îð\n\\([0-9]+\\)ºÐ\\(\\| ǯÎð\n?
\\([0-9]+\\)ºÐ\\( \\)") (defconst mixi-friend-birthday-regexp - "ÃÂÀ¸Æü\n\\([0-9]+\\)·î\\([0-9]+\\)Æü\\(\\| ÃÂÀ¸Æü\n?
\\([0-9]+\\)·î\\([0-9]+\\)Æü\\(\\)") (defconst mixi-friend-blood-type-regexp - "·ì±Õ·¿\n\\([ABO]B?\\)·¿\\(\\| ·ì±Õ·¿\n?
\\([ABO]B?\\)·¿\\(\\)") (defconst mixi-friend-birthplace-regexp - "½Ð¿ÈÃÏ\n?\n\\(.+?\\)\\(\\| ½Ð¿ÈÃÏ\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-hobby-regexp - "¼ñ\\( \\| \\)Ì£\n\\(.+?\\)\\(\\| ¼ñÌ£\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-job-regexp - "¿¦\\( \\| \\)¶È\n\\(.+?\\)\\(\\| ¿¦¶È\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-organization-regexp - "½ê\\( \\| \\)°\n]*>\\(.+?\\)\\(\\| ½ê°\n?
\\(.+?\\)\\(\\)") (defconst mixi-friend-profile-regexp - "¼«¸Ê¾Ò²ð -\\(.+\\)") + "
¼«¸Ê¾Ò²ð
\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) (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 4)) + (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 2))) + (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 2) "ÃË") + (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 2)))) + (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)) @@ -860,11 +886,11 @@ Increase this value when unexpected error frequently occurs." (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 2) ", "))) + (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 2))) + (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 2))) + (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))) @@ -1032,14 +1058,18 @@ 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) @@ -1054,19 +1084,25 @@ 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 () @@ -1128,6 +1164,23 @@ 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 comment-count time title content) @@ -1159,36 +1212,41 @@ Increase this value when unexpected error frequently occurs." (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\\)*?\\)") + "
+\\(\\(.\\|\r?\n\\)*?\\) +
") (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 (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 1)) + (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 7)) - (string-to-number (match-string 6)) + 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 2)) + (string-to-number (match-string 1)))) (mixi-realization-error 'cannot-find-time 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-content-regexp nil t) (mixi-diary-set-content diary (match-string 1)) (mixi-realization-error 'cannot-find-content diary))))) @@ -1264,9 +1322,9 @@ Increase this value when unexpected error frequently occurs." (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) @@ -1283,29 +1341,26 @@ 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) nil - (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)))) + (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) @@ -1360,29 +1417,29 @@ 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 @@ -1440,44 +1497,39 @@ 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) (let ((case-fold-search t)) @@ -1639,7 +1691,7 @@ Increase this value when unexpected error frequently occurs." (defconst mixi-community-list-id-regexp "\\(.+\\)([0-9]+)") + "\\(.+\\)([0-9]+)") ;;;###autoload (defun mixi-get-communities (&rest friend-or-range) @@ -1674,9 +1726,7 @@ Increase this value when unexpected error frequently occurs." "&category_id=0")) (defconst mixi-search-community-list-regexp - "
    - -") + "
    \\(.+\\) ([0-9]+)") ;; FIXME: Support category. ;;;###autoload @@ -1689,6 +1739,23 @@ 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 comment-count time title owner @@ -1718,25 +1785,29 @@ 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 &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 (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)) (mixi-realization-error 'cannot-find-community topic)) + (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)) @@ -1745,15 +1816,12 @@ Increase this value when unexpected error frequently occurs." (string-to-number (match-string 2)) (string-to-number (match-string 1)))) (mixi-realization-error 'cannot-find-time topic)) - (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-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 (re-search-forward mixi-topic-content-regexp nil t) - (mixi-topic-set-content topic (match-string 2)) + (mixi-topic-set-content topic (match-string 1)) (mixi-realization-error 'cannot-find-content topic))) (mixi-object-touch topic))) @@ -1894,46 +1962,35 @@ 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 &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 (or page (mixi-event-page event)) (let ((case-fold-search t)) @@ -1941,6 +1998,9 @@ Increase this value when unexpected error frequently occurs." (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)) @@ -1949,30 +2009,27 @@ Increase this value when unexpected error frequently occurs." (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-title-regexp nil t) - (mixi-event-set-title event (match-string 2)) - (mixi-realization-error 'cannot-find-title event)) - (if (re-search-forward mixi-event-owner-regexp nil t) - (mixi-event-set-owner event (mixi-make-friend (match-string 1) - (match-string 2))) - (if (re-search-forward mixi-event-owner-seceded-regexp nil t) - (mixi-event-set-owner event - (mixi-make-friend nil (match-string 1))) - (mixi-realization-error 'cannot-find-owner 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)) - (when (re-search-forward mixi-event-limit-regexp nil t) - (mixi-event-set-limit - event (encode-time 0 0 0 (string-to-number (match-string 3)) - (string-to-number (match-string 2)) - (string-to-number (match-string 1))))) + (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)))) @@ -2149,11 +2206,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) @@ -2202,7 +2259,7 @@ Increase this value when unexpected error frequently occurs." "&community_id=0&category_id=0")) (defconst mixi-search-bbs-list-regexp - "¾ÜºÙ¤ò¸«¤ë") + "") ;; FIXME: Support community and category. ;;;###autoload @@ -2233,9 +2290,9 @@ Increase this value when unexpected error frequently occurs." (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)) @@ -2264,6 +2321,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) @@ -2271,32 +2334,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" @@ -2341,27 +2372,14 @@ 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) @@ -2379,23 +2397,44 @@ Increase this value when unexpected error frequently occurs." (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) @@ -2416,6 +2455,40 @@ Increase this value when unexpected error frequently occurs." 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))) @@ -2505,7 +2578,7 @@ Increase this value when unexpected error frequently occurs." (defconst mixi-message-title-regexp "·ï\\(¡¡\\| \\)̾ : \\(.*\\)\n?") (defconst mixi-message-content-regexp - "
    ") + "") (defun mixi-realize-message (message) "Realize a MESSAGE." @@ -2781,27 +2854,23 @@ Increase this value when unexpected error frequently occurs." `(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 a expiration of cache? + ;; 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) @@ -2896,7 +2965,8 @@ Increase this value when unexpected error frequently occurs." (aset (cdr news) 6 content)) (defconst mixi-news-category-list '(domestic politics economy area abroad - sports entertainment IT)) + sports entertainment IT game-anime + column)) (defmacro mixi-news-category-p (category) `(memq ,category mixi-news-category-list)) @@ -2929,14 +2999,9 @@ Increase this value when unexpected error frequently occurs." "&type=bn")) (defconst mixi-news-list-regexp - "
    - - - -") + " + +") ;;;###autoload (defun mixi-get-news (category sort &optional range) @@ -2951,19 +3016,227 @@ 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 6 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 2 item) (nth 1 item) (nth 5 item) + (mixi-make-news (nth 1 item) (nth 0 item) (nth 3 item) (encode-time - 0 (string-to-number (nth 9 item)) - (string-to-number (nth 8 item)) - (string-to-number (nth 7 item)) + 0 (string-to-number (nth 7 item)) + (string-to-number (nth 6 item)) + (string-to-number (nth 5 item)) month year) - (nth 3 item)))) + (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" @@ -2305,34 +2356,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]+\\)
    -\\(
    \\) -[^<]+ : -\\(.*\\) - -\\(| -ºï½ü - -\\|\\)
    - - -
    \\(.+\\)
    -
    \\(.*\\)
    \\(.*\\)
    ¿½¤·Ìõ¤´¤¶¤¤¤Þ¤»¤ó¤¬¡¢¤³¤Î¥Ë¥å¡¼¥¹¤Ï·ÇºÜ½ªÎ»¤·¤Þ¤·¤¿¡£\\(.+\\)\\( -\\)?(\\(.+\\) - \\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\))
    - + "
    \\(.+\\) -
    -\\(.* -\\)? - -\\(
    ¡¦\\(.+\\) -\\(\\|\\) - -\\(.+\\)\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\)

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

    \\(.+\\)\\([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