Mercurial > dovecot > original-hg > dovecot-1.2
annotate src/imap/client.c @ 1538:4d1c65eded2c HEAD
Give more verbose protocol level errors + some fixes.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 04 Jun 2003 19:35:11 +0300 |
parents | e850252cdc7e |
children | 6eca99b727a0 |
rev | line source |
---|---|
0 | 1 /* Copyright (C) 2002 Timo Sirainen */ |
2 | |
3 #include "common.h" | |
532
3b53dd1280c6
I/O buffers now use real blocking instead of setting up a sub-ioloop to
Timo Sirainen <tss@iki.fi>
parents:
410
diff
changeset
|
4 #include "ioloop.h" |
164
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
5 #include "network.h" |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
6 #include "istream.h" |
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
7 #include "ostream.h" |
0 | 8 #include "commands.h" |
9 | |
10 #include <stdlib.h> | |
11 | |
12 /* max. size of one parameter in line */ | |
13 #define MAX_INBUF_SIZE 8192 | |
14 | |
15 /* If we can't send a buffer in a minute, disconnect the client */ | |
16 #define CLIENT_OUTPUT_TIMEOUT (60*1000) | |
17 | |
164
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
18 /* If we don't soon receive expected data from client while processing |
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
19 a command, disconnect the client */ |
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
20 #define CLIENT_CMDINPUT_TIMEOUT CLIENT_OUTPUT_TIMEOUT |
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
21 |
1001
fb9c95a8847f
imap-login: disconnect when received 10 invalid commands. imap: disconnect
Timo Sirainen <tss@iki.fi>
parents:
953
diff
changeset
|
22 /* Disconnect client when it sends too many bad commands in a row */ |
0 | 23 #define CLIENT_MAX_BAD_COMMANDS 20 |
24 | |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
25 extern struct mail_storage_callbacks mail_storage_callbacks; |
674
b7aefd0d7611
Locking changes triggered a bit larger cleanup :) If we have to wait for a
Timo Sirainen <tss@iki.fi>
parents:
532
diff
changeset
|
26 |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
27 static struct client *my_client; /* we don't need more than one currently */ |
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
28 static struct timeout *to_idle; |
0 | 29 |
532
3b53dd1280c6
I/O buffers now use real blocking instead of setting up a sub-ioloop to
Timo Sirainen <tss@iki.fi>
parents:
410
diff
changeset
|
30 static void client_output_timeout(void *context) |
0 | 31 { |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
32 struct client *client = context; |
164
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
33 |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
34 i_stream_close(client->input); |
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
35 o_stream_close(client->output); |
0 | 36 } |
37 | |
532
3b53dd1280c6
I/O buffers now use real blocking instead of setting up a sub-ioloop to
Timo Sirainen <tss@iki.fi>
parents:
410
diff
changeset
|
38 static void client_input_timeout(void *context) |
164
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
39 { |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
40 struct client *client = context; |
164
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
41 |
1023
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
42 client_disconnect_with_error(client, |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
43 "Disconnected for inactivity while waiting for command data."); |
164
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
44 } |
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
45 |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
46 struct client *client_create(int hin, int hout, struct mail_storage *storage) |
0 | 47 { |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
48 struct client *client; |
0 | 49 |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
50 client = i_new(struct client, 1); |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
51 client->input = i_stream_create_file(hin, default_pool, |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
52 MAX_INBUF_SIZE, FALSE); |
1499
e850252cdc7e
Removed I/O priorities. They were pretty much useless and were just getting
Timo Sirainen <tss@iki.fi>
parents:
1464
diff
changeset
|
53 client->output = o_stream_create_file(hout, default_pool, 4096, FALSE); |
0 | 54 |
164
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
55 /* set timeout for reading expected data (eg. APPEND). This is |
2660a5684515
Added io_buffer_read_blocking() which can be used to read data blockingly,
Timo Sirainen <tss@iki.fi>
parents:
158
diff
changeset
|
56 different from the actual idle time. */ |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
57 i_stream_set_blocking(client->input, CLIENT_CMDINPUT_TIMEOUT, |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
58 client_input_timeout, client); |
0 | 59 |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
60 /* set timeout for sending data */ |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
61 o_stream_set_blocking(client->output, CLIENT_OUTPUT_TIMEOUT, |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
62 client_output_timeout, client); |
0 | 63 |
1172 | 64 client->io = io_add(hin, IO_READ, _client_input, client); |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
65 client->parser = imap_parser_create(client->input, client->output, |
768
8b3518bb327e
Limited max. command argument elements to 128. Added more verbose error
Timo Sirainen <tss@iki.fi>
parents:
764
diff
changeset
|
66 MAX_INBUF_SIZE, |
8b3518bb327e
Limited max. command argument elements to 128. Added more verbose error
Timo Sirainen <tss@iki.fi>
parents:
764
diff
changeset
|
67 MAX_IMAP_ARG_ELEMENTS); |
0 | 68 client->last_input = ioloop_time; |
69 | |
1168
03f1455664d7
Added setting to limit length of custom flag names.
Timo Sirainen <tss@iki.fi>
parents:
1036
diff
changeset
|
70 client->mailbox_flags.pool = |
03f1455664d7
Added setting to limit length of custom flag names.
Timo Sirainen <tss@iki.fi>
parents:
1036
diff
changeset
|
71 pool_alloconly_create("mailbox_custom_flags", 512); |
0 | 72 client->storage = storage; |
674
b7aefd0d7611
Locking changes triggered a bit larger cleanup :) If we have to wait for a
Timo Sirainen <tss@iki.fi>
parents:
532
diff
changeset
|
73 storage->set_callbacks(storage, &mail_storage_callbacks, client); |
0 | 74 |
75 i_assert(my_client == NULL); | |
76 my_client = client; | |
77 return client; | |
78 } | |
79 | |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
80 void client_destroy(struct client *client) |
0 | 81 { |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
82 o_stream_flush(client->output); |
158
a1204e882bc7
Flush output buffer to client at exit, and send a nice "BYE Server shutting
Timo Sirainen <tss@iki.fi>
parents:
10
diff
changeset
|
83 |
0 | 84 if (client->mailbox != NULL) |
85 client->mailbox->close(client->mailbox); | |
86 mail_storage_destroy(client->storage); | |
87 | |
88 imap_parser_destroy(client->parser); | |
89 io_remove(client->io); | |
90 | |
1212 | 91 if (client->idle_to != NULL) |
92 timeout_remove(client->idle_to); | |
93 | |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
94 i_stream_unref(client->input); |
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
95 o_stream_unref(client->output); |
0 | 96 |
1168
03f1455664d7
Added setting to limit length of custom flag names.
Timo Sirainen <tss@iki.fi>
parents:
1036
diff
changeset
|
97 pool_unref(client->mailbox_flags.pool); |
0 | 98 i_free(client); |
99 | |
100 /* quit the program */ | |
101 my_client = NULL; | |
102 io_loop_stop(ioloop); | |
103 } | |
104 | |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
105 void client_disconnect(struct client *client) |
0 | 106 { |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
107 o_stream_flush(client->output); |
222
cf4d065f2f85
lots of cleanups. also index/datafile is now capable of staying in memory,
Timo Sirainen <tss@iki.fi>
parents:
184
diff
changeset
|
108 |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
109 i_stream_close(client->input); |
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
110 o_stream_close(client->output); |
0 | 111 } |
112 | |
1023
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
113 void client_disconnect_with_error(struct client *client, const char *msg) |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
114 { |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
115 client_send_line(client, t_strconcat("* BYE ", msg, NULL)); |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
116 client_disconnect(client); |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
117 } |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
118 |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
119 void client_send_line(struct client *client, const char *data) |
0 | 120 { |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
121 if (client->output->closed) |
0 | 122 return; |
123 | |
807
35abd7a5d381
Buffer related cleanups. Use PATH_MAX instead of hardcoded 1024 for paths.
Timo Sirainen <tss@iki.fi>
parents:
805
diff
changeset
|
124 (void)o_stream_send_str(client->output, data); |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
125 (void)o_stream_send(client->output, "\r\n", 2); |
0 | 126 } |
127 | |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
128 void client_send_tagline(struct client *client, const char *data) |
0 | 129 { |
130 const char *tag = client->cmd_tag; | |
131 | |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
132 if (client->output->closed) |
0 | 133 return; |
134 | |
135 if (tag == NULL || *tag == '\0') | |
136 tag = "*"; | |
137 | |
807
35abd7a5d381
Buffer related cleanups. Use PATH_MAX instead of hardcoded 1024 for paths.
Timo Sirainen <tss@iki.fi>
parents:
805
diff
changeset
|
138 (void)o_stream_send_str(client->output, tag); |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
139 (void)o_stream_send(client->output, " ", 1); |
807
35abd7a5d381
Buffer related cleanups. Use PATH_MAX instead of hardcoded 1024 for paths.
Timo Sirainen <tss@iki.fi>
parents:
805
diff
changeset
|
140 (void)o_stream_send_str(client->output, data); |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
141 (void)o_stream_send(client->output, "\r\n", 2); |
0 | 142 } |
143 | |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
144 void client_send_command_error(struct client *client, const char *msg) |
0 | 145 { |
1538
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
146 const char *error, *cmd; |
1023
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
147 int fatal; |
0 | 148 |
1023
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
149 if (msg == NULL) { |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
150 msg = imap_parser_get_error(client->parser, &fatal); |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
151 if (fatal) { |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
152 client_disconnect_with_error(client, msg); |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
153 return; |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
154 } |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
155 } |
1538
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
156 |
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
157 if (client->cmd_tag == NULL) |
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
158 error = t_strconcat("BAD Error in IMAP tag: ", msg, NULL); |
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
159 else if (client->cmd_name == NULL) |
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
160 error = t_strconcat("BAD Error in IMAP command: ", msg, NULL); |
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
161 else { |
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
162 cmd = str_ucase(t_strdup_noconst(client->cmd_name)); |
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
163 error = t_strconcat("BAD Error in IMAP command ", |
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
164 cmd, ": ", msg, NULL); |
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
165 } |
0 | 166 |
167 client->cmd_error = TRUE; | |
168 client_send_tagline(client, error); | |
169 | |
170 if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) { | |
1023
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
171 client_disconnect_with_error(client, |
dc660f588218
Disconnect client if given non-sync literal size is too large. Better than
Timo Sirainen <tss@iki.fi>
parents:
1015
diff
changeset
|
172 "Too many invalid IMAP commands."); |
0 | 173 } |
174 } | |
175 | |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
176 int client_read_args(struct client *client, unsigned int count, |
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
177 unsigned int flags, struct imap_arg **args) |
0 | 178 { |
179 int ret; | |
180 | |
1015
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
181 i_assert(count <= INT_MAX); |
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
182 |
0 | 183 ret = imap_parser_read_args(client->parser, count, flags, args); |
720 | 184 if (ret >= (int)count) { |
0 | 185 /* all parameters read successfully */ |
186 return TRUE; | |
187 } else if (ret == -2) { | |
188 /* need more data */ | |
189 return FALSE; | |
190 } else { | |
191 /* error, or missing arguments */ | |
769
f17a1f59ac3f
Fixed "Missing arguments" error msg to work again
Timo Sirainen <tss@iki.fi>
parents:
768
diff
changeset
|
192 client_send_command_error(client, ret < 0 ? NULL : |
f17a1f59ac3f
Fixed "Missing arguments" error msg to work again
Timo Sirainen <tss@iki.fi>
parents:
768
diff
changeset
|
193 "Missing arguments"); |
0 | 194 return FALSE; |
195 } | |
196 } | |
197 | |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
198 int client_read_string_args(struct client *client, unsigned int count, ...) |
0 | 199 { |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
200 struct imap_arg *imap_args; |
0 | 201 va_list va; |
202 const char *str; | |
203 unsigned int i; | |
204 | |
205 if (!client_read_args(client, count, 0, &imap_args)) | |
206 return FALSE; | |
207 | |
208 va_start(va, count); | |
209 for (i = 0; i < count; i++) { | |
210 const char **ret = va_arg(va, const char **); | |
211 | |
1015
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
212 if (imap_args[i].type == IMAP_ARG_EOL) { |
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
213 client_send_command_error(client, "Missing arguments."); |
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
214 break; |
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
215 } |
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
216 |
0 | 217 str = imap_arg_string(&imap_args[i]); |
218 if (str == NULL) { | |
1015
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
219 client_send_command_error(client, "Invalid arguments."); |
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
220 break; |
0 | 221 } |
222 | |
223 if (ret != NULL) | |
224 *ret = str; | |
225 } | |
226 va_end(va); | |
227 | |
1015
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
228 return i == count; |
0 | 229 } |
230 | |
1172 | 231 void _client_reset_command(struct client *client) |
0 | 232 { |
233 client->cmd_tag = NULL; | |
234 client->cmd_name = NULL; | |
235 client->cmd_func = NULL; | |
236 client->cmd_error = FALSE; | |
237 client->cmd_uid = FALSE; | |
238 | |
239 imap_parser_reset(client->parser); | |
240 } | |
241 | |
242 /* Skip incoming data until newline is found, | |
243 returns TRUE if newline was found. */ | |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
244 static int client_skip_line(struct client *client) |
0 | 245 { |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
246 const unsigned char *data; |
184 | 247 size_t i, data_size; |
0 | 248 |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
249 data = i_stream_get_data(client->input, &data_size); |
0 | 250 |
251 for (i = 0; i < data_size; i++) { | |
252 if (data[i] == '\n') { | |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
253 client->input_skip_line = FALSE; |
1538
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
254 i++; |
0 | 255 break; |
256 } | |
257 } | |
258 | |
1538
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
259 i_stream_skip(client->input, i); |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
260 return !client->input_skip_line; |
0 | 261 } |
262 | |
903
fd8888f6f037
Naming style changes, finally got tired of most of the typedefs. Also the
Timo Sirainen <tss@iki.fi>
parents:
807
diff
changeset
|
263 static int client_handle_input(struct client *client) |
0 | 264 { |
265 if (client->cmd_func != NULL) { | |
266 /* command is being executed - continue it */ | |
1015
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
267 client->input_skip_line = TRUE; |
717
3f817df5eba4
Input parsing was a bit broken in some conditions. Mostly visible with
Timo Sirainen <tss@iki.fi>
parents:
674
diff
changeset
|
268 if (client->cmd_func(client) || client->cmd_error) { |
3f817df5eba4
Input parsing was a bit broken in some conditions. Mostly visible with
Timo Sirainen <tss@iki.fi>
parents:
674
diff
changeset
|
269 /* command execution was finished */ |
1172 | 270 _client_reset_command(client); |
1001
fb9c95a8847f
imap-login: disconnect when received 10 invalid commands. imap: disconnect
Timo Sirainen <tss@iki.fi>
parents:
953
diff
changeset
|
271 client->bad_counter = 0; |
0 | 272 return TRUE; |
273 } | |
274 return FALSE; | |
275 } | |
276 | |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
277 if (client->input_skip_line) { |
0 | 278 /* we're just waiting for new line.. */ |
279 if (!client_skip_line(client)) | |
280 return FALSE; | |
281 | |
282 /* got the newline */ | |
1172 | 283 _client_reset_command(client); |
0 | 284 |
285 /* pass through to parse next command */ | |
286 } | |
287 | |
288 if (client->cmd_tag == NULL) { | |
289 client->cmd_tag = imap_parser_read_word(client->parser); | |
290 if (client->cmd_tag == NULL) | |
291 return FALSE; /* need more data */ | |
292 } | |
293 | |
294 if (client->cmd_name == NULL) { | |
295 client->cmd_name = imap_parser_read_word(client->parser); | |
296 if (client->cmd_name == NULL) | |
297 return FALSE; /* need more data */ | |
298 } | |
299 | |
300 if (client->cmd_name == '\0') { | |
301 /* command not given - cmd_func is already NULL. */ | |
302 } else { | |
303 /* find the command function */ | |
1464
bd489d13479e
Added command_register() and related functions so we can dynamically
Timo Sirainen <tss@iki.fi>
parents:
1212
diff
changeset
|
304 client->cmd_func = command_find(client->cmd_name); |
0 | 305 } |
306 | |
307 if (client->cmd_func == NULL) { | |
308 /* unknown command */ | |
1538
4d1c65eded2c
Give more verbose protocol level errors + some fixes.
Timo Sirainen <tss@iki.fi>
parents:
1499
diff
changeset
|
309 client_send_command_error(client, "Unknown command."); |
1015
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
310 client->input_skip_line = TRUE; |
1172 | 311 _client_reset_command(client); |
0 | 312 } else { |
1015
40a327d356de
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
Timo Sirainen <tss@iki.fi>
parents:
1001
diff
changeset
|
313 client->input_skip_line = TRUE; |
0 | 314 if (client->cmd_func(client) || client->cmd_error) { |
315 /* command execution was finished */ | |
1172 | 316 _client_reset_command(client); |
1001
fb9c95a8847f
imap-login: disconnect when received 10 invalid commands. imap: disconnect
Timo Sirainen <tss@iki.fi>
parents:
953
diff
changeset
|
317 client->bad_counter = 0; |
1172 | 318 } else { |
319 /* unfinished */ | |
320 return FALSE; | |
0 | 321 } |
322 } | |
323 | |
324 return TRUE; | |
325 } | |
326 | |
1172 | 327 void _client_input(void *context) |
0 | 328 { |
953
411006be3c66
Naming change for function typedefs.
Timo Sirainen <tss@iki.fi>
parents:
903
diff
changeset
|
329 struct client *client = context; |
411006be3c66
Naming change for function typedefs.
Timo Sirainen <tss@iki.fi>
parents:
903
diff
changeset
|
330 |
0 | 331 client->last_input = ioloop_time; |
332 | |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
333 switch (i_stream_read(client->input)) { |
0 | 334 case -1: |
335 /* disconnected */ | |
336 client_destroy(client); | |
337 return; | |
338 case -2: | |
339 /* parameter word is longer than max. input buffer size. | |
340 this is most likely an error, so skip the new data | |
341 until newline is found. */ | |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
342 client->input_skip_line = TRUE; |
0 | 343 |
344 client_send_command_error(client, "Too long argument."); | |
1172 | 345 _client_reset_command(client); |
0 | 346 break; |
347 } | |
348 | |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
349 o_stream_cork(client->output); |
0 | 350 while (client_handle_input(client)) |
351 ; | |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
352 o_stream_flush(client->output); |
0 | 353 |
764
f57c52738f90
Renamed IBuffer and OBuffer to IStream and OStream which describes their
Timo Sirainen <tss@iki.fi>
parents:
720
diff
changeset
|
354 if (client->output->closed) |
0 | 355 client_destroy(client); |
356 } | |
357 | |
1036
f782b3319553
Removed useless parameters from io_callback_t and timeout_callback_t.
Timo Sirainen <tss@iki.fi>
parents:
1023
diff
changeset
|
358 static void idle_timeout(void *context __attr_unused__) |
0 | 359 { |
360 if (my_client == NULL) | |
361 return; | |
362 | |
363 if (ioloop_time - my_client->last_input >= CLIENT_IDLE_TIMEOUT) { | |
364 client_send_line(my_client, | |
365 "* BYE Disconnected for inactivity."); | |
366 client_destroy(my_client); | |
367 } | |
368 } | |
369 | |
370 void clients_init(void) | |
371 { | |
372 my_client = NULL; | |
373 to_idle = timeout_add(10000, idle_timeout, NULL); | |
374 } | |
375 | |
376 void clients_deinit(void) | |
377 { | |
158
a1204e882bc7
Flush output buffer to client at exit, and send a nice "BYE Server shutting
Timo Sirainen <tss@iki.fi>
parents:
10
diff
changeset
|
378 if (my_client != NULL) { |
a1204e882bc7
Flush output buffer to client at exit, and send a nice "BYE Server shutting
Timo Sirainen <tss@iki.fi>
parents:
10
diff
changeset
|
379 client_send_line(my_client, "* BYE Server shutting down."); |
0 | 380 client_destroy(my_client); |
158
a1204e882bc7
Flush output buffer to client at exit, and send a nice "BYE Server shutting
Timo Sirainen <tss@iki.fi>
parents:
10
diff
changeset
|
381 } |
0 | 382 |
383 timeout_remove(to_idle); | |
384 } |