OSDN Git Service

I-mode emoji color feature [usage] ChxjImodeEmojiColor On|Auto|Off ex) On: &#111111...
[modchxj/mod_chxj.git] / src / mod_chxj.c
1 /*
2  * Copyright (C) 2005-2009 Atsushi Konno All rights reserved.
3  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <unistd.h>
18 #include <string.h>
19 #include <limits.h>
20 #include <errno.h>
21
22 #include "httpd.h"
23 #include "http_config.h"
24 #include "http_core.h"
25 #include "http_protocol.h"
26 #include "http_log.h"
27 #include "ap_config.h"
28 #include "apr_strings.h"
29 #include "util_filter.h"
30 #include "apr_buckets.h"
31 #include "apr_lib.h"
32 #include "apr_tables.h"
33 #include "apr_dso.h"
34 #include "apr_general.h"
35 #include "apr_pools.h"
36
37 #include "mod_chxj.h"
38 #include "chxj_encoding.h"
39 #include "qs_ignore_sp.h"
40 #include "qs_log.h"
41 #include "qs_malloc.h"
42 #include "qs_parse_attr.h"
43 #include "qs_parse_file.h"
44 #include "qs_parse_string.h"
45 #include "qs_parse_tag.h"
46 #include "chxj_load_device_data.h"
47 #include "chxj_load_emoji_data.h"
48 #include "chxj_specified_device.h"
49 #include "chxj_tag_util.h"
50 #include "chxj_xhtml_mobile_1_0.h"
51 #include "chxj_hdml.h"
52 #include "chxj_chtml10.h"
53 #include "chxj_chtml20.h"
54 #include "chxj_chtml30.h"
55 #include "chxj_chtml40.h"
56 #include "chxj_chtml50.h"
57 #include "chxj_ixhtml10.h"
58 #include "chxj_jhtml.h"
59 #include "chxj_jxhtml.h"
60 #include "chxj_img_conv_format.h"
61 #include "chxj_qr_code.h"
62 #include "chxj_encoding.h"
63 #include "chxj_apply_convrule.h"
64 #include "chxj_cookie.h"
65 #include "chxj_url_encode.h"
66 #include "chxj_str_util.h"
67 #include "chxj_dump_string.h"
68 #if defined(USE_MYSQL_COOKIE)
69 #  include "chxj_mysql.h"
70 #endif
71 #include "chxj_serf.h"
72 #include "chxj_add_device_env.h"
73 #include "chxj_header_inf.h"
74 #include "chxj_jreserved_tag.h"
75
76
77 #define CHXJ_VERSION_PREFIX PACKAGE_NAME "/"
78 #define CHXJ_VERSION        PACKAGE_VERSION
79 #define CHXJ_POST_MAX       (0x1000000)
80
81 converter_t convert_routine[] = {
82   {
83     /* CHXJ_SPEC_UNKNOWN          */
84     .converter            = NULL,
85     .encoder              = NULL,
86     .emoji_only_converter = NULL,
87   },
88   {
89     /* CHXJ_SPEC_Chtml_1_0        */
90     .converter            = chxj_convert_chtml10,
91     .encoder              = chxj_encoding,
92     .emoji_only_converter = chxj_chtml10_emoji_only_converter,
93   },
94   {
95     /* CHXJ_SPEC_Chtml_2_0        */
96     .converter            = chxj_convert_chtml20,
97     .encoder              = chxj_encoding,
98     .emoji_only_converter = chxj_chtml20_emoji_only_converter,
99   },
100   {
101     /* CHXJ_SPEC_Chtml_3_0        */
102     .converter            = chxj_convert_chtml30,
103     .encoder              = chxj_encoding,
104     .emoji_only_converter = chxj_chtml30_emoji_only_converter,
105   },
106   {
107     /* CHXJ_SPEC_Chtml_4_0        */
108     .converter            = chxj_convert_chtml40,
109     .encoder              = chxj_encoding,
110     .emoji_only_converter = chxj_chtml40_emoji_only_converter,
111   },
112   {
113     /* CHXJ_SPEC_Chtml_5_0        */
114     .converter            = chxj_convert_chtml50,
115     .encoder              = chxj_encoding,
116     .emoji_only_converter = chxj_chtml50_emoji_only_converter,
117   },
118   {
119     /* CHXJ_SPEC_Chtml_6_0        */
120     .converter = chxj_convert_ixhtml10,
121     .encoder  = chxj_encoding,
122     .emoji_only_converter = chxj_chtml50_emoji_only_converter, /* XXX: TODO */
123   },
124   {
125     /* CHXJ_SPEC_Chtml_7_0        */
126     .converter = chxj_convert_ixhtml10,
127     .encoder  = chxj_encoding,
128     .emoji_only_converter = chxj_chtml50_emoji_only_converter, /* XXX: TODO */
129   },
130   {
131     /* CHXJ_SPEC_XHtml_Mobile_1_0 */
132     .converter            = chxj_convert_xhtml_mobile_1_0,
133     .encoder              = chxj_encoding,
134     .emoji_only_converter = chxj_xhtml_emoji_only_converter,
135   },
136   {
137     /* CHXJ_SPEC_Hdml             */
138     .converter            = chxj_convert_hdml,
139     .encoder              = chxj_encoding,
140     .emoji_only_converter = NULL,
141   },
142   {
143     /* CHXJ_SPEC_Jhtml            */
144     .converter            = chxj_convert_jhtml,
145     .encoder              = chxj_encoding,
146     .emoji_only_converter = chxj_jhtml_emoji_only_converter,
147   },
148   {
149     /* CHXJ_SPEC_Jxhtml            */
150     .converter            = chxj_convert_jxhtml,
151     .encoder              = chxj_encoding,
152     .emoji_only_converter = chxj_jxhtml_emoji_only_converter,
153   },
154   {
155     /* CHXJ_SPEC_HTML             */
156     .converter = NULL,
157     .encoder  = NULL,
158     .emoji_only_converter = NULL,
159   },
160 };
161
162 static int chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_table *spec);
163 static void s_convert_guid_parameter_to_header(request_rec *r, const char *param, device_table *spec);
164 static void s_add_cookie_id_if_has_location_header(request_rec *r, cookie_t *cookie);
165 static void s_clear_cookie_header(request_rec *r, device_table *spec);
166 static void s_add_no_cache_headers(request_rec *r, chxjconvrule_entry  *entryp);
167
168 /**
169  * Only when User-Agent is specified, the User-Agent header is camouflaged. 
170  *
171  * @param r   [i]
172  */
173 static apr_status_t 
174 chxj_headers_fixup(request_rec *r)
175 {
176   mod_chxj_config*    dconf; 
177   chxjconvrule_entry* entryp;
178   char*               user_agent;
179   device_table*       spec;
180   char                *contentType;
181   char                *contentLength;
182
183   DBG(r, "REQ[%X] start chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
184   if (r->main) {
185     DBG(r, "REQ[%X] detect internal redirect.", (unsigned int)(apr_size_t)r);
186     DBG(r, "REQ[%X] end chxj_headers_fixup()",  (unsigned int)(apr_size_t)r);
187     return DECLINED;
188   }
189
190   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
191
192   user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
193   spec = chxj_specified_device(r, user_agent);
194
195   contentType = (char *)apr_table_get(r->headers_in, "Content-Type");
196   if (contentType
197       && strncasecmp("multipart/form-data", contentType, 19) == 0) {
198     DBG(r, "REQ[%X] detect multipart/form-data ==> no target", (unsigned int)(apr_size_t)r);
199     DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
200     return DECLINED;
201   }
202
203
204   switch(spec->html_spec_type) {
205   case CHXJ_SPEC_Chtml_1_0:
206   case CHXJ_SPEC_Chtml_2_0:
207   case CHXJ_SPEC_Chtml_3_0:
208   case CHXJ_SPEC_Chtml_4_0:
209   case CHXJ_SPEC_Chtml_5_0:
210   case CHXJ_SPEC_Chtml_6_0:
211   case CHXJ_SPEC_Chtml_7_0:
212   case CHXJ_SPEC_XHtml_Mobile_1_0:
213   case CHXJ_SPEC_Hdml:
214   case CHXJ_SPEC_Jhtml:
215   case CHXJ_SPEC_Jxhtml:
216     entryp = chxj_apply_convrule(r, dconf->convrules);
217     if (! entryp) {
218       DBG(r, "REQ[%X] end chxj_headers_fixup() (no pattern)", (unsigned int)(apr_size_t)r);
219       return DECLINED;
220     }
221     if (!(entryp->action & CONVRULE_ENGINE_ON_BIT) && !(entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
222       DBG(r, "REQ[%X] end chxj_headers_fixup() (engine off)", (unsigned int)(apr_size_t)r);
223       return DECLINED;
224     }
225     if (entryp->action & CONVRULE_EMOJI_ONLY_BIT) {
226       DBG(r, "REQ[%X] end chxj_headers_fixup() (emoji only)", (unsigned int)(apr_size_t)r);
227       return DECLINED;
228     } 
229   
230     apr_table_setn(r->headers_in, 
231                    CHXJ_HTTP_USER_AGENT, 
232                    user_agent);
233   
234     if (entryp->user_agent)
235       apr_table_setn(r->headers_in, 
236                      HTTP_USER_AGENT, 
237                      entryp->user_agent);
238     /*
239      * this clear process must do before chxj_convert_input_header function.
240      */
241     if ((entryp->action & CONVRULE_COOKIE_ON_BIT) || (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
242       if (r->method_number == M_POST) {
243         if (! apr_table_get(r->headers_in, "X-Chxj-Forward")) {
244           s_clear_cookie_header(r, spec);
245         }
246       }
247       else {
248         s_clear_cookie_header(r, spec);
249       }
250     }
251
252     chxj_convert_input_header(r,entryp, spec);
253
254     break;
255   
256   default:
257     DBG(r, "REQ[%X] end chxj_headers_fixup() (not mobile) spec->device_name[%s] User-Agent:[%s]", (unsigned int)(apr_size_t)r, spec->device_name, user_agent);
258     return DECLINED;
259
260   }
261
262
263   if (r->method_number == M_POST) {
264     if (! apr_table_get(r->headers_in, "X-Chxj-Forward")) {
265         DBG(r, "REQ[%X] set Input handler old:[%s] proxyreq:[%d] uri:[%s] filename:[%s]", (unsigned int)(apr_size_t)r, r->handler, r->proxyreq, r->uri, r->filename);
266         r->proxyreq = PROXYREQ_NONE;
267         r->handler = apr_psprintf(r->pool, "chxj-input-handler");
268     }
269     else {
270       char *client_ip = (char *)apr_table_get(r->headers_in, CHXJ_HEADER_ORIG_CLIENT_IP);
271       if (client_ip) {
272         if (dconf->post_log) {
273           apr_table_setn(r->subprocess_env, dconf->post_log, dconf->post_log);
274         }
275         else {
276           apr_table_setn(r->subprocess_env, "chxj-post-log", "chxj-post-log");
277         }
278         apr_sockaddr_t *address = NULL;
279         apr_status_t rv = apr_sockaddr_info_get(&address, ap_get_server_name(r), APR_UNSPEC, ap_get_server_port(r), 0, r->pool);
280         if (rv != APR_SUCCESS) {
281           char buf[256];
282           ERR(r, "REQ[%X] %s:%d apr_sockaddr_info_get() failed: rv:[%d|%s]", (unsigned int)(apr_size_t)r, APLOG_MARK, rv, apr_strerror(rv, buf, 256));
283           DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
284           return DECLINED;
285         }
286         char *addr;
287         if (dconf->forward_server_ip) {
288           addr = dconf->forward_server_ip;
289         }
290         else {
291           apr_sockaddr_ip_get(&addr, address);
292         }
293         DBG(r, "REQ[%X] Client IP:[%s] vs Orig Client IP:[%s] vs Server IP:[%s]", (unsigned int)(apr_size_t)r, r->connection->remote_ip, client_ip, addr);
294         if (strcmp(addr, r->connection->remote_ip) == 0) {
295           r->connection->remote_ip = apr_pstrdup(r->connection->pool, client_ip);
296         }
297         if (! apr_table_get(r->headers_in, "Content-Length")) {
298           contentLength = (char *)apr_table_get(r->headers_in, "X-Chxj-Content-Length");
299           if (contentLength) {
300             apr_table_set(r->headers_in, "Content-Length", contentLength);
301           }
302         }
303       }
304     }
305   }
306
307   chxj_add_device_env(r, spec);
308
309   DBG(r, "REQ[%X] end chxj_headers_fixup()", (unsigned int)(apr_size_t)r);
310
311   return DECLINED;
312 }
313
314
315 static void
316 s_clear_cookie_header(request_rec *r, device_table *spec)
317 {
318   DBG(r, "REQ[%X] start s_clear_cookie_header()", TO_ADDR(r));
319   switch(spec->html_spec_type) {
320   case CHXJ_SPEC_Chtml_1_0:
321   case CHXJ_SPEC_Chtml_2_0:
322   case CHXJ_SPEC_Chtml_3_0:
323   case CHXJ_SPEC_Chtml_4_0:
324   case CHXJ_SPEC_Chtml_5_0:
325   case CHXJ_SPEC_Chtml_6_0:
326   case CHXJ_SPEC_Chtml_7_0:
327   case CHXJ_SPEC_XHtml_Mobile_1_0:
328   case CHXJ_SPEC_Jhtml:
329     apr_table_unset(r->headers_in, "Cookie");
330     break;
331   default:
332     break;
333   }
334   DBG(r, "REQ[%X] end   s_clear_cookie_header()", TO_ADDR(r));
335 }
336
337
338 /**
339  * It converts it from CHTML into XXML corresponding to each model. 
340  *
341  * @param r   [i]
342  * @param src [i]   It is former HTML character string. 
343  * @param len [i/o] It is length of former HTML character string. 
344  */
345 static char * 
346 chxj_convert(request_rec *r, const char **src, apr_size_t *len, device_table *spec, const char *ua, cookie_t **cookiep)
347 {
348   char                *user_agent;
349   char                *dst;
350   char                *tmp;
351   cookie_t            *cookie;
352   mod_chxj_config     *dconf; 
353   chxjconvrule_entry  *entryp;
354
355   DBG(r,"REQ[%X] start of chxj_convert()", (unsigned int)(apr_size_t)r);
356
357   chxj_dump_string(r, APLOG_MARK, "INPUT Data", *src, *len);
358
359   dst  = apr_pstrcat(r->pool, (char *)*src, NULL);
360
361   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
362
363
364   entryp = chxj_apply_convrule(r, dconf->convrules);
365
366   if (!entryp || (!(entryp->action & CONVRULE_ENGINE_ON_BIT) && !(entryp->action & CONVRULE_COOKIE_ONLY_BIT))) {
367     DBG(r,"REQ[%X] end of chxj_convert()", (unsigned int)(apr_size_t)r);
368     return (char *)*src;
369   }
370
371
372   /*------------------------------------------------------------------------*/
373   /* get UserAgent from http header                                         */
374   /*------------------------------------------------------------------------*/
375   if (entryp->user_agent)
376     user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
377   else
378     user_agent = (char *)apr_table_get(r->headers_in, HTTP_USER_AGENT);
379
380   DBG(r,"REQ[%X] User-Agent:[%s]", (unsigned int)(apr_size_t)r, user_agent);
381   DBG(r,"REQ[%X] content type is %s", (unsigned int)(apr_size_t)r, r->content_type);
382
383
384   if (  ! STRNCASEEQ('t','T', "text/html", r->content_type, sizeof("text/html")-1)
385     &&  ! STRNCASEEQ('a','A', "application/xhtml+xml", r->content_type, sizeof("application/xhtml+xml")-1)) {
386     DBG(r,"REQ[%X] no convert. content type is %s", (unsigned int)(apr_size_t)r, r->content_type);
387     DBG(r,"REQ[%X] end of chxj_convert()", (unsigned int)(apr_size_t)r);
388     return (char *)*src;
389   }
390
391   if (ua && user_agent && strcasecmp(user_agent, ua) != 0) {
392     /* again */
393     spec = chxj_specified_device(r, user_agent);
394   }
395
396   /*
397    * save cookie.
398    */
399   cookie = NULL;
400   if ((entryp->action & CONVRULE_COOKIE_ON_BIT 
401       && !(entryp->action & CONVRULE_EMOJI_ONLY_BIT)
402       && !(entryp->action & CONVRULE_ENVINFO_ONLY_BIT))
403       || (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
404     switch(spec->html_spec_type) {
405     case CHXJ_SPEC_Chtml_1_0:
406     case CHXJ_SPEC_Chtml_2_0:
407     case CHXJ_SPEC_Chtml_3_0:
408     case CHXJ_SPEC_Chtml_4_0:
409     case CHXJ_SPEC_Chtml_5_0:
410     case CHXJ_SPEC_Chtml_6_0:
411     case CHXJ_SPEC_Chtml_7_0:
412     case CHXJ_SPEC_XHtml_Mobile_1_0:
413     case CHXJ_SPEC_Jhtml:
414       cookie = chxj_save_cookie(r);
415       break;
416     default:
417       break;
418     }
419   }
420
421   if (!r->header_only) {
422     if ((entryp->action & CONVRULE_COOKIE_ONLY_BIT) && cookie) {
423       dst = chxj_cookie_only_mode(r, *src, (apr_size_t *)len, cookie);
424     }
425     else {
426       tmp = NULL;
427       if (convert_routine[spec->html_spec_type].encoder)
428         tmp = convert_routine[spec->html_spec_type].encoder(r, 
429                                                             *src, 
430                                                             (apr_size_t *)len);
431   
432       if (entryp->action & CONVRULE_EMOJI_ONLY_BIT) {
433         if (tmp) {
434           tmp = chxj_node_convert_chxjif_only(r, spec, (const char*)tmp, (apr_size_t *)len);
435         }
436         else {
437           tmp = chxj_node_convert_chxjif_only(r, spec, (const char *)*src, (apr_size_t *)len);
438         }
439         if (convert_routine[spec->html_spec_type].emoji_only_converter) {
440           dst = convert_routine[spec->html_spec_type].emoji_only_converter(r,spec, tmp,*len);
441           if (dst != NULL) {
442             *len = strlen(dst);
443           }
444           else {
445             dst = apr_palloc(r->pool, 1);
446             *dst = 0;
447             *len = 0;
448           }
449         }
450         DBG(r, "REQ[%X] end of chxj_convert()(emoji only)", (unsigned int)(apr_size_t)r);
451       }
452   
453       if (   !(entryp->action & CONVRULE_EMOJI_ONLY_BIT) 
454           && !(entryp->action & CONVRULE_ENVINFO_ONLY_BIT)) {
455         if (convert_routine[spec->html_spec_type].converter) {
456           if (tmp)
457             dst = convert_routine[spec->html_spec_type].converter(r, 
458                                                                   spec, 
459                                                                   tmp, 
460                                                                   *len, 
461                                                                   len, 
462                                                                   entryp, 
463                                                                   cookie);
464           else
465             dst = convert_routine[spec->html_spec_type].converter(r,
466                                                                   spec, 
467                                                                   *src, 
468                                                                   *len, 
469                                                                   len, 
470                                                                   entryp, 
471                                                                   cookie);
472         }
473       }
474     }
475   }
476   ap_set_content_length(r, *len);
477
478   if (*len == 0) {
479     dst = apr_psprintf(r->pool, "\n");
480     *len = 1;
481   }
482   dst[*len] = 0;
483   if (cookie) {
484     *cookiep = cookie;
485   }
486
487
488   DBG(r, "REQ[%X] end of chxj_convert()", (unsigned int)(apr_size_t)r);
489
490   return dst;
491 }
492
493
494 /**
495  * convert GUID parameter.
496  *
497  */
498 static void
499 s_convert_guid_parameter_to_header(request_rec *r, const char *param, device_table *spec)
500 {
501   DBG(r, "REQ[%X] start s_convert_guid_parameter() param:[%s]", (unsigned int)(apr_size_t)r, param);
502   if (strcasecmp(param, "guid") == 0) {
503     switch(spec->html_spec_type) {
504     case CHXJ_SPEC_XHtml_Mobile_1_0:
505       do {
506         char *x_up_subno = (char *)apr_table_get(r->headers_in, "x-up-subno");
507         if (x_up_subno) {
508           apr_table_setn(r->headers_in, "X-DCMGUID", x_up_subno);
509         }
510       } while(0);
511       break;
512     case CHXJ_SPEC_Jhtml:
513     case CHXJ_SPEC_Jxhtml:
514       do {
515         char *x_jphone_uid = (char *)apr_table_get(r->headers_in, "x-jphone-uid");
516         if (x_jphone_uid) {
517           apr_table_setn(r->headers_in, "X-DCMGUID", x_jphone_uid);
518         }
519       } while(0);
520       break;
521     default:
522       break;
523     }
524   }
525   DBG(r, "REQ[%X] end s_convert_guid_parameter()", (unsigned int)(apr_size_t)r);
526 }
527
528 /**
529  * It converts it from HEADER.
530  *
531  * @param r   [i]
532  */
533 static int
534 chxj_convert_input_header(request_rec *r,chxjconvrule_entry *entryp, device_table *spec) 
535 {
536
537   char       *buff;
538   char       *buff_pre;
539   apr_size_t urilen;
540   char       *result;
541   char       *pair;
542   char       *name;
543   char       *value;
544   char       *pstate;
545   char       *vstate;
546   cookie_t   *cookie = NULL;
547   int        no_update_flag = 0;
548
549   DBG(r, "REQ[%X] start chxj_convert_input_header()", (unsigned int)(apr_size_t)r);
550
551   if (! r->args) {
552     DBG(r, "REQ[%X] r->args=[null]", (unsigned int)(apr_size_t)r);
553     DBG(r, "REQ[%X] end   chxj_convert_input_header()", (unsigned int)(apr_size_t)r);
554     return 0;
555   }
556   urilen = strlen(r->args);
557
558   result = qs_alloc_zero_byte_string(r->pool);
559
560   buff_pre = apr_pstrdup(r->pool, r->args);
561
562   for (;;) {
563     char *pair_sv;
564
565     pair = apr_strtok(buff_pre, "&", &pstate);
566     if (pair == NULL)
567       break;
568
569     buff_pre = NULL;
570
571     pair_sv = apr_pstrdup(r->pool, pair);
572
573     name  = apr_strtok(pair, "=", &vstate);
574     value = apr_strtok(NULL, "=", &vstate);
575     if (! name) continue;
576     if (strcasecmp(name, CHXJ_COOKIE_NOUPDATE_PARAM) == 0 || strcasecmp(name, chxj_url_encode(r->pool, CHXJ_COOKIE_NOUPDATE_PARAM)) == 0) {
577       DBG(r, "REQ[%X] found cookie no update parameter", (unsigned int)(apr_size_t)r);
578       no_update_flag++;
579     }
580   }
581
582   buff = apr_pstrdup(r->pool, r->args);
583   DBG(r, "REQ[%X] r->args=[%s]", (unsigned int)(apr_size_t)r, buff);
584
585   /* _chxj_dmy */
586   /* _chxj_c_ */
587   /* _chxj_r_ */
588   /* _chxj_s_ */
589   for (;;) {
590     char *pair_sv;
591
592     pair = apr_strtok(buff, "&", &pstate);
593     if (pair == NULL)
594       break;
595
596     buff = NULL;
597
598     pair_sv = apr_pstrdup(r->pool, pair);
599
600     name  = apr_strtok(pair, "=", &vstate);
601     value = apr_strtok(NULL, "=", &vstate);
602     if (! name) continue;
603     name = chxj_safe_to_jreserved_tag(r, name);
604     if (strncasecmp(name, "_chxj", 5) != 0 && strncasecmp(name, "%5Fchxj", sizeof("%5Fchxj")-1) != 0) {
605       if (strlen(result) != 0) 
606         result = apr_pstrcat(r->pool, result, "&", NULL);
607
608       if (strcasecmp(entryp->encoding, "NONE") != 0) {
609         apr_size_t dlen;
610         char *dvalue;
611         char *dname;
612
613         if (value && *value != 0) {
614           value = chxj_url_decode(r->pool, value);
615           dlen   = strlen(value);
616           DBG(r, "************ before encoding[%s]", value);
617   
618           dvalue = chxj_rencoding(r, value, &dlen);
619           dvalue = chxj_url_encode(r->pool, dvalue);
620   
621           DBG(r, "************ after encoding[%s]", dvalue);
622         }
623         else {
624           dvalue = "";
625         }
626
627         if (name && *name != 0) {
628           name = chxj_url_decode(r->pool, name);
629           dlen = strlen(name);
630           dname = chxj_rencoding(r, name, &dlen);
631           dname = chxj_url_encode(r->pool, dname);
632         }
633         else {
634           dname = "";
635         }
636         s_convert_guid_parameter_to_header(r, dname, spec);
637         result = apr_pstrcat(r->pool, result, dname, "=", dvalue, NULL);
638       }
639       else {
640         s_convert_guid_parameter_to_header(r, name, spec);
641         if (strcmp(name, pair_sv) != 0) {
642           result = apr_pstrcat(r->pool, result, name, "=", value, NULL);
643         } 
644         else {
645           result = apr_pstrcat(r->pool, result, name, NULL);
646         }
647       }
648     }
649     else
650     if ( (strncasecmp(name, "_chxj_c_", 8) == 0 || strncasecmp(name, "%5Fchxj%5Fc%5F", sizeof("%5Fchxj%5Fc%5F")-1) == 0)
651       || (strncasecmp(name, "_chxj_r_", 8) == 0 || strncasecmp(name, "%5Fchxj%5Fr%5F", sizeof("%5Fchxj%5Fr%5F")-1) == 0)
652       || (strncasecmp(name, "_chxj_s_", 8) == 0 || strncasecmp(name, "%5Fchxj%5Fs%5F", sizeof("%5Fchxj%5Fs%5F")-1) == 0)) {
653       if (value == NULL)
654         continue;
655
656       if (strlen(value) == 0)
657         continue;
658
659       if (strlen(result) != 0)
660         result = apr_pstrcat(r->pool, result, "&", NULL);
661
662       result = apr_pstrcat(r->pool, result, &name[8], "=", value, NULL);
663     }
664     else
665     if (strcasecmp(name, CHXJ_COOKIE_PARAM) == 0 || strcasecmp(name, "%5Fchxj%5Fcc") == 0) {
666       if (! cookie) {
667         apr_table_unset(r->headers_in, "Cookie");
668         DBG(r, "REQ[%X] found cookie parameter[%s]",    (unsigned int)(apr_size_t)r, value);
669         DBG(r, "REQ[%X] call start chxj_load_cookie()", (unsigned int)(apr_size_t)r);
670         cookie_lock_t *lock = chxj_cookie_lock(r);
671         cookie = chxj_load_cookie(r, value);
672         DBG(r, "REQ[%X] call end   chxj_load_cookie()", (unsigned int)(apr_size_t)r);
673         if (! no_update_flag && cookie) {
674           cookie = chxj_update_cookie(r, cookie);
675         }
676         chxj_cookie_unlock(r, lock);
677       }
678       if (cookie && cookie->cookie_id) {
679         if (strlen(result) != 0)
680           result = apr_pstrcat(r->pool, result, "&", NULL);
681         result = apr_pstrcat(r->pool, result, name, "=", cookie->cookie_id, NULL);
682       }
683     }
684     else
685     if (strcasecmp(name, CHXJ_COOKIE_NOUPDATE_PARAM) == 0) {
686       if (strlen(result) != 0)
687         result = apr_pstrcat(r->pool, result, "&", NULL);
688       result = apr_pstrcat(r->pool, result, name, "=", value, NULL);
689     }
690   }
691   apr_table_setn(r->headers_in, "X-Chxj-Cookie-No-Update", "true");
692   if (! no_update_flag) {
693     result = apr_pstrcat(r->pool, result, "&_chxj_nc=true", NULL);
694   }
695   r->args = result;
696
697   DBG(r, "REQ[%X] result r->args=[%s]",               (unsigned int)(apr_size_t)r, r->args);
698   DBG(r, "REQ[%X] end   chxj_convert_input_header()", (unsigned int)(apr_size_t)r);
699   return 0;
700 }
701
702
703 /**
704  * It converts it from POSTDATA .
705  *
706  * @param r   [i]
707  * @param src [i]   It is POSTDATA character string.
708  * @param len [i/o] It is length of former HTML character string.
709  */
710 static char *
711 chxj_input_convert(
712   request_rec         *r, 
713   const char          **src, 
714   apr_size_t          *len, 
715   chxjconvrule_entry  *entryp,
716   device_table        *spec)
717 {
718   char     *pair;
719   char     *name;
720   char     *value;
721   char     *pstate;
722   char     *vstate;
723   char     *s;
724   char     *result;
725   cookie_t *cookie = NULL;
726   char     *buff_pre;
727   int      no_update_flag = 0;
728   apr_size_t ilen = 0;
729   apr_pool_t *pool;
730
731   DBG(r, "REQ[%X] start of chxj_input_convert()", (unsigned int)(apr_size_t)r);
732
733   if (! *src) {
734     DBG(r, "REQ[%X] end of chxj_input_convert() (input is null)", (unsigned int)(apr_size_t)r);
735     return apr_pstrdup(r->pool, "");
736   }
737
738   apr_pool_create(&pool, r->pool);
739
740   s        = apr_pstrdup(pool, *src);
741   ilen     = strlen(s);
742   buff_pre = apr_pstrdup(pool, *src);
743
744   result   = qs_alloc_zero_byte_string(pool);
745
746   chxj_dump_string(r, APLOG_MARK, "BEFORE input convert source", s, ilen);
747
748   for (;;) {
749     char *pair_sv;
750
751     pair = apr_strtok(buff_pre, "&", &pstate);
752     if (pair == NULL)
753       break;
754
755     buff_pre = NULL;
756
757     pair_sv = apr_pstrdup(pool, pair);
758
759     name  = apr_strtok(pair, "=", &vstate);
760     value = apr_strtok(NULL, "=", &vstate);
761     if (! name) continue;
762     if (strcasecmp(name, CHXJ_COOKIE_NOUPDATE_PARAM) == 0 || strcasecmp(name, chxj_url_encode(r->pool, CHXJ_COOKIE_NOUPDATE_PARAM)) == 0) {
763       DBG(r, "REQ[%X] found cookie no update parameter", (unsigned int)(apr_size_t)r);
764       no_update_flag++;
765     }
766   }
767
768   /* _chxj_dmy */
769   /* _chxj_c_ */
770   /* _chxj_r_ */
771   /* _chxj_s_ */
772   for (;;) {
773     pair = apr_strtok(s, "&", &pstate);
774     if (pair == NULL)
775       break;
776     s = NULL;
777
778     name  = apr_strtok(pair, "=", &vstate);
779     value = apr_strtok(NULL, "=", &vstate);
780     if (! name) continue;
781     name  = chxj_safe_to_jreserved_tag(r, name);
782
783     if (strncasecmp(name, "_chxj", 5) != 0 && strncasecmp(name, "%5Fchxj", sizeof("%5Fchxj")-1) != 0) {
784       if (strlen(result) != 0) 
785         result = apr_pstrcat(pool, result, "&", NULL);
786
787       if (strcasecmp(entryp->encoding, "NONE") != 0) {
788         apr_size_t dlen;
789         char *dvalue;
790         char *dname;
791
792         if (value && *value != 0) {
793           value = chxj_url_decode(pool, value);
794           dlen   = strlen(value);
795           dvalue = chxj_rencoding(r, value, &dlen);
796           dvalue = chxj_url_encode(pool, dvalue);
797         }
798         else {
799           dvalue = "";
800         }
801
802         if (name && *name != 0) {
803           name = chxj_url_decode(pool, name);
804           dlen = strlen(name);
805           dname = chxj_rencoding(r, name, &dlen);
806           dname = chxj_url_encode(pool, dname);
807         }
808         else {
809           dname = "";
810         }
811
812
813         result = apr_pstrcat(pool, result, dname, "=", dvalue, NULL);
814       }
815       else {
816         result = apr_pstrcat(pool, result, name, "=", value, NULL);
817       }
818     }
819     else
820     if ( (strncasecmp(name, "_chxj_c_", 8) == 0 || strncasecmp(name, "%5Fchxj%5Fc%5F", sizeof("%5Fchxj%5Fc%5F")-1) == 0)
821       || (strncasecmp(name, "_chxj_r_", 8) == 0 || strncasecmp(name, "%5Fchxj%5Fr%5F", sizeof("%5Fchxj%5Fr%5F")-1) == 0)
822       || (strncasecmp(name, "_chxj_s_", 8) == 0 || strncasecmp(name, "%5Fchxj%5Fs%5F", sizeof("%5Fchxj%5Fs%5F")-1) == 0)) {
823       if (value == NULL)
824         continue;
825
826       if (strlen(value) == 0)
827         continue;
828
829       if (strlen(result) != 0)
830         result = apr_pstrcat(pool, result, "&", NULL);
831
832       if (strcasecmp(entryp->encoding, "NONE") != 0 && value && strlen(value)) {
833         apr_size_t dlen;
834         char       *dvalue;
835
836         dlen   = strlen(value);
837         value = chxj_url_decode(pool, value);
838         dvalue = chxj_rencoding(r, value, &dlen);
839         dvalue = chxj_url_encode(pool,dvalue);
840         result = apr_pstrcat(pool, result, &name[8], "=", dvalue, NULL);
841
842       }
843       else {
844         result = apr_pstrcat(pool, result, &name[8], "=", value, NULL);
845       }
846     }
847     else
848     if (strcasecmp(name, CHXJ_COOKIE_PARAM) == 0 || strcasecmp(name, "%5Fchxj%5Fcc") == 0) {
849       if (! cookie) {
850         apr_table_unset(r->headers_in, "Cookie");
851         DBG(r, "REQ[%X] found cookie parameter[%s]",    (unsigned int)(apr_size_t)r, value);
852         DBG(r, "REQ[%X] call start chxj_load_cookie()", (unsigned int)(apr_size_t)r);
853         cookie_lock_t *lock = chxj_cookie_lock(r);
854         cookie = chxj_load_cookie(r, value);
855         DBG(r, "REQ[%X] call end   chxj_load_cookie()", (unsigned int)(apr_size_t)r);
856         if (! no_update_flag && cookie) {
857           cookie = chxj_update_cookie(r, cookie);
858         }
859         chxj_cookie_unlock(r, lock);
860       }
861       if (cookie && cookie->cookie_id) {
862         if (strlen(result) != 0)
863           result = apr_pstrcat(pool, result, "&", NULL);
864         result = apr_pstrcat(pool, result, name, "=", cookie->cookie_id, NULL);
865       }
866     }
867     else
868     if (strcasecmp(name, CHXJ_COOKIE_NOUPDATE_PARAM) == 0) {
869       if (strlen(result) != 0)
870         result = apr_pstrcat(pool, result, "&", NULL);
871       result = apr_pstrcat(pool, result, name, "=", value, NULL);
872     }
873     else
874     if ( strncasecmp(name, CHXJ_QUERY_STRING_PARAM_PREFIX,     sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX)-1) == 0) {
875       apr_size_t dlen;
876       char*      dvalue;
877       dlen   = strlen(value);
878       if (dlen && value) {
879         value = chxj_url_decode(pool, value);
880         dvalue = chxj_rencoding(r, value, &dlen);
881         dvalue = chxj_url_encode(pool,dvalue);
882         if (r->args && strlen(r->args) > 0) {
883           r->args = apr_pstrcat(pool, r->args, "&", &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX)-1], "=", dvalue, NULL);
884         }
885         else {
886           r->args = apr_pstrcat(pool, &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX)-1], "=", dvalue, NULL);
887         }
888         s_convert_guid_parameter_to_header(r, &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX)-1], spec);
889       }
890     }
891     else
892     if (strncasecmp(name, CHXJ_QUERY_STRING_PARAM_PREFIX_ENC, sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX_ENC)-1) == 0) {
893       apr_size_t dlen;
894       char*      dvalue;
895       dlen   = strlen(value);
896       if (dlen && value) {
897         value = chxj_url_decode(pool, value);
898         dvalue = chxj_rencoding(r, value, &dlen);
899         dvalue = chxj_url_encode(pool,dvalue);
900         if (r->args && strlen(r->args) > 0) {
901           r->args = apr_pstrcat(pool, r->args, "&", &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX_ENC)-1], "=", dvalue, NULL);
902         }
903         else {
904           r->args = apr_pstrcat(pool, &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX_ENC)-1], "=", dvalue, NULL);
905         }
906         s_convert_guid_parameter_to_header(r, &name[sizeof(CHXJ_QUERY_STRING_PARAM_PREFIX_ENC)-1], spec);
907       }
908     }
909     DBG(r, "REQ[%X] ************************ name:[%s]", (unsigned int)(apr_size_t)r, name);
910   }
911   *len = strlen(result);
912   apr_table_setn(r->headers_in, "X-Chxj-Cookie-No-Update", "true");
913   if (! no_update_flag) {
914     result = apr_pstrcat(pool, result, "&_chxj_nc=true", NULL);
915   }
916
917   DBG(r, "REQ[%X] AFTER input convert result = [%s]", (unsigned int)(apr_size_t)r, result);
918   DBG(r, "REQ[%X] end chxj_input_convert()", (unsigned int)(apr_size_t)r);
919
920   return result;
921 }
922
923
924 /**
925  * The received data is returned to the filter.
926  *
927  * @param f    [i/o] It is a filter. 
928  * @param data [i]   It is data returned to the filter. 
929  * @param len  [i]   It is length of the data returned to the filter. 
930  */
931 static apr_status_t 
932 pass_data_to_filter(ap_filter_t *f, const char *data, 
933                                         apr_size_t len)
934 {
935   request_rec         *r = f->r;
936   conn_rec            *c = r->connection;
937   apr_status_t        rv;
938   apr_bucket_brigade  *bb;
939   apr_bucket          *b;
940
941   DBG(r, "REQ[%X] start pass_data_to_filter()", (unsigned int)(apr_size_t)r);
942
943   chxj_header_inf_clear(r);
944
945   bb = apr_brigade_create(r->pool, c->bucket_alloc);
946   b  = apr_bucket_transient_create(data, len, c->bucket_alloc);
947
948   APR_BRIGADE_INSERT_TAIL(bb, b);
949   b = apr_bucket_eos_create(f->c->bucket_alloc);
950   APR_BRIGADE_INSERT_TAIL(bb, b);
951
952   rv = ap_pass_brigade(f->next, bb);
953   if (rv != APR_SUCCESS) {
954     DBG(r, "REQ[%X] end pass_data_to_filter() (apr_pass_brigade)", (unsigned int)(apr_size_t)r);
955     return rv;
956   }
957
958   DBG(r, "REQ[%X] end pass_data_to_filter()", (unsigned int)(apr_size_t)r);
959
960   return rv;
961 }
962
963 /**
964  * Add No Cache Header
965  */
966 static void
967 s_add_no_cache_headers(request_rec *r, chxjconvrule_entry  *entryp)
968 {
969   if (entryp->action & CONVRULE_NOCACHE_ON_BIT) {
970     apr_table_unset(r->headers_out,     "Pragma");
971     apr_table_unset(r->err_headers_out, "Pragma");
972     apr_table_unset(r->headers_out,     "Expires");
973     apr_table_unset(r->err_headers_out, "Expires");
974     apr_table_unset(r->headers_out,     "Cache-Control");
975     apr_table_unset(r->err_headers_out, "Cache-Control");
976
977     apr_table_setn(r->err_headers_out, "Pragma", "no-cache");
978     apr_table_setn(r->err_headers_out, "Expires", "Thu, 01 Jan 1970 00:00:00 GMT");
979     apr_table_setn(r->err_headers_out, "Cache-Control", "no-cache, no-store");
980   }
981 }
982
983
984 /**
985  * It is the main loop of the output filter. 
986  *
987  * @param f   [i/o] It is a filter.
988  * @param bb  [i]   
989  */
990 static apr_status_t 
991 chxj_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
992 {
993   request_rec         *r;
994   apr_status_t        rv;
995   apr_bucket          *b;
996   const char          *data;
997   char                *user_agent = NULL;
998   apr_size_t          len;
999   mod_chxj_ctx        *ctx = (mod_chxj_ctx *)f->ctx;
1000   cookie_t            *cookie = NULL;
1001   mod_chxj_config     *dconf;
1002   chxjconvrule_entry  *entryp = NULL;
1003   device_table        *spec = NULL;
1004   apr_pool_t          *pool;
1005
1006   r  = f->r;
1007   DBG(f->r, "REQ[%X] start of chxj_output_filter()", (unsigned int)(apr_size_t)r);
1008   rv = APR_SUCCESS;
1009
1010   apr_pool_create(&pool, r->pool);
1011
1012   entryp = ctx->entryp;
1013   spec   = ctx->spec;
1014   dconf  = chxj_get_module_config(r->per_dir_config, &chxj_module);
1015
1016
1017   if (apr_table_get(r->headers_out, "Location") || apr_table_get(r->err_headers_out, "Location")) {
1018     DBG(r, "REQ[%X] found Location header", TO_ADDR(r));
1019     if ((entryp->action & CONVRULE_COOKIE_ON_BIT) || (entryp->action & CONVRULE_COOKIE_ONLY_BIT)) {
1020       cookie_lock_t *lock = NULL;
1021       DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", TO_ADDR(r));
1022       switch(spec->html_spec_type) {
1023       case CHXJ_SPEC_Chtml_1_0:
1024       case CHXJ_SPEC_Chtml_2_0:
1025       case CHXJ_SPEC_Chtml_3_0:
1026       case CHXJ_SPEC_Chtml_4_0:
1027       case CHXJ_SPEC_Chtml_5_0:
1028       case CHXJ_SPEC_Chtml_6_0:
1029       case CHXJ_SPEC_Chtml_7_0:
1030       case CHXJ_SPEC_XHtml_Mobile_1_0:
1031       case CHXJ_SPEC_Jhtml:
1032         lock = chxj_cookie_lock(r);
1033         cookie = chxj_save_cookie(r);
1034         s_add_cookie_id_if_has_location_header(r, cookie);
1035         chxj_cookie_unlock(r, lock);
1036         break;
1037       default:
1038         break;
1039       }
1040     }
1041     if (! ap_is_HTTP_REDIRECT(r->status)) {
1042       r->status = HTTP_MOVED_TEMPORARILY;
1043     }
1044     s_add_no_cache_headers(r, entryp);
1045     /* must not send body. */
1046     rv = pass_data_to_filter(f, "", 0);
1047     DBG(f->r, "REQ[%X] end of chxj_output_filter()", TO_ADDR(r));
1048     return rv;
1049   }
1050
1051
1052   if (r->content_type) {
1053     if (! STRNCASEEQ('t','T',"text/html",r->content_type, sizeof("text/html")-1)
1054     &&  ! STRNCASEEQ('t','T',"text/xml", r->content_type, sizeof("text/xml")-1)
1055     &&  ! STRNCASEEQ('a','A',"application/xhtml+xml", r->content_type, sizeof("application/xhtml+xml")-1)
1056     &&  ! (dconf->image == CHXJ_IMG_ON
1057           && ! apr_table_get(r->headers_in, "CHXJ_IMG_CONV")
1058           && STRNCASEEQ('i','I',"image/",  r->content_type, sizeof("image/") -1)
1059           && ( STRCASEEQ('j','J',"jpeg",            &r->content_type[6])         /* JPEG */
1060             || STRCASEEQ('j','J',"jp2",             &r->content_type[6])         /* JPEG2000 */
1061             || STRCASEEQ('j','J',"jpeg2000",        &r->content_type[6])         /* JPEG2000 */
1062             || STRCASEEQ('j','J',"jpeg2000-image",  &r->content_type[6])         /* JPEG2000 */
1063             || STRCASEEQ('x','X',"x-jpeg2000-image",&r->content_type[6])         /* JPEG2000 */
1064             || STRCASEEQ('x','X',"x-ms-bmp",        &r->content_type[6])         /* BMP */
1065             || STRCASEEQ('p','P',"png",             &r->content_type[6])         /* PNG */
1066             || STRCASEEQ('x','X',"x-png",           &r->content_type[6])         /* PNG */
1067             || STRCASEEQ('g','G',"gif",             &r->content_type[6])))) {     /* GIF */
1068       
1069       DBG(r, "REQ[%X] not convert content-type:[%s] dconf->image:[%d]", (unsigned int)(apr_size_t)r, r->content_type, dconf->image);
1070       if (entryp->action & CONVRULE_COOKIE_ON_BIT) {
1071         cookie_lock_t *lock = NULL;
1072         DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", (unsigned int)(apr_size_t)r);
1073         switch(spec->html_spec_type) {
1074         case CHXJ_SPEC_Chtml_1_0:
1075         case CHXJ_SPEC_Chtml_2_0:
1076         case CHXJ_SPEC_Chtml_3_0:
1077         case CHXJ_SPEC_Chtml_4_0:
1078         case CHXJ_SPEC_Chtml_5_0:
1079         case CHXJ_SPEC_Chtml_6_0:
1080         case CHXJ_SPEC_Chtml_7_0:
1081         case CHXJ_SPEC_XHtml_Mobile_1_0:
1082         case CHXJ_SPEC_Jhtml:
1083           lock = chxj_cookie_lock(r);
1084           cookie = chxj_save_cookie(r);
1085           s_add_cookie_id_if_has_location_header(r, cookie);
1086           chxj_cookie_unlock(r, lock);
1087           break;
1088         default:
1089           break;
1090         }
1091       }
1092       if (apr_table_get(r->headers_out, "Location") || apr_table_get(r->err_headers_out, "Location")) {
1093         if (! ap_is_HTTP_REDIRECT(r->status)) {
1094           r->status = HTTP_MOVED_TEMPORARILY;
1095         }
1096       }
1097       s_add_no_cache_headers(r, entryp);
1098       ap_pass_brigade(f->next, bb);
1099       DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
1100       return APR_SUCCESS;
1101     }
1102   }
1103   else {
1104     DBG(r, "REQ[%X] not convert content-type:[(null)]", (unsigned int)(apr_size_t)r);
1105     ap_pass_brigade(f->next, bb);
1106     DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
1107     return APR_SUCCESS;
1108   }
1109
1110
1111   for (b = APR_BRIGADE_FIRST(bb);
1112        b != APR_BRIGADE_SENTINEL(bb); 
1113        b = APR_BUCKET_NEXT(b)) {
1114
1115     if (apr_bucket_read(b, &data, &len, APR_BLOCK_READ) == APR_SUCCESS) {
1116       chxj_dump_string(r, APLOG_MARK, "READ Data", data, len);
1117
1118       /*--------------------------------------------------------------------*/
1119       /* append data                                                        */
1120       /*--------------------------------------------------------------------*/
1121       char *tmp;
1122       DBG(r, "append data start");
1123       ctx = (mod_chxj_ctx *)f->ctx;
1124
1125       if (len > 0) {
1126         tmp = apr_palloc(r->pool, ctx->len);
1127         memcpy(tmp, ctx->buffer, ctx->len);
1128
1129         ctx->buffer = apr_palloc(pool, ctx->len + len);
1130
1131         memcpy(ctx->buffer, tmp, ctx->len);
1132         memcpy(&ctx->buffer[ctx->len], data, len);
1133
1134         ctx->len += len;
1135       }
1136       DBG(r, "REQ[%X] append data end", (unsigned int)(apr_size_t)r);
1137     }
1138
1139     if (APR_BUCKET_IS_EOS(b)) {
1140
1141       DBG(r, "REQ[%X] eos", (unsigned int)(apr_size_t)r);
1142       /*----------------------------------------------------------------------*/
1143       /* End Of File                                                          */
1144       /*----------------------------------------------------------------------*/
1145       if (ctx) {
1146         cookie_lock_t *lock = NULL;
1147         ctx = (mod_chxj_ctx *)f->ctx;
1148
1149         DBG(r, "REQ[%X] content_type=[%s]", (unsigned int)(apr_size_t)r, r->content_type);
1150         lock = chxj_cookie_lock(r);
1151
1152         if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN 
1153             && r->content_type 
1154             && (STRNCASEEQ('a','A',"application/xhtml+xml", r->content_type, sizeof("application/xhtml+xml")-1)
1155             ||  STRNCASEEQ('t','T',"text/html", r->content_type, sizeof("text/html")-1))) {
1156           DBG(r, "REQ[%X] detect convert target:[%s]", (unsigned int)(apr_size_t)r, r->content_type);
1157
1158           if (ctx->len) {
1159             char *tmp;
1160
1161             tmp = apr_palloc(pool, ctx->len + 1);
1162
1163             memset(tmp, 0, ctx->len + 1);
1164             memcpy(tmp, ctx->buffer, ctx->len);
1165
1166             ctx->buffer = chxj_convert(r, 
1167                                        (const char **)&tmp, 
1168                                        (apr_size_t *)&ctx->len,
1169                                        spec,
1170                                        user_agent, &cookie);
1171
1172           }
1173           else {
1174             ctx->buffer = apr_psprintf(r->pool, "\n");
1175             ctx->len += 1;
1176             ctx->buffer = chxj_convert(r, 
1177                                        (const char **)&ctx->buffer, 
1178                                        (apr_size_t *)&ctx->len,
1179                                        spec,
1180                                        user_agent, &cookie);
1181
1182           }
1183         }
1184         if (r->content_type
1185             && *(char *)r->content_type == 't'
1186             && strncmp(r->content_type, "text/xml",   8) == 0) {
1187           DBG(r, "REQ[%X] text/XML", (unsigned int)(apr_size_t)r);
1188
1189           Doc       doc;
1190           Node      *root;
1191           Node      *child;
1192           qr_code_t qrcode;
1193           int       sts;
1194       
1195           memset(&doc,    0, sizeof(Doc));
1196           memset(&qrcode, 0, sizeof(qr_code_t));
1197           doc.r = r;
1198           doc.parse_mode  = PARSE_MODE_CHTML;
1199           qrcode.doc      = &doc;
1200           qrcode.r        = r;
1201       
1202           qs_init_malloc(&doc);
1203       
1204           root = qs_parse_string(&doc, ctx->buffer, ctx->len);
1205
1206           sts = 0;
1207           for (child = qs_get_child_node(&doc,root);
1208                child ;
1209                child = qs_get_next_node(&doc,child)) {
1210             char *name = qs_get_node_name(&doc,child);
1211             if (strcasecmp("qrcode",name) == 0) {
1212               sts++;
1213               break;
1214             }
1215           }
1216           qs_all_free(&doc,QX_LOGMARK);
1217           if (sts) {
1218             r->handler = apr_psprintf(r->pool, "chxj-qrcode");
1219             chxj_qrcode_node_to_qrcode(&qrcode, root);
1220             sts = chxj_qrcode_create_image_data(&qrcode, &ctx->buffer, &ctx->len);
1221             if (sts != OK) {
1222               ERR(r, "REQ[%X] qrcode create failed.", (unsigned int)(apr_size_t)r);
1223               chxj_cookie_unlock(r, lock);
1224               DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
1225               return sts;
1226             }
1227             r->content_type = apr_psprintf(r->pool, "image/jpeg");
1228           }
1229         }
1230
1231         if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN 
1232             && r->content_type 
1233             && ( *r->content_type == 'i' || *r->content_type == 'I')
1234             && dconf->image == CHXJ_IMG_ON
1235             && strncasecmp("image/", r->content_type, 6) == 0
1236             && ( STRCASEEQ('j','J',"jpeg",            &r->content_type[6])         /* JPEG */
1237               || STRCASEEQ('j','J',"jp2",             &r->content_type[6])         /* JPEG2000 */
1238               || STRCASEEQ('j','J',"jpeg2000",        &r->content_type[6])         /* JPEG2000 */
1239               || STRCASEEQ('j','J',"jpeg2000-image",  &r->content_type[6])         /* JPEG2000 */
1240               || STRCASEEQ('x','X',"x-jpeg2000-image",&r->content_type[6])         /* JPEG2000 */
1241               || STRCASEEQ('p','P',"png",             &r->content_type[6])         /* PNG */
1242               || STRCASEEQ('x','X',"x-png",           &r->content_type[6])         /* PNG */
1243               || STRCASEEQ('x','X',"x-ms-bmp",     &r->content_type[6])         /* BMP */
1244               || STRCASEEQ('g','G',"gif",             &r->content_type[6]))) {     /* GIF */
1245           DBG(r, "REQ[%X] detect convert target:[%s]", (unsigned int)(apr_size_t)r, r->content_type);
1246           if (ctx->len) {
1247             char *tmp;
1248
1249             tmp = apr_palloc(pool, ctx->len + 1);
1250
1251             memset(tmp, 0, ctx->len + 1);
1252             memcpy(tmp, ctx->buffer, ctx->len);
1253             ctx->buffer = 
1254               chxj_convert_image(r, 
1255                                   (const char **)&tmp,
1256                                   (apr_size_t *)&ctx->len);
1257             if (ctx->buffer == NULL) {
1258               ctx->buffer = tmp;
1259             }
1260           }
1261         }
1262
1263         apr_table_unset(r->headers_out, "Content-Length");
1264         apr_table_unset(r->err_headers_out, "Content-Length");
1265         ap_set_content_length(r, (apr_off_t)ctx->len);
1266
1267         
1268         if (ctx->len > 0) {
1269           DBG(r, "REQ[%X] call pass_data_to_filter()", (unsigned int)(apr_size_t)r);
1270           s_add_cookie_id_if_has_location_header(r, cookie);
1271           if (apr_table_get(r->headers_out, "Location") || apr_table_get(r->err_headers_out, "Location")) {
1272             if (! ap_is_HTTP_REDIRECT(r->status)) {
1273               r->status = HTTP_MOVED_TEMPORARILY;
1274             }
1275           }
1276           if (ctx->len && ap_is_HTTP_REDIRECT(r->status)) {
1277             ctx->buffer = apr_pstrdup(pool, "");
1278             ctx->len    = 0;
1279             ap_set_content_length(r, (apr_off_t)ctx->len);
1280           }
1281           chxj_cookie_unlock(r,lock);
1282           s_add_no_cache_headers(r, entryp);
1283           rv = pass_data_to_filter(f, 
1284                                    (const char *)ctx->buffer, 
1285                                    (apr_size_t)ctx->len);
1286         }
1287         else {
1288           ctx->buffer = apr_pstrdup(pool, "");
1289           ctx->len    = 0;
1290           ap_set_content_length(r, (apr_off_t)ctx->len);
1291           chxj_cookie_unlock(r, lock);
1292           s_add_no_cache_headers(r, entryp);
1293           rv = pass_data_to_filter(f, 
1294                                    (const char *)ctx->buffer, 
1295                                    (apr_size_t)ctx->len);
1296         }
1297         DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
1298         return rv;
1299       }
1300       else {
1301         DBG(r, "REQ[%X] SAVE COOKIE[%x]", (unsigned int)(apr_size_t)r, entryp->action);
1302
1303         /*
1304          * save cookie.
1305          */
1306         if (entryp->action & CONVRULE_COOKIE_ON_BIT) {
1307           cookie_lock_t *lock = NULL;
1308           DBG(r, "REQ[%X] entryp->action == COOKIE_ON_BIT", (unsigned int)(apr_size_t)r);
1309           switch(spec->html_spec_type) {
1310           case CHXJ_SPEC_Chtml_1_0:
1311           case CHXJ_SPEC_Chtml_2_0:
1312           case CHXJ_SPEC_Chtml_3_0:
1313           case CHXJ_SPEC_Chtml_4_0:
1314           case CHXJ_SPEC_Chtml_5_0:
1315           case CHXJ_SPEC_Chtml_6_0:
1316           case CHXJ_SPEC_Chtml_7_0:
1317           case CHXJ_SPEC_XHtml_Mobile_1_0:
1318           case CHXJ_SPEC_Jhtml:
1319             lock = chxj_cookie_lock(r);
1320             cookie = chxj_save_cookie(r);
1321             /*
1322              * Location Header Check to add cookie parameter.
1323              */
1324             s_add_cookie_id_if_has_location_header(r, cookie);
1325             chxj_cookie_unlock(r, lock);
1326             apr_table_unset(r->headers_out, "Set-Cookie");
1327             apr_table_unset(r->err_headers_out, "Set-Cookie");
1328             break;
1329
1330           default:
1331             break;
1332           }
1333         }
1334         if (apr_table_get(r->headers_out, "Location") || apr_table_get(r->err_headers_out, "Location")) {
1335           if (! ap_is_HTTP_REDIRECT(r->status)) {
1336             r->status = HTTP_MOVED_TEMPORARILY;
1337           }
1338         }
1339         apr_table_setn(r->headers_out, "Content-Length", "0");
1340         DBG(r, "REQ[%X] call pass_data_to_filter()", (unsigned int)(apr_size_t)r);
1341         s_add_no_cache_headers(r, entryp);
1342         rv = pass_data_to_filter(f, (const char *)"", (apr_size_t)0);
1343         DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
1344         return rv;
1345       }
1346     }
1347   }
1348   apr_brigade_destroy(bb);
1349
1350   DBG(f->r, "REQ[%X] end of chxj_output_filter()", (unsigned int)(apr_size_t)r);
1351
1352   return APR_SUCCESS;
1353 }
1354
1355 /**
1356  * Add Cookie_id if it has location header.
1357  */
1358 static void
1359 s_add_cookie_id_if_has_location_header(request_rec *r, cookie_t *cookie)
1360 {
1361   char *location_header = (char *)apr_table_get(r->headers_out, "Location");
1362   if (! location_header) {
1363     location_header = (char *)apr_table_get(r->err_headers_out, "Location");
1364   }
1365   if (cookie && location_header) {
1366     DBG(r, "REQ[%X] Location Header=[%s]", (unsigned int)(apr_size_t)r, location_header);
1367     location_header = chxj_add_cookie_parameter(r,
1368                                                 location_header,
1369                                                 cookie);
1370     apr_table_unset(r->headers_out, "Location");
1371     apr_table_setn(r->headers_out, "Location", location_header);
1372     DBG(r, "REQ[%X] Location Header=[%s]", (unsigned int)(apr_size_t)r, location_header);
1373     if (!ap_is_HTTP_REDIRECT(r->status)) {
1374       r->status = HTTP_MOVED_TEMPORARILY;
1375     }
1376   }
1377 }
1378
1379 /**
1380  * It is the main loop of the input filter handler. 
1381  *
1382  */
1383 static apr_status_t
1384 chxj_input_handler(request_rec *r)
1385 {
1386   mod_chxj_config     *dconf;
1387   chxjconvrule_entry  *entryp = NULL;
1388   device_table        *spec   = NULL;
1389   char                *post_data = NULL;
1390   apr_size_t          post_data_len = 0;
1391   char                *response;
1392   char                *user_agent;
1393   apr_pool_t          *pool;
1394   apr_size_t          ii;
1395   int                 response_code = 0;
1396   
1397   DBG(r, "start of chxj_input_handler()");
1398
1399   if (strcasecmp(r->handler, "chxj-input-handler")) {
1400     DBG(r, "end chxj_input_handler()");
1401     return DECLINED;
1402   }
1403   apr_pool_create(&pool, r->pool);
1404
1405   dconf      = chxj_get_module_config(r->per_dir_config, &chxj_module);
1406   user_agent = (char*)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
1407   if (!user_agent) {
1408     user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
1409   }
1410   spec       = chxj_specified_device(r, user_agent);
1411   entryp     = chxj_apply_convrule(r, dconf->convrules);
1412
1413   post_data = apr_pstrdup(pool, "");
1414   if (ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK) == OK) {
1415     if (ap_should_client_block(r)) {
1416       while (post_data_len < CHXJ_POST_MAX) {
1417 #define BUFSZ (256)
1418         char buffer[BUFSZ];
1419         int read_bytes = ap_get_client_block(r, buffer, BUFSZ-1);
1420         if (read_bytes<=0) {
1421           break;
1422         }
1423         buffer[read_bytes] = '\0';
1424         post_data = apr_pstrcat(pool, post_data, buffer, NULL);
1425         post_data_len += read_bytes;
1426 #undef BUFSZ
1427       }
1428     }
1429   }
1430
1431   /* 
1432    * now convert.
1433    */
1434   if (post_data_len > 0) {
1435     post_data = chxj_input_convert(r, (const char**)&post_data, (apr_size_t*)&post_data_len, entryp, spec);
1436     DBG(r, "(in:exchange)POSTDATA:[%s]", post_data);
1437   }
1438
1439   char *url_path;
1440   if (dconf->forward_url_base) {
1441     url_path = apr_psprintf(pool, "%s%s", dconf->forward_url_base, r->uri);
1442   }
1443   else {
1444     url_path = apr_psprintf(pool, "%s://%s:%d%s", chxj_apache_run_http_scheme(r), ap_get_server_name(r), ap_get_server_port(r), r->uri);
1445   }
1446   if (r->args) {
1447     url_path = apr_pstrcat(pool, url_path, "?", r->args, NULL);
1448   }
1449   DBG(r, "==> new url_path:[%s]", url_path);
1450
1451   apr_size_t res_len;
1452   apr_table_setn(r->headers_in, CHXJ_HEADER_ORIG_CLIENT_IP, r->connection->remote_ip);
1453   apr_table_unset(r->headers_in, "Content-Length");
1454   apr_table_setn(r->headers_in, "Content-Length", apr_psprintf(pool, "%" APR_SIZE_T_FMT, post_data_len));
1455   response = chxj_serf_post(r, pool, url_path, post_data, post_data_len, 1, &res_len, &response_code);
1456   DBG(r, "REQ[%X] -------------------------------------------------------", (unsigned int)(apr_size_t)r);
1457   DBG(r, "REQ[%X] response length:[%" APR_SIZE_T_FMT "]", (unsigned int)(apr_size_t)r, res_len);
1458   for (ii=0; ii<res_len/64; ii++) {
1459     DBG(r, "REQ[%X] response:[%.*s]", (unsigned int)(apr_size_t)r, 64, &response[ii*64]);
1460   }
1461   DBG(r, "REQ[%X] -------------------------------------------------------", (unsigned int)(apr_size_t)r);
1462
1463   char *chunked;
1464   if ((chunked = (char *)apr_table_get(r->headers_out, "Transfer-Encoding")) != NULL) {
1465     if (strcasecmp(chunked, "chunked") == 0) {
1466       r->chunked = 1;  
1467       apr_table_unset(r->headers_out, "Transfer-Encoding");
1468     }
1469   }
1470   if (ap_is_HTTP_ERROR(response_code)) {
1471     DBG(r, "REQ[%X] end of chxj_input_handler() (HTTP-ERROR received. response code:[%d])", (unsigned int)(apr_size_t)r, response_code);
1472     return response_code;
1473   }
1474   {
1475     apr_pool_t *wpool;
1476     apr_pool_create(&wpool, r->pool);
1477     apr_bucket_brigade *bb;
1478     apr_bucket *e;
1479     apr_status_t rv;
1480     conn_rec *c = r->connection;
1481     
1482     bb = apr_brigade_create(wpool, c->bucket_alloc);
1483     e  = apr_bucket_transient_create(response, res_len, c->bucket_alloc);
1484     APR_BRIGADE_INSERT_TAIL(bb, e);
1485     e = apr_bucket_eos_create(c->bucket_alloc);
1486     APR_BRIGADE_INSERT_TAIL(bb, e);
1487     if ((rv = ap_pass_brigade(r->output_filters, bb)) != APR_SUCCESS) {
1488       ERR(r, "REQ[%X] %s:%d failed ap_pass_brigade()", (unsigned int)(apr_size_t)r, APLOG_MARK);
1489       return rv;
1490     }
1491     apr_brigade_cleanup(bb);
1492   }
1493
1494   DBG(r, "REQ[%X] end of chxj_input_handler()", (unsigned int)(apr_size_t)r);
1495   return APR_SUCCESS;
1496 }
1497
1498 static mod_chxj_global_config *
1499 chxj_global_config_create(apr_pool_t *pool, server_rec *s)
1500 {
1501   mod_chxj_global_config *conf;
1502
1503   SDBG(s, "start chxj_global_config_create()");
1504
1505   /*--------------------------------------------------------------------------*/
1506   /* allocate an own subpool which survives server restarts                   */
1507   /*--------------------------------------------------------------------------*/
1508   conf = (mod_chxj_global_config *)apr_palloc(pool, 
1509                   sizeof(mod_chxj_global_config));
1510 #if 0
1511   conf->cookie_db_lock = NULL;
1512 #endif
1513   SDBG(s, "end   chxj_global_config_create()");
1514
1515   return conf;
1516 }
1517
1518
1519 /**
1520  * initialize chxj module
1521  */
1522 static int 
1523 chxj_init_module(apr_pool_t *p, 
1524                  apr_pool_t *UNUSED(plog), 
1525                  apr_pool_t *UNUSED(ptemp), 
1526                  server_rec *s)
1527 {
1528   void *user_data;
1529   apr_status_t rv;
1530
1531   SDBG(s, "start chxj_init_module()");
1532
1533   apr_pool_userdata_get(&user_data, CHXJ_MOD_CONFIG_KEY, s->process->pool);
1534   SDBG(s, " ");
1535   if (user_data == NULL) {
1536     SDBG(s, " ");
1537     /*
1538      * dummy user_data set.
1539      */
1540     apr_pool_userdata_set(
1541       (const void *)(1), 
1542       CHXJ_MOD_CONFIG_KEY, 
1543       apr_pool_cleanup_null, 
1544       s->process->pool);
1545     SDBG(s, "end  chxj_init_module()");
1546     return OK;
1547   }
1548
1549   ap_add_version_component(p, CHXJ_VERSION_PREFIX CHXJ_VERSION);
1550
1551   if ((rv = apr_proc_mutex_create(&global_cookie_mutex, NULL,  APR_LOCK_FCNTL, s->process->pool)) != APR_SUCCESS) {
1552     char errstr[255];
1553     SERR(s, "%s:%d end chxj_init_module(). mutex create failure.(%d:%s)",APLOG_MARK, rv,apr_strerror(rv,errstr,255));
1554     return HTTP_INTERNAL_SERVER_ERROR;
1555   }
1556
1557   SDBG(s, "end  chxj_init_module()");
1558
1559   return OK;
1560 }
1561
1562
1563 static void 
1564 chxj_child_init(apr_pool_t *UNUSED(p), server_rec *s)
1565 {
1566   apr_status_t rv;
1567   SDBG(s, "start chxj_child_init()");
1568   if ((rv = apr_proc_mutex_child_init(&global_cookie_mutex, NULL, s->process->pool)) != APR_SUCCESS) {
1569     char errstr[255];
1570     SERR(s, "%s:%d ERROR end chxj_init_module(). mutex create failure.(%d:%s)", APLOG_MARK, rv,apr_strerror(rv,errstr,255));
1571   }
1572   SDBG(s, "end   chxj_child_init()");
1573 }
1574
1575
1576 /**
1577  * A set structure of each server is generated. 
1578  * 
1579  * @param p
1580  * @param s
1581  */
1582 static void *
1583 chxj_config_server_create(apr_pool_t *p, server_rec *s)
1584 {
1585   mod_chxj_global_config *gc;
1586
1587   gc = chxj_global_config_create(p,s);
1588
1589   return gc;
1590 }
1591
1592
1593 static int
1594 chxj_translate_name(request_rec *r)
1595 {
1596   DBG(r, "REQ[%X] =======================================================================", (unsigned int)(apr_size_t)r);
1597   DBG(r, "REQ[%X] ", (unsigned int)(apr_size_t)r);
1598   DBG(r, "REQ[%X] START REQUEST (uri:[%s] args:[%s])", (unsigned int)(apr_size_t)r, r->unparsed_uri, r->args ? r->args : "");
1599   DBG(r, "REQ[%X] METHOD [%s]", TO_ADDR(r), r->method);
1600   DBG(r, "REQ[%X] ", (unsigned int)(apr_size_t)r);
1601   DBG(r, "REQ[%X] =======================================================================", (unsigned int)(apr_size_t)r);
1602 #if 0
1603   return chxj_trans_name(r);
1604 #else
1605   return DECLINED;
1606 #endif
1607 }
1608
1609
1610 static void 
1611 chxj_insert_filter(request_rec *r)
1612 {
1613   char                *user_agent;
1614   device_table        *spec;
1615   mod_chxj_config     *dconf;
1616   chxjconvrule_entry  *entryp;
1617   mod_chxj_ctx        *ctx;
1618   apr_status_t        rv;
1619   char                *contentType;
1620
1621   DBG(r, "REQ[%X] start chxj_insert_filter()", (unsigned int)(apr_size_t)r);
1622
1623   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1624
1625   /* we get User-Agent from CHXJ_HTTP_USER_AGENT header if any */
1626   user_agent = (char *)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
1627   if (!user_agent) {
1628     user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
1629   }
1630
1631   contentType = (char *)apr_table_get(r->headers_in, "Content-Type");
1632   if (contentType
1633       && strncasecmp("multipart/form-data", contentType, 19) == 0) {
1634     DBG(r, "REQ[%X] detect multipart/form-data ==> no target", (apr_size_t)(unsigned int)r);
1635     DBG(r, "REQ[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
1636     return;
1637   }
1638
1639   spec = chxj_specified_device(r, user_agent);
1640   entryp = chxj_apply_convrule(r, dconf->convrules);
1641   if (!entryp) {
1642     DBG(r, "REQ[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
1643     return;
1644   }
1645   ctx = apr_palloc(r->pool, sizeof(*ctx));
1646   memset(ctx, 0, sizeof(*ctx));
1647   if ((rv = apr_pool_create(&ctx->pool, r->pool)) != APR_SUCCESS) {
1648     ERR(r, "%s:%d: failed: new pool create. rv:[%d]", __FILE__,__LINE__,rv);
1649     DBG(r, "REQ:[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
1650     return;
1651   }
1652   ctx->entryp = entryp;
1653   ctx->spec   = spec;
1654   ctx->buffer = apr_palloc(ctx->pool, 1);
1655   ctx->buffer[0] = 0;
1656
1657   if (!entryp || (!(entryp->action & CONVRULE_ENGINE_ON_BIT) && !(entryp->action & CONVRULE_COOKIE_ONLY_BIT))) {
1658     DBG(r,"REQ[%X] EngineOff", (unsigned int)(apr_size_t)r);
1659     DBG(r, "REQ[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
1660     return;
1661   }
1662
1663   switch(spec->html_spec_type) {
1664   case CHXJ_SPEC_Chtml_1_0:
1665   case CHXJ_SPEC_Chtml_2_0:
1666   case CHXJ_SPEC_Chtml_3_0:
1667   case CHXJ_SPEC_Chtml_4_0:
1668   case CHXJ_SPEC_Chtml_5_0:
1669   case CHXJ_SPEC_Chtml_6_0:
1670   case CHXJ_SPEC_Chtml_7_0:
1671   case CHXJ_SPEC_XHtml_Mobile_1_0:
1672   case CHXJ_SPEC_Hdml:
1673   case CHXJ_SPEC_Jhtml:
1674   case CHXJ_SPEC_Jxhtml:
1675     break;
1676
1677   default:
1678     DBG(r, "REQ[%X] end chxj_insert_filter() Unknown spec type(%d).", (unsigned int)(apr_size_t)r, spec->html_spec_type);
1679     return;
1680   }
1681
1682
1683   if (! apr_table_get(r->headers_in, "X-Chxj-Forward")) {
1684     ap_add_output_filter("chxj_output_filter", ctx, r, r->connection);
1685     DBG(r, "REQ[%X] added Output Filter", (unsigned int)(apr_size_t)r);
1686   }
1687
1688   DBG(r, "REQ[%X] end chxj_insert_filter()", (unsigned int)(apr_size_t)r);
1689 }
1690
1691
1692 /**
1693  * The hook is registered.
1694  *
1695  * @param p
1696  */
1697 static void 
1698 chxj_register_hooks(apr_pool_t *UNUSED(p))
1699 {
1700   ap_hook_post_config(chxj_init_module,
1701                       NULL,
1702                       NULL,
1703                       APR_HOOK_REALLY_FIRST);
1704   ap_hook_child_init(chxj_child_init, 
1705                      NULL, 
1706                      NULL, 
1707                      APR_HOOK_REALLY_FIRST);
1708   ap_register_output_filter (
1709                       "chxj_output_filter", 
1710                       chxj_output_filter, 
1711                       NULL, 
1712                       AP_FTYPE_RESOURCE);
1713   ap_hook_insert_filter(chxj_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
1714   ap_hook_handler(chxj_img_conv_format_handler, NULL, NULL, APR_HOOK_MIDDLE);
1715   ap_hook_handler(chxj_qr_code_handler, NULL, NULL, APR_HOOK_MIDDLE);
1716   ap_hook_handler(chxj_input_handler, NULL, NULL, APR_HOOK_MIDDLE);
1717   ap_hook_translate_name(chxj_translate_name, NULL, NULL, APR_HOOK_MIDDLE);
1718   ap_hook_fixups(chxj_headers_fixup, NULL, NULL, APR_HOOK_FIRST);
1719 }
1720
1721
1722 /**
1723  * A set structure according to the directory is generated. 
1724  *
1725  * @param p
1726  * @param arg
1727  */
1728 static void * 
1729 chxj_create_per_dir_config(apr_pool_t *p, char *arg) 
1730 {
1731   mod_chxj_config *conf;
1732
1733   conf = apr_pcalloc(p, sizeof(mod_chxj_config));
1734   conf->device_data_file = NULL;
1735   conf->devices          = NULL;
1736   conf->emoji_data_file  = NULL;
1737   conf->emoji            = NULL;
1738   conf->emoji_tail       = NULL;
1739   conf->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_NONE;
1740   conf->image            = CHXJ_IMG_NONE;
1741   conf->image_cache_dir  = apr_psprintf(p, "%s",DEFAULT_IMAGE_CACHE_DIR);
1742   conf->image_cache_limit = 0;
1743   conf->server_side_encoding = NULL;
1744   conf->cookie_db_dir    = NULL;
1745   conf->cookie_timeout   = 0;
1746   conf->cookie_store_type = COOKIE_STORE_TYPE_NONE;
1747   conf->cookie_lazy_mode  = 0;
1748   conf->cookie_dbm_type  = NULL;
1749 #if defined(USE_MYSQL_COOKIE)
1750   memset((void *)&conf->mysql, 0, sizeof(mysql_t));
1751   conf->mysql.port       = MYSQL_PORT;
1752   conf->mysql.host       = NULL;
1753 #endif
1754 #if defined(USE_MEMCACHE_COOKIE)
1755   memset((void *)&conf->memcache, 0, sizeof(memcache_t));
1756   conf->memcache.host    = NULL;
1757   conf->memcache.port    = 0;
1758 #endif
1759   conf->forward_url_base = NULL;
1760   conf->forward_server_ip = NULL;
1761   conf->allowed_cookie_domain = NULL;
1762   conf->post_log              = NULL;
1763
1764   if (arg == NULL) {
1765     conf->dir                  = NULL;
1766   }
1767   else {
1768     conf->dir                  = apr_pcalloc(p, strlen(arg)+1);
1769     memset(conf->dir, 0, strlen(arg)+1);
1770     strcpy(conf->dir, arg);
1771   }
1772   conf->convrules   = apr_array_make(p, 2, sizeof(chxjconvrule_entry));
1773
1774   /* Default is copyleft */
1775   conf->image_copyright = NULL; 
1776
1777   return conf;
1778 }
1779
1780
1781 /*
1782  *  Merge per-directory CHXJ configurations
1783  */
1784 static void *
1785 chxj_merge_per_dir_config(apr_pool_t *p, void *basev, void *addv)
1786 {
1787   mod_chxj_config *base;
1788   mod_chxj_config *add;
1789   mod_chxj_config *mrg;
1790
1791   base = (mod_chxj_config *)basev;
1792   add  = (mod_chxj_config *)addv;
1793   mrg  = (mod_chxj_config *)apr_palloc(p, sizeof(mod_chxj_config));
1794
1795   mrg->device_data_file = NULL;
1796   mrg->devices          = NULL;
1797   mrg->emoji_data_file  = NULL;
1798   mrg->image            = CHXJ_IMG_NONE;
1799   mrg->image_cache_dir  = NULL;
1800   mrg->image_copyright  = NULL;
1801   mrg->image_cache_limit  = 0;
1802   mrg->emoji            = NULL;
1803   mrg->emoji_tail       = NULL;
1804   mrg->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_NONE;
1805   mrg->new_line_type    = NLTYPE_NIL;
1806   mrg->forward_url_base = NULL;
1807   mrg->forward_server_ip = NULL;
1808   mrg->allowed_cookie_domain = NULL;
1809   mrg->post_log         = NULL;
1810   mrg->cookie_dbm_type  = NULL;
1811
1812   mrg->dir = apr_pstrdup(p, add->dir);
1813
1814   if (! add->device_data_file) {
1815     mrg->devices = base->devices;
1816     mrg->device_data_file = apr_pstrdup(p, base->device_data_file);
1817   }
1818   else {
1819     mrg->devices = add->devices;
1820     mrg->device_data_file = apr_pstrdup(p, add->device_data_file);
1821   }
1822
1823   if (! add->emoji_data_file) {
1824     mrg->emoji = base->emoji;
1825     mrg->emoji_tail = base->emoji_tail;
1826     mrg->emoji_data_file = apr_pstrdup(p, base->emoji_data_file);
1827   }
1828   else {
1829     mrg->emoji = add->emoji;
1830     mrg->emoji_tail = add->emoji_tail;
1831     mrg->emoji_data_file = apr_pstrdup(p, add->emoji_data_file);
1832   }
1833
1834   if (add->image == CHXJ_IMG_NONE) {
1835     mrg->image = base->image;
1836   }
1837   else {
1838     mrg->image = add->image;
1839   }
1840
1841   if (strcasecmp(add->image_cache_dir ,DEFAULT_IMAGE_CACHE_DIR)==0) {
1842     mrg->image_cache_dir = apr_pstrdup(p, base->image_cache_dir);
1843   }
1844   else {
1845     mrg->image_cache_dir = apr_pstrdup(p, add->image_cache_dir);
1846   }
1847
1848   if (add->image_cache_limit) {
1849     mrg->image_cache_limit = add->image_cache_limit;
1850   }
1851   else {
1852     mrg->image_cache_limit = base->image_cache_limit;
1853   }
1854
1855   if (add->image_copyright) 
1856     mrg->image_copyright = apr_pstrdup(p, add->image_copyright);
1857   else
1858     mrg->image_copyright = apr_pstrdup(p, base->image_copyright);
1859
1860   if (add->server_side_encoding) {
1861     mrg->server_side_encoding = apr_pstrdup(p, add->server_side_encoding);
1862   }
1863   else 
1864   if (base->server_side_encoding) {
1865     mrg->server_side_encoding = apr_pstrdup(p, base->server_side_encoding);
1866   }
1867   else {
1868     mrg->server_side_encoding = apr_pstrdup(p, DEFAULT_SERVER_SIDE_ENCODING);
1869   }
1870
1871   mrg->convrules    = apr_array_append(p, add->convrules, base->convrules);
1872
1873   if (add->cookie_db_dir) {
1874     mrg->cookie_db_dir = apr_pstrdup(p, add->cookie_db_dir);
1875   }
1876   else
1877   if (base->cookie_db_dir) {
1878     mrg->cookie_db_dir = apr_pstrdup(p, base->cookie_db_dir);
1879   }
1880   else {
1881     mrg->cookie_db_dir = NULL;
1882   }
1883
1884   if (add->cookie_timeout) {
1885     mrg->cookie_timeout   = add->cookie_timeout;
1886   }
1887   else
1888   if (base->cookie_db_dir) {
1889     mrg->cookie_timeout   = base->cookie_timeout;
1890   }
1891   else {
1892     mrg->cookie_timeout   = 0;
1893   }
1894
1895 #if defined(USE_MYSQL_COOKIE)
1896   if (add->mysql.host) {
1897     mrg->mysql.host = apr_pstrdup(p, add->mysql.host);
1898   }
1899   else if (base->mysql.host) {
1900     mrg->mysql.host = apr_pstrdup(p, base->mysql.host);
1901   }
1902   else {
1903     mrg->mysql.host = NULL;
1904   }
1905   if (add->mysql.port) {
1906     mrg->mysql.port = add->mysql.port;
1907   }
1908   else if (base->mysql.port) {
1909     mrg->mysql.port = base->mysql.port;
1910   }
1911   else {
1912     mrg->mysql.port = 0;
1913   }
1914
1915   if (add->mysql.database) {
1916     mrg->mysql.database = apr_pstrdup(p, add->mysql.database);
1917   }
1918   else if (base->mysql.database) {
1919     mrg->mysql.database = apr_pstrdup(p, base->mysql.database);
1920   }
1921   else {
1922     mrg->mysql.database = NULL;
1923   }
1924
1925   if (add->mysql.username) {
1926     mrg->mysql.username = apr_pstrdup(p, add->mysql.username);
1927   }
1928   else if (base->mysql.username) {
1929     mrg->mysql.username = apr_pstrdup(p, base->mysql.username);
1930   }
1931   else {
1932     mrg->mysql.username = NULL;
1933   }
1934
1935   if (add->mysql.password) {
1936     mrg->mysql.password = apr_pstrdup(p, add->mysql.password);
1937   }
1938   else if (base->mysql.password) {
1939     mrg->mysql.password = apr_pstrdup(p, base->mysql.password);
1940   }
1941   else {
1942     mrg->mysql.password = NULL;
1943   }
1944
1945   if (add->mysql.tablename) {
1946     mrg->mysql.tablename = apr_pstrdup(p, add->mysql.tablename);
1947   }
1948   else if (base->mysql.tablename) {
1949     mrg->mysql.tablename = apr_pstrdup(p, base->mysql.tablename);
1950   }
1951   else {
1952     mrg->mysql.tablename = NULL;
1953   }
1954
1955   if (add->mysql.socket_path) {
1956     mrg->mysql.socket_path = apr_pstrdup(p, add->mysql.socket_path);
1957   }
1958   else if (base->mysql.socket_path) {
1959     mrg->mysql.socket_path = apr_pstrdup(p, base->mysql.socket_path);
1960   }
1961   else {
1962     mrg->mysql.socket_path = NULL;
1963   }
1964
1965   if (add->mysql.charset) {
1966     mrg->mysql.charset = apr_pstrdup(p, add->mysql.charset);
1967   }
1968   else if (base->mysql.charset) {
1969     mrg->mysql.charset = apr_pstrdup(p, base->mysql.charset);
1970   }
1971   else {
1972     mrg->mysql.charset = NULL;
1973   }
1974 #endif
1975 #if defined(USE_MEMCACHE_COOKIE)
1976   if (add->memcache.host) {
1977     mrg->memcache.host = apr_pstrdup(p, add->memcache.host);
1978   }
1979   else if (base->memcache.host) {
1980     mrg->memcache.host = apr_pstrdup(p, base->memcache.host);
1981   }
1982   else {
1983     mrg->memcache.host = NULL;
1984   }
1985   if (add->memcache.port) {
1986     mrg->memcache.port = add->memcache.port;
1987   }
1988   else if (base->memcache.port) {
1989     mrg->memcache.port = base->memcache.port;
1990   }
1991   else {
1992     mrg->memcache.port = 0;
1993   }
1994 #endif
1995   if (add->cookie_store_type) {
1996     mrg->cookie_store_type = add->cookie_store_type;
1997   }
1998   else if (base->cookie_store_type) {
1999     mrg->cookie_store_type = base->cookie_store_type;
2000   }
2001   else {
2002     mrg->cookie_store_type = COOKIE_STORE_TYPE_NONE;
2003   }
2004   if (add->cookie_lazy_mode) {
2005     mrg->cookie_lazy_mode = add->cookie_lazy_mode;
2006   }
2007   else if (base->cookie_lazy_mode) {
2008     mrg->cookie_lazy_mode = base->cookie_lazy_mode;
2009   }
2010   else {
2011     mrg->cookie_lazy_mode = 0;
2012   }
2013   if (add->new_line_type) {
2014     mrg->new_line_type = add->new_line_type;
2015   }
2016   else if (base->new_line_type) {
2017     mrg->new_line_type = base->new_line_type;
2018   }
2019   else {
2020     mrg->new_line_type = NLTYPE_NIL;
2021   }
2022
2023   if (add->forward_url_base) {
2024     mrg->forward_url_base = add->forward_url_base;
2025   }
2026   else if (base->forward_url_base) {
2027     mrg->forward_url_base = base->forward_url_base;
2028   }
2029
2030   if (add->allowed_cookie_domain) {
2031     mrg->allowed_cookie_domain = add->allowed_cookie_domain;
2032   }
2033   else {
2034     mrg->allowed_cookie_domain = base->allowed_cookie_domain;
2035   }
2036   if (add->post_log) {
2037     mrg->post_log = add->post_log;
2038   }
2039   else {
2040     mrg->post_log = base->post_log;
2041   }
2042   if (add->cookie_dbm_type) {
2043     mrg->cookie_dbm_type = add->cookie_dbm_type;
2044   }
2045   else {
2046     mrg->cookie_dbm_type = base->cookie_dbm_type;
2047   }
2048   
2049   if (add->imode_emoji_color == CHXJ_IMODE_EMOJI_COLOR_NONE) {
2050     mrg->imode_emoji_color = base->imode_emoji_color;
2051   }
2052   else {
2053     mrg->imode_emoji_color = add->imode_emoji_color;
2054   }
2055   
2056   return mrg;
2057 }
2058
2059
2060 static int
2061 chxj_command_parse_take5(
2062   const char *arg, 
2063   char       **prm1, 
2064   char       **prm2, 
2065   char       **prm3, 
2066   char       **prm4, 
2067   char       **prm5)
2068 {
2069   int  isquoted;
2070   char *strp;
2071
2072   strp = (char *)arg;
2073
2074   for (;*strp == ' '||*strp == '\t'; strp++) ;
2075
2076   isquoted = 0; 
2077   if (*strp == '"') { 
2078     isquoted = 1;
2079     strp++;
2080   }
2081
2082   *prm1 = strp;
2083
2084   for (; *strp != '\0'; strp++) {
2085     if ((isquoted && (*strp == ' ' || *strp == '\t'))
2086     ||  (*strp == '\\' && (*(strp+1) == ' ' || *(strp+1) == '\t'))) {
2087       strp++;
2088       continue;
2089     }
2090
2091     if ((!isquoted && (*strp == ' ' || *strp == '\t'))
2092     ||  (isquoted  && *strp == '"'))
2093       break;
2094   }
2095
2096   if (! *strp) {
2097     *prm2 = strp;
2098     *prm3 = strp;
2099     *prm4 = strp;
2100     *prm5 = strp;
2101     return 1;
2102   }
2103
2104   *strp++ = '\0';
2105
2106   for (;*strp == ' '||*strp == '\t'; strp++) ;
2107
2108   isquoted = 0; 
2109   if (*strp == '"') { 
2110     isquoted = 1;
2111     strp++;
2112   }
2113
2114   *prm2 = strp;
2115   for (; *strp != '\0'; strp++) {
2116     if ((isquoted && (*strp == ' ' || *strp == '\t'))
2117     ||  (*strp == '\\' && (*(strp+1) == ' ' || *(strp+1) == '\t'))) {
2118       strp++;
2119       continue;
2120     }
2121
2122     if ((!isquoted && (*strp == ' ' || *strp == '\t'))
2123     ||  (isquoted  && *strp == '"'))
2124       break;
2125   }
2126
2127   if (! *strp) {
2128     *prm3 = strp;
2129     *prm4 = strp;
2130     *prm5 = strp;
2131     return 0;
2132   }
2133
2134   *strp++ = '\0';
2135
2136   for (;*strp == ' '||*strp == '\t'; strp++);
2137
2138   isquoted = 0; 
2139   if (*strp == '"') { 
2140     isquoted = 1;
2141     strp++;
2142   }
2143   *prm3 = strp;
2144   for (; *strp != '\0'; strp++) {
2145     if ((isquoted && (*strp == ' ' || *strp == '\t'))
2146     ||  (*strp == '\\' && (*(strp+1) == ' ' || *(strp+1) == '\t'))) {
2147       strp++;
2148       continue;
2149     }
2150
2151     if ((!isquoted && (*strp == ' ' || *strp == '\t'))
2152     ||  (isquoted  && *strp == '"'))
2153       break;
2154   }
2155
2156   if (! *strp) {
2157     *prm4 = strp;
2158     *prm5 = strp;
2159     return 0;
2160   }
2161
2162   *strp++ = '\0';
2163
2164   for (;*strp == ' '||*strp == '\t'; strp++);
2165
2166   isquoted = 0; 
2167   if (*strp == '"') { 
2168     isquoted = 1;
2169     strp++;
2170   }
2171   *prm4 = strp;
2172   for (; *strp != '\0'; strp++) {
2173     if ((isquoted && (*strp == ' ' || *strp == '\t'))
2174     ||  (*strp == '\\' && (*(strp+1) == ' ' || *(strp+1) == '\t'))) {
2175       strp++;
2176       continue;
2177     }
2178
2179     if ((!isquoted && (*strp == ' ' || *strp == '\t'))
2180     ||  (isquoted  && *strp == '"'))
2181       break;
2182   }
2183
2184   if (! *strp) {
2185     *prm5 = strp;
2186     return 0;
2187   }
2188
2189   *strp++ = '\0';
2190
2191   for (;*strp == ' '||*strp == '\t'; strp++);
2192
2193   isquoted = 0; 
2194   if (*strp == '"') { 
2195     isquoted = 1;
2196     strp++;
2197   }
2198   *prm5 = strp;
2199   for (; *strp != '\0'; strp++) {
2200     if ((isquoted && (*strp == ' ' || *strp == '\t'))
2201     ||  (*strp == '\\' && (*(strp+1) == ' ' || *(strp+1) == '\t'))) {
2202       strp++;
2203       continue;
2204     }
2205
2206     if ((!isquoted && (*strp == ' ' || *strp == '\t'))
2207     ||  (isquoted  && *strp == '"'))
2208       break;
2209   }
2210   *strp = '\0';
2211
2212   return 0;
2213 }
2214
2215
2216 /**
2217  * The device definition file is loaded. 
2218  *
2219  * @param arg     [i]   The name of the device definition file is specified.
2220  * @param mconfig [i/o] The pointer to a set structure is specified. 
2221  * @param parms   [i]   
2222  */
2223 static const char * 
2224 cmd_load_device_data(cmd_parms *parms, void *mconfig, const char *arg) 
2225 {
2226   mod_chxj_config  *conf;
2227   Doc              doc;
2228
2229   doc.r = NULL;
2230
2231   if (strlen(arg) > 256) 
2232     return "mod_chxj: device data filename too long.";
2233
2234   conf = (mod_chxj_config *)mconfig;
2235   conf->device_data_file = apr_pstrdup(parms->pool, arg);
2236
2237   qs_init_malloc(&doc);
2238   qs_init_root_node(&doc);
2239
2240   qs_parse_file((Doc *)&doc, (const char *)arg);
2241   chxj_load_device_data(&doc,parms->pool, conf);
2242   qs_all_free(&doc, QX_LOGMARK);
2243
2244   return NULL;
2245 }
2246
2247
2248 /**
2249  * Device definition information is loaded. 
2250  *
2251  * @param parms 
2252  * @param arg     [i]   The name of the device definition file is specified. 
2253  * @param mconfig [i/o] The pointer to a set structure is specified. 
2254  * @return 
2255  */
2256 static const char * 
2257 cmd_load_emoji_data(cmd_parms *parms, void *mconfig, const char *arg) 
2258 {
2259   mod_chxj_config *conf;
2260   char            *rtn;
2261   Doc              doc;
2262
2263   doc.r = NULL;
2264
2265
2266   if (strlen(arg) > 256) 
2267     return "mod_chxj: emoji data filename too long.";
2268
2269   conf = (mod_chxj_config *)mconfig;
2270   conf->emoji_data_file = apr_pstrdup(parms->pool, arg);
2271   qs_init_malloc(&doc);
2272   qs_init_root_node(&doc);
2273
2274   qs_parse_file((Doc *)&doc, (const char *)arg);
2275
2276   rtn = chxj_load_emoji_data(&doc,parms->pool, conf);
2277
2278   qs_all_free(&doc, QX_LOGMARK);
2279
2280
2281   return rtn;
2282 }
2283
2284
2285 static const char * 
2286 cmd_set_image_engine(cmd_parms * UNUSED(parms), void *mconfig, const char *arg) 
2287 {
2288   mod_chxj_config *conf;
2289   Doc              doc;
2290
2291   doc.r = NULL;
2292
2293   if (strlen(arg) > 256) 
2294     return "image uri is too long.";
2295
2296   conf = (mod_chxj_config*)mconfig;
2297   if (strcasecmp("ON", arg) == 0) {
2298     conf->image = CHXJ_IMG_ON;
2299   }
2300   else {
2301     conf->image = CHXJ_IMG_OFF;
2302   }
2303
2304   return NULL;
2305 }
2306
2307
2308 static const char * 
2309 cmd_set_image_cache_dir(cmd_parms *parms, void *mconfig, const char *arg) 
2310 {
2311   mod_chxj_config *conf;
2312   Doc              doc;
2313
2314   doc.r = NULL;
2315
2316   if (strlen(arg) > 256) 
2317     return "cache dir name is too long.";
2318
2319   conf = (mod_chxj_config *)mconfig;
2320   conf->image_cache_dir = apr_pstrdup(parms->pool, arg);
2321
2322   return NULL;
2323 }
2324
2325
2326 static const char * 
2327 cmd_set_image_cache_limit(cmd_parms *parms, void *mconfig, const char *arg) 
2328 {
2329   mod_chxj_config *conf;
2330   Doc              doc;
2331
2332   doc.r = NULL;
2333
2334   if (strlen(arg) > IMAGE_CACHE_LIMIT_FMT_LEN) 
2335     return "cache size is too long.";
2336
2337   conf = (mod_chxj_config *)mconfig;
2338   errno = 0;
2339   /* 
2340    * I use strtol function because strtoul is not portable function. 
2341    */
2342   conf->image_cache_limit = (unsigned long)strtol(arg, NULL, 10);
2343   switch (errno) {
2344   case EINVAL:
2345     return apr_psprintf(parms->pool, "ChxjImageCacheLimit invalid value [%s] errno:[%d]", arg, errno);
2346   case ERANGE:
2347     return apr_psprintf(parms->pool, "ChxjImageCacheLimit Out of range [%s] errno:[%d]", arg, errno);
2348   default:
2349     break;
2350   }
2351   return NULL;
2352 }
2353
2354
2355 static const char * 
2356 cmd_set_image_copyright(cmd_parms *parms, void *mconfig, const char *arg) 
2357 {
2358   mod_chxj_config *conf;
2359   Doc              doc;
2360
2361   doc.r = NULL;
2362
2363   if (strlen(arg) > 256) 
2364     return "Copyright Flag is too long.";
2365
2366   conf = (mod_chxj_config *)mconfig;
2367   conf->image_copyright = apr_pstrdup(parms->pool, arg);
2368
2369   return NULL;
2370 }
2371
2372
2373 static const char *
2374 cmd_convert_rule(cmd_parms *cmd, void *mconfig, const char *arg)
2375 {
2376   int                 mode;
2377   ap_regex_t          *regexp;
2378   mod_chxj_config     *dconf;
2379   chxjconvrule_entry  *newrule;
2380   char                *prm1;
2381   char                *prm2;
2382   char                *prm3;
2383   char                *prm4;
2384   char                *prm5;
2385   char                *pstate;
2386   char                *action;
2387   char                *pp;
2388
2389   dconf = (mod_chxj_config *)mconfig;
2390
2391   if (strlen(arg) > 4096) 
2392     return "mod_chxj: ChxjConvertRule: is too long.";
2393
2394   dconf = (mod_chxj_config *)mconfig;
2395   if (dconf->convrules == NULL)
2396     dconf->convrules   = apr_array_make(cmd->pool, 
2397                                         2, 
2398                                         sizeof(chxjconvrule_entry));
2399
2400   newrule = apr_array_push(dconf->convrules);
2401
2402   newrule->flags  = 0;
2403   newrule->action = 0;
2404
2405   if (chxj_command_parse_take5(arg, &prm1, &prm2, &prm3, &prm4, &prm5))
2406     return "ChxjConvertRule: bad argument line";
2407
2408   newrule->pattern = apr_pstrdup(cmd->pool, prm1);
2409
2410   /* Parse action */
2411   for (;;) {
2412     if ((action = apr_strtok(prm2, ",", &pstate)) == NULL)
2413       break;
2414     prm2 = NULL;
2415     switch(*action) {
2416     case 'e':
2417     case 'E':
2418       if (strcasecmp(CONVRULE_ENGINE_ON_CMD, action) == 0) {
2419         newrule->action |= CONVRULE_ENGINE_ON_BIT;
2420       }
2421       else
2422       if (strcasecmp(CONVRULE_ENGINE_OFF_CMD, action) == 0) {
2423         newrule->action |= CONVRULE_ENGINE_OFF_BIT;
2424       }
2425       else
2426       if (strcasecmp(CONVRULE_EMOJI_ONLY_CMD, action) == 0) {
2427         newrule->action |= CONVRULE_EMOJI_ONLY_BIT;
2428       }
2429       else
2430       if (strcasecmp(CONVRULE_ENVINFO_ONLY_CMD, action) == 0) {
2431         newrule->action |= CONVRULE_ENVINFO_ONLY_BIT;
2432       }
2433       break;
2434
2435     case 'C':
2436     case 'c':
2437       if (strcasecmp(CONVRULE_COOKIE_ON_CMD, action) == 0) {
2438         newrule->action |= CONVRULE_COOKIE_ON_BIT;
2439       }
2440       else if (strcasecmp(CONVRULE_COOKIE_OFF_CMD, action) == 0) {
2441         newrule->action &= (0xffffffff ^ CONVRULE_COOKIE_ON_BIT);
2442       }
2443       else if (strcasecmp(CONVRULE_CSS_ON_CMD, action) == 0) {
2444         newrule->action |= CONVRULE_CSS_ON_BIT;
2445       }
2446       else if (strcasecmp(CONVRULE_CSS_OFF_CMD, action) == 0) {
2447         newrule->action &= (0xffffffff ^ CONVRULE_CSS_ON_BIT);
2448       }
2449       else if (strcasecmp(CONVRULE_COOKIE_ONLY_CMD, action) == 0) {
2450         newrule->action |= CONVRULE_COOKIE_ONLY_BIT;
2451       }
2452       break;
2453
2454     case 'J':
2455     case 'j':
2456       if (strcasecmp(CONVRULE_JRCONV_OFF_CMD, action) == 0) {
2457         newrule->action |= CONVRULE_JRCONV_OFF_BIT;
2458       }
2459       break;
2460
2461     case 'N':
2462     case 'n':
2463       if (strcasecmp(CONVRULE_NOCACHE_ON_CMD, action) == 0) {
2464         newrule->action |= CONVRULE_NOCACHE_ON_BIT;
2465       }
2466       break;
2467
2468     case 'Q':
2469     case 'q':
2470       if (strcasecmp(CONVRULE_QSCONV_OFF_CMD, action) == 0) {
2471         newrule->action |= CONVRULE_QSCONV_OFF_BIT;
2472       }
2473       break;
2474
2475     case 'Z':
2476     case 'z':
2477       if (strcasecmp(CONVRULE_Z2H_ON_CMD, action) == 0) {
2478         newrule->action |= CONVRULE_Z2H_ON_BIT;
2479       }
2480       else
2481       if (strcasecmp(CONVRULE_Z2H_OFF_CMD, action) == 0) {
2482         newrule->action |= CONVRULE_Z2H_OFF_BIT;
2483       }
2484       else
2485       if (strcasecmp(CONVRULE_Z2H_ALPHA_ON_CMD, action) == 0) {
2486         newrule->action |= CONVRULE_Z2H_ALPHA_ON_BIT;
2487       }
2488       else
2489       if (strcasecmp(CONVRULE_Z2H_ALPHA_OFF_CMD, action) == 0) {
2490         newrule->action |= CONVRULE_Z2H_ALPHA_OFF_BIT;
2491       }
2492       else
2493       if (strcasecmp(CONVRULE_Z2H_NUM_ON_CMD, action) == 0) {
2494         newrule->action |= CONVRULE_Z2H_NUM_ON_BIT;
2495       }
2496       else
2497       if (strcasecmp(CONVRULE_Z2H_NUM_OFF_CMD, action) == 0) {
2498         newrule->action |= CONVRULE_Z2H_NUM_OFF_BIT;
2499       }
2500       else
2501       if (strcasecmp(CONVRULE_Z2H_ALL_ON_CMD, action) == 0) {
2502         newrule->action |= CONVRULE_Z2H_ON_BIT | CONVRULE_Z2H_ALPHA_ON_BIT | CONVRULE_Z2H_NUM_ON_BIT;
2503       }
2504       else
2505       if (strcasecmp(CONVRULE_Z2H_NUM_OFF_CMD, action) == 0) {
2506         newrule->action |= CONVRULE_Z2H_OFF_BIT | CONVRULE_Z2H_ALPHA_OFF_BIT | CONVRULE_Z2H_NUM_OFF_BIT;
2507       }
2508       break;
2509
2510     default:
2511       break;
2512     }
2513   }
2514   
2515   pp = prm1;
2516   if (*pp == '!') {
2517     newrule->flags |= CONVRULE_FLAG_NOTMATCH;
2518     pp++;
2519   }
2520
2521   mode = AP_REG_EXTENDED;
2522   if ((regexp = ap_pregcomp((apr_pool_t *)cmd->pool, (const char *)pp, mode)) == NULL)
2523     return "RewriteRule: cannot compile regular expression ";
2524
2525   newrule->regexp = regexp;
2526   if (*prm3)
2527     newrule->encoding = apr_pstrdup(cmd->pool, prm3);
2528   else
2529     newrule->encoding = apr_pstrdup(cmd->pool, "none");
2530
2531   newrule->pc_flag = CONVRULE_PC_FLAG_OFF_BIT;
2532   if (*prm4)
2533     if (strcasecmp(CONVRULE_PC_FLAG_ON_CMD, prm4) == 0)
2534       newrule->pc_flag = CONVRULE_PC_FLAG_ON_BIT;
2535
2536   newrule->user_agent = NULL;
2537   if (*prm5)
2538     newrule->user_agent = apr_pstrdup(cmd->pool, prm5);
2539     
2540   return NULL;
2541 }
2542
2543
2544 static const char *
2545 cmd_set_cookie_dir(
2546   cmd_parms   *cmd, 
2547   void        *mconfig, 
2548   const char  *arg)
2549 {
2550   mod_chxj_config *dconf;
2551
2552
2553   if (strlen(arg) > 4096) 
2554     return "mod_chxj: ChxjCookieDir is too long.";
2555
2556   dconf = (mod_chxj_config *)mconfig;
2557
2558   dconf->cookie_db_dir = apr_pstrdup(cmd->pool, arg);
2559
2560   return NULL;
2561 }
2562
2563
2564 static const char *
2565 cmd_set_cookie_timeout(
2566   cmd_parms   *UNUSED(cmd), 
2567   void        *mconfig, 
2568   const char  *arg)
2569 {
2570   mod_chxj_config *dconf;
2571
2572   if (strlen(arg) > 4096) 
2573     return "mod_chxj: ChxjCookieTimeout is too long.";
2574
2575   if (chxj_chk_numeric(arg) != 0)
2576     return "mod_chxj: ChxjCookieTimeout is not numeric.";
2577
2578   dconf = (mod_chxj_config *)mconfig;
2579
2580   dconf->cookie_timeout = atoi(arg);
2581
2582   return NULL;
2583 }
2584
2585
2586 #if defined(USE_MYSQL_COOKIE)
2587 static const char *
2588 cmd_set_cookie_mysql_database(
2589   cmd_parms   *cmd, 
2590   void        *mconfig, 
2591   const char  *arg)
2592 {
2593   mod_chxj_config  *dconf;
2594
2595   if (strlen(arg) > 255) 
2596     return "mod_chxj: ChxjCookieMysqlDatabase is too long.";
2597
2598   dconf = (mod_chxj_config *)mconfig;
2599
2600   dconf->mysql.database = apr_pstrdup(cmd->pool, arg);
2601
2602   return NULL;
2603 }
2604
2605
2606 static const char *
2607 cmd_set_cookie_mysql_username(
2608   cmd_parms   *cmd, 
2609   void        *mconfig, 
2610   const char  *arg)
2611 {
2612   mod_chxj_config  *dconf;
2613
2614   if (strlen(arg) > 255) 
2615     return "mod_chxj: ChxjCookieMysqlUsername is too long.";
2616
2617   dconf = (mod_chxj_config *)mconfig;
2618
2619   dconf->mysql.username = apr_pstrdup(cmd->pool, arg);
2620
2621   return NULL;
2622 }
2623
2624
2625 static const char *
2626 cmd_set_cookie_mysql_password(
2627   cmd_parms   *cmd, 
2628   void        *mconfig, 
2629   const char  *arg)
2630 {
2631   mod_chxj_config  *dconf;
2632
2633   if (strlen(arg) > 255) 
2634     return "mod_chxj: ChxjCookieMysqlPassword is too long.";
2635
2636   dconf = (mod_chxj_config *)mconfig;
2637
2638   dconf->mysql.password = apr_pstrdup(cmd->pool, arg);
2639
2640   return NULL;
2641 }
2642
2643
2644 static const char *
2645 cmd_set_cookie_mysql_table_name(
2646   cmd_parms   *cmd, 
2647   void        *mconfig, 
2648   const char  *arg)
2649 {
2650   mod_chxj_config  *dconf;
2651
2652   if (strlen(arg) > 255) 
2653     return "mod_chxj: ChxjCookieMysqlTableName is too long.";
2654
2655   dconf = (mod_chxj_config *)mconfig;
2656
2657   dconf->mysql.tablename = apr_pstrdup(cmd->pool, arg);
2658
2659   return NULL;
2660 }
2661
2662 static const char *
2663 cmd_set_cookie_mysql_port(
2664   cmd_parms   *UNUSED(cmd), 
2665   void        *mconfig, 
2666   const char  *arg)
2667 {
2668   mod_chxj_config *dconf;
2669
2670   if (strlen(arg) > 255) 
2671     return "mod_chxj: ChxjCookieMysqlPort is too long.";
2672
2673   dconf = (mod_chxj_config *)mconfig;
2674
2675   if (chxj_chk_numeric(arg) != 0)
2676     return "mod_chxj: ChxjCookieMysqlPort is not numeric.";
2677
2678   dconf = (mod_chxj_config *)mconfig;
2679
2680   dconf->mysql.port = chxj_atoi(arg);
2681
2682   return NULL;
2683 }
2684
2685
2686 static const char *
2687 cmd_set_cookie_mysql_host(
2688   cmd_parms   *cmd, 
2689   void        *mconfig, 
2690   const char  *arg)
2691 {
2692   mod_chxj_config  *dconf;
2693
2694   if (strlen(arg) > 255) 
2695     return "mod_chxj: ChxjCookieMysqlHost is too long.";
2696
2697   dconf = (mod_chxj_config *)mconfig;
2698
2699   dconf->mysql.host = apr_pstrdup(cmd->pool, arg);
2700
2701   return NULL;
2702 }
2703
2704
2705 static const char *
2706 cmd_set_cookie_mysql_socket_path(
2707   cmd_parms   *cmd, 
2708   void        *mconfig, 
2709   const char  *arg)
2710 {
2711   mod_chxj_config  *dconf;
2712
2713   if (strlen(arg) > 4096) 
2714     return "mod_chxj: ChxjCookieMysqlSocketPath is too long.";
2715
2716   dconf = (mod_chxj_config *)mconfig;
2717
2718   dconf->mysql.socket_path = apr_pstrdup(cmd->pool, arg);
2719
2720   return NULL;
2721 }
2722
2723
2724 static const char *
2725 cmd_set_cookie_mysql_charset(
2726   cmd_parms   *cmd, 
2727   void        *mconfig, 
2728   const char  *arg)
2729 {
2730   mod_chxj_config  *dconf;
2731
2732   if (strlen(arg) > 255) 
2733     return "mod_chxj: ChxjCookieMysqlCharset is too long.";
2734
2735   dconf = (mod_chxj_config *)mconfig;
2736
2737   dconf->mysql.charset = apr_pstrdup(cmd->pool, arg);
2738
2739   return NULL;
2740 }
2741 #endif
2742 #if defined(USE_MEMCACHE_COOKIE)
2743 static const char *
2744 cmd_set_cookie_memcache_port(
2745   cmd_parms   *UNUSED(cmd), 
2746   void        *mconfig, 
2747   const char  *arg)
2748 {
2749   mod_chxj_config *dconf;
2750
2751   if (strlen(arg) > 255) 
2752     return "mod_chxj: ChxjCookieMemcachePort is too long.";
2753
2754   dconf = (mod_chxj_config *)mconfig;
2755
2756   if (chxj_chk_numeric(arg) != 0)
2757     return "mod_chxj: ChxjCookieMemcachePort is not numeric.";
2758
2759   dconf = (mod_chxj_config *)mconfig;
2760
2761   dconf->memcache.port = (apr_port_t)chxj_atoi(arg);
2762
2763   return NULL;
2764 }
2765
2766
2767 static const char *
2768 cmd_set_cookie_memcache_host(
2769   cmd_parms   *cmd, 
2770   void        *mconfig, 
2771   const char  *arg)
2772 {
2773   mod_chxj_config  *dconf;
2774
2775   if (strlen(arg) > 255) 
2776     return "mod_chxj: ChxjCookieMemcacheHost is too long.";
2777
2778   dconf = (mod_chxj_config *)mconfig;
2779
2780   dconf->memcache.host = apr_pstrdup(cmd->pool, arg);
2781
2782   return NULL;
2783 }
2784 #endif
2785
2786 static const char *
2787 cmd_set_cookie_lazy_mode(
2788   cmd_parms   *UNUSED(cmd), 
2789   void        *mconfig, 
2790   const char  *arg)
2791 {
2792   mod_chxj_config  *dconf;
2793
2794   if (strlen(arg) > 255) 
2795     return "mod_chxj: ChxjCookieLazyMode is too long.";
2796
2797   dconf = (mod_chxj_config *)mconfig;
2798
2799   if (strcasecmp("TRUE",arg) == 0) {
2800     dconf->cookie_lazy_mode = COOKIE_LAZY_ON;
2801   }
2802   else {
2803     dconf->cookie_lazy_mode = COOKIE_LAZY_OFF;
2804   }
2805
2806   return NULL;
2807 }
2808
2809 static const char *
2810 cmd_set_cookie_store_type(
2811   cmd_parms   *UNUSED(cmd), 
2812   void        *mconfig, 
2813   const char  *arg)
2814 {
2815   mod_chxj_config  *dconf;
2816
2817   if (strlen(arg) > 255) 
2818     return "mod_chxj: ChxjCookieStoreType is too long.";
2819
2820   dconf = (mod_chxj_config *)mconfig;
2821
2822   if (strcasecmp(CHXJ_COOKIE_STORE_TYPE_DBM, arg) == 0) {
2823     dconf->cookie_store_type = COOKIE_STORE_TYPE_DBM;
2824   }
2825   else if (strcasecmp(CHXJ_COOKIE_STORE_TYPE_MYSQL, arg) == 0) {
2826     dconf->cookie_store_type = COOKIE_STORE_TYPE_MYSQL;
2827   }
2828   else if (strcasecmp(CHXJ_COOKIE_STORE_TYPE_MEMCACHE, arg) == 0) {
2829     dconf->cookie_store_type = COOKIE_STORE_TYPE_MEMCACHE;
2830   }
2831   else {
2832     dconf->cookie_store_type = COOKIE_STORE_TYPE_NONE;
2833   }
2834
2835   return NULL;
2836 }
2837
2838 static const char *
2839 cmd_set_forward_url_base(
2840   cmd_parms   *cmd,
2841   void        *mconfig,
2842   const char  *arg)
2843 {
2844  mod_chxj_config *dconf;
2845
2846   if (strlen(arg) > 255)
2847     return "mod_chxj: ChxjForwardUrlBase is too long.";
2848
2849   dconf = (mod_chxj_config *)mconfig;
2850
2851   dconf->forward_url_base = apr_pstrdup(cmd->pool, arg);
2852
2853   return NULL;
2854 }
2855
2856 static const char *
2857 cmd_set_forward_server_ip(
2858   cmd_parms   *cmd,
2859   void        *mconfig,
2860   const char  *arg)
2861 {
2862   mod_chxj_config *dconf;
2863
2864   if (strlen(arg) > 255)
2865     return "mod_chxj: ChxjForwardServerIp is too long.";
2866
2867   dconf = (mod_chxj_config *)mconfig;
2868
2869   dconf->forward_server_ip = apr_pstrdup(cmd->pool, arg);
2870
2871   return NULL;
2872 }
2873
2874 static const char *
2875 cmd_allowed_cookie_domain(
2876   cmd_parms   *cmd,
2877   void        *mconfig,
2878   const char  *arg)
2879 {
2880   mod_chxj_config *dconf;
2881
2882   if (strlen(arg) > 255)
2883     return "mod_chxj: ChxjAllowedCookieDomain is too long.";
2884
2885   dconf = (mod_chxj_config *)mconfig;
2886
2887   dconf->allowed_cookie_domain = apr_pstrdup(cmd->pool, arg);
2888
2889   return NULL;
2890 }
2891
2892 static const char *
2893 cmd_set_new_line_type(
2894   cmd_parms   *UNUSED(cmd), 
2895   void        *mconfig, 
2896   const char  *arg)
2897 {
2898   mod_chxj_config  *dconf;
2899   if (strlen(arg) > 255)
2900     return "mod_chxj: ChxjNewLineType is too long.";
2901
2902   dconf = (mod_chxj_config *)mconfig;
2903
2904   if (strcasecmp(CHXJ_NEW_LINE_TYPE_CRLF, arg) == 0) {
2905     dconf->new_line_type = NLTYPE_CRLF;
2906   }
2907   else if (strcasecmp(CHXJ_NEW_LINE_TYPE_LF, arg) == 0) {
2908     dconf->new_line_type = NLTYPE_LF;
2909   }
2910   else if (strcasecmp(CHXJ_NEW_LINE_TYPE_CR, arg) == 0) {
2911     dconf->new_line_type = NLTYPE_CR;
2912   }
2913   else if (strcasecmp(CHXJ_NEW_LINE_TYPE_NONE, arg) == 0) {
2914     dconf->new_line_type = NLTYPE_NONE;
2915   }
2916   else {
2917     return "mod_chxj: invalid value (ChxjNewLineType)";
2918   }
2919   return NULL;
2920 }
2921
2922 static const char *
2923 cmd_post_log_env(
2924   cmd_parms   *cmd, 
2925   void        *mconfig, 
2926   const char  *arg)
2927 {
2928   mod_chxj_config  *dconf;
2929   if (strlen(arg) > 255)
2930     return "mod_chxj: ChxjPostLogEnv is too long.";
2931
2932   dconf = (mod_chxj_config *)mconfig;
2933
2934   dconf->post_log = apr_pstrdup(cmd->pool, arg);
2935
2936   return NULL;
2937 }
2938
2939 static const char *
2940 cmd_cookie_dbm_type(
2941   cmd_parms   *cmd, 
2942   void        *mconfig, 
2943   const char  *arg)
2944 {
2945   mod_chxj_config  *dconf;
2946   if (strlen(arg) > 255)
2947     return "mod_chxj: ChxjCookieDbmType is too long.";
2948
2949   dconf = (mod_chxj_config *)mconfig;
2950
2951   dconf->cookie_dbm_type = apr_pstrdup(cmd->pool, arg);
2952
2953   return NULL;
2954 }
2955
2956 static const char *
2957 cmd_imode_emoji_color(
2958   cmd_parms   *cmd, 
2959   void        *mconfig, 
2960   const char  *arg)
2961 {
2962   mod_chxj_config  *dconf;
2963   
2964   if (strlen(arg) > 256) 
2965     return "imode emoji color is too long.";
2966
2967   dconf = (mod_chxj_config *)mconfig;
2968   if (strcasecmp("ON", arg) == 0) {
2969     dconf->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_ON;
2970   }
2971   else if(strcasecmp("AUTO",arg) == 0) {
2972     dconf->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_AUTO;
2973   }
2974   else {
2975     dconf->imode_emoji_color = CHXJ_IMODE_EMOJI_COLOR_OFF;
2976   }
2977   
2978   return NULL;
2979 }
2980
2981
2982 static const command_rec cmds[] = {
2983   AP_INIT_TAKE1(
2984     "ChxjLoadDeviceData",
2985     cmd_load_device_data,
2986     NULL,
2987     OR_ALL,
2988     "Load Device Data"),
2989   AP_INIT_TAKE1(
2990     "ChxjLoadEmojiData",
2991     cmd_load_emoji_data,
2992     NULL,
2993     OR_ALL,
2994     "Load Emoji Data"),
2995   AP_INIT_TAKE1(
2996     "ChxjImageEngine",
2997     cmd_set_image_engine,
2998     NULL,
2999     OR_ALL,
3000     "Convert Target URI"),
3001   AP_INIT_TAKE1(
3002     "ChxjImageCacheDir",
3003     cmd_set_image_cache_dir,
3004     NULL,
3005     OR_ALL,
3006     "Image Cache Directory"),
3007   AP_INIT_TAKE1(
3008     "ChxjImageCacheLimit",
3009     cmd_set_image_cache_limit,
3010     NULL,
3011     OR_ALL,
3012     "Image Cache Limit"),
3013   AP_INIT_TAKE1(
3014     "ChxjImageCopyright",
3015     cmd_set_image_copyright,
3016     NULL,
3017     OR_ALL,
3018     "Copyright Flag"),
3019   AP_INIT_RAW_ARGS(
3020     "ChxjConvertRule",
3021     cmd_convert_rule,
3022     NULL, 
3023     OR_FILEINFO,
3024     "an URL-applied regexp-pattern and a substitution URL"),
3025   AP_INIT_TAKE1(
3026     "ChxjCookieDir",
3027     cmd_set_cookie_dir,
3028     NULL,
3029     OR_ALL,
3030     "save cookie.db directory."),
3031   AP_INIT_TAKE1(
3032     "ChxjCookieTimeout",
3033     cmd_set_cookie_timeout,
3034     NULL,
3035     OR_ALL,
3036     "The compulsion time-out time of the cookie is specified. "),
3037   AP_INIT_TAKE1(
3038     "ChxjCookieStoreType",
3039     cmd_set_cookie_store_type,
3040     NULL,
3041     OR_ALL,
3042     "It specifies preserving of the cookie ahead. (DBM/MYSQL/MEMCACHE)"),
3043   AP_INIT_TAKE1(
3044     "ChxjCookieLazyMode",
3045     cmd_set_cookie_lazy_mode,
3046     NULL,
3047     OR_ALL,
3048     "OneTimeID is negligently done. (TRUE/FALSE)"),
3049 #if defined(USE_MYSQL_COOKIE)
3050   AP_INIT_TAKE1(
3051     "ChxjCookieMysqlHost",
3052     cmd_set_cookie_mysql_host,
3053     NULL,
3054     OR_ALL,
3055     "The MySQL database host used by saving Cookie"),
3056   AP_INIT_TAKE1(
3057     "ChxjCookieMysqlPort",
3058     cmd_set_cookie_mysql_port,
3059     NULL,
3060     OR_ALL,
3061     "The MySQL database port used by saving Cookie"),
3062   AP_INIT_TAKE1(
3063     "ChxjCookieMysqlDatabase",
3064     cmd_set_cookie_mysql_database,
3065     NULL,
3066     OR_ALL,
3067     "The MySQL database name used by saving Cookie"),
3068   AP_INIT_TAKE1(
3069     "ChxjCookieMysqlUsername",
3070     cmd_set_cookie_mysql_username,
3071     NULL,
3072     OR_ALL,
3073     "The MySQL username used by saving Cookie"),
3074   AP_INIT_TAKE1(
3075     "ChxjCookieMysqlPassword",
3076     cmd_set_cookie_mysql_password,
3077     NULL,
3078     OR_ALL,
3079     "The MySQL password used by saving Cookie"),
3080   AP_INIT_TAKE1(
3081     "ChxjCookieMysqlTableName",
3082     cmd_set_cookie_mysql_table_name,
3083     NULL,
3084     OR_ALL,
3085     "The MySQL table name used by saving Cookie"),
3086   AP_INIT_TAKE1(
3087     "ChxjCookieMysqlSocketPath",
3088     cmd_set_cookie_mysql_socket_path,
3089     NULL,
3090     OR_ALL,
3091     "The MySQL socket path used by saving Cookie"),
3092   AP_INIT_TAKE1(
3093     "ChxjCookieMysqlCharset",
3094     cmd_set_cookie_mysql_charset,
3095     NULL,
3096     OR_ALL,
3097     "The MySQL charset used by saving Cookie"),
3098 #endif
3099 #if defined(USE_MEMCACHE_COOKIE)
3100   AP_INIT_TAKE1(
3101     "ChxjCookieMemcacheHost",
3102     cmd_set_cookie_memcache_host,
3103     NULL,
3104     OR_ALL,
3105     "The Memcached host used by saving Cookie"),
3106   AP_INIT_TAKE1(
3107     "ChxjCookieMemcachePort",
3108     cmd_set_cookie_memcache_port,
3109     NULL,
3110     OR_ALL,
3111     "The Memcached port used by saving Cookie"),
3112 #endif
3113   AP_INIT_TAKE1(
3114     "ChxjNewLineType",
3115     cmd_set_new_line_type,
3116     NULL,
3117     OR_ALL,
3118     "HTML new line type (NONE|CRLF|LF|CR). default is CRLF"),
3119   AP_INIT_TAKE1(
3120     "ChxjForwardUrlBase",
3121     cmd_set_forward_url_base,
3122     NULL,
3123     OR_ALL,
3124     "The forward url base(default: {request protocol}://{this server}:{this server port}"),
3125   AP_INIT_TAKE1(
3126     "ChxjForwardServerIp",
3127     cmd_set_forward_server_ip,
3128     NULL,
3129     OR_ALL,
3130     "The forward server ip(default: this server ip)"),
3131   AP_INIT_TAKE1(
3132     "ChxjAllowedCookieDomain",
3133     cmd_allowed_cookie_domain,
3134     NULL,
3135     OR_ALL,
3136     "Domain that permits parameter addition for cookie besides hostname.(Default:hostname Only)"),
3137   AP_INIT_TAKE1(
3138     "ChxjPostLogEnv",
3139     cmd_post_log_env,
3140     NULL,
3141     OR_ALL,
3142     "for CustomLog directive. mod_chxj's internal POST log environment name.(Default:chxj-post-log)"),
3143   AP_INIT_TAKE1(
3144     "ChxjCookieDbmType",
3145     cmd_cookie_dbm_type,
3146     NULL,
3147     OR_ALL,
3148     "Kind of DBM used with Cookie simulator.(default|GDBM|SDBM|DB|NDBM)"),
3149   AP_INIT_TAKE1(
3150     "ChxjImodeEmojiColor",
3151     cmd_imode_emoji_color,
3152     NULL,
3153     OR_ALL,
3154     "Auto i-mode emoji color"),
3155   {NULL,{NULL},NULL,0,0,NULL},
3156 };
3157
3158
3159 /*----------------------------------------------------------------------------*/
3160 /* Dispatch list for API hooks                                                */
3161 /*----------------------------------------------------------------------------*/
3162 module AP_MODULE_DECLARE_DATA chxj_module = {
3163   STANDARD20_MODULE_STUFF, 
3164   chxj_create_per_dir_config,          /* create per-dir    config structures */
3165   chxj_merge_per_dir_config,           /* merge  per-dir    config structures */
3166   chxj_config_server_create,           /* create per-server config structures */
3167   NULL,                                /* merge  per-server config structures */
3168   cmds,                                /* table of config file commands       */
3169   chxj_register_hooks                  /* register hooks                      */
3170 };
3171 /*
3172  * vim:ts=2 et
3173  */