PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/scm/sj3v2-socket.scm

https://bitbucket.org/ohac/uim
Scheme | 443 lines | 362 code | 40 blank | 41 comment | 0 complexity | b43f6a4270deb13b354b51c35682e1c5 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. ;;; sj3v2-socket.scm: SJ3 protocol version 2 for uim.
  2. ;;;
  3. ;;; Copyright (c) 2009- uim Project http://code.google.com/p/uim/
  4. ;;;
  5. ;;; All rights reserved.
  6. ;;;
  7. ;;; Redistribution and use in source and binary forms, with or without
  8. ;;; modification, are permitted provided that the following conditions
  9. ;;; are met:
  10. ;;; 1. Redistributions of source code must retain the above copyright
  11. ;;; notice, this list of conditions and the following disclaimer.
  12. ;;; 2. Redistributions in binary form must reproduce the above copyright
  13. ;;; notice, this list of conditions and the following disclaimer in the
  14. ;;; documentation and/or other materials provided with the distribution.
  15. ;;; 3. Neither the name of authors nor the names of its contributors
  16. ;;; may be used to endorse or promote products derived from this software
  17. ;;; without specific prior written permission.
  18. ;;;
  19. ;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
  20. ;;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. ;;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
  23. ;;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25. ;;; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. ;;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. ;;; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28. ;;; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. ;;; SUCH DAMAGE.
  30. ;;;;
  31. (use srfi-1)
  32. (require "util.scm")
  33. (require "i18n.scm")
  34. (require "socket.scm")
  35. (require "lolevel.scm")
  36. (require "process.scm") ;; getpid
  37. ;; sj3v2 protocol operators
  38. (define $SJ3_CONNECT 1)
  39. (define $SJ3_DISCONNECT 2)
  40. (define $SJ3_OPENDICT 11)
  41. (define $SJ3_CLOSEDICT 12)
  42. (define $SJ3_OPENSTDY 21)
  43. (define $SJ3_CLOSESTDY 22)
  44. (define $SJ3_STDYSIZE 23)
  45. (define $SJ3_STUDY 61)
  46. (define $SJ3_MAKEDICT 81)
  47. (define $SJ3_MAKESTDY 82)
  48. (define $SJ3_MAKEDIR 83)
  49. (define $SJ3_ACCESS 84)
  50. (define $SJ3_PH2KNJ_EUC 111)
  51. (define $SJ3_CL2KNJ_ALL_EUC 115)
  52. (define $SJ3_CL2KNJ_CNT_EUC 116)
  53. (define $SJ3_CLSTUDY_EUC 117)
  54. (define sj3-lib-error-str-alist
  55. '((-1 . (N_ "Internal server error.")) ;; SJ3_InternalError
  56. (0 . (N_ "No error.")) ;; SJ3_NormalEnd
  57. (1 . (N_ "Serverdown.")) ;; SJ3_ServerDown
  58. (2 . (N_ "Cannot open socket.")) ;; SJ3_OpenSocket
  59. (3 . (N_ "Cannot connect socket.")) ;; SJ3_ConnectSocket
  60. (4 . (N_ "Unknown hostname.")) ;; SJ3_GetHostByName
  61. (5 . (N_ "Not opened.")) ;; SJ3_NotOpened
  62. (6 . (N_ "Not enough memory.")) ;; SJ3_NotEnoughMemory
  63. (7 . (N_ "Illegal command.")) ;; SJ3_IllegalCommand
  64. (11 . (N_ "Different version.")) ;; SJ3_DifferentVersion
  65. (12 . (N_ "No host name.")) ;; SJ3_NoHostName
  66. (13 . (N_ "No user name.")) ;; SJ3_NoUserName
  67. (14 . (N_ "User not allowd.")) ;; SJ3_NotAllowedUser
  68. (15 . (N_ "Already connected.")) ;; SJ3_AlreadyConnected
  69. (16 . (N_ "Not connected.")) ;; SJ3_NotConnected
  70. (21 . (N_ "Too long parameter.")) ;; SJ3_TooLongParameter
  71. (22 . (N_ "Illegal parameter.")) ;; SJ3_IllegalParameter
  72. (31 . (N_ "Bad dictionary ID.")) ;; SJ3_BadDictID
  73. (32 . (N_ "Illegal dictionary file.")) ;; SJ3_IllegalDictFile
  74. (33 . (N_ "Illegal study file.")) ;; SJ3_IllegalStdyFile
  75. (34 . (N_ "Incorrect password.")) ;; SJ3_IncorrectPasswd
  76. (35 . (N_ "File not exist.")) ;; SJ3_FileNotExist
  77. (36 . (N_ "Cannot access file.")) ;; SJ3_CannotAccessFile
  78. (37 . (N_ "Cannot open file.")) ;; SJ3_CannotOpenFile
  79. (38 . (N_ "Cannot create file.")) ;; SJ3_CannotCreateFile
  80. (39 . (N_ "File read error.")) ;; SJ3_FileReadError
  81. (40 . (N_ "File write error.")) ;; SJ3_FileWriteError
  82. (41 . (N_ "File seek error.")) ;; SJ3_FileSeekError
  83. (51 . (N_ "Study already opened.")) ;; SJ3_StdyAlreadyOpened
  84. (52 . (N_ "Study file not opened.")) ;; SJ3_StdyFileNotOpened
  85. (53 . (N_ "Too small study area.")) ;; SJ3_TooSmallStdyArea
  86. (61 . (N_ "Locked by other.")) ;; SJ3_LockedByOther
  87. (62 . (N_ "Not locked.")) ;; SJ3_NotLocked
  88. (71 . (N_ "No such dictionary.")) ;; SJ3_NoSuchDict
  89. (72 . (N_ "Dictionary is read only.")) ;; SJ3_ReadOnlyDict
  90. (73 . (N_ "Dictionary is locked.")) ;; SJ3_DictLocked
  91. (74 . (N_ "Yomi string is bad.")) ;; SJ3_BadYomiString
  92. (75 . (N_ "Kanji string is bad.")) ;; SJ3_BadKanjiString
  93. (76 . (N_ "Hinshi code is bad.")) ;; SJ3_BadHinsiCode
  94. (81 . (N_ "Add dictionary failed.")) ;; SJ3_AddDictFailed
  95. (82 . (N_ "Word is already exist.")) ;; SJ3_AlreadyExistWord
  96. (83 . (N_ "No more douon word.")) ;; SJ3_NoMoreDouonWord
  97. (84 . (N_ "No more user dictionary.")) ;; SJ3_NoMoreUserDict
  98. (85 . (N_ "No more index block")) ;; SJ3_NoMoreIndexBlock
  99. (91 . (N_ "Delete dictionary failed.")) ;; SJ3_DelDictFailed
  100. (92 . (N_ "No such word.")) ;; SJ3_NoSuchWord
  101. (101 . (N_ "Directory already exist.")) ;; SJ3_DirAlreadyExist
  102. (102 . (N_ "Cannot create directory.")) ;; SJ3_CannotCreateDir
  103. (111 . (N_ "No more dictionary data.")) ;; SJ3_NoMoreDictData
  104. (121 . (N_ "User connected.")) ;; SJ3_UserConnected
  105. (131 . (N_ "Too long password.")) ;; SJ3_TooLongPasswd
  106. (132 . (N_ "Too long comment.")) ;; SJ3_TooLongComment
  107. (133 . (N_ "Cannot code convert.")))) ;; SJ3_CannotCodeConvert
  108. (define sj3-protocol-version 2)
  109. ;; helper functions
  110. (define (sj3-lib-get-string-with-terminate socket)
  111. (let loop ((c (file-read socket 1))
  112. (rest '()))
  113. (cond ((eof-object? c)
  114. (uim-notify-fatal (N_ "unexpected terminate string."))
  115. "")
  116. ((eq? (car c) #\nul)
  117. (file-buf->string (reverse rest)))
  118. (else
  119. (loop (file-read socket 1) (cons (car c) rest))))))
  120. ;;
  121. ;; sj3 protocol api
  122. ;;
  123. (define (sj3-lib-connect socket user)
  124. (file-write socket
  125. (u8list->string-buf
  126. (u8list-pack '(u32 u32 s8 s8 s8)
  127. $SJ3_CONNECT sj3-protocol-version
  128. "unix" user (format "~a.uim-sj3" (current-process-id)))))
  129. (call-with-u8list-unpack
  130. '(u32) (string-buf->u8list (file-read socket 4))
  131. (lambda (result)
  132. (= -2 result))))
  133. (define (sj3-lib-disconnect socket)
  134. (file-write socket
  135. (u8list->string-buf
  136. (u8list-pack '(u32) $SJ3_DISCONNECT)))
  137. (call-with-u8list-unpack
  138. '(u32) (string-buf->u8list (file-read socket 4))
  139. (lambda (result)
  140. (= 0 result))))
  141. (define (sj3-lib-opendict socket dictionary-name passwd)
  142. (file-write socket
  143. (u8list->string-buf
  144. (u8list-pack '(u32 s8 s8) $SJ3_OPENDICT
  145. dictionary-name passwd)))
  146. (call-with-u8list-unpack
  147. '(u32) (string-buf->u8list (file-read socket 4))
  148. (lambda (result)
  149. (and (= result 0)
  150. (call-with-u8list-unpack
  151. '(u32) (string-buf->u8list (file-read socket 4))
  152. (lambda (result)
  153. result))))))
  154. (define (sj3-lib-closedict socket dict-id)
  155. (file-write socket
  156. (u8list->string-buf
  157. (u8list-pack '(u32 u32) $SJ3_CLOSEDICT dict-id)))
  158. (call-with-u8list-unpack
  159. '(u32) (string-buf->u8list (file-read socket 4))
  160. (lambda (result)
  161. (= 0 result))))
  162. (define (sj3-lib-openstdy socket stdy-name)
  163. (file-write socket
  164. (u8list->string-buf
  165. (u8list-pack '(u32 s8 s8) $SJ3_OPENSTDY stdy-name "")))
  166. (call-with-u8list-unpack
  167. '(u32) (string-buf->u8list (file-read socket 4))
  168. (lambda (result)
  169. result)))
  170. (define (sj3-lib-closestdy socket)
  171. (file-write socket
  172. (u8list->string-buf
  173. (u8list-pack '(u32) $SJ3_CLOSESTDY)))
  174. (call-with-u8list-unpack
  175. '(u32) (string-buf->u8list (file-read socket 4))
  176. (lambda (result)
  177. result)))
  178. (define (sj3-lib-stdy-size socket)
  179. (file-write socket
  180. (u8list->string-buf
  181. (u8list-pack '(u32) $SJ3_STDYSIZE)))
  182. (call-with-u8list-unpack
  183. '(u32) (string-buf->u8list (file-read socket 4))
  184. (lambda (result)
  185. (and (= result 0)
  186. (call-with-u8list-unpack
  187. '(u32) (string-buf->u8list (file-read socket 4))
  188. (lambda (result)
  189. result))))))
  190. (define (sj3-lib-study socket stdy)
  191. (file-write socket
  192. (u8list->string-buf
  193. (u8list-pack '(u32 u8list) $SJ3_STUDY stdy)))
  194. (call-with-u8list-unpack
  195. '(u32) (string-buf->u8list (file-read socket 4))
  196. (lambda (result)
  197. result)))
  198. (define (sj3-lib-makedict socket dictionary-name)
  199. (file-write socket
  200. (u8list->string-buf
  201. (u8list-pack '(u32 s8 u32 u32 u32) $SJ3_MAKEDICT
  202. dictionary-name
  203. 2048 ; Index length
  204. 2048 ; Length
  205. 256 ; Number
  206. )))
  207. (call-with-u8list-unpack
  208. '(u32) (string-buf->u8list (file-read socket 4))
  209. (lambda (result)
  210. (= 0 result))))
  211. (define (sj3-lib-makestdy socket stdy-name)
  212. (file-write socket
  213. (u8list->string-buf
  214. (u8list-pack '(u32 s8 u32 u32 u32) $SJ3_MAKESTDY
  215. stdy-name
  216. 2048 ; Number
  217. 1 ; Step
  218. 2048 ; Length
  219. )))
  220. (call-with-u8list-unpack
  221. '(u32) (string-buf->u8list (file-read socket 4))
  222. (lambda (result)
  223. (= 0 result))))
  224. (define (sj3-lib-makedir socket directory-name)
  225. (file-write socket
  226. (u8list->string-buf
  227. (u8list-pack '(u32 s8) $SJ3_MAKEDIR directory-name)))
  228. (call-with-u8list-unpack
  229. '(u32) (string-buf->u8list (file-read socket 4))
  230. (lambda (result)
  231. result)))
  232. (define (sj3-lib-access? socket directory-name mode)
  233. (file-write socket
  234. (u8list->string-buf
  235. (u8list-pack '(u32 s8 u32) $SJ3_ACCESS
  236. directory-name
  237. mode)))
  238. (call-with-u8list-unpack
  239. '(u32) (string-buf->u8list (file-read socket 4))
  240. (lambda (result)
  241. (= 0 result))))
  242. (define (sj3-lib-ph2knj-euc socket stdy-size yomi)
  243. (file-write socket
  244. (u8list->string-buf
  245. (u8list-pack '(u32 s8) $SJ3_PH2KNJ_EUC yomi)))
  246. (call-with-u8list-unpack
  247. '(u32 u32) (string-buf->u8list (file-read socket 8))
  248. (lambda (result yomi-length)
  249. (and (= result 0)
  250. (let loop ((yomi-len (cons (car (string-buf->u8list (file-read socket 1)))
  251. '()))
  252. (rest-stdy '())
  253. (rest-kouho '()))
  254. (if (<= (car yomi-len) 0)
  255. (values (reverse yomi-len) (reverse rest-stdy) (reverse rest-kouho))
  256. (let* ((new-stdy (string-buf->u8list (file-read socket stdy-size)))
  257. (new-kouho (sj3-lib-get-string-with-terminate socket)))
  258. (loop (cons (car (string-buf->u8list (file-read socket 1)))
  259. yomi-len)
  260. (cons new-stdy rest-stdy)
  261. (cons new-kouho rest-kouho)))))))))
  262. (define (sj3-lib-cl2knj-all-euc socket stdy-size len yomi)
  263. (file-write socket
  264. (u8list->string-buf
  265. (u8list-pack '(u32 u32 s8) $SJ3_CL2KNJ_ALL_EUC len yomi)))
  266. (call-with-u8list-unpack
  267. '(u32) (string-buf->u8list (file-read socket 4))
  268. (lambda (result)
  269. (and (= result 0)
  270. (let loop ((yomi-len
  271. (cons (u8list->u32 (string-buf->u8list (file-read socket 4)))
  272. '()))
  273. (rest-stdy '())
  274. (rest-kouho '()))
  275. (if (<= (car yomi-len) 0)
  276. (values (reverse yomi-len) (reverse rest-stdy) (reverse rest-kouho))
  277. (let* ((new-stdy (string-buf->u8list (file-read socket stdy-size)))
  278. (new-kouho (sj3-lib-get-string-with-terminate socket)))
  279. (loop (cons (u8list->u32 (string-buf->u8list (file-read socket 4)))
  280. yomi-len)
  281. (cons new-stdy rest-stdy)
  282. (cons new-kouho rest-kouho)))))))))
  283. (define (sj3-lib-cl2knj-cnt-euc socket stdy-size len yomi)
  284. (file-write socket
  285. (u8list->string-buf
  286. (u8list-pack '(u32 u32 s8) $SJ3_CL2KNJ_CNT_EUC len yomi)))
  287. (call-with-u8list-unpack
  288. '(u32) (string-buf->u8list (file-read socket 4))
  289. (lambda (result)
  290. (and (= result 0)
  291. (call-with-u8list-unpack
  292. '(u32) (string-buf->u8list (file-read socket 4))
  293. (lambda (result)
  294. result))))))
  295. (define (sj3-lib-clstudy-euc socket yomi1 yomi2 stdy)
  296. (file-write socket
  297. (u8list->string-buf
  298. (u8list-pack '(u32 s8 s8 u8list) $SJ3_CLSTUDY_EUC
  299. yomi1 yomi2 stdy)))
  300. (call-with-u8list-unpack
  301. '(u32) (string-buf->u8list (file-read socket 4))
  302. (lambda (result)
  303. result)))
  304. ;;
  305. ;; helper functions
  306. ;;
  307. (define (sj3-lib-mkdir-p socket path)
  308. (let ((entries (string-split path "/")))
  309. (fold (lambda (acc rest)
  310. (let ((new-path (if (string=? rest "")
  311. acc
  312. (string-append rest "/" acc))))
  313. (if (not (sj3-lib-access? socket acc 0))
  314. (sj3-lib-makedir socket new-path))
  315. new-path))
  316. ""
  317. entries)))
  318. (define (sj3-lib-split-yomi yomi yomi-length-list)
  319. (let loop ((yomi yomi)
  320. (yomi-length-list yomi-length-list)
  321. (rest '()))
  322. (if (= (car yomi-length-list) 0)
  323. (reverse rest)
  324. (loop (substring yomi (car yomi-length-list) (string-length yomi))
  325. (cdr yomi-length-list)
  326. (cons (substring yomi 0 (car yomi-length-list)) rest)))))
  327. ;;
  328. ;; sj3lib compatible functions
  329. ;;
  330. (define *sj3-lib-socket* #f)
  331. (define *sj3-lib-stdy-size* 20)
  332. (define *sj3-lib-main-dict* #f)
  333. (define *sj3-lib-user-dict* #f)
  334. (define (sj3-lib-get-private-path user-name)
  335. (format "user/~a" user-name))
  336. (define (sj3-lib-get-private-dicionary-name user-name)
  337. (format "~a/private.dic" (sj3-lib-get-private-path user-name)))
  338. (define (sj3-lib-get-private-study-name user-name)
  339. (format "~a/study.dat" (sj3-lib-get-private-path user-name)))
  340. (define (sj3-lib-open-with-server server)
  341. (let ((server-name (if (equal? server "")
  342. "localhost")))
  343. (if sj3-use-remote-server?
  344. (tcp-connect server-name 3086)
  345. (unix-domain-socket-connect sj3-unix-domain-socket-path))))
  346. (define (sj3-lib-open server user-name)
  347. (set! *sj3-lib-socket* (sj3-lib-open-with-server server))
  348. (if *sj3-lib-socket*
  349. (begin
  350. (sj3-lib-connect *sj3-lib-socket* user-name)
  351. (set! *sj3-lib-main-dict* (sj3-lib-opendict *sj3-lib-socket* "sj3main.dic" ""))
  352. (if (not (sj3-lib-access? *sj3-lib-socket* (sj3-lib-get-private-path user-name) 0))
  353. (begin
  354. (sj3-lib-mkdir-p *sj3-lib-socket* (sj3-lib-get-private-path user-name))
  355. (sj3-lib-makedict *sj3-lib-socket* (sj3-lib-get-private-dicionary-name user-name))
  356. (uim-notify-info (N_ "SJ3: create new dictionary"))))
  357. (if (not (sj3-lib-access? *sj3-lib-socket* (sj3-lib-get-private-study-name user-name) 0))
  358. (sj3-lib-makestdy *sj3-lib-socket* (sj3-lib-get-private-study-name user-name)))
  359. (set! *sj3-lib-user-dict*
  360. (sj3-lib-opendict *sj3-lib-socket* (sj3-lib-get-private-dicionary-name user-name) ""))
  361. (sj3-lib-openstdy *sj3-lib-socket* (sj3-lib-get-private-study-name user-name))
  362. (set! *sj3-lib-stdy-size* (sj3-lib-stdy-size *sj3-lib-socket*))))
  363. *sj3-lib-socket*)
  364. (define (sj3-lib-close)
  365. (if *sj3-lib-socket*
  366. (begin
  367. (sj3-lib-closestdy *sj3-lib-socket*)
  368. (sj3-lib-closedict *sj3-lib-socket* *sj3-lib-user-dict*)
  369. (sj3-lib-closedict *sj3-lib-socket* *sj3-lib-main-dict*)
  370. (sj3-lib-disconnect *sj3-lib-socket*)
  371. (file-close *sj3-lib-socket*))))
  372. (define (sj3-lib-getkan yomi)
  373. (receive (yomi-len stdy cands)
  374. (sj3-lib-ph2knj-euc *sj3-lib-socket* *sj3-lib-stdy-size* yomi)
  375. (cons (apply string-append cands)
  376. (zip (sj3-lib-split-yomi yomi yomi-len)
  377. cands
  378. stdy))))
  379. (define (sj3-lib-douoncnt yomi)
  380. (sj3-lib-cl2knj-cnt-euc *sj3-lib-socket* *sj3-lib-stdy-size*
  381. (length (string->list yomi)) ;; byte length
  382. yomi))
  383. (define (sj3-lib-getdouon yomi)
  384. (receive (yomi-len stdy cand)
  385. (sj3-lib-cl2knj-all-euc *sj3-lib-socket* *sj3-lib-stdy-size*
  386. (length (string->list yomi)) ;; byte length
  387. yomi)
  388. (zip cand stdy)))
  389. (define (sj3-lib-get-nth-douon yomi nth)
  390. (receive (yomi-len stdy cand)
  391. (sj3-lib-cl2knj-all-euc *sj3-lib-socket* *sj3-lib-stdy-size*
  392. (length (string->list yomi)) ;; byte length
  393. yomi)
  394. (list (list-ref cand nth)
  395. (list-ref stdy nth))))
  396. (define (sj3-lib-gakusyuu stdy)
  397. (sj3-lib-study *sj3-lib-socket* stdy))
  398. (define (sj3-lib-gakusyuu2 yomi1 yomi2 stdy)
  399. (let ((new-yomi1 (and yomi1 ""))
  400. (new-yomi2 (and yomi2 "")))
  401. (sj3-lib-clstudy-euc *sj3-lib-socket*
  402. new-yomi1 new-yomi2
  403. stdy)))