diff options
Diffstat (limited to 'mailutils/mail.c')
-rw-r--r-- | mailutils/mail.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/mailutils/mail.c b/mailutils/mail.c new file mode 100644 index 000000000..ab1304a7f --- /dev/null +++ b/mailutils/mail.c | |||
@@ -0,0 +1,242 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * helper routines | ||
4 | * | ||
5 | * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com> | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | #include "libbb.h" | ||
10 | #include "mail.h" | ||
11 | |||
12 | static void kill_helper(void) | ||
13 | { | ||
14 | // TODO!!!: is there more elegant way to terminate child on program failure? | ||
15 | if (G.helper_pid > 0) | ||
16 | kill(G.helper_pid, SIGTERM); | ||
17 | } | ||
18 | |||
19 | // generic signal handler | ||
20 | static void signal_handler(int signo) | ||
21 | { | ||
22 | #define err signo | ||
23 | if (SIGALRM == signo) { | ||
24 | kill_helper(); | ||
25 | bb_error_msg_and_die("timed out"); | ||
26 | } | ||
27 | |||
28 | // SIGCHLD. reap zombies | ||
29 | if (safe_waitpid(G.helper_pid, &err, WNOHANG) > 0) | ||
30 | if (WIFEXITED(err)) { | ||
31 | G.helper_pid = 0; | ||
32 | if (WEXITSTATUS(err)) | ||
33 | bb_error_msg_and_die("child exited (%d)", WEXITSTATUS(err)); | ||
34 | } | ||
35 | #undef err | ||
36 | } | ||
37 | |||
38 | void FAST_FUNC launch_helper(const char **argv) | ||
39 | { | ||
40 | // setup vanilla unidirectional pipes interchange | ||
41 | int idx; | ||
42 | int pipes[4]; | ||
43 | |||
44 | xpipe(pipes); | ||
45 | xpipe(pipes+2); | ||
46 | G.helper_pid = vfork(); | ||
47 | if (G.helper_pid < 0) | ||
48 | bb_perror_msg_and_die("vfork"); | ||
49 | idx = (!G.helper_pid) * 2; | ||
50 | xdup2(pipes[idx], STDIN_FILENO); | ||
51 | xdup2(pipes[3-idx], STDOUT_FILENO); | ||
52 | if (ENABLE_FEATURE_CLEAN_UP) | ||
53 | for (int i = 4; --i >= 0; ) | ||
54 | if (pipes[i] > STDOUT_FILENO) | ||
55 | close(pipes[i]); | ||
56 | if (!G.helper_pid) { | ||
57 | // child: try to execute connection helper | ||
58 | BB_EXECVP(*argv, (char **)argv); | ||
59 | _exit(127); | ||
60 | } | ||
61 | // parent: check whether child is alive | ||
62 | bb_signals(0 | ||
63 | + (1 << SIGCHLD) | ||
64 | + (1 << SIGALRM) | ||
65 | , signal_handler); | ||
66 | signal_handler(SIGCHLD); | ||
67 | // child seems OK -> parent goes on | ||
68 | atexit(kill_helper); | ||
69 | } | ||
70 | |||
71 | const FAST_FUNC char *command(const char *fmt, const char *param) | ||
72 | { | ||
73 | const char *msg = fmt; | ||
74 | if (timeout) | ||
75 | alarm(timeout); | ||
76 | if (msg) { | ||
77 | msg = xasprintf(fmt, param); | ||
78 | printf("%s\r\n", msg); | ||
79 | } | ||
80 | fflush(stdout); | ||
81 | return msg; | ||
82 | } | ||
83 | |||
84 | // NB: parse_url can modify url[] (despite const), but only if '@' is there | ||
85 | /* | ||
86 | static char FAST_FUNC *parse_url(char *url, char **user, char **pass) | ||
87 | { | ||
88 | // parse [user[:pass]@]host | ||
89 | // return host | ||
90 | char *s = strchr(url, '@'); | ||
91 | *user = *pass = NULL; | ||
92 | if (s) { | ||
93 | *s++ = '\0'; | ||
94 | *user = url; | ||
95 | url = s; | ||
96 | s = strchr(*user, ':'); | ||
97 | if (s) { | ||
98 | *s++ = '\0'; | ||
99 | *pass = s; | ||
100 | } | ||
101 | } | ||
102 | return url; | ||
103 | } | ||
104 | */ | ||
105 | |||
106 | void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol) | ||
107 | { | ||
108 | enum { | ||
109 | SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */ | ||
110 | DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), | ||
111 | }; | ||
112 | |||
113 | #define src_buf text | ||
114 | FILE *fp = fp; | ||
115 | ssize_t len = len; | ||
116 | char dst_buf[DST_BUF_SIZE + 1]; | ||
117 | |||
118 | if (fname) { | ||
119 | fp = (NOT_LONE_DASH(fname)) ? xfopen_for_read(fname) : (FILE *)text; | ||
120 | src_buf = bb_common_bufsiz1; | ||
121 | // N.B. strlen(NULL) segfaults! | ||
122 | } else if (text) { | ||
123 | // though we do not call uuencode(NULL, NULL) explicitly | ||
124 | // still we do not want to break things suddenly | ||
125 | len = strlen(text); | ||
126 | } else | ||
127 | return; | ||
128 | |||
129 | while (1) { | ||
130 | size_t size; | ||
131 | if (fname) { | ||
132 | size = fread((char *)src_buf, 1, SRC_BUF_SIZE, fp); | ||
133 | if ((ssize_t)size < 0) | ||
134 | bb_perror_msg_and_die(bb_msg_read_error); | ||
135 | } else { | ||
136 | size = len; | ||
137 | if (len > SRC_BUF_SIZE) | ||
138 | size = SRC_BUF_SIZE; | ||
139 | } | ||
140 | if (!size) | ||
141 | break; | ||
142 | // encode the buffer we just read in | ||
143 | bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64); | ||
144 | if (fname) { | ||
145 | printf("%s\n", eol); | ||
146 | } else { | ||
147 | src_buf += size; | ||
148 | len -= size; | ||
149 | } | ||
150 | fwrite(dst_buf, 1, 4 * ((size + 2) / 3), stdout); | ||
151 | } | ||
152 | if (fname && NOT_LONE_DASH(fname)) | ||
153 | fclose(fp); | ||
154 | #undef src_buf | ||
155 | } | ||
156 | |||
157 | void FAST_FUNC decode_base64(FILE *src_stream, FILE *dst_stream) | ||
158 | { | ||
159 | int term_count = 1; | ||
160 | |||
161 | while (1) { | ||
162 | char translated[4]; | ||
163 | int count = 0; | ||
164 | |||
165 | while (count < 4) { | ||
166 | char *table_ptr; | ||
167 | int ch; | ||
168 | |||
169 | /* Get next _valid_ character. | ||
170 | * global vector bb_uuenc_tbl_base64[] contains this string: | ||
171 | * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" | ||
172 | */ | ||
173 | do { | ||
174 | ch = fgetc(src_stream); | ||
175 | if (ch == EOF) { | ||
176 | bb_error_msg_and_die(bb_msg_read_error); | ||
177 | } | ||
178 | // - means end of MIME section | ||
179 | if ('-' == ch) { | ||
180 | // push it back | ||
181 | ungetc(ch, src_stream); | ||
182 | return; | ||
183 | } | ||
184 | table_ptr = strchr(bb_uuenc_tbl_base64, ch); | ||
185 | } while (table_ptr == NULL); | ||
186 | |||
187 | /* Convert encoded character to decimal */ | ||
188 | ch = table_ptr - bb_uuenc_tbl_base64; | ||
189 | |||
190 | if (*table_ptr == '=') { | ||
191 | if (term_count == 0) { | ||
192 | translated[count] = '\0'; | ||
193 | break; | ||
194 | } | ||
195 | term_count++; | ||
196 | } else if (*table_ptr == '\n') { | ||
197 | /* Check for terminating line */ | ||
198 | if (term_count == 5) { | ||
199 | return; | ||
200 | } | ||
201 | term_count = 1; | ||
202 | continue; | ||
203 | } else { | ||
204 | translated[count] = ch; | ||
205 | count++; | ||
206 | term_count = 0; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | /* Merge 6 bit chars to 8 bit */ | ||
211 | if (count > 1) { | ||
212 | fputc(translated[0] << 2 | translated[1] >> 4, dst_stream); | ||
213 | } | ||
214 | if (count > 2) { | ||
215 | fputc(translated[1] << 4 | translated[2] >> 2, dst_stream); | ||
216 | } | ||
217 | if (count > 3) { | ||
218 | fputc(translated[2] << 6 | translated[3], dst_stream); | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | |||
224 | /* | ||
225 | * get username and password from a file descriptor | ||
226 | */ | ||
227 | void FAST_FUNC get_cred_or_die(int fd) | ||
228 | { | ||
229 | // either from TTY | ||
230 | if (isatty(fd)) { | ||
231 | G.user = xstrdup(bb_askpass(0, "User: ")); | ||
232 | G.pass = xstrdup(bb_askpass(0, "Password: ")); | ||
233 | // or from STDIN | ||
234 | } else { | ||
235 | FILE *fp = fdopen(fd, "r"); | ||
236 | G.user = xmalloc_fgetline(fp); | ||
237 | G.pass = xmalloc_fgetline(fp); | ||
238 | fclose(fp); | ||
239 | } | ||
240 | if (!G.user || !*G.user || !G.pass || !*G.pass) | ||
241 | bb_error_msg_and_die("no username or password"); | ||
242 | } | ||