00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "libjwgc.h"
00026
00027
00028 static void jwg_startElement(void *userdata, const char *name, const char **attribs);
00029 static void jwg_endElement(void *userdata, const char *name);
00030 static void jwg_charData(void *userdata, const char *s, int slen);
00031
00032
00033
00034
00035
00036
00037
00038
00039 jwgconn
00040 jwg_new()
00041 {
00042 xode_pool p;
00043 jwgconn jwg;
00044
00045 p = xode_pool_new();
00046 if (!p)
00047 return (NULL);
00048 jwg = xode_pool_mallocx(p, sizeof(jwgconn_struct), 0);
00049 if (!jwg)
00050 return (NULL);
00051 jwg->p = p;
00052
00053 jwg->state = JWGCONN_STATE_OFF;
00054 jwg->fd = -1;
00055 jwg->sckfd = -1;
00056
00057 return jwg;
00058 }
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 jwgconn
00069 jwg_server()
00070 {
00071 xode_pool p;
00072 jwgconn jwg;
00073
00074 p = xode_pool_new();
00075 if (!p)
00076 return (NULL);
00077 jwg = xode_pool_mallocx(p, sizeof(jwgconn_struct), 0);
00078 if (!jwg)
00079 return (NULL);
00080 jwg->p = p;
00081
00082 jwg->state = JWGCONN_STATE_OFF;
00083 jwg->fd = -1;
00084 jwg->sckfd = -1;
00085
00086 return jwg;
00087 }
00088
00089
00090
00091
00092
00093
00094
00095
00096 void
00097 jwg_delete(jwgconn jwg)
00098 {
00099 if (!jwg)
00100 return;
00101
00102 jwg_stop(jwg);
00103 xode_pool_free(jwg->p);
00104 }
00105
00106 void
00107 jwg_cleanup(jwgconn jwg)
00108 {
00109 if (!jwg)
00110 return;
00111 if (jwg->sckfd == -1)
00112 return;
00113
00114 close(jwg->sckfd);
00115 jwg->sckfd = -1;
00116 }
00117
00118
00119
00120
00121
00122
00123
00124
00125 void
00126 jwg_event_handler(jwgconn jwg, jwgconn_packet_h h)
00127 {
00128 if (!jwg)
00129 return;
00130
00131 jwg->on_packet = h;
00132 }
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 void
00143 jwg_start(jwgconn jwg)
00144 {
00145 xode x;
00146 char *t, *t2;
00147 int len, fromlen, errcode;
00148 struct sockaddr_in from;
00149
00150 if (!jwg || jwg->state != JWGCONN_STATE_OFF)
00151 return;
00152
00153 jwg->parser = XML_ParserCreate(NULL);
00154 XML_SetUserData(jwg->parser, (void *) jwg);
00155 XML_SetElementHandler(jwg->parser, jwg_startElement, jwg_endElement);
00156 XML_SetCharacterDataHandler(jwg->parser, jwg_charData);
00157
00158 jwg->fd = JConnect();
00159 if (jwg->fd < 0) {
00160 return;
00161 }
00162 jwg->state = JWGCONN_STATE_CONNECTED;
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 void
00174 jwg_servstart(jwgconn jwg)
00175 {
00176 int flags = 0;
00177
00178 if (!jwg || jwg->state != JWGCONN_STATE_OFF)
00179 return;
00180
00181 jwg->parser = XML_ParserCreate(NULL);
00182 XML_SetUserData(jwg->parser, (void *) jwg);
00183 XML_SetElementHandler(jwg->parser, jwg_startElement, jwg_endElement);
00184 XML_SetCharacterDataHandler(jwg->parser, jwg_charData);
00185
00186 jwg->fd = JSetupComm();
00187 if (jwg->fd < 0) {
00188 return;
00189 }
00190
00191
00192
00193
00194 jwg->state = JWGCONN_STATE_CONNECTED;
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204 void
00205 jwg_reset(jwgconn jwg)
00206 {
00207 XML_ParserFree(jwg->parser);
00208 jwg->parser = XML_ParserCreate(NULL);
00209 XML_SetUserData(jwg->parser, (void *) jwg);
00210 XML_SetElementHandler(jwg->parser, jwg_startElement, jwg_endElement);
00211 XML_SetCharacterDataHandler(jwg->parser, jwg_charData);
00212 }
00213
00214
00215
00216
00217
00218
00219
00220 void
00221 jwg_stop(jwgconn jwg)
00222 {
00223 if (!jwg || jwg->state == JWGCONN_STATE_OFF)
00224 return;
00225
00226 jwg->state = JWGCONN_STATE_OFF;
00227 close(jwg->fd);
00228 jwg->fd = -1;
00229 jwg->sckfd = -1;
00230 XML_ParserFree(jwg->parser);
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 int
00243 jwg_getfd(jwgconn jwg)
00244 {
00245 if (jwg) {
00246 return jwg->fd;
00247 }
00248 else {
00249 return -1;
00250 }
00251 }
00252
00253
00254
00255
00256
00257
00258
00259
00260 void
00261 jwg_send(jwgconn jwg, xode x)
00262 {
00263 char *buf = xode_to_str(x);
00264 fd_set fds;
00265 FILE *selfd;
00266 struct timeval tv;
00267 int numwrote, totalsize, len, ret;
00268
00269 if (!jwg || jwg->state == JWGCONN_STATE_OFF)
00270 return;
00271
00272 if (!buf)
00273 return;
00274
00275 FD_ZERO(&fds);
00276 FD_SET(jwg->fd, &fds);
00277 selfd = (FILE *) jwg->fd;
00278 tv.tv_sec = 0;
00279 tv.tv_usec = 100000;
00280
00281 ret = jwg_sockselect((int) selfd + 1, NULL, &fds, NULL, &tv);
00282 if (ret < 0) {
00283 dprintf(dJWG, "Error on select: %s\n", strerror(errno));
00284 return;
00285 }
00286 else if (ret == 0) {
00287 dprintf(dJWG, "Time expired while waiting to write.\n");
00288 return;
00289 }
00290
00291 totalsize = strlen(buf) + 1;
00292 numwrote = 0;
00293 while (numwrote < totalsize) {
00294
00295
00296
00297 len = jwg_socksend(jwg->fd, buf, totalsize - numwrote);
00298 if (len < 0) {
00299 dprintf(dJWG, "Error writing to socket: %s\n", strerror(errno));
00300 break;
00301 }
00302 numwrote += len;
00303 dprintf(dJWG, "sent %d bytes, %d wrote out of %d\n", len, numwrote, totalsize);
00304 buf += len;
00305 }
00306 dprintf(dJWG, "out[%d]: %s\n", totalsize, buf);
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316 void
00317 jwg_servsend(jwgconn jwg, xode x)
00318 {
00319 char *buf = xode_to_str(x);
00320 int numwrote, totalsize, len, ret;
00321 FILE *selfd;
00322 struct timeval tv;
00323 fd_set fds;
00324
00325 if (!jwg || jwg->state == JWGCONN_STATE_OFF)
00326 return;
00327
00328 if (!buf)
00329 return;
00330
00331 FD_ZERO(&fds);
00332 FD_SET(jwg->sckfd, &fds);
00333 selfd = (FILE *) jwg->sckfd;
00334 tv.tv_sec = 0;
00335 tv.tv_usec = 100000;
00336
00337 ret = jwg_sockselect((int) selfd + 1, NULL, &fds, NULL, &tv);
00338 if (ret < 0) {
00339 dprintf(dJWG, "Error on select: %s\n", strerror(errno));
00340 return;
00341 }
00342 else if (ret == 0) {
00343 dprintf(dJWG, "Time expired while waiting to write.\n");
00344 return;
00345 }
00346
00347 totalsize = strlen(buf) + 1;
00348 numwrote = 0;
00349 dprintf(dJWG, "out[%d]: %s\n", totalsize, buf);
00350 while (numwrote < totalsize) {
00351
00352
00353
00354 len = jwg_socksend(jwg->sckfd, buf, totalsize - numwrote);
00355 if (len < 0) {
00356 dprintf(dJWG, "Error writing to socket: %s\n", strerror(errno));
00357 break;
00358 }
00359 numwrote += len;
00360 dprintf(dJWG, "sent %d bytes, %d wrote out of %d\n", len, numwrote, totalsize);
00361 buf += len;
00362 }
00363 }
00364
00365
00366
00367
00368
00369
00370
00371
00372 void
00373 jwg_serverror(jwgconn jwg, char *text)
00374 {
00375 xode out;
00376
00377 out = xode_new("error");
00378 xode_insert_cdata(out, text, strlen(text));
00379 jwg_servsend(jwg, out);
00380 xode_free(out);
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390 void
00391 jwg_servsuccess(jwgconn jwg, char *text)
00392 {
00393 xode out;
00394
00395 out = xode_new("success");
00396 xode_insert_cdata(out, text, strlen(text));
00397 jwg_servsend(jwg, out);
00398 xode_free(out);
00399 }
00400
00401
00402
00403
00404
00405
00406
00407
00408 void
00409 jwg_send_raw(jwgconn jwg, const char *str)
00410 {
00411 if (jwg && jwg->state != JWGCONN_STATE_OFF)
00412 write(jwg->fd, str, strlen(str));
00413 dprintf(dJWG, "out: %s\n", str);
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423 void
00424 jwg_servsend_raw(jwgconn jwg, const char *str)
00425 {
00426 if (jwg && jwg->state != JWGCONN_STATE_OFF)
00427 write(jwg->sckfd, str, strlen(str));
00428 dprintf(dJWG, "out: %s\n", str);
00429 }
00430
00431 int
00432 jwg_sockselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
00433 struct timeval *timeout)
00434 {
00435 int ret;
00436 struct timeval currenttv, parttv;
00437
00438 if (!timeout) {
00439 while (1) {
00440 ret = select(nfds, readfds, writefds, exceptfds, NULL);
00441 if (ret < 0 && errno != EINTR) {
00442 return ret;
00443 }
00444 else if (ret >= 0) {
00445 return ret;
00446 }
00447 }
00448 }
00449
00450 currenttv.tv_sec = 0;
00451 currenttv.tv_usec = timeout->tv_usec;
00452
00453 while (currenttv.tv_usec > 0) {
00454 parttv.tv_sec = 0;
00455 parttv.tv_usec = 1;
00456 ret = select(nfds, readfds, writefds, exceptfds, &parttv);
00457 if (ret < 0 && errno != EINTR) {
00458 return ret;
00459 }
00460 else if (ret >= 0) {
00461 return ret;
00462 }
00463 currenttv.tv_sec = 0;
00464 currenttv.tv_usec -= 1;
00465 }
00466
00467 return 0;
00468 }
00469
00470 int
00471 jwg_sockrecv(int sockfd, char *buf, size_t maxsize)
00472 {
00473 size_t totalread = 0;
00474 int ret;
00475
00476 do {
00477 ret = recv(sockfd, buf, maxsize - totalread, 0);
00478 if (ret < 0 && errno != EINTR) {
00479 return ret;
00480 }
00481 else if (ret == 0) {
00482 return totalread;
00483 }
00484 else if (ret > 0) {
00485 totalread += ret;
00486 return totalread;
00487 }
00488 else if (ret == -1 && errno == EINTR) {
00489 if (recv(sockfd, buf, maxsize - totalread, MSG_PEEK)
00490 <= 0) {
00491 return totalread;
00492 }
00493 }
00494 } while (totalread < maxsize);
00495
00496 return totalread;
00497 }
00498
00499 int
00500 jwg_socksend(int sockfd, char *buf, size_t len)
00501 {
00502 size_t totalsent = 0;
00503 int ret;
00504
00505 do {
00506 ret = send(sockfd, buf, len - totalsent, 0);
00507 if (ret < 0 && errno != EINTR) {
00508 return ret;
00509 }
00510 else if (ret == 0) {
00511 return totalsent;
00512 }
00513 else if (ret > 0) {
00514 totalsent += ret;
00515 return totalsent;
00516 }
00517 } while (totalsent < len);
00518
00519 return totalsent;
00520 }
00521
00522
00523
00524
00525
00526
00527
00528 void
00529 jwg_recv(jwgconn jwg)
00530 {
00531 char *fullbuf;
00532 static char buf[4096];
00533 int len, totallen, fromlen, errcode;
00534 struct sockaddr_in from;
00535 fd_set fds;
00536 FILE *selfd;
00537 struct timeval tv;
00538
00539 if (!jwg || jwg->state == JWGCONN_STATE_OFF)
00540 return;
00541
00542 fullbuf = (char *) malloc(sizeof(char));
00543 fullbuf[0] = '\0';
00544 totallen = 0;
00545
00546 FD_ZERO(&fds);
00547 FD_SET(jwg->fd, &fds);
00548 selfd = (FILE *) jwg->fd;
00549 tv.tv_sec = 0;
00550 tv.tv_usec = 100000;
00551
00552 while (jwg_sockselect((int) selfd + 1, &fds, NULL, NULL, &tv) > 0) {
00553 len = jwg_sockrecv(jwg->fd, buf, sizeof(buf) - 1);
00554 if (len <= 0) {
00555 break;
00556 }
00557 dprintf(dJWG, " in piece[%d]: %s\n", len, buf);
00558 fullbuf = (char *) realloc(fullbuf, strlen(fullbuf) + strlen(buf) + 1);
00559 strcat(fullbuf, buf);
00560 totallen += len;
00561 }
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 if (totallen > 0) {
00572 dprintf(dJWG, " in[%d]: %s\n", totallen, fullbuf);
00573 errcode = XML_Parse(jwg->parser, fullbuf, totallen - 1, 0);
00574 dprintf(dParser, "parser index %d, line %d, col %d\n", XML_GetCurrentByteIndex(jwg->parser), XML_GetCurrentLineNumber(jwg->parser), XML_GetCurrentColumnNumber(jwg->parser));
00575 if (errcode == 0) {
00576 dprintf(dParser, "parser error %d at byte %d: %s\n", XML_GetErrorCode(jwg->parser), XML_GetCurrentByteIndex(jwg->parser), XML_ErrorString(XML_GetErrorCode(jwg->parser)));
00577 }
00578 else {
00579 dprintf(dParser, "parser complete\n");
00580 }
00581 }
00582 else {
00583 dprintf(dJWG, "jwg_recv: read failed, %d:%d:%s\n", totallen, errno, strerror(errno));
00584 }
00585
00586 free(fullbuf);
00587 }
00588
00589
00590
00591
00592
00593
00594
00595 void
00596 jwg_servrecv(jwgconn jwg)
00597 {
00598 char *fullbuf;
00599 static char buf[4096];
00600 int len, totallen, fromlen, errcode;
00601 struct sockaddr_in from;
00602 fd_set fds;
00603 FILE *selfd;
00604 struct timeval tv;
00605 struct linger li;
00606
00607 li.l_onoff = 1;
00608 li.l_linger = 900;
00609
00610 if (!jwg || jwg->state == JWGCONN_STATE_OFF)
00611 return;
00612
00613 fullbuf = (char *) malloc(sizeof(char));
00614 fullbuf[0] = '\0';
00615 totallen = 0;
00616
00617 fromlen = sizeof(from);
00618 jwg->sckfd = accept(jwg->fd, (struct sockaddr *) & from, &fromlen);
00619 if (jwg->sckfd < 0) {
00620 dprintf(dJWG, "jwg_recv: accept failed, %d:%s\n", errno, strerror(errno));
00621 return;
00622 }
00623
00624 if (setsockopt(jwg->sckfd, SOL_SOCKET, SO_LINGER, (char *)&li,
00625 sizeof(li)) == -1) {
00626 dprintf(dJWG, "jwg_recv: set linger failed, %d:%s\n", errno, strerror(errno));
00627 return;
00628 }
00629
00630 FD_ZERO(&fds);
00631 FD_SET(jwg->sckfd, &fds);
00632 selfd = (FILE *) jwg->sckfd;
00633 tv.tv_sec = 0;
00634 tv.tv_usec = 100000;
00635
00636 while (jwg_sockselect((int) selfd + 1, &fds, NULL, NULL, &tv) > 0) {
00637 len = jwg_sockrecv(jwg->sckfd, buf, sizeof(buf) - 1);
00638 if (len <= 0) {
00639 break;
00640 }
00641 dprintf(dJWG, " in piece[%d]: %s\n", len, buf);
00642 fullbuf = (char *) realloc(fullbuf, strlen(fullbuf) + strlen(buf) + 1);
00643 strcat(fullbuf, buf);
00644 totallen += len;
00645 }
00646
00647 if (totallen > 0) {
00648 dprintf(dJWG, " in[%d]: %s\n", totallen, fullbuf);
00649 errcode = XML_Parse(jwg->parser, fullbuf, totallen - 1, 0);
00650 dprintf(dParser, "parser index %d, line %d, col %d\n", XML_GetCurrentByteIndex(jwg->parser), XML_GetCurrentLineNumber(jwg->parser), XML_GetCurrentColumnNumber(jwg->parser));
00651 if (errcode == 0) {
00652 dprintf(dParser, "parser error %d at byte %d: %s\n", XML_GetErrorCode(jwg->parser), XML_GetCurrentByteIndex(jwg->parser), XML_ErrorString(XML_GetErrorCode(jwg->parser)));
00653 }
00654 else {
00655 dprintf(dParser, "parser complete\n");
00656 }
00657 jwg_reset(jwg);
00658 }
00659 else {
00660 dprintf(dJWG, "jwg_servrecv: read failed, %d:%d:%s\n", totallen, errno, strerror(errno));
00661 }
00662
00663 free(fullbuf);
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673 void
00674 jwg_poll(jwgconn jwg, int timeout)
00675 {
00676 fd_set fds;
00677 FILE *selfd;
00678 struct timeval tv;
00679
00680 if (!jwg || jwg->state == JWGCONN_STATE_OFF)
00681 return;
00682
00683 FD_ZERO(&fds);
00684 FD_SET(jwg->fd, &fds);
00685 selfd = (FILE *) jwg->fd;
00686
00687 if (timeout < 0) {
00688 if (jwg_sockselect((int) selfd + 1, &fds, NULL, NULL, NULL) > 0)
00689 jwg_recv(jwg);
00690 }
00691 else {
00692 tv.tv_sec = 0;
00693 tv.tv_usec = timeout;
00694
00695 if (jwg_sockselect((int) selfd + 1, &fds, NULL, NULL, &tv) > 0)
00696 jwg_recv(jwg);
00697 }
00698 }
00699
00700
00701
00702
00703
00704
00705
00706
00707 void
00708 jwg_servpoll(jwgconn jwg, int timeout)
00709 {
00710 fd_set fds;
00711 FILE *selfd;
00712 struct timeval tv;
00713
00714 if (!jwg || jwg->state == JWGCONN_STATE_OFF)
00715 return;
00716
00717 FD_ZERO(&fds);
00718 FD_SET(jwg->fd, &fds);
00719 selfd = (FILE *) jwg->fd;
00720
00721
00722 if (timeout < 0) {
00723 if (select((int) selfd + 1, &fds, NULL, NULL, NULL) > 0)
00724 jwg_servrecv(jwg);
00725 }
00726 else {
00727 tv.tv_sec = 0;
00728 tv.tv_usec = timeout;
00729
00730 if (jwg_sockselect((int) selfd + 1, &fds, NULL, NULL, &tv) > 0)
00731 jwg_servrecv(jwg);
00732 }
00733 }
00734
00735 jwgpacket
00736 jwgpacket_new(xode x)
00737 {
00738 jwgpacket p;
00739
00740 if (x == NULL)
00741 return NULL;
00742
00743 p = xode_pool_malloc(xode_get_pool(x), sizeof(_jwgpacket));
00744 p->x = x;
00745
00746 return jwgpacket_reset(p);
00747 }
00748
00749 jwgpacket
00750 jwgpacket_reset(jwgpacket p)
00751 {
00752 xode x;
00753
00754 x = p->x;
00755 memset(p, 0, sizeof(_jwgpacket));
00756 p->x = x;
00757 p->p = xode_get_pool(x);
00758
00759 if (strncmp(xode_get_name(x), "message", 7) == 0) {
00760 p->type = JWGPACKET_MESSAGE;
00761 }
00762 else if (strncmp(xode_get_name(x), "locate", 6) == 0) {
00763 p->type = JWGPACKET_LOCATE;
00764 }
00765 else if (strncmp(xode_get_name(x), "status", 6) == 0) {
00766 p->type = JWGPACKET_STATUS;
00767 }
00768 else if (strncmp(xode_get_name(x), "shutdown", 8) == 0) {
00769 p->type = JWGPACKET_SHUTDOWN;
00770 }
00771 else if (strncmp(xode_get_name(x), "check", 5) == 0) {
00772 p->type = JWGPACKET_CHECK;
00773 }
00774 else if (strncmp(xode_get_name(x), "reread", 6) == 0) {
00775 p->type = JWGPACKET_REREAD;
00776 }
00777 else if (strncmp(xode_get_name(x), "showvar", 7) == 0) {
00778 p->type = JWGPACKET_SHOWVAR;
00779 }
00780 else if (strncmp(xode_get_name(x), "subscribe", 9) == 0) {
00781 p->type = JWGPACKET_SUBSCRIBE;
00782 }
00783 else if (strncmp(xode_get_name(x), "unsubscribe", 11) == 0) {
00784 p->type = JWGPACKET_UNSUBSCRIBE;
00785 }
00786 else if (strncmp(xode_get_name(x), "nickname", 8) == 0) {
00787 p->type = JWGPACKET_NICKNAME;
00788 }
00789 else if (strncmp(xode_get_name(x), "group", 5) == 0) {
00790 p->type = JWGPACKET_GROUP;
00791 }
00792 else if (strncmp(xode_get_name(x), "register", 8) == 0) {
00793 p->type = JWGPACKET_REGISTER;
00794 }
00795 else if (strncmp(xode_get_name(x), "search", 6) == 0) {
00796 p->type = JWGPACKET_SEARCH;
00797 }
00798 else if (strncmp(xode_get_name(x), "setvar", 6) == 0) {
00799 p->type = JWGPACKET_SETVAR;
00800 }
00801 else if (strncmp(xode_get_name(x), "join", 4) == 0) {
00802 p->type = JWGPACKET_JOIN;
00803 }
00804 else if (strncmp(xode_get_name(x), "leave", 5) == 0) {
00805 p->type = JWGPACKET_LEAVE;
00806 }
00807 else if (strncmp(xode_get_name(x), "debug", 5) == 0) {
00808 p->type = JWGPACKET_DEBUG;
00809 }
00810 else if (strncmp(xode_get_name(x), "ping", 4) == 0) {
00811 p->type = JWGPACKET_PING;
00812 }
00813 else {
00814 p->type = JWGPACKET_UNKNOWN;
00815 }
00816
00817 return p;
00818 }
00819
00820
00821
00822 static void
00823 jwg_startElement(void *userdata, const char *name, const char **attribs)
00824 {
00825 xode x;
00826 jwgconn jwg = (jwgconn) userdata;
00827
00828 if (jwg->current) {
00829
00830 x = xode_insert_tag(jwg->current, name);
00831 xode_put_expat_attribs(x, attribs);
00832
00833 jwg->current = x;
00834 }
00835 else {
00836 x = xode_new(name);
00837 xode_put_expat_attribs(x, attribs);
00838 jwg->current = x;
00839 }
00840 }
00841
00842 static void
00843 jwg_endElement(void *userdata, const char *name)
00844 {
00845 jwgconn jwg = (jwgconn) userdata;
00846 xode x;
00847 jwgpacket p;
00848
00849 x = xode_get_parent(jwg->current);
00850
00851 if (x == NULL) {
00852 p = jwgpacket_new(jwg->current);
00853
00854 if (jwg->on_packet)
00855 (jwg->on_packet) (jwg, p);
00856 xode_free(jwg->current);
00857 }
00858 jwg->current = x;
00859 }
00860
00861 static void
00862 jwg_charData(void *userdata, const char *s, int slen)
00863 {
00864 jwgconn jwg = (jwgconn) userdata;
00865
00866 if (jwg->current)
00867 xode_insert_cdata(jwg->current, s, slen);
00868 }