Line data Source code
1 : /********************************************************************\
2 :
3 : Name: elog.c
4 : Created by: Stefan Ritt
5 :
6 : Contents: Electronic logbook utility
7 :
8 : $Id:$
9 :
10 : \********************************************************************/
11 :
12 : #include <stdio.h>
13 : #include <sys/types.h>
14 : #include <fcntl.h>
15 : #include <stdarg.h>
16 : #include <string.h>
17 : #include <stdlib.h>
18 :
19 : #ifdef _MSC_VER
20 : #include <windows.h>
21 : #include <io.h>
22 : #else
23 : #include <netdb.h>
24 : #include <netinet/in.h>
25 : #include <sys/socket.h>
26 : #include <sys/time.h>
27 : #include <unistd.h>
28 : #include <signal.h>
29 : #define closesocket(s) close(s)
30 : #ifndef O_BINARY
31 : #define O_BINARY 0
32 : #endif
33 : #endif
34 :
35 : typedef int INT;
36 :
37 : #define MAX_ATTACHMENTS 10
38 : #define NAME_LENGTH 100
39 : #define MAX_N_ATTR 20
40 :
41 : int verbose;
42 :
43 : /*------------------------------------------------------------------*/
44 :
45 : const char *map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
46 :
47 0 : void base64_encode(char *s, char *d)
48 : {
49 : unsigned int t, pad;
50 :
51 0 : pad = 3 - strlen(s) % 3;
52 0 : while (*s) {
53 0 : t = (*s++) << 16;
54 0 : if (*s)
55 0 : t |= (*s++) << 8;
56 0 : if (*s)
57 0 : t |= (*s++) << 0;
58 :
59 0 : *(d + 3) = map[t & 63];
60 0 : t >>= 6;
61 0 : *(d + 2) = map[t & 63];
62 0 : t >>= 6;
63 0 : *(d + 1) = map[t & 63];
64 0 : t >>= 6;
65 0 : *(d + 0) = map[t & 63];
66 :
67 0 : d += 4;
68 : }
69 0 : *d = 0;
70 0 : while (pad--)
71 0 : *(--d) = '=';
72 0 : }
73 :
74 : /*------------------------------------------------------------------*/
75 :
76 0 : void sgets(char *string, int size)
77 : {
78 : char *p;
79 :
80 : do {
81 0 : p = fgets(string, size, stdin);
82 0 : } while (p == NULL);
83 :
84 0 : if (strlen(p) > 0 && p[strlen(p) - 1] == '\n')
85 0 : p[strlen(p) - 1] = 0;
86 0 : }
87 :
88 : /*------------------------------------------------------------------*/
89 :
90 : char request[600000], response[10000], content[600000];
91 :
92 0 : INT submit_elog(char *host, int port, char *experiment, char *passwd,
93 : char *uname, char *upwd,
94 : char attrib_name[MAX_N_ATTR][NAME_LENGTH],
95 : char attrib[MAX_N_ATTR][NAME_LENGTH],
96 : int n_attr,
97 : char *text,
98 : char afilename[MAX_ATTACHMENTS][256],
99 : char *buffer[MAX_ATTACHMENTS], INT buffer_size[MAX_ATTACHMENTS])
100 : /********************************************************************\
101 :
102 : Routine: submit_elog
103 :
104 : Purpose: Submit an ELog entry
105 :
106 : Input:
107 : char *host Host name where ELog server runs
108 : in port ELog server port number
109 : char *passwd Write password
110 : char *uname User name
111 : char *upwd User password
112 : int run Run number
113 : char *attrib_name Attribute names
114 : char *attrib Attribute values
115 : char *text Message text
116 :
117 : char afilename[] File names of attachments
118 : char *buffer[] Attachment contents
119 : INT buffer_size[] Size of buffer in bytes
120 :
121 : Function value:
122 : EL_SUCCESS Successful completion
123 :
124 : \********************************************************************/
125 : {
126 : int status, sock, i, n, header_length, content_length;
127 : struct hostent *phe;
128 : struct sockaddr_in bind_addr;
129 : char host_name[256], boundary[80], str[80], *p;
130 :
131 : #if defined( _MSC_VER )
132 : {
133 : WSADATA WSAData;
134 :
135 : /* Start windows sockets */
136 : if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
137 : return -1;
138 : }
139 : #endif
140 :
141 : /* get local host name */
142 0 : gethostname(host_name, sizeof(host_name));
143 :
144 0 : phe = gethostbyname(host_name);
145 0 : if (phe == NULL) {
146 0 : perror("Cannot retrieve host name");
147 0 : return -1;
148 : }
149 0 : phe = gethostbyaddr(phe->h_addr, sizeof(int), AF_INET);
150 0 : if (phe == NULL) {
151 0 : perror("Cannot retrieve host name");
152 0 : return -1;
153 : }
154 :
155 : /* if domain name is not in host name, hope to get it from phe */
156 0 : if (strchr(host_name, '.') == NULL)
157 0 : strcpy(host_name, phe->h_name);
158 :
159 : /* create socket */
160 0 : if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
161 0 : perror("cannot create socket");
162 0 : return -1;
163 : }
164 :
165 : /* compose remote address */
166 0 : memset(&bind_addr, 0, sizeof(bind_addr));
167 0 : bind_addr.sin_family = AF_INET;
168 0 : bind_addr.sin_addr.s_addr = 0;
169 0 : bind_addr.sin_port = htons((unsigned short) port);
170 :
171 0 : phe = gethostbyname(host);
172 0 : if (phe == NULL) {
173 0 : perror("cannot get host name");
174 0 : return -1;
175 : }
176 0 : memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
177 :
178 : /* connect to server */
179 0 : status = connect(sock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
180 0 : if (status != 0) {
181 0 : printf("Cannot connect to host %s, port %d\n", host, port);
182 0 : return -1;
183 : }
184 :
185 0 : if (verbose)
186 0 : printf("Successfully connected to host %s, port %d\n", host, port);
187 :
188 : /* compose content */
189 0 : strcpy(boundary, "---------------------------7d0bf1a60904bc");
190 0 : strcpy(content, boundary);
191 0 : strcat(content, "\r\nContent-Disposition: form-data; name=\"cmd\"\r\n\r\nSubmit\r\n");
192 :
193 0 : if (uname[0])
194 0 : snprintf(content + strlen(content), sizeof(content) - strlen(content),
195 : "%s\r\nContent-Disposition: form-data; name=\"unm\"\r\n\r\n%s\r\n",
196 : boundary, uname);
197 :
198 0 : if (upwd[0]) {
199 0 : base64_encode(upwd, str);
200 0 : snprintf(content + strlen(content), sizeof(content) - strlen(content),
201 : "%s\r\nContent-Disposition: form-data; name=\"upwd\"\r\n\r\n%s\r\n",
202 : boundary, str);
203 : }
204 :
205 0 : if (experiment[0])
206 0 : snprintf(content + strlen(content), sizeof(content) - strlen(content),
207 : "%s\r\nContent-Disposition: form-data; name=\"exp\"\r\n\r\n%s\r\n",
208 : boundary, experiment);
209 :
210 0 : for (i = 0; i < n_attr; i++)
211 0 : snprintf(content + strlen(content), sizeof(content) - strlen(content),
212 : "%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", boundary,
213 0 : attrib_name[i], attrib[i]);
214 :
215 0 : snprintf(content + strlen(content), sizeof(content) - strlen(content),
216 : "%s\r\nContent-Disposition: form-data; name=\"Text\"\r\n\r\n%s\r\n%s\r\n",
217 : boundary, text, boundary);
218 :
219 0 : content_length = strlen(content);
220 0 : p = content + content_length;
221 :
222 0 : for (i = 0; i < MAX_ATTACHMENTS; i++)
223 0 : if (afilename[i][0]) {
224 0 : snprintf(p, sizeof(content) - strlen(content),
225 : "Content-Disposition: form-data; name=\"attfile%d\"; filename=\"%s\"\r\n\r\n",
226 0 : i + 1, afilename[i]);
227 :
228 0 : content_length += strlen(p);
229 0 : p += strlen(p);
230 0 : memcpy(p, buffer[i], buffer_size[i]);
231 0 : p += buffer_size[i];
232 0 : strcpy(p, boundary);
233 0 : strcat(p, "\r\n");
234 :
235 0 : content_length += buffer_size[i] + strlen(p);
236 0 : p += strlen(p);
237 : }
238 :
239 : /* compose request */
240 0 : snprintf(request, sizeof(request), "POST /EL/ HTTP/1.0\r\n");
241 0 : snprintf(request + strlen(request), sizeof(request) - strlen(request),
242 : "Content-Type: multipart/form-data; boundary=%s\r\n", boundary);
243 0 : snprintf(request + strlen(request), sizeof(request) - strlen(request), "Host: %s\r\n", host_name);
244 0 : snprintf(request + strlen(request), sizeof(request) - strlen(request), "User-Agent: ELOG\r\n");
245 0 : snprintf(request + strlen(request), sizeof(request) - strlen(request), "Content-Length: %d\r\n", content_length);
246 :
247 0 : if (passwd[0]) {
248 0 : base64_encode(passwd, str);
249 0 : snprintf(request + strlen(request), sizeof(request) - strlen(request), "Cookie: elog_wpwd=%s\r\n", str);
250 : }
251 :
252 0 : strcat(request, "\r\n");
253 :
254 0 : header_length = strlen(request);
255 0 : memcpy(request + header_length, content, content_length);
256 :
257 : /*
258 : {
259 : FILE *f;
260 : f = fopen("elog.log", "w");
261 : fwrite(request, header_length+content_length, 1, f);
262 : fclose(f);
263 : }
264 : */
265 :
266 : /* send request */
267 0 : if (verbose) {
268 0 : printf("Request sent to host:\n");
269 0 : puts(request);
270 : }
271 :
272 0 : send(sock, request, header_length + content_length, 0);
273 :
274 : /* receive response */
275 0 : i = recv(sock, response, 10000, 0);
276 0 : if (i < 0) {
277 0 : perror("Cannot receive response");
278 0 : return -1;
279 : }
280 :
281 : /* discard remainder of response */
282 0 : n = i;
283 0 : while (i > 0) {
284 0 : i = recv(sock, response + n, 10000, 0);
285 0 : if (i > 0)
286 0 : n += i;
287 : }
288 0 : response[n] = 0;
289 :
290 0 : closesocket(sock);
291 :
292 0 : if (verbose) {
293 0 : printf("Response received:\n");
294 0 : puts(response);
295 : }
296 :
297 : /* check response status */
298 0 : if (strstr(response, "302 Found"))
299 0 : printf("Message successfully transmitted\n");
300 0 : else if (strstr(response, "Logbook Selection"))
301 0 : printf("No logbook specified\n\n");
302 0 : else if (strstr(response, "Enter password"))
303 0 : printf("Missing or invalid password\n");
304 0 : else if (strstr(response, "login"))
305 0 : printf("Missing or invalid user name/password\n");
306 : else
307 0 : printf("Error transmitting message\n");
308 :
309 0 : return 1;
310 : }
311 :
312 : /*------------------------------------------------------------------*/
313 :
314 0 : int main(int argc, char *argv[])
315 : {
316 : char str[1000], text[10000], uname[80], upwd[80];
317 : char host_name[256], logbook[32], textfile[256], password[80];
318 : char *buffer[MAX_ATTACHMENTS], attachment[MAX_ATTACHMENTS][256];
319 : INT att_size[MAX_ATTACHMENTS];
320 : INT i, n, fh, n_att, n_attr, size, port;
321 : char attr_name[MAX_N_ATTR][NAME_LENGTH], attrib[MAX_N_ATTR][NAME_LENGTH];
322 :
323 0 : text[0] = textfile[0] = uname[0] = upwd[0] = 0;
324 0 : host_name[0] = logbook[0] = password[0] = n_att = n_attr = 0;
325 0 : port = 80;
326 0 : for (i = 0; i < MAX_ATTACHMENTS; i++) {
327 0 : attachment[i][0] = 0;
328 0 : buffer[i] = NULL;
329 0 : att_size[i] = 0;
330 : }
331 :
332 : /* parse command line parameters */
333 0 : for (i = 1; i < argc; i++) {
334 0 : if (argv[i][0] == '-' && argv[i][1] == 'v')
335 0 : verbose = 1;
336 : else {
337 0 : if (argv[i][0] == '-') {
338 0 : if (i + 1 >= argc || argv[i + 1][0] == '-')
339 0 : goto usage;
340 0 : if (argv[i][1] == 'h')
341 0 : strcpy(host_name, argv[++i]);
342 0 : else if (argv[i][1] == 'p')
343 0 : port = atoi(argv[++i]);
344 0 : else if (argv[i][1] == 'l')
345 0 : strcpy(logbook, argv[++i]);
346 0 : else if (argv[i][1] == 'w')
347 0 : strcpy(password, argv[++i]);
348 0 : else if (argv[i][1] == 'u') {
349 0 : strcpy(uname, argv[++i]);
350 0 : strcpy(upwd, argv[++i]);
351 0 : } else if (argv[i][1] == 'a') {
352 0 : strcpy(str, argv[++i]);
353 0 : if (strchr(str, '=')) {
354 0 : strcpy(attrib[n_attr], strchr(str, '=') + 1);
355 0 : *strchr(str, '=') = 0;
356 0 : strcpy(attr_name[n_attr], str);
357 0 : n_attr++;
358 : } else {
359 : printf
360 0 : ("Error: Attributes must be supplied in the form \"-a <attribute>=<value>\".\n");
361 0 : return 0;
362 : }
363 0 : } else if (argv[i][1] == 'f')
364 0 : strcpy(attachment[n_att++], argv[++i]);
365 0 : else if (argv[i][1] == 'm')
366 0 : strcpy(textfile, argv[++i]);
367 : else {
368 0 : usage:
369 0 : printf("\nusage: elog -h <hostname> [-p port]\n");
370 0 : printf(" [-l logbook/experiment]\n");
371 0 : printf(" [-v] for verbose output\n");
372 : printf
373 0 : (" [-w password] write password defined on server\n");
374 0 : printf(" [-u username password] user name and password\n");
375 0 : printf(" [-f <attachment>] (up to %d times)\n",
376 : MAX_ATTACHMENTS);
377 0 : printf(" -a <attribute>=<value> (up to %d times)\n",
378 : MAX_N_ATTR);
379 0 : printf(" -m <textfile>] | <text>\n");
380 0 : printf("\nArguments with blanks must be enclosed in quotes\n");
381 0 : printf("The elog message can either be submitted on the command line\n");
382 : printf
383 0 : ("or in a file with the -m flag. Multiple attributes and attachments\n");
384 0 : printf("can be supplied\n");
385 0 : return 0;
386 : }
387 : } else
388 0 : strcpy(text, argv[i]);
389 : }
390 : }
391 :
392 0 : if (host_name[0] == 0 || n_attr == 0 || (text[0] == 0 && textfile[0] == 0))
393 0 : goto usage;
394 :
395 : /*---- open text file ----*/
396 :
397 0 : if (textfile[0]) {
398 0 : fh = open(textfile, O_RDONLY | O_BINARY);
399 0 : if (fh < 0) {
400 0 : printf("Message file \"%s\" does not exist.\n", textfile);
401 0 : return 0;
402 : }
403 :
404 0 : size = lseek(fh, 0, SEEK_END);
405 0 : lseek(fh, 0, SEEK_SET);
406 :
407 0 : if (size > (int)sizeof(text) - 1) {
408 0 : printf("Message file \"%s\" is too long (%d bytes max).\n", textfile,
409 : (int)sizeof(text));
410 0 : return 0;
411 : }
412 :
413 0 : memset(text, 0, sizeof(text));
414 0 : i = read(fh, text, size);
415 0 : if (i < size) {
416 0 : printf("Cannot fully read message file \"%s\".\n", textfile);
417 0 : return 0;
418 : }
419 :
420 0 : close(fh);
421 : }
422 :
423 : /*---- open attachment file ----*/
424 :
425 0 : for (i = 0; i < MAX_ATTACHMENTS; i++) {
426 0 : if (!attachment[i][0])
427 0 : break;
428 :
429 0 : fh = open(attachment[i], O_RDONLY | O_BINARY);
430 0 : if (fh < 0) {
431 0 : printf("Attachment file \"%s\" does not exist.\n", attachment[i]);
432 0 : return 0;
433 : }
434 :
435 0 : att_size[i] = lseek(fh, 0, SEEK_END);
436 0 : lseek(fh, 0, SEEK_SET);
437 :
438 0 : buffer[i] = (char*)malloc(att_size[i] + 1);
439 0 : if (buffer[i] == NULL || att_size[i] > 500 * 1024) {
440 0 : printf("Attachment file \"%s\" is too long (500k max).\n", attachment[i]);
441 0 : return 0;
442 : }
443 :
444 0 : n = read(fh, buffer[i], att_size[i]);
445 0 : if (n < att_size[i]) {
446 0 : printf("Cannot fully read attachment file \"%s\".\n", attachment[i]);
447 0 : return 0;
448 : }
449 0 : buffer[i][n] = 0;
450 :
451 0 : close(fh);
452 : }
453 :
454 : /* now submit message */
455 0 : submit_elog(host_name, port, logbook, password,
456 : uname, upwd,
457 : attr_name, attrib, n_attr, text, attachment, buffer, att_size);
458 :
459 0 : for (i = 0; i < MAX_ATTACHMENTS; i++)
460 0 : if (buffer[i])
461 0 : free(buffer[i]);
462 :
463 0 : return 1;
464 : }
|