Fix.
[riece] / lisp / riece-google.el
1 ;;; riece-google.el --- Interface to Google API
2 ;; Copyright (C) 2005 OHASHI Akira
3
4 ;; Author: OHASHI Akira <bg66@koka-in.org>
5 ;;         SASADA Koichi <ko1 at atdot.net>
6 ;; Keywords: IRC, riece
7
8 ;; This file is part of Riece.
9
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)
13 ;; any later version.
14
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.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;; This add-on searches keywords by Google.
28
29 ;; Ruby code was stolen (and modified) from nadoka.
30
31 ;; To use, add the following line to your ~/.riece/init.el:
32 ;; (add-to-list 'riece-addons 'riece-google)
33
34 ;;; Code:
35
36 (require 'riece-message)
37
38 (defgroup riece-google nil
39   "Interface to Google API."
40   :prefix "riece-"
41   :group 'riece)
42
43 (defcustom riece-google-ruby-command "ruby"
44   "Command name for Ruby interpreter."
45   :type 'string
46   :group 'riece-google)
47
48 (defcustom riece-google-program
49   '("\
50 # Copyright (c) 2004 SASADA Koichi <ko1 at atdot.net>
51 #
52 # This program is free software with ABSOLUTELY NO WARRANTY.
53 # You can re-distribute and/or modify this program under
54 # the same terms of the Ruby's lisence.
55
56 require 'soap/wsdlDriver'
57 require 'iconv'
58 require 'kconv'
59 require 'cgi'
60
61 keywords            = '" keywords "'
62 max_results         = " max-results "
63 license_key         = '" license-key "'
64 default_lang        = '" lang "'
65 google_wsdl         = 'http://api.google.com/GoogleSearch.wsdl'
66 google              = SOAP::WSDLDriverFactory.new(google_wsdl).create_driver
67
68 def erace_tag str
69   CGI.unescapeHTML(str.gsub(/\\<.+?\\>/, ''))
70 end
71
72 def lang_check lang
73   if lang.empty? || /^lang_/ =~ lang
74     lang
75   else
76     'lang_' + lang
77   end
78 end
79
80 def show_char_code_and_erace_tag str
81   case $KCODE
82   when 'EUC', 'SJIS'
83     CGI.unescapeHTML(str.gsub(/\\<.+?\\>/, '')).tojis
84   when 'NONE', 'UTF-8'
85     begin
86       str = Iconv.conv(\"EUC-JP\", \"UTF-8\", str)
87       CGI.unescapeHTML(str.gsub(/\\<.+?\\>/, '')).tojis
88     rescue => e
89       \"(char code problem: #{e.class}[#{e.message.dump}])\"
90     end
91   else
92     str
93   end
94 end
95
96 def search_char_code str
97   case $KCODE
98   when 'EUC', 'SJIS'
99     str.toeuc
100   when 'NONE'
101     begin
102       Iconv.conv(\"UTF-8\", \"EUC-JP\", str.toeuc)
103     rescue => e
104       \"(char code problem: #{e.class})\"
105     end
106   when 'UTF-8'
107     str
108   else
109     raise
110   end
111 end
112
113 begin
114   lang = lang_check(default_lang)
115   word = search_char_code(keywords)
116   result = google.doGoogleSearch(
117     license_key, word, 0, max_results, false, \"\",
118     false, lang, 'utf-8', 'utf-8'
119   )
120
121   count = result.estimatedTotalResultsCount
122   if count > 0
123     word = show_char_code_and_erace_tag(keywords)
124     count = count.to_s.gsub(/(\\d)(?=\\d{3}+$)/, '\\\\1,')
125     time = result.searchTime.to_s
126     print \"Search results for #{word} (Hits: #{count}: Time: #{time}):\\n\"
127
128     result.resultElements.each_with_index{|e, i|
129       title = show_char_code_and_erace_tag(e.title)
130       url   = e.URL
131       print \"#{title} - #{url}\\n\"
132     }
133   else
134     print \"no match\\n\"
135   end
136
137 rescue Exception => e
138   print \"#{e.class}(#{e.message})\"
139 end
140 ")
141   "Ruby program for searching by Google."
142   :type 'list
143   :group 'riece-google)
144
145 (defcustom riece-google-license-key nil
146   "*License key for Google API."
147   :type 'string
148   :group 'riece-google)
149
150 (defcustom riece-google-default-lang '("lang_en" "lang_ja")
151   "*Default language for searching keywords."
152   :type '(repeat (choice (const "lang_en" :tag "English")
153                          (const "lang_ja" :tag "Japanese")
154                          (string :tag "The other language")))
155   :group 'riece-google)
156
157 (defconst riece-google-regexp
158   "^go\\(o+\\)gle\\(:\\([a-z]+\\)\\)?>\\s-*\\(.*\\)")
159
160 (defvar riece-google-enabled nil)
161
162 (defconst riece-google-description
163   "Search keywords by Google.")
164
165 (defvar riece-google-target nil)
166
167 (defun riece-google-display-message-function (message)
168   (when (and riece-google-enabled
169              (stringp riece-google-license-key)
170              (string-match riece-google-regexp (riece-message-text message)))
171     (let ((keywords (match-string 4 (riece-message-text message)))
172           (max-results (number-to-string
173                         (length
174                          (match-string 1 (riece-message-text message)))))
175           (lang (or (match-string 3 (riece-message-text message))
176                     riece-google-default-lang))
177           (process-connection-type nil)
178           selective-display
179           (coding-system-for-read 'binary)
180           (coding-system-for-write 'binary)
181           (process (start-process "Google" (generate-new-buffer " *Google*")
182                                   riece-google-ruby-command)))
183       (when (listp lang)
184         (setq lang (mapconcat #'identity lang " ")))
185       (setq riece-google-target (riece-message-target message))
186       (process-send-string process
187                            (apply #'concat
188                                   (riece-google-substitute-variables
189                                    (riece-google-substitute-variables
190                                     (riece-google-substitute-variables
191                                      (riece-google-substitute-variables
192                                       riece-google-program
193                                       'keywords keywords)
194                                      'max-results max-results)
195                                      'license-key riece-google-license-key)
196                                    'lang lang)))
197       (process-send-eof process)
198       (with-current-buffer (process-buffer process)
199         (set-buffer-multibyte t)
200         (erase-buffer)
201       (set-buffer-modified-p nil))
202       (set-process-filter process #'riece-google-filter)
203       (set-process-sentinel process #'riece-google-sentinel))))
204
205 (defun riece-google-filter (process output)
206   (when (buffer-live-p (process-buffer process))
207     (with-current-buffer (process-buffer process)
208       (goto-char (point-max))
209       (insert output)
210       (goto-char (point-min))
211       (while (progn (end-of-line) (and (not (eobp)) (eq (char-after) ?\n)))
212         (if (eq (char-after (1- (point))) ?\r) ; cut off preceding LF
213             (delete-region (1- (point)) (point)))
214         (riece-google-send-string riece-google-target
215                                   (buffer-substring (point-min) (point)))
216         (delete-region (point-min) (progn (beginning-of-line 2) (point)))))))
217
218 (defun riece-google-sentinel (process string)
219   (delete-process process))
220
221 (defun riece-google-send-string (target message)
222   (riece-send-string
223    (format "NOTICE %s :%s\r\n" (riece-identity-prefix target) message))
224   (riece-display-message
225    (riece-make-message (riece-current-nickname) target message 'notice)))
226
227 (defun riece-google-substitute-variables (program variable value)
228   (setq program (copy-sequence program))
229   (let ((pointer program))
230     (while pointer
231       (setq pointer (memq variable program))
232       (if pointer
233           (setcar pointer value)))
234     program))
235
236 (defun riece-google-insinuate ()
237   (add-hook 'riece-after-display-message-functions
238             'riece-google-display-message-function))
239
240 (defun riece-google-enable ()
241   (setq riece-google-enabled t))
242
243 (defun riece-google-disable ()
244   (setq riece-google-enabled nil))
245
246 (provide 'riece-google)
247
248 ;;; riece-google.el ends here