/********************************************************************\ Name: elog.c Created by: Stefan Ritt Contents: Electronic logbook utility $Log$ Revision 1.10 2003/07/15 12:17:45 midas Removed BOOL Revision 1.9 2003/07/15 12:17:13 midas Removed FALSE/TRUE Revision 1.8 2003/07/15 12:16:52 midas Removed FALSE/TRUE Revision 1.7 2003/07/15 11:19:45 midas Added -e flag, reply now quotes original text Revision 1.6 2003/06/25 15:25:13 midas Fixed bug with 'reply_to' Revision 1.5 2003/06/05 07:16:36 midas Creat boundary randomly Revision 1.4 2003/06/04 14:26:59 midas elog utility can read text from stdin Revision 1.3 2003/06/03 13:18:00 midas Fixed bug in base64_encode Revision 1.2 2003/03/01 16:07:02 midas Show error if wrong username/password Revision 1.1 2003/01/30 14:45:07 midas Moved files to src/ subdirectory Revision 1.10 2002/10/14 08:26:26 midas Made attachment size variable Revision 1.9 2002/08/02 11:01:34 midas Added -r for replies Revision 1.8 2002/07/23 11:31:08 midas Fixed problems with password cookie Revision 1.7 2002/07/08 08:39:38 midas Fixed return code Revision 1.6 2002/06/12 07:52:41 midas Increased text size Revision 1.5 2002/06/11 12:01:45 midas Added -s for subdirectory Revision 1.4 2002/02/25 15:28:01 midas Require -l flag, output better error messages Revision 1.3 2001/12/21 15:28:51 midas Initial version as separate package, corresponds to V1.3.2 \********************************************************************/ #include #include #include #include #include #include #include #ifdef _MSC_VER #include #include #else #include #include #include #include #include #include #define closesocket(s) close(s) #ifndef O_BINARY #define O_BINARY 0 #endif #endif typedef int INT; #define MAX_ATTACHMENTS 50 #define NAME_LENGTH 500 #define MAX_N_ATTR 50 #define TEXT_SIZE 100000 int verbose; char text[TEXT_SIZE], old_text[TEXT_SIZE], new_text[TEXT_SIZE]; /*------------------------------------------------------------------*/ char *map= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; void base64_encode(char *s, char *d) { unsigned int t, pad; pad = 3 - strlen(s) % 3; if (pad == 3) pad = 0; while (*s) { t = (*s++) << 16; if (*s) t |= (*s++) << 8; if (*s) t |= (*s++) << 0; *(d+3) = map[t & 63]; t >>= 6; *(d+2) = map[t & 63]; t >>= 6; *(d+1) = map[t & 63]; t >>= 6; *(d+0) = map[t & 63]; d += 4; } *d = 0; while (pad--) *(--d) = '='; } /*---- string comparison -------------------------------------------*/ int equal_ustring(char *str1, char *str2) { if (str1 == NULL && str2 != NULL) return 0; if (str1 != NULL && str2 == NULL) return 0; if (str1 == NULL && str2 == NULL) return 1; while (*str1) if (toupper(*str1++) != toupper(*str2++)) return 0; if (*str2) return 0; return 1; } /*---- strlcpy and strlcat to avoid buffer overflow ----------------*/ /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless size == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t size) { char *d = dst; const char *s = src; size_t n = size; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (size != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++); } return (s - src - 1); /* count does not include NUL */ } /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless size <= strlen(dst)). * Returns strlen(src) + MIN(size, strlen(initial dst)). * If retval >= size, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t size) { char *d = dst; const char *s = src; size_t n = size; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = size - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } /*------------------------------------------------------------------*/ void sgets(char *string, int size) { char *p; do { p = fgets(string, size, stdin); } while (p == NULL); if (strlen(p) > 0 && p[strlen(p)-1] == '\n') p[strlen(p)-1] = 0; } /*------------------------------------------------------------------*/ char request[100000], response[100000], *content; INT retrieve_elog(char *host, int port, char *subdir, char *experiment, char *passwd, char *uname, char *upwd, int message_id, char attrib_name[MAX_N_ATTR][NAME_LENGTH], char attrib[MAX_N_ATTR][NAME_LENGTH], char *text) /********************************************************************\ Routine: retrive_elog Purpose: Retrive an ELog entry for edit/reply Input: char *host Host name where ELog server runs in port ELog server port number char *subdir Subdirectoy to elog server char *passwd Write password char *uname User name char *upwd User password int message_id Message to retrieve char *attrib_name Attribute names char *attrib Attribute values char *text Message text Function value: EL_SUCCESS Successful completion \********************************************************************/ { int status, sock, i, n, first, index; struct hostent *phe; struct sockaddr_in bind_addr; char host_name[256], str[80], *ph, *ps; #if defined( _MSC_VER ) { WSADATA WSAData; /* Start windows sockets */ if ( WSAStartup(MAKEWORD(1,1), &WSAData) != 0) return -1; } #endif /* get local host name */ gethostname(host_name, sizeof(host_name)); phe = gethostbyname(host_name); if (phe == NULL) { perror("Cannot retrieve host name"); return -1; } phe = gethostbyaddr(phe->h_addr, sizeof(int), AF_INET); if (phe == NULL) { perror("Cannot retrieve host name"); return -1; } /* if domain name is not in host name, hope to get it from phe */ if (strchr(host_name, '.') == NULL) strcpy(host_name, phe->h_name); /* create socket */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("cannot create socket"); return -1; } /* compose remote address */ memset(&bind_addr, 0, sizeof(bind_addr)); bind_addr.sin_family = AF_INET; bind_addr.sin_addr.s_addr = 0; bind_addr.sin_port = htons((unsigned short)port); phe = gethostbyname(host); if (phe == NULL) { perror("cannot get host name"); return -1; } memcpy((char *)&(bind_addr.sin_addr), phe->h_addr, phe->h_length); /* connect to server */ status = connect(sock, (void *) &bind_addr, sizeof(bind_addr)); if (status != 0) { printf("Cannot connect to host %s, port %d\n", host, port); return -1; } if (verbose) printf("Successfully connected to host %s, port %d\n", host, port); /* compose request */ strcpy(request, "GET /"); if (subdir[0]) sprintf(request+strlen(request), "%s/%d?cmd=download", subdir, message_id); if (experiment[0]) sprintf(request+strlen(request), "%s/%d?cmd=download", experiment, message_id); strcat(request, " HTTP/1.0\r\n"); sprintf(request+strlen(request), "Host: %s\r\n", host_name); sprintf(request+strlen(request), "User-Agent: ELOG\r\n"); first = 1; if (passwd[0]) { if (first) sprintf(request+strlen(request), "Cookie: "); first = 0; base64_encode(passwd, str); sprintf(request+strlen(request), "wpwd=%s;", str); } if (uname[0]) { if (first) sprintf(request+strlen(request), "Cookie: "); first = 0; sprintf(request+strlen(request), "unm=%s;", uname); } if (upwd[0]) { if (first) sprintf(request+strlen(request), "Cookie: "); first = 0; base64_encode(upwd, str); sprintf(request+strlen(request), "upwd=%s;", str); } /* finish cookie line */ if (!first) strcat(request, "\r\n"); strcat(request, "\r\n"); /* send request */ send(sock, request, strlen(request), 0); if (verbose) { printf("Request sent to host:\n"); puts(request); } /* receive response */ i = recv(sock, response, sizeof(response), 0); if (i < 0) { perror("Cannot receive response"); return -1; } n = i; while (i > 0) { i = recv(sock, response+n, sizeof(response)-n, 0); if (i > 0) n += i; } response[n] = 0; closesocket(sock); if (verbose) { printf("Response received:\n"); puts(response); } /* check response status */ if (strstr(response, "$@MID@$:")) { /* separate attributes and message */ ph = strstr(response, "========================================\n"); /* skip first line */ ps = strstr(response, "$@MID@$:"); while (*ps && *ps != '\n') ps++; while (*ps && (*ps == '\n' || *ps == '\r')) ps++; for (index = 0; index= ph) break; strlcpy(attrib_name[index], ps, NAME_LENGTH); if (strchr(attrib_name[index], ':')) *(strchr(attrib_name[index], ':')) = 0; ps += strlen(attrib_name[index])+2; strlcpy(attrib[index], ps, NAME_LENGTH); for (i=0 ; i " */ text[0] = 0; p = old_text; do { if (strchr(p, '\n')) { *strchr(p, '\n') = 0; if (encoding[0] == 'H') { strlcat(text, "> ", TEXT_SIZE); strlcat(text, p, TEXT_SIZE); strlcat(text, "
\n", TEXT_SIZE); } else { strlcat(text, "> ", TEXT_SIZE); strlcat(text, p, TEXT_SIZE); strlcat(text, "\n", TEXT_SIZE); } p += strlen(p)+1; if (*p == '\n') p++; } else { if (encoding[0] == 'H') { strlcat(text, "> ", TEXT_SIZE); strlcat(text, p, TEXT_SIZE); strlcat(text, "

