00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: linemode.c,v 1.9 2006-11-14 14:51:23 sven Exp $";
00022 #endif
00023
00024 #include <eggdrop/eggdrop.h>
00025 #include <unistd.h>
00026
00027 #define LINEMODE_LEVEL SOCKBUF_LEVEL_TEXT_BUFFER
00028
00029 typedef struct {
00030 char *data;
00031 int len;
00032 } linemode_t;
00033
00034 static int linemode_on_read(void *client_data, int idx, char *data, int len)
00035 {
00036 linemode_t *old_data = client_data;
00037 char *line, *stop, *save;
00038 int linelen, savelen;
00039
00040 while (1) {
00041
00042 stop = memchr(data, '\n', len);
00043 if (!stop) {
00044 stop = memchr(data, '\r', len);
00045 if (!stop) {
00046
00047 save = data;
00048 savelen = len;
00049 break;
00050 }
00051 }
00052
00053
00054 save = stop+1;
00055 savelen = len - (save - data);
00056
00057 if (stop > data && *(stop-1) == '\r') stop--;
00058 linelen = stop - data;
00059 *stop = 0;
00060
00061
00062 if (old_data->len) {
00063
00064 old_data->data = realloc(old_data->data, old_data->len + linelen + 1);
00065 memcpy(old_data->data+old_data->len, data, linelen + 1);
00066
00067 line = old_data->data;
00068 linelen += old_data->len;
00069
00070
00071 old_data->len = 0;
00072 }
00073 else {
00074 line = data;
00075 }
00076
00077 sockbuf_on_read(idx, LINEMODE_LEVEL, line, linelen);
00078
00079 if (!sockbuf_isvalid(idx)) return 0;
00080
00081
00082 if (savelen <= 0) return(0);
00083
00084 data = save;
00085 len = savelen;
00086 }
00087
00088
00089 old_data->data = realloc(old_data->data, savelen + old_data->len + 1);
00090 memcpy(old_data->data + old_data->len, save, savelen);
00091 old_data->len += savelen;
00092 return(0);
00093 }
00094
00095 static int linemode_on_eof(void *client_data, int idx, int err, const char *errmsg)
00096 {
00097 linemode_t *old_data = client_data;
00098
00099 if (old_data->len) {
00100 old_data->data[old_data->len] = 0;
00101 sockbuf_on_read(idx, LINEMODE_LEVEL, old_data->data, old_data->len);
00102 old_data->len = 0;
00103 }
00104
00105
00106 return sockbuf_on_eof(idx, LINEMODE_LEVEL, err, errmsg);
00107 }
00108
00109 static int linemode_on_delete(void *client_data, int idx)
00110 {
00111 linemode_t *old_data = client_data;
00112
00113 if (old_data->data) free(old_data->data);
00114 free(old_data);
00115 return(0);
00116 }
00117
00118 static sockbuf_filter_t linemode_filter = {
00119 "linemode",
00120 LINEMODE_LEVEL,
00121 NULL, linemode_on_eof, NULL,
00122 linemode_on_read, NULL, NULL,
00123 NULL, linemode_on_delete
00124 };
00125
00133 int linemode_on(int idx)
00134 {
00135 linemode_t *old_data;
00136
00137 if (linemode_check(idx)) return -1;
00138 old_data = calloc(1, sizeof(*old_data));
00139 sockbuf_attach_filter(idx, &linemode_filter, old_data);
00140 return(0);
00141 }
00142
00152 int linemode_off(int idx)
00153 {
00154 int ret;
00155 linemode_t *old_data;
00156
00157 ret = sockbuf_detach_filter(idx, &linemode_filter, &old_data);
00158 if (ret) return ret;
00159 if (old_data) {
00160 if (old_data->data) {
00161 if (old_data->len) {
00162 old_data->data[old_data->len] = 0;
00163 sockbuf_on_read(idx, LINEMODE_LEVEL, old_data->data, old_data->len);
00164 old_data->len = 0;
00165 }
00166 free(old_data->data);
00167 }
00168 free(old_data);
00169 }
00170 return(0);
00171 }
00172
00180 int linemode_check(int idx)
00181 {
00182 if (!sockbuf_isvalid(idx)) return -1;
00183 return !sockbuf_get_filter_data(idx, &linemode_filter, 0);
00184 }