sekka 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,22 @@
1
+
2
+ Sekka (石火)
3
+
4
+ Sekkaはモードレスなローマ字かな漢字変換エンジンです。SKKにインスパイアされています。
5
+
6
+ 1. 特徴
7
+
8
+ 1) Emacsの上で動き、次のようなインタフェースを持ちます。
9
+ 日本語変換モードというものはありません。(Emacsのマイナーモードで作成)
10
+ いつでも[Ctrl-J]キーで、カーソルキーの直前のローマ字が変換可能です。
11
+ 例えば、Nihongo[Ctrl-J] で 「日本語」に変換します。
12
+
13
+ 2) SKKの大文字小文字指定ルールが適用されます。
14
+ OkonaU => 行う に変換される。(送り仮名あり)
15
+ okonaU => 行う アルファベット中に大文字が1文字でもあれば漢字かな混じりとみなされる。
16
+ okonau => おこなう (全て平仮名)に変換される。
17
+ Kanji => 漢字,幹事 など、送り仮名なしの漢字に変換される
18
+
19
+ 3) ローマ字綴りミスはあいまい検索により、適度に救済されます。
20
+ (Jaro-Winkler文字列類似度による検索)
21
+
22
+ 4) ローマ字の表記ゆれ、AZIK等の特殊ローマ字にも標準で対応します。(通常ローマ字、AZICなどモード切替なしですべて対応可能)
data/bin/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /sekka-jisyo~
data/bin/sekka-jisyo ADDED
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: nendo; syntax: scheme ; coding: utf-8 -*-
3
+ require 'nendo'
4
+ $LOAD_PATH.push( File.dirname(__FILE__) + "/../lib" )
5
+ core = Nendo::Core.new()
6
+ core.setArgv( ARGV )
7
+ core.loadInitFile
8
+ core.evalStr( <<";;END-OF-SCRIPT" )
9
+ ;;;
10
+ ;;; sekka-jisyo - Sekkaの辞書メンテナンスツール
11
+ ;;;
12
+ ;;; Copyright (c) 2010 Kiyoka Nishiyama <kiyoka@sumibi.org>
13
+ ;;;
14
+ ;;; Redistribution and use in source and binary forms, with or without
15
+ ;;; modification, are permitted provided that the following conditions
16
+ ;;; are met:
17
+ ;;;
18
+ ;;; 1. Redistributions of source code must retain the above copyright
19
+ ;;; notice, this list of conditions and the following disclaimer.
20
+ ;;;
21
+ ;;; 2. Redistributions in binary form must reproduce the above copyright
22
+ ;;; notice, this list of conditions and the following disclaimer in the
23
+ ;;; documentation and/or other materials provided with the distribution.
24
+ ;;;
25
+ ;;; 3. Neither the name of the authors nor the names of its contributors
26
+ ;;; may be used to endorse or promote products derived from this
27
+ ;;; software without specific prior written permission.
28
+ ;;;
29
+ ;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30
+ ;;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31
+ ;;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32
+ ;;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33
+ ;;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34
+ ;;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
35
+ ;;; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36
+ ;;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37
+ ;;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38
+ ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39
+ ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
+ ;;;
41
+ ;;; $Id:
42
+ ;;;
43
+ (use sekka.convert-jisyo)
44
+ (use sekka.jisyo-db)
45
+
46
+ (define (convert-skk-jisyo filename)
47
+ (let1 lines (with-open
48
+ filename
49
+ (lambda (f)
50
+ (convert-skk-jisyo-f f)))
51
+ (for-each print lines)))
52
+
53
+
54
+ (define (load-sekka-jisyo sekka-file target)
55
+ (with-open
56
+ sekka-file
57
+ (lambda (f)
58
+ (when (not (rxmatch #/.tch$/ target))
59
+ (set-kvs-type 'memcache))
60
+ (load-sekka-jisyo-f f target))))
61
+
62
+
63
+ (define (dump-sekka-jisyo sekka-file)
64
+ (let1 f STDOUT
65
+ (dump-sekka-jisyo-f f (+ sekka-file ".tch"))))
66
+
67
+
68
+ (define (display-help)
69
+ (print "Usage : ")
70
+ (print " sekka-jisyo convert SKK-JISYO.L ... output SEKKA-JISYO to STDOUT")
71
+ (print " sekka-jisyo load SEKKA-JISYO.L SEKKA-JISYO.L.tch ... load SEKKA-JISYO to DB(*.tch)")
72
+ (print " sekka-jisyo dump SEKKA-JISYO.L ... dump DB(*.tch) to SEKKA-JISYO(STDOUT)"))
73
+
74
+
75
+ (define (main argv)
76
+ (cond
77
+ ((= 0 (length argv))
78
+ (display-help))
79
+ (else
80
+ (let1 command (string->symbol (first argv))
81
+ (cond
82
+ ((eq? 'convert command)
83
+ (if (< (length argv) 2)
84
+ (display-help)
85
+ (convert-skk-jisyo (second argv))))
86
+ ((eq? 'load command)
87
+ (if (< (length argv) 3)
88
+ (display-help)
89
+ (load-sekka-jisyo (second argv) (third argv))))
90
+ ((eq? 'dump command)
91
+ (if (< (length argv) 2)
92
+ (display-help)
93
+ (dump-sekka-jisyo (second argv))))
94
+ (else
95
+ (errorf "Error: no such command [%s] \n" command )))))))
96
+
97
+ (main *argv*)
98
+ ;;END-OF-SCRIPT
data/bin/sekka-server ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'digest/md5'
5
+ require 'fileutils'
6
+ require 'rack'
7
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/sekkaconfig")
8
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/sekka/sekkaversion")
9
+
10
+
11
+
12
+ DICTDIR = File.expand_path( "~/.sekka-server" )
13
+ DICTURL = "http://sumibi.org/sekka/dict/" + SekkaVersion.version
14
+
15
+ TC_FILE = DICTDIR + "/SEKKA-JISYO.SMALL.tch"
16
+ SUMFILE = DICTDIR + "/SEKKA-JISYO.SMALL.md5"
17
+ TC_URL = DICTURL + "/SEKKA-JISYO.SMALL.tch"
18
+ SUMURL = DICTURL + "/SEKKA-JISYO.SMALL.md5"
19
+
20
+ TC_FILE_LIST = [ DICTDIR + "/SEKKA-JISYO.CUSTOM.tch",
21
+ DICTDIR + "/SEKKA-JISYO.LARGE.tch",
22
+ DICTDIR + "/SEKKA-JISYO.SMALL.tch" ]
23
+
24
+ MEMCACHED = "localhost:11211" # memcahced
25
+
26
+
27
+ def main
28
+ if not File.directory?( DICTDIR )
29
+ Dir.mkdir( DICTDIR )
30
+ STDERR.printf( "Info: created directory [%s]\n", DICTDIR )
31
+ end
32
+
33
+ if not File.exist?( TC_FILE )
34
+ STDERR.printf( "Info: Downloading SEKKA-JISYO\n" )
35
+ # 辞書をダウンロードする
36
+ cmd = sprintf( "curl -o %s %s", TC_FILE, TC_URL )
37
+ STDERR.printf( "Command : %s\n", cmd )
38
+ system( cmd )
39
+ cmd = sprintf( "curl -o %s %s", SUMFILE, SUMURL )
40
+ STDERR.printf( "Command : %s\n", cmd )
41
+ system( cmd )
42
+
43
+ # チェックサムを確認する
44
+ downloadSum = ""
45
+ open( TC_FILE ) { |f|
46
+ dataBody = f.read
47
+ downloadSum = Digest::MD5.hexdigest( dataBody )
48
+ }
49
+ open( SUMFILE ) { |f|
50
+ correctSum = f.readline.chomp.split[0]
51
+ STDERR.printf( " downloaded file's MD5 : %s\n", downloadSum )
52
+ STDERR.printf( " correct MD5 : %s\n", correctSum )
53
+ if downloadSum == correctSum
54
+ STDERR.printf( "Info: downloaded file [%s] verify OK.\n", TC_FILE )
55
+ else
56
+ STDERR.printf( "Error: downloaded file [%s] verify NG.\n", TC_FILE )
57
+ File.unlink( TC_FILE )
58
+ exit( 1 )
59
+ end
60
+ }
61
+ end
62
+
63
+ # 辞書ディレクトリに存在している辞書ファイルリストを作る
64
+ list = TC_FILE_LIST.select { |name| File.exist?( name ) }
65
+
66
+ # 設定項目をConfigオブジェクトに代入
67
+ SekkaServer::Config.setup( list[0], MEMCACHED, 12929 )
68
+
69
+ # サーバースクリプトのrootディレクトリへ移動
70
+ FileUtils.cd(File.dirname(__FILE__) + "/../")
71
+
72
+ # サーバー起動
73
+ Rack::Server.start(
74
+ :environment => "development",
75
+ :pid => nil,
76
+ :Port => SekkaServer::Config.listenPort,
77
+ :Host => "0.0.0.0",
78
+ :AccessLog => [],
79
+ :config => "./lib/sekka.ru"
80
+ )
81
+ end
82
+
83
+ main()
@@ -0,0 +1,416 @@
1
+ ;;; http-cookies.el --- simple HTTP cookies implementation
2
+
3
+ ;; Copyright (C) 2004, David Hansen
4
+
5
+ ;; Author: David Hansen <david.hansen@physik.fu-berlin.de>
6
+ ;; Maintainer: David Hansen <david.hansen@physik.fu-berlin.de>
7
+ ;; Version: 1.0.0
8
+ ;; Keywords: hypermedia
9
+
10
+ ;; This file is not part of GNU Emacs.
11
+
12
+ ;; This is free software; you can redistribute it and/or modify
13
+ ;; it under the terms of the GNU General Public License as published by
14
+ ;; the Free Software Foundation; either version 2, or (at your option)
15
+ ;; any later version.
16
+
17
+ ;; This is distributed in the hope that it will be useful,
18
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ ;; GNU General Public License for more details.
21
+
22
+ ;; You should have received a copy of the GNU General Public License
23
+ ;; along with GNU Emacs; see the file COPYING. If not, write to the
24
+ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25
+ ;; Boston, MA 02111-1307, USA.
26
+
27
+
28
+ ;;; Commentary:
29
+
30
+ ;; Implementation of old netscape cookies (used by maybe all servers) and
31
+ ;; version 1 cookies.
32
+ ;;
33
+ ;; See http://www.faqs.org/rfcs/rfc2109.html and
34
+ ;; http://wp.netscape.com/newsref/std/cookie_spec.html
35
+
36
+ ;;; Change log:
37
+
38
+ ;;; TODO:
39
+
40
+ ;; - whitelist
41
+ ;; - blacklist
42
+ ;; - reading from file, saving to file
43
+ ;; - expire
44
+
45
+ ;;; Code:
46
+
47
+ (require 'time-date)
48
+
49
+ (defconst http-cookies-version "1.0.0")
50
+
51
+ (defgroup http-emacs ()
52
+ "Simple HTTP client implementation in elisp.")
53
+
54
+ (defcustom http-emacs-use-cookies nil
55
+ "Use cookies in the http-emacs package. *EXPERIMENTAL*"
56
+ :type 'boolean
57
+ :group 'http-emacs)
58
+
59
+ (defcustom http-emacs-cookie-file "~/.emacs-cookies"
60
+ "*File where to store the cookies."
61
+ :type 'file
62
+ :group 'http-emacs)
63
+
64
+ (defconst http-token-value-regexp
65
+ "^[ \t]*\\(.*?\\)[ \t]*=[ \t]*\"?\\(.*?\\)\"?[ \t]*;?[ \t]*$"
66
+ "Regexp to match a token=\"value\"; in a cookie.")
67
+
68
+ (defvar http-cookies-accept-functions
69
+ '(http-cookie-check-path
70
+ http-cookie-check-domain
71
+ http-cookie-check-hostname)
72
+ "*List of functions used to determine if we accept a cookie or not.
73
+ If one of these function returns nil the cookie will be rejected. Each
74
+ function can access the free variables `cookie', `host' (from the url)
75
+ `path' (from the URL) and `url' to make its decision.")
76
+
77
+ (defvar http-cookies-host-hash
78
+ (make-hash-table :test 'equal)
79
+ "Hash to look up cookies by host name.")
80
+
81
+ (defvar http-cookies-domain-hash
82
+ (make-hash-table :test 'equal)
83
+ "Hash to look up cookies by domain.")
84
+
85
+
86
+
87
+ ;; functions for parsing the header
88
+
89
+ (defun http-cookies-ns-to-rfc (line)
90
+ "Make the header value LINE a bit more RFC compatible.
91
+ Make old netscape cookies a bit more RFC 2109 compatible by quoting
92
+ the \"expires\" value. We need this to be able to properly split
93
+ the header value if there is more than one cookie."
94
+ (let ((start 0))
95
+ (while (string-match "expires[ \t]*=[ \t]*\\([^\";]+?\\)\\(;\\|$\\)"
96
+ line start)
97
+ (setq start (match-end 0))
98
+ (setq line (replace-match "\"\\1\"" t nil line 1)))
99
+ line))
100
+
101
+ (defun http-cookies-find-char-in-string (char string &optional start)
102
+ "Return the first position of CHAR in STRING.
103
+ If START is non-nil start at position START."
104
+ (unless start
105
+ (setq start 0))
106
+ (let ((i start) (len (length string)) pos)
107
+ (while (and (not pos) (< i len))
108
+ (when (= (aref string i) char)
109
+ (setq pos i))
110
+ (setq i (1+ i)))
111
+ pos))
112
+
113
+ (defun http-cookies-find-quoted-strings (header-value)
114
+ "Return list of positions of quoted strings in HEADER_VALUE.
115
+ Return a list of pairs with the beginning and end of quoted strings
116
+ in a \"Set-cookie: \" header value."
117
+ (let ((start 0) qstring-pos)
118
+ (while (string-match "=[ \t]*\\(\".*?[^\\]\"\\)" header-value start)
119
+ (add-to-list 'qstring-pos (cons (match-beginning 1) (1- (match-end 1))))
120
+ (setq start (match-end 1)))
121
+ qstring-pos))
122
+
123
+ (defun http-cookies-split-string (header-value sep-char)
124
+ "Split the HEADER-VALUE at the character SEP-CHAR.
125
+ Ignores SEP-CHAR if it is in a quoted string. Return a list of the
126
+ substrings."
127
+ (let ((qstrings (http-cookies-find-quoted-strings header-value))
128
+ (start 0) (beg 0) pos in-qstring strings)
129
+ (while (setq pos (http-cookies-find-char-in-string
130
+ sep-char header-value start))
131
+ (unless (= pos start) ; ignore empty strings
132
+ ;; check if pos is in a quoted string
133
+ (dolist (qstring-pos qstrings)
134
+ (unless in-qstring
135
+ (when (and (> pos (car qstring-pos)) (< pos (cdr qstring-pos)))
136
+ (setq in-qstring t))))
137
+ (if in-qstring
138
+ (setq in-qstring nil)
139
+ (add-to-list 'strings (substring header-value beg pos))
140
+ (setq beg (1+ pos))))
141
+ (setq start (1+ pos)))
142
+ ;; add the last token
143
+ (add-to-list 'strings (substring header-value beg))
144
+ strings))
145
+
146
+ (defun http-cookies-parse-cookie (string)
147
+ "Parse one cookie.
148
+ Return an alist ((NAME . VALUE) (attr1 . value1) (attr2 . value2) ...)
149
+ or nil on error."
150
+ (let (attrs error)
151
+ (dolist (attr (http-cookies-split-string string ?\;))
152
+ (if (string-match http-token-value-regexp attr)
153
+ (add-to-list 'attrs (cons (match-string 1 attr)
154
+ (match-string 2 attr)))
155
+ ;; match the secure attribute
156
+ (if (string-match "[ \t]*\\([a-zA-Z]+\\)[ \t]*" attr)
157
+ (add-to-list 'attrs (cons (match-string 1 attr) t))
158
+ (setq error t)
159
+ (message "Cannot parse cookie %s" string))))
160
+ (unless error
161
+ attrs)))
162
+
163
+ (defun http-cookies-set (url headers)
164
+ "Set the cookies from the response to a request of URL.
165
+ Set HEADERS to the headers of the response."
166
+ (let ((host (http-cookies-url-host url)) (path (http-cookies-url-path url))
167
+ header-value cookie)
168
+ ;; The server may send several "Set-Cookie:" headers.
169
+ (dolist (line headers)
170
+ (when (equal (car line) "set-cookie")
171
+ (setq header-value (http-cookies-ns-to-rfc (cdr line)))
172
+ ;; there may be several cookies separated by ","
173
+ (dolist (raw-cookie (http-cookies-split-string header-value ?\,))
174
+ (setq cookie (http-cookies-parse-cookie raw-cookie))
175
+ ;; (message "%s" raw-cookie)
176
+ (when (http-cookies-accept)
177
+ ;; (message "accepted")
178
+ (http-cookies-store host cookie)))))))
179
+
180
+
181
+
182
+ ;; storing cookies
183
+
184
+ (defun http-cookies-name (cookie)
185
+ "Return the name of the COOKIE."
186
+ (car (car cookie)))
187
+
188
+ (defun http-cookies-path (cookie)
189
+ "Return the value of the path attribute of the COOKIE."
190
+ (let ((attr (or (assoc "path" cookie) (assoc "Path" cookie))))
191
+ (when attr
192
+ (cdr attr))))
193
+
194
+ (defun http-cookies-domain (cookie)
195
+ "Return the value of the domain attribute of the COOKIE."
196
+ (let ((attr (or (assoc "domain" cookie) (assoc "Domain" cookie))))
197
+ (when attr
198
+ (cdr attr))))
199
+
200
+ (defun http-cookies-expires (cookie)
201
+ "Return the value of the expires attribute of the COOKIE."
202
+ (let ((attr (assoc "expires" cookie)))
203
+ (when attr
204
+ (cdr attr))))
205
+
206
+ (defun http-cookies-max-age (cookie)
207
+ "Return the value of the Max-Age attribute of the COOKIE."
208
+ (let ((attr (assoc "Max-Age" cookie)))
209
+ (when attr
210
+ (cdr attr))))
211
+
212
+ (defun http-cookies-version (cookie)
213
+ "Return the value of the version attribute of the COOKIE."
214
+ (let ((version (assoc "Version" cookie)))
215
+ (when version
216
+ (if (equal version "1")
217
+ t
218
+ (message "Cookie version %s not supported." version)
219
+ nil))))
220
+
221
+ (defun http-cookies-equal (c1 c2)
222
+ "Return non nil if the given cookies are equal.
223
+ Old netscape cookies are equal if the name and path attributes are equal.
224
+ Version 1 cookies are equal if name path and domain are equal."
225
+ (if (and (http-cookies-version c1) (http-cookies-version c2))
226
+ ;; version 1 cookies
227
+ (and (equal (http-cookies-name c1) (http-cookies-name c2))
228
+ (equal (http-cookies-path c1) (http-cookies-path c2))
229
+ (equal (http-cookies-domain c1) (http-cookies-domain c2)))
230
+ ;; netscape cookies
231
+ (and (equal (http-cookies-name c1) (http-cookies-name c2))
232
+ (equal (http-cookies-path c1) (http-cookies-path c2)))))
233
+
234
+ (defun http-cookies-expired (expire-string)
235
+ "Return non nil if EXPIRE-STRING is in the past."
236
+ (> (time-to-seconds (time-since expire-string)) 0.0))
237
+
238
+ (defun http-cookies-remove (cookie key table)
239
+ "Remove cookies \"equal\" to COOKIE from the list stored with KEY in TABLE."
240
+ (let ((cookie-list (gethash key table)) new-list)
241
+ (dolist (entry cookie-list)
242
+ (unless (http-cookies-equal entry cookie)
243
+ (add-to-list 'new-list entry)))
244
+ (when cookie-list
245
+ (remhash key table)
246
+ (puthash key new-list table))))
247
+
248
+ (defun http-cookies-store (host cookie)
249
+ "Store the given COOKIE from HOST in the hash tables.
250
+ Remove cookie from the tables if the given COOKIE expires in the past or
251
+ has an \"Max-Age\" of 0."
252
+ (let ((domain (http-cookies-domain cookie))
253
+ (max-age (http-cookies-max-age cookie))
254
+ (expires (http-cookies-expires cookie))
255
+ (cookie-list))
256
+ ;; remove an possible "equal" old cookie
257
+ (http-cookies-remove cookie host http-cookies-host-hash)
258
+ (when domain
259
+ (http-cookies-remove cookie domain http-cookies-domain-hash))
260
+ ;; check if expires is in the past or Max-Age is zero
261
+ (unless (or (and max-age (= (string-to-number max-age) 0))
262
+ (and expires (http-cookies-expired expires)))
263
+ ;; convert "Max-Age" to "expire"
264
+ (when max-age
265
+ ;; this value does not have to be in the "right" format
266
+ ;; it's enough if `parse-time-string' can parse it
267
+ (setq expires (format-time-string
268
+ "%Y-%m-%d %T %z"
269
+ (time-add (current-time) (seconds-to-time max-age))
270
+ t))
271
+ (setcdr (assoc "Max-Age" cookie) expires)
272
+ (setcar (assoc "Max-Age" cookie) "expires"))
273
+ (setq cookie-list (gethash host http-cookies-host-hash))
274
+ (add-to-list 'cookie-list cookie)
275
+ (puthash host cookie-list http-cookies-host-hash)
276
+ (when domain
277
+ (setq cookie-list (gethash domain http-cookies-domain-hash))
278
+ (add-to-list 'cookie-list cookie)
279
+ (puthash domain cookie-list http-cookies-domain-hash)))))
280
+
281
+
282
+
283
+ ;; building the header to send back the cookie
284
+
285
+ (defun http-cookies-cookie-to-string (cookie)
286
+ "Return the cookie as a string to be used as a header value."
287
+ (let* ((name (http-cookies-name cookie))
288
+ (value (cdr (assoc name cookie)))
289
+ (path (http-cookies-path cookie))
290
+ (domain (http-cookies-domain cookie))
291
+ (string))
292
+ (if (http-cookies-version cookie)
293
+ ;; version 1 cookie
294
+ (progn
295
+ (setq string (concat "$Version = \"1\"; " name " = \"" value "\""))
296
+ (when path
297
+ (setq string (concat string "; $Path = \"" path "\"")))
298
+ (when domain
299
+ (setq string (concat string "; $Domain = \"" domain "\""))))
300
+ ;; netscape cookies
301
+ (setq string (concat name "=" value)))))
302
+
303
+ (defun http-cookies-cookie-in-list (cookie list)
304
+ "Return non-nil if a cookie \"equal\" to the given COOKIE is in LIST."
305
+ (let ((in-list))
306
+ (dolist (element list)
307
+ (unless in-list
308
+ (setq in-list (http-cookies-equal cookie element))))
309
+ in-list))
310
+
311
+ (defun http-cookies-path-depth (cookie)
312
+ "Return the number of dashes in the path attribute of the cookie."
313
+ (let ((patch http-cookies-path cookie) (n 0) (start 0))
314
+ (while (setq start (http-cookies-find-char-in-string ?\/ path start))
315
+ (setq n (1+ n)))
316
+ n))
317
+
318
+ (defun http-cookie-path-depth-less (c1 c2)
319
+ "Return non nil if the path depth of cookie C1 is less than C2."
320
+ (< (http-cookies-path-depth c1) (http-cookies-path-depth c2)))
321
+
322
+ (defun http-cookies-build-header (url)
323
+ "Return a pair (\"Cookie\" . <header value>).
324
+ Use this to send back cookies to the given URL."
325
+ (let ((host (http-cookies-url-host url)) (domain) (cookie-list) (string))
326
+ (when (string-match "^[^.]+\\(\\..+\\)" host)
327
+ (setq domain (match-string 1 host))
328
+ (dolist (cookie (gethash host http-cookies-host-hash))
329
+ (unless (http-cookies-expired (http-cookies-expires cookie))
330
+ (add-to-list 'cookie-list cookie)))
331
+ (dolist (cookie (gethash domain http-cookies-domain-hash))
332
+ (unless (or (http-cookies-cookie-in-list cookie cookie-list)
333
+ (http-cookies-expired (http-cookies-expires cookie)))
334
+ (add-to-list 'cookie-list cookie)))
335
+ (setq cookie-list (sort cookie-list 'http-cookies-path-depth-less))
336
+ (dolist (cookie cookie-list)
337
+ (if string
338
+ (setq string (concat string "; "
339
+ (http-cookies-cookie-to-string cookie)))
340
+ (setq string (http-cookies-cookie-to-string cookie)))))
341
+ (cons "Cookie" string)))
342
+
343
+
344
+
345
+ ;; extract parts of the url
346
+
347
+ (defun http-cookies-url-host (url)
348
+ "Return the hostname of URL"
349
+ (unless (string-match
350
+ "http://\\([^/:]+\\)\\(:\\([0-9]+\\)\\)?/\\(.*/\\)?\\([^:]*\\)"
351
+ url)
352
+ (error "Cannot parse URL %s." url))
353
+ (match-string 1 url))
354
+
355
+ (defun http-cookies-url-path (url)
356
+ "Return the path of the URL."
357
+ (unless (string-match
358
+ "http://\\([^/:]+\\)\\(:\\([0-9]+\\)\\)?/\\(.*/\\)?\\([^:]*\\)"
359
+ url)
360
+ (error "Cannot parse URL %s." url))
361
+ (concat "/" (or (match-string 4 url) "")))
362
+
363
+
364
+
365
+ ;; functions to check the cookie (implementation of 4.3.2 of RFC 2109)
366
+
367
+ (defun http-cookies-accept ()
368
+ "Return non nil if the cookie should be accepted.
369
+ The tests are based on the functions in `http-cookies-accept-functions'."
370
+ (let ((accept t))
371
+ (dolist (fun http-cookies-accept-functions)
372
+ (when accept
373
+ (setq accept (funcall fun))))
374
+ accept))
375
+
376
+ (defun http-cookie-check-path ()
377
+ "Return nil if the \"path\" attribute is not a prefix of th URL."
378
+ (let ((cookie-path (cdr (assoc "path" cookie))))
379
+ (if cookie-path
380
+ (if (string-match (concat "^" cookie-path) path)
381
+ t
382
+ (message "Rejecting cookie: path attribute \"%s\" is not a prefix\
383
+ of the URL %s." cookie-path url)
384
+ nil)
385
+ t)))
386
+
387
+ (defun http-cookie-check-domain ()
388
+ "Return nil if the domain is bogus.
389
+ Return nil if the domain does not start with a \".\" or does not contain
390
+ an embedded dot."
391
+ (let ((domain (cdr (assoc "domain" cookie))))
392
+ (if domain
393
+ (if (string-match "^\\.[^.]+\\.[^.]+" domain)
394
+ t
395
+ (message "Rejection cookie: domain \"%s\" does not start with a dot\
396
+ or does not contain an embedded dot." domain)
397
+ nil)
398
+ t)))
399
+
400
+ (defun http-cookie-check-hostname ()
401
+ "Return nil if the domain doesn't match the host.
402
+ Return nil if the domain attribute does not match the host name or the
403
+ host name without the domain attribute still contains one or more dots."
404
+ ;; FIXME: hostname might be an IP address
405
+ (let ((domain (cdr (assoc "domain" cookie))))
406
+ (if (not domain)
407
+ t
408
+ (when (string-match (concat domain "$") host)
409
+ (not (http-cookies-find-char-in-string
410
+ ?\. (substring host 0 (match-beginning 0))))))))
411
+
412
+
413
+
414
+ (provide 'http-cookies)
415
+
416
+ ;;; http-cookies.el ends here