sekka 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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