\n", TEXT_SIZE); } else { strlcat(text, "> ", TEXT_SIZE); strlcat(text, p, TEXT_SIZE); strlcat(text, "\n\n", TEXT_SIZE); } break; } } while (1); strlcat(text, new_text, TEXT_SIZE); } /* get local host name */ gethostname(host_name, sizeof(host_name)); phe = gethostbyname(host_name); if (phe == NULL) { perror("Cannot retrieve host name"); return -1; } phe = gethostbyaddr(phe->h_addr, sizeof(int), AF_INET); if (phe == NULL) { perror("Cannot retrieve host name"); return -1; } /* if domain name is not in host name, hope to get it from phe */ if (strchr(host_name, '.') == NULL) strcpy(host_name, phe->h_name); /* create socket */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("cannot create socket"); return -1; } /* compose remote address */ memset(&bind_addr, 0, sizeof(bind_addr)); bind_addr.sin_family = AF_INET; bind_addr.sin_addr.s_addr = 0; bind_addr.sin_port = htons((unsigned short)port); phe = gethostbyname(host); if (phe == NULL) { perror("cannot get host name"); return -1; } memcpy((char *)&(bind_addr.sin_addr), phe->h_addr, phe->h_length); /* connect to server */ status = connect(sock, (void *) &bind_addr, sizeof(bind_addr)); if (status != 0) { printf("Cannot connect to host %s, port %d\n", host, port); return -1; } if (verbose) printf("Successfully connected to host %s, port %d\n", host, port); content_length = 100000; for (i=0 ; i 0) { i = recv(sock, response+n, 10000, 0); if (i > 0) n += i; } response[n] = 0; closesocket(sock); if (verbose) { printf("Response received:\n"); puts(response); } /* check response status */ if (strstr(response, "302 Found")) { if (strstr(response, "Location:")) { if (strstr(response, "wpwd")) printf("Error: Invalid password\n"); else if (strstr(response, "wusr")) printf("Error: Invalid user name\n"); else { strncpy(str, strstr(response, "Location:")+10, sizeof(str)); if (strchr(str, '?')) *strchr(str, '?') = 0; if (strchr(str, '\n')) *strchr(str, '\n') = 0; if (strchr(str, '\r')) *strchr(str, '\r') = 0; if (strrchr(str, '/')) printf("Message successfully transmitted, ID=%s\n", strrchr(str, '/')+1); else printf("Message successfully transmitted, ID=%s\n", str); } } else printf("Message successfully transmitted\n"); } else if (strstr(response, "Logbook Selection")) printf("Error: No logbook specified\n"); else if (strstr(response, "enter password")) printf("Error: Missing or invalid password\n"); else if (strstr(response, "form name=form1")) printf("Error: Missing or invalid user name/password\n"); else if (strstr(response, "Error: Attribute")) { strncpy(str, strstr(response, "Error: Attribute")+20, sizeof(str)); if (strchr(str, '<')) *strchr(str, '<') = 0; printf("Error: Missing required attribute \"%s\"\n", str); } else printf("Error transmitting message\n"); return 1; } /*------------------------------------------------------------------*/ int main(int argc, char *argv[]) { char str[1000], uname[80], upwd[80]; char host_name[256], logbook[32], textfile[256], password[80], subdir[256]; char *buffer[MAX_ATTACHMENTS], attachment[MAX_ATTACHMENTS][256]; INT att_size[MAX_ATTACHMENTS]; INT i, n, fh, n_att, n_attr, size, port, reply, edit; char attr_name[MAX_N_ATTR][NAME_LENGTH], attrib[MAX_N_ATTR][NAME_LENGTH]; text[0] = textfile[0] = uname[0] = upwd[0] = 0; host_name[0] = logbook[0] = password[0] = subdir[0] = n_att = n_attr = reply = edit = 0; port = 80; for (i=0 ; i= argc || argv[i+1][0] == '-') goto usage; if (argv[i][1] == 'h') strcpy(host_name, argv[++i]); else if (argv[i][1] == 'p') port = atoi(argv[++i]); else if (argv[i][1] == 'l') strcpy(logbook, argv[++i]); else if (argv[i][1] == 'w') strcpy(password, argv[++i]); else if (argv[i][1] == 's') strcpy(subdir, argv[++i]); else if (argv[i][1] == 'u') { strcpy(uname, argv[++i]); strcpy(upwd, argv[++i]); } else if (argv[i][1] == 'a') { strcpy(str, argv[++i]); if (strchr(str, '=')) { strcpy(attrib[n_attr], strchr(str, '=')+1); *strchr(str, '=') = 0; strcpy(attr_name[n_attr], str); n_attr++; } else { printf("Error: Attributes must be supplied in the form \"-a =\".\n"); return 1; } } else if (argv[i][1] == 'f') strcpy(attachment[n_att++], argv[++i]); else if (argv[i][1] == 'r') reply = atoi(argv[++i]); else if (argv[i][1] == 'e') edit = atoi(argv[++i]); else if (argv[i][1] == 'm') strcpy(textfile, argv[++i]); else { usage: printf("\nusage: elog\n"); printf(" -h [-p port] [-s subdir]\n"); printf(" Location where elogd is running\n"); printf(" -l logbook/experiment Name of logbook or experiment\n"); printf(" [-v] for verbose output\n"); printf(" [-w password] write password defined on server\n"); printf(" [-u username password] user name and password\n"); printf(" [-f ] (up to %d times)\n", MAX_ATTACHMENTS); printf(" -a = (up to %d times)\n", MAX_N_ATTR); printf(" [-r ] Reply to existing message\n"); printf(" [-e ] Edit existing message\n"); printf(" -m ] | \n"); printf("\nArguments with blanks must be enclosed in quotes\n"); printf("The elog message can either be submitted on the command line, piped in like\n"); printf("\"cat text | elog -h ... -l ... -a ...\" or in a file with the -m flag.\n"); printf("Multiple attributes and attachments can be supplied\n"); return 1; } } else strcpy(text, argv[i]); } } if (host_name[0] == 0) { printf("Please specify hostname.\n"); return 1; } if (logbook[0] == 0) { printf("Please specify logbook with the \"-l\" flag.\n"); return 1; } if (n_attr == 0 && !edit && !reply) { printf("Please specify attribute(s) with the \"-a\" flag.\n"); return 1; } fh = -1; if (textfile[0]) { fh = open(textfile, O_RDONLY | O_BINARY); if (fh < 0) { printf("Message file \"%s\" does not exist.\n", textfile); return 1; } size = lseek(fh, 0, SEEK_END); lseek(fh, 0, SEEK_SET); if (size > sizeof(text)-1) { printf("Message file \"%s\" is too long (%d bytes max).\n", textfile, sizeof(text)); return 1; } i = read(fh, text, size); if (i < size) { printf("Cannot fully read message from file %s.\n", textfile); return 1; } close(fh); } if (text[0] == 0 && textfile[0] == 0 && !edit) { /* read from stdin */ n = 0; do { i = getchar(); text[n++] = i; } while (i != EOF); if (n>0) text[n-1] = 0; } /*---- open attachment file ----*/ for (i = 0 ; i