1 ;; mixi.el --- API library for accessing to Mixi
3 ;; Copyright (C) 2005,2006 OHASHI Akira
5 ;; Author: OHASHI Akira <bg66@koka-in.org>
6 ;; Keywords: hypermedia
8 ;; This file is *NOT* a part of Emacs.
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program; if not, you can either send email to this
22 ;; program's maintainer or write to: The Free Software Foundation,
23 ;; Inc.; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 ;; API for getting contents:
30 ;; * mixi-get-favorites
33 ;; * mixi-get-new-diaries
34 ;; * mixi-get-communities
36 ;; * mixi-get-new-topics
37 ;; * mixi-get-comments
38 ;; * mixi-get-new-comments
42 ;; Display only the first page of new diaries like a mail format.
44 ;; (let ((mixi-new-diary-max-pages 1)
45 ;; (buffer (generate-new-buffer "*temp*"))
46 ;; (format "%Y/%m/%d %H:%M"))
47 ;; (pop-to-buffer buffer)
48 ;; (mapc (lambda (diary)
49 ;; (let ((subject (mixi-diary-title diary))
50 ;; ;; Don't get owner's nick at first for omitting a useless
52 ;; (from (mixi-friend-nick (mixi-diary-owner diary)))
53 ;; (date (format-time-string format (mixi-diary-time diary)))
54 ;; (body (mixi-diary-content diary)))
55 ;; (insert "From: " from "\n"
56 ;; "Subject: " subject "\n"
57 ;; "Date: " date "\n\n"
59 ;; (mixi-get-new-diaries))
60 ;; (set-buffer-modified-p nil)
61 ;; (setq buffer-read-only t)
62 ;; (goto-char (point-min)))
64 ;; Display only the first page of new diaries including all comments like a
65 ;; mail format. Comments are displayed like a reply mail.
67 ;; (let ((mixi-new-diary-max-pages 1)
68 ;; (buffer (generate-new-buffer "*temp*"))
69 ;; (format "%Y/%m/%d %H:%M"))
70 ;; (pop-to-buffer buffer)
71 ;; (mapc (lambda (diary)
72 ;; (let ((subject (mixi-diary-title diary))
73 ;; ;; Don't get owner's nick at first for omitting a useless
75 ;; (from (mixi-friend-nick (mixi-diary-owner diary)))
76 ;; (date (format-time-string format (mixi-diary-time diary)))
77 ;; (body (mixi-diary-content diary)))
78 ;; (insert "From: " from "\n"
79 ;; "Subject: " subject "\n"
80 ;; "Date: " date "\n\n"
82 ;; (mapc (lambda (comment)
83 ;; (let ((from (mixi-friend-nick
84 ;; (mixi-comment-owner comment)))
85 ;; (subject (concat "Re: " subject))
86 ;; (date (format-time-string
87 ;; format (mixi-comment-time comment)))
88 ;; (body (mixi-comment-content comment)))
89 ;; (insert "From: " from "\n"
90 ;; "Subject: " subject "\n"
91 ;; "Date: " date "\n\n"
93 ;; (mixi-get-comments diary))))
94 ;; (mixi-get-new-diaries))
95 ;; (set-buffer-modified-p nil)
96 ;; (setq buffer-read-only t)
97 ;; (goto-char (point-min)))
102 (eval-when-compile (require 'cl))
105 "API library for accessing to Mixi."
108 (defcustom mixi-url "http://mixi.jp"
113 (defcustom mixi-coding-system 'euc-jp
114 "*Coding system for Mixi."
118 (defcustom mixi-default-email nil
119 "*Default E-mail address that is used to login automatically."
120 :type '(choice (string :tag "E-mail address")
121 (const :tag "Asked when it is necessary" nil))
124 (defcustom mixi-default-password nil
125 "*Default password that is used to login automatically."
126 :type '(choice (string :tag "Password")
127 (const :tag "Asked when it is necessary" nil))
130 (defcustom mixi-accept-adult-contents t
135 (defcustom mixi-continuously-access-interval 3.0
136 "*Time interval between each Mixi access.
137 Increase this value when unexpected error frequently occurs."
141 (defcustom mixi-cache-expires 3600
142 "*Seconds for expiration of a cached object."
143 :type '(choice (integer :tag "Expired seconds")
144 (const :tag "Don't expire" nil))
147 ;; FIXME: Not implemented.
148 (defcustom mixi-cache-use-file t
149 "*If non-nil, caches are saved to files."
153 (defcustom mixi-cache-directory (expand-file-name "~/.mixi")
154 "*Where to look for cache files."
158 (defcustom mixi-friend-max-pages 10
159 "*Number of pages which is retrieved for friends."
160 :type '(choice (integer :tag "Number of pages")
161 (const :tag "Infinity" nil))
164 (defcustom mixi-favorite-max-pages nil
165 "*Number of pages which is retrieved for favorites."
166 :type '(choice (integer :tag "Number of pages")
167 (const :tag "Infinity" nil))
170 (defcustom mixi-log-max-pages 1
171 "*Number of pages which is retrieved for logs."
172 :type '(choice (integer :tag "Number of pages")
173 (const :tag "Infinity" nil))
176 (defcustom mixi-diary-max-pages nil
177 "*Number of pages which is retrieved for diaries."
178 :type '(choice (integer :tag "Number of pages")
179 (const :tag "Infinity" nil))
182 (defcustom mixi-new-diary-max-pages nil
183 "*Number of pages which is retrieved for new diaries."
184 :type '(choice (integer :tag "Number of pages")
185 (const :tag "Infinity" nil))
188 (defcustom mixi-community-max-pages nil
189 "*Number of pages which is retrieved for communities."
190 :type '(choice (integer :tag "Number of pages")
191 (const :tag "Infinity" nil))
194 (defcustom mixi-topic-max-pages nil
195 "*Number of pages which is retrieved for topics."
196 :type '(choice (integer :tag "Number of pages")
197 (const :tag "Infinity" nil))
200 (defcustom mixi-new-comment-max-pages nil
201 "*Number of pages which is retrieved for new comments."
202 :type '(choice (integer :tag "Number of pages")
203 (const :tag "Infinity" nil))
206 (defcustom mixi-new-topic-max-pages nil
207 "*Number of pages which is retrieved for new topics."
208 :type '(choice (integer :tag "Number of pages")
209 (const :tag "Infinity" nil))
212 ;; FIXME: defcustom regexp.
214 (defcustom mixi-verbose t
215 "*Flag controls whether `mixi' should be verbose.
216 If it is non-ni, the `w3m-verbose' variable will be bound to nil
217 while `mixi' is waiting for a server's response."
224 (defmacro mixi-message (string)
225 `(concat "[Mixi] " ,string))
227 (defconst mixi-message-adult-contents
228 "¤³¤Î¥Ú¡¼¥¸¤«¤éÀè¤Ï¥¢¥À¥ë¥È¡ÊÀ®¿Í¸þ¤±¡Ë¥³¥ó¥Æ¥ó¥Ä¤¬´Þ¤Þ¤ì¤Æ¤¤¤Þ¤¹¡£<br>
229 ±ÜÍ÷¤ËƱ°Õ¤µ¤ì¤¿Êý¤Î¤ß¡¢Àè¤Ø¤ª¿Ê¤ß¤¯¤À¤µ¤¤¡£")
230 (defconst mixi-message-continuously-accessing
231 "°ÂÄꤷ¤Æ¥µ¥¤¥È¤Î±¿±Ä¤ò¤ª¤³¤Ê¤¦°Ù¡¢´Ö³Ö¤ò¶õ¤±¤Ê¤¤Ï¢Â³Åª¤Ê¥Ú¡¼¥¸¤ÎÁ«°Ü¡¦¹¹<br>
232 ¿·¤ÏÀ©¸Â¤µ¤»¤Æ¤¤¤¿¤À¤¤¤Æ¤ª¤ê¤Þ¤¹¡£¤´ÌÂÏǤò¤ª¤«¤±¤¤¤¿¤·¤Þ¤¹¤¬¡¢¤·¤Ð¤é¤¯¤ª<br>
233 ÂÔ¤Á¤¤¤¿¤À¤¤¤Æ¤«¤éÁàºî¤ò¤ª¤³¤Ê¤Ã¤Æ¤¯¤À¤µ¤¤¡£")
234 (defconst mixi-warning-continuously-accessing
235 "´Ö³Ö¤ò¶õ¤±¤Ê¤¤Ï¢Â³Åª¤Ê¥Ú¡¼¥¸¤ÎÁ«°Ü¡¦¹¹¿·¤òÉÑÈˤˤª¤³¤Ê¤ï¤ì¤Æ¤¤¤ë¤³¤È¤¬¸«<br>
236 ¼õ¤±¤é¤ì¤Þ¤·¤¿¤Î¤Ç¡¢°ì»þŪ¤ËÁàºî¤òÄä»ß¤µ¤»¤Æ¤¤¤¿¤À¤¤Þ¤¹¡£¿½¤·Ìõ¤´¤¶¤¤¤Þ<br>
237 ¤»¤ó¤¬¡¢¤·¤Ð¤é¤¯¤Î´Ö¤ªÂÔ¤Á¤¯¤À¤µ¤¤¡£")
239 (defun mixi-retrieve (url &optional post-data)
240 "Retrieve the URL and return getted strings."
241 (let ((url (w3m-expand-url url mixi-url)))
243 (let ((w3m-verbose (if mixi-verbose nil w3m-verbose)))
244 (if (not (string= (w3m-retrieve url nil nil post-data) "text/html"))
245 (error (mixi-message "Cannot retrieve"))
246 (w3m-decode-buffer url)
247 (let ((ret (buffer-substring-no-properties (point-min) (point-max))))
248 (when (string-match mixi-message-adult-contents ret)
249 (if mixi-accept-adult-contents
250 (setq ret (mixi-retrieve url "submit=agree"))
251 (setq ret (mixi-retrieve (concat url "?")))))
252 (when (string-match mixi-warning-continuously-accessing ret)
253 (error (mixi-message "Continuously accessing")))
254 (if (not (string-match mixi-message-continuously-accessing ret))
256 (message (mixi-message "Waiting for continuously accessing..."))
257 (sit-for mixi-continuously-access-interval)
258 (mixi-retrieve url post-data))))))))
260 (defconst mixi-my-id-regexp
261 "<a href=\"add_diary\\.pl\\?id=\\([0-9]+\\)")
263 (defun mixi-login (&optional email password)
265 (let ((email (or email mixi-default-email
266 (read-from-minibuffer (mixi-message "Login Email: "))))
267 (password (or password mixi-default-password
268 (read-passwd (mixi-message "Login Password: ")))))
270 (setq buffer (mixi-retrieve "/login.pl"
271 (concat "email=" email
272 "&password=" password
275 (unless (string-match "url=/check\\.pl\\?n=" buffer)
276 (error (mixi-message "Cannot login")))
277 (setq buffer (mixi-retrieve "/check.pl?n=home.pl"))
278 (if (string-match mixi-my-id-regexp buffer)
279 (setq mixi-me (mixi-make-friend
280 (string-to-number (match-string 1 buffer))))
281 (error (mixi-message "Cannot login"))))))
283 (defun mixi-logout ()
284 (mixi-retrieve "/logout.pl"))
286 (defmacro with-mixi-retrieve (url &rest body)
289 (setq buffer (mixi-retrieve ,url))
290 (when (string-match "login.pl" buffer)
292 (setq buffer (mixi-retrieve ,url))))
294 (put 'with-mixi-retrieve 'lisp-indent-function 'defun)
296 (defun mixi-get-matched-items (url max-pages regexp)
297 "Get matched items to REGEXP in URL."
301 (while (or (null max-pages) (<= page max-pages))
302 (with-mixi-retrieve (format url page)
304 (while (string-match regexp buffer pos)
307 (while (match-string num buffer)
308 (let ((string (match-string num buffer)))
310 (when (string-match "^[0-9]+$" string)
311 (setq string (string-to-number string))))
312 (setq list (cons string list)))
314 (setq ids (cons (reverse list) ids))
315 (setq pos (match-end (1- num)))))
319 ;; FIXME: Sort? Now order by newest.
322 (defun mixi-remove-markup (string)
323 "Remove markups from STRING."
327 (goto-char (point-min))
328 (while (search-forward "<!--" nil t)
329 (delete-region (match-beginning 0)
330 (or (search-forward "-->" nil t)
332 (goto-char (point-min))
333 (while (re-search-forward "<[^>]+>" nil t)
334 (replace-match "" t t))
335 (goto-char (point-min))
336 (while (re-search-forward "
\r" nil t)
337 (replace-match "\n" t t)))
338 (w3m-decode-entities)
342 ;; FIXME: Is Caches saved to files?
344 (defun mixi-cache-expired-p (object)
345 "Whether a cache of OBJECT is expired."
346 ;; FIXME: Use method instead of `(aref (cdr object) 0)'.
347 (let ((timestamp (aref (cdr object) 0)))
348 (unless (or (null mixi-cache-expires)
350 (time-less-p (time-add timestamp
351 (seconds-to-time mixi-cache-expires))
354 (defun mixi-make-cache (key value table)
355 "Make a cache object and return it."
356 (let ((cache (gethash key table)))
357 (if (and cache (not (mixi-cache-expired-p cache)))
359 (puthash key value table))))
362 (defconst mixi-object-prefix "mixi-")
364 (defmacro mixi-object-class (object)
367 (defmacro mixi-object-p (object)
368 `(eq (string-match (concat "^" mixi-object-prefix)
369 (symbol-name (mixi-object-class ,object))) 0))
371 (defun mixi-object-name (object)
372 "Return the name of OBJECT."
373 (unless (mixi-object-p object)
374 (signal 'wrong-type-argument (list 'mixi-object-p object)))
375 (let ((class (mixi-object-class object)))
376 (substring (symbol-name class) (length mixi-object-prefix))))
378 (defun mixi-object-id (object)
379 "Return the id of OBJECT."
380 (unless (mixi-object-p object)
381 (signal 'wrong-type-argument (list 'mixi-object-p object)))
382 (let ((func (intern (concat mixi-object-prefix
383 (mixi-object-name object) "-id"))))
384 (funcall func object)))
387 (defvar mixi-friend-cache (make-hash-table :test 'equal))
388 (defun mixi-make-friend (id &optional nick)
389 "Return a friend object."
390 (mixi-make-cache id (cons 'mixi-friend (vector nil id nick nil))
393 (defun mixi-make-me ()
395 (with-mixi-retrieve "/home.pl"
396 (if (string-match mixi-my-id-regexp buffer)
398 (mixi-make-friend (string-to-number (match-string 1 buffer))))
399 (signal 'error (list 'who-am-i)))))
402 (defmacro mixi-friend-p (friend)
403 `(eq (mixi-object-class ,friend) 'mixi-friend))
405 (defmacro mixi-friend-page (friend)
406 `(concat "/show_friend.pl?id=" (number-to-string (mixi-friend-id ,friend))))
408 (defconst mixi-friend-nick-regexp
409 "<img alt=\"\\*\" src=\"http://img\\.mixi\\.jp/img/dot0\\.gif\" width=\"1\" height=\"5\"><br>\n\\(.*\\)¤µ¤ó([0-9]+)")
410 (defconst mixi-friend-name-regexp
411 "<td BGCOLOR=#F2DDB7 WIDTH=80 NOWRAP><font COLOR=#996600>̾ Á°</font></td>\n<td WIDTH=345>\\([^<]+\\)</td>")
412 (defconst mixi-my-name-regexp
413 "<td BGCOLOR=#F2DDB7 WIDTH=80 NOWRAP><font COLOR=#996600>̾ Á°</font></td>\n\n<td WIDTH=345>\\([^<]+\\)</td>")
415 (defun mixi-friend-realize (friend)
417 ;; FIXME: Check a expiration of cache?
418 (unless (mixi-friend-realize-p friend)
420 (with-mixi-retrieve (mixi-friend-page friend)
421 (if (string-match mixi-friend-nick-regexp buffer)
422 (mixi-friend-set-nick friend (match-string 1 buffer))
423 (signal 'error (list 'cannot-find-nick friend)))
424 (when (string-match mixi-friend-name-regexp buffer)
425 (setq name (match-string 1 buffer))))
426 ;; For getting my name.
428 (with-mixi-retrieve "/show_profile.pl"
429 (if (string-match mixi-my-name-regexp buffer)
430 (setq name (match-string 1 buffer))
431 (signal 'error (list 'cannot-find-name friend)))))
432 (mixi-friend-set-name friend name))
433 (mixi-friend-touch friend)))
435 (defun mixi-friend-realize-p (friend)
436 "Return the timestamp of FRIEND."
437 (unless (mixi-friend-p friend)
438 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
439 (aref (cdr friend) 0))
441 (defun mixi-friend-id (friend)
442 "Return the id of FRIEND."
443 (unless (mixi-friend-p friend)
444 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
445 (aref (cdr friend) 1))
447 (defun mixi-friend-nick (friend)
448 "Return the nick of FRIEND."
449 (unless (mixi-friend-p friend)
450 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
451 (unless (aref (cdr friend) 2)
452 (mixi-friend-realize friend))
453 (aref (cdr friend) 2))
455 (defun mixi-friend-name (friend)
456 "Return the name of FRIEND."
457 (unless (mixi-friend-p friend)
458 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
459 (mixi-friend-realize friend)
460 (aref (cdr friend) 3))
462 (defun mixi-friend-touch (friend)
463 "Set the timestamp of FRIEND."
464 (unless (mixi-friend-p friend)
465 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
466 (aset (cdr friend) 0 (current-time)))
468 (defun mixi-friend-set-nick (friend nick)
469 "Set the nick of FRIEND."
470 (unless (mixi-friend-p friend)
471 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
472 (aset (cdr friend) 2 nick))
474 (defun mixi-friend-set-name (friend name)
475 "Set the name of FRIEND."
476 (unless (mixi-friend-p friend)
477 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
478 (aset (cdr friend) 3 name))
480 (defmacro mixi-friend-list-page (&optional friend)
481 `(concat "/list_friend.pl?page=%d"
482 (when ,friend (concat "&id=" (number-to-string
483 (mixi-friend-id ,friend))))))
485 (defconst mixi-friend-list-id-regexp
486 "<a href=show_friend\\.pl\\?id=\\([0-9]+\\)")
487 (defconst mixi-friend-list-nick-regexp
488 "<td valign=middle>\\(.+\\)¤µ¤ó([0-9]+)<br />")
490 (defun mixi-get-friends (&optional friend)
491 "Get friends of FRIEND."
492 (unless (or (null friend) (mixi-friend-p friend))
493 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
494 (let ((ids (mixi-get-matched-items (mixi-friend-list-page friend)
495 mixi-friend-max-pages
496 mixi-friend-list-id-regexp))
497 (nicks (mixi-get-matched-items (mixi-friend-list-page friend)
498 mixi-friend-max-pages
499 mixi-friend-list-nick-regexp)))
502 (while (< index (length ids))
503 (setq ret (cons (mixi-make-friend (nth 0 (nth index ids))
504 (nth 0 (nth index nicks))) ret))
509 (defmacro mixi-favorite-list-page ()
510 `(concat "/list_bookmark.pl?page=%d"))
512 (defconst mixi-favorite-list-id-regexp
513 "<td ALIGN=center BGCOLOR=#FDF9F2 width=330><a href=\"show_friend\\.pl\\?id=\\([0-9]+\\)\">")
514 (defconst mixi-favorite-list-nick-regexp
515 "<td BGCOLOR=#FDF9F2><font COLOR=#996600>̾ Á°</font></td>
516 <td COLSPAN=2 BGCOLOR=#FFFFFF>\\(.+\\)</td></tr>")
518 (defun mixi-get-favorites ()
520 (let ((ids (mixi-get-matched-items (mixi-favorite-list-page)
521 mixi-favorite-max-pages
522 mixi-favorite-list-id-regexp))
523 (nicks (mixi-get-matched-items (mixi-favorite-list-page)
524 mixi-favorite-max-pages
525 mixi-favorite-list-nick-regexp)))
528 (while (< index (length ids))
529 (setq ret (cons (mixi-make-friend (nth 0 (nth index ids))
530 (nth 0 (nth index nicks))) ret))
535 (defun mixi-make-log (friend time)
536 "Return a log object."
537 (cons 'mixi-log (vector friend time)))
539 (defmacro mixi-log-p (log)
540 `(eq (mixi-object-class ,log) 'mixi-log))
542 (defun mixi-log-friend (log)
543 "Return the friend of LOG."
544 (unless (mixi-log-p log)
545 (signal 'wrong-type-argument (list 'mixi-log-p log)))
548 (defun mixi-log-time (log)
549 "Return the time of LOG."
550 (unless (mixi-log-p log)
551 (signal 'wrong-type-argument (list 'mixi-log-p log)))
554 (defmacro mixi-log-list-page ()
555 `(concat "/show_log.pl"))
557 (defconst mixi-log-list-regexp
558 "\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü \\([0-9]+\\):\\([0-9]+\\) <a href=\"show_friend\\.pl\\?id=\\([0-9]+\\)\">\\(.+\\)</a><br>")
560 (defun mixi-get-logs ()
562 (let ((items (mixi-get-matched-items (mixi-log-list-page)
564 mixi-log-list-regexp)))
565 (mapcar (lambda (item)
566 (mixi-make-log (mixi-make-friend (nth 5 item) (nth 6 item))
567 (encode-time 0 (nth 4 item) (nth 3 item)
568 (nth 2 item) (nth 1 item)
573 (defvar mixi-diary-cache (make-hash-table :test 'equal))
574 (defun mixi-make-diary (owner id)
575 "Return a diary object."
576 (let ((owner (or owner (mixi-make-me))))
577 (mixi-make-cache (list (mixi-friend-id owner) id)
578 (cons 'mixi-diary (vector nil owner id nil nil nil))
581 (defmacro mixi-diary-p (diary)
582 `(eq (mixi-object-class ,diary) 'mixi-diary))
584 (defmacro mixi-diary-page (diary)
585 `(concat "/view_diary.pl?id=" (number-to-string (mixi-diary-id ,diary))
586 "&owner_id=" (number-to-string (mixi-friend-id
587 (mixi-diary-owner ,diary)))))
589 ;; FIXME: Remove `¤µ¤ó'.
590 (defconst mixi-diary-owner-nick-regexp
591 "<td WIDTH=490 background=http://img\\.mixi\\.jp/img/bg_w\\.gif><b><font COLOR=#605048>\\(.+\\)\\(¤µ¤ó\\)?¤ÎÆüµ</font></b></td>")
592 (defconst mixi-diary-time-regexp
593 "<td ALIGN=center ROWSPAN=2 NOWRAP WIDTH=95 bgcolor=#FFD8B0>\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü<br>\\([0-9]+\\):\\([0-9]+\\)</td>")
594 (defconst mixi-diary-title-regexp
595 "<td BGCOLOR=#FFF4E0 WIDTH=430> \\([^<]+\\)</td></tr>")
596 (defconst mixi-diary-content-regexp
597 "<td CLASS=h12>\\(.+\\)</td></tr>")
599 (defun mixi-diary-realize (diary)
601 ;; FIXME: Check a expiration of cache?
602 (unless (mixi-diary-realize-p diary)
603 (with-mixi-retrieve (mixi-diary-page diary)
604 (if (string-match mixi-diary-owner-nick-regexp buffer)
605 (mixi-friend-set-nick (mixi-diary-owner diary)
606 (match-string 1 buffer))
607 (signal 'error (list 'cannot-find-owner-nick diary)))
608 (if (string-match mixi-diary-time-regexp buffer)
610 diary (encode-time 0 (string-to-number (match-string 5 buffer))
611 (string-to-number (match-string 4 buffer))
612 (string-to-number (match-string 3 buffer))
613 (string-to-number (match-string 2 buffer))
614 (string-to-number (match-string 1 buffer))))
615 (signal 'error (list 'cannot-find-time diary)))
616 (if (string-match mixi-diary-title-regexp buffer)
617 (mixi-diary-set-title diary (match-string 1 buffer))
618 (signal 'error (list 'cannot-find-title diary)))
619 (if (string-match mixi-diary-content-regexp buffer)
620 (mixi-diary-set-content diary (mixi-remove-markup
621 (match-string 1 buffer)))
622 (signal 'error (list 'cannot-find-content diary))))
623 (mixi-diary-touch diary)))
625 (defun mixi-diary-realize-p (diary)
626 "Return the timestamp of DIARY."
627 (unless (mixi-diary-p diary)
628 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
629 (aref (cdr diary) 0))
631 (defun mixi-diary-owner (diary)
632 "Return the owner of DIARY."
633 (unless (mixi-diary-p diary)
634 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
635 (aref (cdr diary) 1))
637 (defun mixi-diary-id (diary)
638 "Return the id of DIARY."
639 (unless (mixi-diary-p diary)
640 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
641 (aref (cdr diary) 2))
643 (defun mixi-diary-time (diary)
644 "Return the time of DIARY."
645 (unless (mixi-diary-p diary)
646 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
647 (mixi-diary-realize diary)
648 (aref (cdr diary) 3))
650 (defun mixi-diary-title (diary)
651 "Return the title of DIARY."
652 (unless (mixi-diary-p diary)
653 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
654 (mixi-diary-realize diary)
655 (aref (cdr diary) 4))
657 (defun mixi-diary-content (diary)
658 "Return the content of DIARY."
659 (unless (mixi-diary-p diary)
660 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
661 (mixi-diary-realize diary)
662 (aref (cdr diary) 5))
664 (defun mixi-diary-touch (diary)
665 "Set the timestamp of DIARY."
666 (unless (mixi-diary-p diary)
667 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
668 (aset (cdr diary) 0 (current-time)))
670 (defun mixi-diary-set-time (diary time)
671 "Set the time of DIARY."
672 (unless (mixi-diary-p diary)
673 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
674 (aset (cdr diary) 3 time))
676 (defun mixi-diary-set-title (diary title)
677 "Set the title of DIARY."
678 (unless (mixi-diary-p diary)
679 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
680 (aset (cdr diary) 4 title))
682 (defun mixi-diary-set-content (diary content)
683 "Set the content of DIARY."
684 (unless (mixi-diary-p diary)
685 (signal 'wrong-type-argument (list 'mixi-diary-p diary)))
686 (aset (cdr diary) 5 content))
688 (defmacro mixi-diary-list-page (&optional friend)
689 `(concat "/list_diary.pl?page=%d"
690 (when ,friend (concat "&id=" (number-to-string
691 (mixi-friend-id ,friend))))))
693 (defconst mixi-diary-list-regexp
694 "<a href=\"view_diary\\.pl\\?id=\\([0-9]+\\)&owner_id=[0-9]+\">")
696 (defun mixi-get-diaries (&optional friend)
697 "Get diaries of FRIEND."
698 (unless (or (null friend) (mixi-friend-p friend))
699 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
700 (let ((items (mixi-get-matched-items (mixi-diary-list-page friend)
702 mixi-diary-list-regexp)))
703 (mapcar (lambda (item)
704 (mixi-make-diary friend (nth 0 item)))
707 (defmacro mixi-new-diary-list-page ()
708 `(concat "/new_friend_diary.pl?page=%d"))
710 (defconst mixi-new-diary-list-regexp
711 "<a class=\"new_link\" href=view_diary\\.pl\\?id=\\([0-9]+\\)&owner_id=\\([0-9]+\\)>")
713 (defun mixi-get-new-diaries ()
715 (let ((items (mixi-get-matched-items (mixi-new-diary-list-page)
716 mixi-new-diary-max-pages
717 mixi-new-diary-list-regexp)))
718 (mapcar (lambda (item)
719 (mixi-make-diary (mixi-make-friend (nth 1 item)) (nth 0 item)))
723 (defvar mixi-community-cache (make-hash-table :test 'equal))
724 (defun mixi-make-community (id &optional name)
725 "Return a community object."
726 (mixi-make-cache id (cons 'mixi-community (vector nil id name nil nil nil
728 mixi-community-cache))
730 (defmacro mixi-community-p (community)
731 `(eq (mixi-object-class ,community) 'mixi-community))
733 (defmacro mixi-community-page (community)
734 `(concat "/view_community.pl?id=" (number-to-string
735 (mixi-community-id ,community))))
737 (defconst mixi-community-nodata-regexp
738 "^¥Ç¡¼¥¿¤¬¤¢¤ê¤Þ¤»¤ó")
739 (defconst mixi-community-name-regexp
740 "<td WIDTH=345>\\(.*\\)</td></tr>")
741 (defconst mixi-community-birthday-regexp
742 "<td BGCOLOR=#F2DDB7><font COLOR=#996600>³«ÀßÆü</font></td>\n<td>\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü</td>")
743 ;; FIXME: Care when the owner has seceded.
744 (defconst mixi-community-owner-regexp
745 "<td BGCOLOR=#F2DDB7><font COLOR=#996600>´ÉÍý¿Í</font></td>\n<td>\n\n<a href=\"\\(home\\.pl\\|show_friend\\.pl\\?id=\\([0-9]+\\)\\)\">\n\\(.+\\)</a>")
746 (defconst mixi-community-category-regexp
747 "<td BGCOLOR=#F2DDB7><font COLOR=#996600>¥«¥Æ¥´¥ê</font></td>\n<td>\\([^<]+\\)</td>")
748 (defconst mixi-community-description-regexp
749 "<td CLASS=h120>\\(.+\\)</td>")
751 (defun mixi-community-realize (community)
752 "Realize a COMMUNITY."
753 ;; FIXME: Check a expiration of cache?
754 (unless (mixi-community-realize-p community)
755 (with-mixi-retrieve (mixi-community-page community)
756 (if (string-match mixi-community-nodata-regexp buffer)
757 ;; FIXME: Set all members?
758 (mixi-community-set-name community "¥Ç¡¼¥¿¤¬¤¢¤ê¤Þ¤»¤ó")
759 (if (string-match mixi-community-name-regexp buffer)
760 (mixi-community-set-name community (match-string 1 buffer))
761 (signal 'error (list 'cannot-find-name community)))
762 (if (string-match mixi-community-birthday-regexp buffer)
763 (mixi-community-set-birthday
765 (encode-time 0 0 0 (string-to-number (match-string 3 buffer))
766 (string-to-number (match-string 2 buffer))
767 (string-to-number (match-string 1 buffer))))
768 (signal 'error (list 'cannot-find-birthday community)))
769 (if (string-match mixi-community-owner-regexp buffer)
770 (if (string= (match-string 1 buffer) "home.pl")
771 (mixi-community-set-owner community (mixi-make-me))
772 (mixi-community-set-owner
773 community (mixi-make-friend
774 (string-to-number (match-string 2 buffer))
775 (match-string 3 buffer))))
776 (signal 'error (list 'cannot-find-owner community)))
777 (if (string-match mixi-community-category-regexp buffer)
778 (mixi-community-set-category community (match-string 1 buffer))
779 (signal 'error (list 'cannot-find-category community)))
780 (if (string-match mixi-community-description-regexp buffer)
781 (mixi-community-set-description community (match-string 1 buffer))
782 (signal 'error (list 'cannot-find-description community)))))
783 (mixi-community-touch community)))
785 (defun mixi-community-realize-p (community)
786 "Return the timestamp of COMMUNITY."
787 (unless (mixi-community-p community)
788 (signal 'wrong-type-argument (list 'mixi-community-p community)))
789 (aref (cdr community) 0))
791 (defun mixi-community-id (community)
792 "Return the id of COMMUNITY."
793 (unless (mixi-community-p community)
794 (signal 'wrong-type-argument (list 'mixi-community-p community)))
795 (aref (cdr community) 1))
797 (defun mixi-community-name (community)
798 "Return the name of COMMUNITY."
799 (unless (mixi-community-p community)
800 (signal 'wrong-type-argument (list 'mixi-community-p community)))
801 (unless (aref (cdr community) 2)
802 (mixi-community-realize community))
803 (aref (cdr community) 2))
805 (defun mixi-community-birthday (community)
806 "Return the birthday of COMMUNITY."
807 (unless (mixi-community-p community)
808 (signal 'wrong-type-argument (list 'mixi-community-p community)))
809 (mixi-community-realize community)
810 (aref (cdr community) 3))
812 (defun mixi-community-owner (community)
813 "Return the owner of COMMUNITY."
814 (unless (mixi-community-p community)
815 (signal 'wrong-type-argument (list 'mixi-community-p community)))
816 (mixi-community-realize community)
817 (aref (cdr community) 4))
819 (defun mixi-community-category (community)
820 "Return the category of COMMUNITY."
821 (unless (mixi-community-p community)
822 (signal 'wrong-type-argument (list 'mixi-community-p community)))
823 (mixi-community-realize community)
824 (aref (cdr community) 5))
826 (defun mixi-community-description (community)
827 "Return the description of COMMUNITY."
828 (unless (mixi-community-p community)
829 (signal 'wrong-type-argument (list 'mixi-community-p community)))
830 (mixi-community-realize community)
831 (aref (cdr community) 6))
833 (defun mixi-community-touch (community)
834 "Set the timestamp of COMMUNITY."
835 (unless (mixi-community-p community)
836 (signal 'wrong-type-argument (list 'mixi-community-p community)))
837 (aset (cdr community) 0 (current-time)))
839 (defun mixi-community-set-name (community name)
840 "Set the name of COMMUNITY."
841 (unless (mixi-community-p community)
842 (signal 'wrong-type-argument (list 'mixi-community-p community)))
843 (aset (cdr community) 2 name))
845 (defun mixi-community-set-birthday (community birthday)
846 "Set the birthday of COMMUNITY."
847 (unless (mixi-community-p community)
848 (signal 'wrong-type-argument (list 'mixi-community-p community)))
849 (aset (cdr community) 3 birthday))
851 (defun mixi-community-set-owner (community owner)
852 "Set the owner of COMMUNITY."
853 (unless (mixi-community-p community)
854 (signal 'wrong-type-argument (list 'mixi-community-p community)))
855 (unless (mixi-friend-p owner)
856 (signal 'wrong-type-argument (list 'mixi-friend-p owner)))
857 (aset (cdr community) 4 owner))
859 (defun mixi-community-set-category (community category)
860 "Set the category of COMMUNITY."
861 (unless (mixi-community-p community)
862 (signal 'wrong-type-argument (list 'mixi-community-p community)))
863 (aset (cdr community) 5 category))
865 (defun mixi-community-set-description (community description)
866 "Set the name of COMMUNITY."
867 (unless (mixi-community-p community)
868 (signal 'wrong-type-argument (list 'mixi-community-p community)))
869 (aset (cdr community) 6 description))
871 (defmacro mixi-community-list-page (&optional friend)
872 `(concat "/list_community.pl?page=%d"
873 (when ,friend (concat "&id=" (number-to-string
874 (mixi-friend-id ,friend))))))
876 (defconst mixi-community-list-id-regexp
877 "<a href=view_community\\.pl\\?id=\\([0-9]+\\)")
878 (defconst mixi-community-list-name-regexp
879 "<td valign=middle>\\(.+\\)([0-9]+)</td>")
881 (defun mixi-get-communities (&optional friend)
882 "Get communities of FRIEND."
883 (unless (or (null friend) (mixi-friend-p friend))
884 (signal 'wrong-type-argument (list 'mixi-friend-p friend)))
885 (let ((ids (mixi-get-matched-items (mixi-community-list-page friend)
886 mixi-community-max-pages
887 mixi-community-list-id-regexp))
888 (names (mixi-get-matched-items (mixi-community-list-page friend)
889 mixi-community-max-pages
890 mixi-community-list-name-regexp)))
893 (while (< index (length ids))
894 (setq ret (cons (mixi-make-community (nth 0 (nth index ids))
895 (nth 0 (nth index names))) ret))
900 (defvar mixi-topic-cache (make-hash-table :test 'equal))
901 (defun mixi-make-topic (community id)
902 "Return a topic object."
903 (mixi-make-cache (list (mixi-community-id community) id)
904 (cons 'mixi-topic (vector nil community id nil nil nil nil))
907 (defmacro mixi-topic-p (topic)
908 `(eq (mixi-object-class ,topic) 'mixi-topic))
910 (defmacro mixi-topic-page (topic)
911 `(concat "/view_bbs.pl?id=" (number-to-string (mixi-topic-id ,topic))
912 "&comm_id=" (number-to-string
913 (mixi-community-id (mixi-topic-community ,topic)))))
915 (defconst mixi-topic-time-regexp
916 "<td rowspan=\"3\" width=\"110\" bgcolor=\"#ffd8b0\" align=\"center\" valign=\"top\" nowrap>\\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü<br>\\([0-9]+\\):\\([0-9]+\\)</td>")
917 (defconst mixi-topic-title-regexp
918 "<td bgcolor=\"#fff4e0\"> \\([^<]+\\)</td>")
919 ;; FIXME: Remove `¤µ¤ó'.
920 (defconst mixi-topic-owner-regexp
921 "<td bgcolor=\"#fdf9f2\"> <font color=\"#dfb479\"></font> <a href=\"show_friend\\.pl\\?id=\\([0-9]+\\)\">\\(.+\\)\\(¤µ¤ó\\)?</a>")
922 (defconst mixi-topic-content-regexp
923 "<td class=\"h120\"><table><tr>\\(.+\\)?</tr></table>\\(.+\\)</td>")
925 (defun mixi-topic-realize (topic)
927 ;; FIXME: Check a expiration of cache?
928 (unless (mixi-topic-realize-p topic)
929 (with-mixi-retrieve (mixi-topic-page topic)
930 (if (string-match mixi-topic-time-regexp buffer)
932 topic (encode-time 0 (string-to-number (match-string 5 buffer))
933 (string-to-number (match-string 4 buffer))
934 (string-to-number (match-string 3 buffer))
935 (string-to-number (match-string 2 buffer))
936 (string-to-number (match-string 1 buffer))))
937 (signal 'error (list 'cannot-find-time topic)))
938 (if (string-match mixi-topic-title-regexp buffer)
939 (mixi-topic-set-title topic (match-string 1 buffer))
940 (signal 'error (list 'cannot-find-title topic)))
941 (if (string-match mixi-topic-owner-regexp buffer)
942 (mixi-topic-set-owner topic
944 (string-to-number (match-string 1 buffer))
945 (match-string 2 buffer)))
946 (signal 'error (list 'cannot-find-owner topic)))
947 (if (string-match mixi-topic-content-regexp buffer)
948 (mixi-topic-set-content topic (mixi-remove-markup
949 (match-string 2 buffer)))
950 (signal 'error (list 'cannot-find-content topic))))
951 (mixi-topic-touch topic)))
953 (defun mixi-topic-realize-p (topic)
954 "Return the timestamp of TOPIC."
955 (unless (mixi-topic-p topic)
956 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
957 (aref (cdr topic) 0))
959 (defun mixi-topic-community (topic)
960 "Return the community of TOPIC."
961 (unless (mixi-topic-p topic)
962 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
963 (aref (cdr topic) 1))
965 (defun mixi-topic-id (topic)
966 "Return the id of TOPIC."
967 (unless (mixi-topic-p topic)
968 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
969 (aref (cdr topic) 2))
971 (defun mixi-topic-time (topic)
972 "Return the time of TOPIC."
973 (unless (mixi-topic-p topic)
974 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
975 (mixi-topic-realize topic)
976 (aref (cdr topic) 3))
978 (defun mixi-topic-title (topic)
979 "Return the title of TOPIC."
980 (unless (mixi-topic-p topic)
981 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
982 (mixi-topic-realize topic)
983 (aref (cdr topic) 4))
985 (defun mixi-topic-owner (topic)
986 "Return the owner of TOPIC."
987 (unless (mixi-topic-p topic)
988 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
989 (mixi-topic-realize topic)
990 (aref (cdr topic) 5))
992 (defun mixi-topic-content (topic)
993 "Return the content of TOPIC."
994 (unless (mixi-topic-p topic)
995 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
996 (mixi-topic-realize topic)
997 (aref (cdr topic) 6))
999 (defun mixi-topic-touch (topic)
1000 "Set the timestamp of TOPIC."
1001 (unless (mixi-topic-p topic)
1002 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
1003 (aset (cdr topic) 0 (current-time)))
1005 (defun mixi-topic-set-time (topic time)
1006 "Set the time of TOPIC."
1007 (unless (mixi-topic-p topic)
1008 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
1009 (aset (cdr topic) 3 time))
1011 (defun mixi-topic-set-title (topic title)
1012 "Set the title of TOPIC."
1013 (unless (mixi-topic-p topic)
1014 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
1015 (aset (cdr topic) 4 title))
1017 (defun mixi-topic-set-owner (topic owner)
1018 "Set the owner of TOPIC."
1019 (unless (mixi-topic-p topic)
1020 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
1021 (unless (mixi-friend-p owner)
1022 (signal 'wrong-type-argument (list 'mixi-friend-p owner)))
1023 (aset (cdr topic) 5 owner))
1025 (defun mixi-topic-set-content (topic content)
1026 "Set the content of TOPIC."
1027 (unless (mixi-topic-p topic)
1028 (signal 'wrong-type-argument (list 'mixi-topic-p topic)))
1029 (aset (cdr topic) 6 content))
1031 (defmacro mixi-topic-list-page (community)
1032 `(concat "/list_bbs.pl?page=%d"
1033 "&id=" (number-to-string (mixi-community-id ,community))))
1035 (defconst mixi-topic-list-regexp
1036 "<a href=view_bbs\\.pl\\?id=\\([0-9]+\\)")
1038 (defun mixi-get-topics (community)
1039 "Get topics of COMMUNITY."
1040 (unless (mixi-community-p community)
1041 (signal 'wrong-type-argument (list 'mixi-community-p community)))
1042 (let ((items (mixi-get-matched-items (mixi-topic-list-page community)
1043 mixi-topic-max-pages
1044 mixi-topic-list-regexp)))
1045 (mapcar (lambda (item)
1046 (mixi-make-topic community (nth 0 item)))
1049 (defmacro mixi-new-topic-list-page ()
1050 `(concat "/new_bbs.pl?page=%d"))
1052 (defconst mixi-new-topic-list-regexp
1053 "<a href=\"view_bbs\\.pl\\?id=\\([0-9]+\\)&comment_count=[0-9]+&comm_id=\\([0-9]+\\)\" class=\"new_link\">")
1055 (defun mixi-get-new-topics ()
1057 (let ((items (mixi-get-matched-items (mixi-new-topic-list-page)
1058 mixi-new-topic-max-pages
1059 mixi-new-topic-list-regexp)))
1060 (mapcar (lambda (item)
1061 (mixi-make-topic (mixi-make-community (nth 1 item))
1066 (defun mixi-make-comment (parent owner time content)
1067 "Return a comment object."
1068 (cons 'mixi-comment (vector parent owner time content)))
1070 (defmacro mixi-comment-p (comment)
1071 `(eq (mixi-object-class ,comment) 'mixi-comment))
1073 (defun mixi-comment-parent (comment)
1074 "Return the parent of COMMENT."
1075 (unless (mixi-comment-p comment)
1076 (signal 'wrong-type-argument (list 'mixi-comment-p comment)))
1077 (aref (cdr comment) 0))
1079 (defun mixi-comment-owner (comment)
1080 "Return the owner of COMMENT."
1081 (unless (mixi-comment-p comment)
1082 (signal 'wrong-type-argument (list 'mixi-comment-p comment)))
1083 (aref (cdr comment) 1))
1085 (defun mixi-comment-time (comment)
1086 "Return the time of COMMENT."
1087 (unless (mixi-comment-p comment)
1088 (signal 'wrong-type-argument (list 'mixi-comment-p comment)))
1089 (aref (cdr comment) 2))
1091 (defun mixi-comment-content (comment)
1092 "Return the content of COMMENT."
1093 (unless (mixi-comment-p comment)
1094 (signal 'wrong-type-argument (list 'mixi-comment-p comment)))
1095 (aref (cdr comment) 3))
1097 (defun mixi-diary-comment-list-page (diary)
1098 (concat "/view_diary.pl?page=all"
1099 "&id=" (number-to-string (mixi-diary-id diary))
1100 "&owner_id=" (number-to-string
1101 (mixi-friend-id (mixi-diary-owner diary)))))
1103 ;; FIXME: Split regexp to time, owner(id and nick) and contents.
1104 (defconst mixi-diary-comment-list-regexp
1105 "<td rowspan=\"2\" align=\"center\" width=\"95\" bgcolor=\"#f2ddb7\" nowrap>
1106 \\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü<br>\\([0-9]+\\):\\([0-9]+\\)\\(<br>
1107 <input type=checkbox name=comment_id value=\".+\">
1110 <td ALIGN=center BGCOLOR=#FDF9F2 WIDTH=430>
1111 <table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" width=\"410\">
1114 <a href=\"show_friend\\.pl\\?id=\\([0-9]+\\)\">\\(.+\\)</a>
1121 <!-- ËÜʸ : start -->
1123 <td bgcolor=\"#ffffff\">
1124 <table BORDER=0 CELLSPACING=0 CELLPADDING=[35] WIDTH=410>
1128 </td></tr></table>")
1130 (defun mixi-topic-comment-list-page (topic)
1131 (concat "/view_bbs.pl?page=all"
1132 "&id=" (number-to-string (mixi-topic-id topic))
1133 "&comm_id=" (number-to-string
1134 (mixi-community-id (mixi-topic-community topic)))))
1136 ;; FIXME: Split regexp to time, owner(id and nick) and contents.
1137 (defconst mixi-topic-comment-list-regexp
1138 "<tr valign=\"top\">
1139 <td rowspan=\"2\" width=\"110\" bgcolor=\"#f2ddb7\" align=\"center\" nowrap>
1140 \\([0-9]+\\)ǯ\\([0-9]+\\)·î\\([0-9]+\\)Æü<br>
1141 \\([0-9]+\\):\\([0-9]+\\)<br>
1143 <td bgcolor=\"#fdf9f2\"> <font color=\"#f8a448\">
1144 <b> [0-9]+</b>:</font>
1146 <a href=\"show_friend\\.pl\\?id=\\([0-9]+\\)\">\\(.+\\)</a>
1153 <td bgcolor=\"#ffffff\" align=\"center\">
1154 <table border=\"0\" cellspacing=\"0\" cellpadding=\"5\" width=\"500\">
1165 (defun mixi-get-comments (parent)
1166 "Get comments of PARENT."
1167 (unless (mixi-object-p parent)
1168 (signal 'wrong-type-argument (list 'mixi-object-p object)))
1169 (let* ((name (mixi-object-name parent))
1170 (list-page (intern (concat mixi-object-prefix name
1171 "-comment-list-page")))
1172 (regexp (eval (intern (concat mixi-object-prefix name
1173 "-comment-list-regexp")))))
1174 (let ((items (mixi-get-matched-items (funcall list-page parent) 1 regexp)))
1175 (mapcar (lambda (item)
1176 (mixi-make-comment parent (mixi-make-friend
1177 (nth 6 item) (nth 7 item))
1178 (encode-time 0 (nth 4 item)
1183 (mixi-remove-markup (nth 8 item))))
1186 (defmacro mixi-new-comment-list-page ()
1187 `(concat "/new_comment.pl?page=%d"))
1189 (defconst mixi-new-comment-list-regexp
1190 "<a href=\"view_diary\\.pl\\?id=\\([0-9]+\\)&owner_id=\\([0-9]+\\)&comment_count=[0-9]+\" class=\"new_link\">")
1192 (defun mixi-get-new-comments ()
1194 (let ((items (mixi-get-matched-items (mixi-new-comment-list-page)
1195 mixi-new-comment-max-pages
1196 mixi-new-comment-list-regexp)))
1197 (mapcar (lambda (item)
1198 (let ((diary (mixi-make-diary
1199 (mixi-make-friend (nth 1 item))
1201 (mixi-get-comments diary)))
1206 ;; FIXME: Move to the class method.
1208 ;; FIXME: When it got some results, this function doesn't work fine.
1209 (defun mixi-friend-to-id (friend)
1210 (with-mixi-retrieve (concat "/search.pl?submit=main&nickname="
1211 (w3m-url-encode-string friend
1212 mixi-coding-system))
1213 (when (string-match "show_friend\\.pl\\?id=\\([0-9]+\\)" buffer)
1214 (string-to-number (match-string 1 buffer)))))
1216 ;; FIXME: When it got some results, this function doesn't work fine.
1217 (defun mixi-community-to-id (community)
1218 (with-mixi-retrieve (concat "/search_community.pl?sort="
1219 "&type=com&submit=main&keyword="
1220 (w3m-url-encode-string community
1221 mixi-coding-system))
1222 (when (string-match "view_community\\.pl\\?id=\\([0-9]+\\)" buffer)
1223 (string-to-number (match-string 1 buffer)))))
1227 ;;; mixi.el ends here