/* * This file is provided for unrestricted use * provided that this legend is included on all tape media * and as a part of the software program in whole or part. Users * may copy or modify this file without charge, but are not authorized to * license or distribute it to anyone else except as part of a product * or program developed by the user. * * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * This file is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even * if Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ #include #include #include #include #ifdef SVR4 #include #include #endif #ifdef linux #include #endif #include #include #include #define _OTHER_TEXTSW_FUNCTIONS /* For additional defines in textsw.h */ #include #include #include #include #include #include #include #include #include "xvnews_ui.h" #include "xvnews.h" #include "codes.h" #include "patchlevel.h" extern struct globals *Global; STATIC_FUNCTION( int checkHeader, (xvnews_post_popup_objects *, char *, char *)); STATIC_FUNCTION( int confirm_cancel, (xvnews_post_popup_objects *)); #ifndef USE_INEWS_TO_POST STATIC_FUNCTION( void errorPost, (xvnews_post_popup_objects *, char *)); #endif STATIC_FUNCTION( char *replyAuthor, (xvnews_xvnews_window_objects *)); extern void get_news_header(ip, flg) xvnews_post_popup_objects *ip; int flg; { char *head, *sig; char file1[128]; Textsw_index point; xvnews_xvnews_window_objects *bp = (xvnews_xvnews_window_objects *) xv_get(ip->post_popup, XV_KEY_DATA, POST_PARENT, NULL); xv_set(ip->post_window, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, TEXTSW_LOWER_CONTEXT, -1, NULL); head = newsHead(bp, flg, &point); textsw_insert(ip->post_window, head, strlen(head)); #ifdef ADD_SIGNATURE sprintf(file1, "%s/.signature", Global->home); if (Global->group) { char file2[128]; sprintf(file2, "%s/%s/.signature", Global->newsdir, groupDir(Global->group->newsgroup)); sig = addSignature(file1, file2); } else sig = addSignature(file1, NULL); #else sig = NULL; #endif if (sig != NULL) { textsw_insert(ip->post_window, sig, strlen(sig)); free(sig); } xv_set(ip->post_window, TEXTSW_INSERTION_POINT, point - 1, TEXTSW_LOWER_CONTEXT, 0, NULL); } extern int headToFile(head, file) char *head, *file; { FILE *ifp_out; if ((ifp_out = fopen(file, "a")) == NULL) return -1; fprintf(ifp_out, "%s", head); fclose(ifp_out); return 0; } extern void get_mail_header(ip, flg) xvnews_post_popup_objects *ip; int flg; { char buff[256], *head; char *indent, *old, *err; char file[128], *sig = NULL; int art; Textsw_index point; xvnews_xvnews_window_objects *bp = (xvnews_xvnews_window_objects *) xv_get(ip->post_popup, XV_KEY_DATA, POST_PARENT, NULL); xvnews_props_objects *prp = (xvnews_props_objects *)xv_get(bp->xvnews_window, XV_KEY_DATA, PROPS_POPUP, NULL); head = mailHead(bp, flg, (int *)&point); textsw_insert(ip->post_window, head, strlen(head)); xv_set(ip->post_window, TEXTSW_INSERTION_POINT, point - 1, NULL); #ifdef ADD_SIGNATURE sprintf(file, "%s/.signature", Global->home); sig = addSignature(file, NULL); #endif if (flg == MAIL_FORWARD) { if (getenv("NO_ARTICLE_ID")) sprintf(buff, "In %s, %s writes:\n", Global->group->newsgroup, (char *)currentAuthor(0)); else sprintf(buff, "In article <%s>, %s writes:\n", get_messageid(0), (char *)currentAuthor(0)); textsw_insert(ip->post_window, buff, strlen(buff)); old = (char *)xv_get(bp->articles_list, PANEL_LIST_STRING, xv_get(bp->articles_list, PANEL_LIST_FIRST_SELECTED), NULL); sscanf(old, "%d", &art); indent = (char *)xv_get(prp->indent_text, PANEL_VALUE, NULL); if ((err = include_news(art, "/tmp/.xvnews.include", indent)) != NULL) xv_set(ip->post_window, FRAME_LEFT_FOOTER, err, NULL); else { xv_set(ip->post_window, TEXTSW_LOWER_CONTEXT, -1, NULL); xv_set(ip->post_window, TEXTSW_INSERT_FROM_FILE, "/tmp/.xvnews.include", NULL); xv_set(ip->post_window, TEXTSW_LOWER_CONTEXT, 0, NULL); unlink("/tmp/.xvnews.include"); if (sig != NULL) textsw_insert(ip->post_window, sig, strlen(sig)); xv_set(ip->post_window, TEXTSW_INSERTION_POINT, 4, NULL); } } else if (sig != NULL) { textsw_insert(ip->post_window, sig, strlen(sig)); xv_set(ip->post_window, TEXTSW_INSERTION_POINT, point - 1, NULL); } if (sig != NULL) free(sig); xv_set(ip->post_window, TEXTSW_LOWER_CONTEXT, 0, NULL); textsw_normalize_view(ip->post_window, 0); } extern char * mailHead(ip, flg, point) xvnews_xvnews_window_objects *ip; int flg; int *point; { static char header[2048]; char *subject; subject = (char *)currentSubject(ip, xv_get(ip->articles_list, PANEL_LIST_FIRST_SELECTED)); if (flg == MAIL_REPLY) { if (toupper(subject[0]) == 'R' && toupper(subject[1]) == 'E' && subject[2] == ':') sprintf(header, "To: %s\nSubject: Re:%s\nCc: \n\n\n", replyAuthor(ip), &subject[3]); else sprintf(header, "To: %s\nSubject: Re: %s\nCc: \n\n\n", replyAuthor(ip), subject); } else sprintf(header, "To: \nSubject: %s\nCc: \n\n\n", subject); *point = strlen(header); return header; } char * getname(engr) char *engr; { static char fullname[64]; char *a; struct passwd *pw; if (getenv("NAME") != NULL) return (char *)getenv("NAME"); if ((pw = getpwnam(engr)) == NULL) strcpy(fullname,""); else strncpy(fullname, pw->pw_gecos, 63); if ((a = strchr(fullname, '&')) != NULL) { strcpy(a, (char *)cuserid(NULL)); a = (char *)strstr(fullname, (char *)cuserid(NULL)); *a = toupper(*a); } if ((a = strchr(fullname, ',')) != NULL) *a = '\0'; return(fullname); } static int confirm_cancel(pp) xvnews_post_popup_objects *pp; { return notice_prompt(pp->post_controls, NULL, NOTICE_MESSAGE_STRINGS, "Do you really want to cancel?", NULL, NOTICE_BUTTON_YES, "Cancel Post", NOTICE_BUTTON_NO, "Abort Cancel", NULL); } extern void cancel_message(ip) xvnews_post_popup_objects *ip; { int result; result = confirm_cancel(ip); if (!result) return; xv_destroy_safe(ip->post_popup); } extern void deliver_message(ip) xvnews_post_popup_objects *ip; { char *mbuf; int i, lines, post; Textsw_index len; FILE *pipe; #ifdef USE_INEWS_TO_POST #else static char message[MAX_MESSAGE_LEN]; int result; #endif xvnews_xvnews_window_objects *bp = (xvnews_xvnews_window_objects *) xv_get(ip->post_popup, XV_KEY_DATA, POST_PARENT, NULL); xv_set(ip->post_window, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, NULL); len = (Textsw_index)xv_get(ip->post_window, TEXTSW_INSERTION_POINT); if (len > 0) { if ((mbuf = (char *)malloc(len+8)) == NULL) { xvnews_err(bp, "Malloc failed for posting!\n"); return; } memset(mbuf, '\0', len+1); len = (Textsw_index)xv_get(ip->post_window, TEXTSW_CONTENTS, 0, mbuf, len); if (len > 0) { i = strlen(mbuf); post = xv_get(ip->post_popup, XV_KEY_DATA, POST_TYPE); if (post == NEWS_POST || post == NEWS_REPLY) { if (checkHeader(ip, mbuf, "Newsgroups") || checkHeader(ip, mbuf, "Subject")) { window_bell(ip->post_popup); free(mbuf); return; } lines = textsw_file_line_count(ip->post_window, mbuf); mbuf = checkPeriods(mbuf, lines); #ifdef USE_INEWS_TO_POST if ((pipe = popen(INEWS_PROGRAM, "w")) == NULL) { xvnews_err(bp, "Couldn't open a pipe to inews!\n"); free(mbuf); return; } fprintf(pipe, "%s\n", mbuf); pclose(pipe); xvnews_err(bp, "Article passed to Inews for posting ...\n"); #else put_server("POST"); result = get_server(message, sizeof(message)); if (result != CONT_POST) { reconnect_server(); put_server("POST"); result = get_server(message, sizeof(message)); if (result != CONT_POST) { xv_set(ip->post_popup, FRAME_LEFT_FOOTER, "Posting not allowed!\n", NULL); window_bell(ip->post_popup); free(mbuf); return; } } put_server("%s", mbuf); put_server("\n.\n"); result = get_server(message, sizeof(message)); if (result != POSTED_OK) { if (result != ERR_POSTFAIL) { reconnect_server(); put_server("POST"); get_server(message, sizeof(message)); put_server("%s", mbuf); put_server("\n.\n"); result = get_server(message, sizeof(message)); } if (result != POSTED_OK) { errorPost(ip, message); free(mbuf); return; } } xvnews_err(bp, "Article Posted\n"); #endif /* USE_INEWS_TO_POST */ filePost(ip, bp, mbuf); } else { if ((pipe = popen(MAIL_PROGRAM, "w")) == NULL) { xvnews_err(bp, "Couldn't open a mail pipe!\n"); free(mbuf); return; } fprintf(pipe, "%s\n", mbuf); xvnews_err(bp, "Mail sent\n"); pclose(pipe); } } free(mbuf); } textsw_reset(ip->post_window, 0, 0); xv_destroy_safe(ip->post_popup); } extern char * include_news(art, file, indent) int art; char *file, *indent; { static char article[MAX_ARTICLE_LEN]; int status; FILE *ifp_out; if ((ifp_out = fopen(file, "a")) == NULL) { sprintf(article, "Unable to open file %s!\n", file); return article; } put_server("BODY"); status = get_server(article, sizeof(article)); if (status != OK_BODY) { reconnect_server(); put_server("BODY %d", art); status = get_server(article, sizeof(article)); if (status != OK_BODY) return "Cannot include article, news server problems!\n"; } for (;;) { get_server(article, sizeof(article)); if (article[0] == '.' && article[1] == '\0') break; else fprintf(ifp_out, "%s%s\n", indent, article); } fprintf(ifp_out, "\n"); fclose(ifp_out); return NULL; } extern char * get_messageid() { char *c, article[MAX_ARTICLE_LEN]; static char number[80]; int status; put_server("STAT"); status = get_server(article, sizeof(article)); if (status != OK_NOTEXT) { reconnect_server(); put_server("STAT %d", Global->article); status = get_server(article, sizeof(article)); if (status != OK_NOTEXT) return NULL; } c = strchr(article, '<'); sscanf(++c, "%[^>]s", number); return number; } /* * This function retrieves the article-number from the currently * selected group. */ STATIC int get_art_num(ip) xvnews_xvnews_window_objects *ip; { int row; char *str; int art; row = (int)xv_get(ip->articles_list, PANEL_LIST_FIRST_SELECTED, NULL); str = (char *)xv_get(ip->articles_list, PANEL_LIST_STRING, row, NULL); sscanf(str, "%d", &art); return art; } STATIC char *get_header_field(fieldname, art) char *fieldname; int art; { char message[MAX_MESSAGE_LEN]; static char *c, follow[MAX_MESSAGE_LEN]; int status; assert( fieldname ); assert( art > 0 ); put_server("XHDR %s %d", fieldname, art); status = get_server(message, sizeof(message)); if (status != OK_HEAD) { reconnect_server(); return NULL; } strcpy(follow, "(none)"); while(*message != '.') { get_server(message, sizeof(message)); if (*message != '.') strcpy(follow, message); } if (strstr(follow, "(none)")) { return NULL; } /* TODO: poster should be handeld properly! For now I ignore it... Should only be handled in Followup-To: */ c = follow; while (isdigit(*c)) c++; while (*c == ' ') c++; return c; } extern void includeFile(win, file) Xv_window win; char *file; { char str[256], name[256]; int result, i = strlen(file), lines = textsw_file_line_count(win, NULL); int size = 0; xvnews_post_popup_objects *ip = (xvnews_post_popup_objects *) xv_get(xv_get(win, XV_OWNER, NULL), XV_KEY_DATA, INSTANCE, NULL); xvnews_xvnews_window_objects *bp = (xvnews_xvnews_window_objects *) xv_get(ip->post_popup, XV_KEY_DATA, POST_PARENT, NULL); struct stat statbuf; if (stat(file, &statbuf)) { xvnews_err(bp, "%s: No such file!\n", file); return; } sprintf(str, "Would you like %s", file); result = notice_prompt(win, NULL, NOTICE_MESSAGE_STRINGS, str, "loaded as text or uuencoded?", NULL, NOTICE_BUTTON, "text", 101, NOTICE_BUTTON, "compress & uuencode", 102, NOTICE_BUTTON, "uuencode", 103, NOTICE_BUTTON, "cancel", 104, NULL); while(file[i] != '/') --i; strncpy(name, &file[i+1], strlen(file)); switch (result) { case 101: strcpy(str, file); size = statbuf.st_size; break; case 102: sprintf(str, "%s -c %s | /usr/bin/uuencode %s.%s > /tmp/xvnews.uu\n", COMPRESS_PROGRAM, file, name, COMPRESS_EXTENSION); system(str); strcpy(str, "/tmp/xvnews.uu"); if (!stat(str, &statbuf)) size = statbuf.st_size; break; case 103: sprintf(str, "/usr/bin/uuencode %s %s > /tmp/xvnews.uu\n", file, name); system(str); strcpy(str, "/tmp/xvnews.uu"); if (!stat(str, &statbuf)) size = statbuf.st_size; break; default: return; } xv_set(win, TEXTSW_INSERT_FROM_FILE, str, NULL); unlink("/tmp/xvnews.uu"); sprintf(name, "Loaded %d lines, %d bytes from file %s\n", textsw_file_line_count(win, NULL) - lines, size, file); xv_set(ip->post_popup, FRAME_LEFT_FOOTER, name, NULL); } static int checkHeader(ip, art, line) xvnews_post_popup_objects *ip; char *art; char *line; { char error[64], *a, *c = strstr(art, line); Textsw_index first = 0, last = TEXTSW_INFINITY; if (c == NULL) return 0; a = strchr(c, '\n'); *a = '\0'; if ((int)strlen(c) > (int)strlen(line) + 2) { *a = '\n'; return 0; } sprintf(error, "No %s specified for article!\n", line); xv_set(ip->post_popup, FRAME_LEFT_FOOTER, error, NULL); if (textsw_find_bytes(ip->post_window, &first, &last, line, strlen(line), 0) != -1) xv_set(ip->post_window, TEXTSW_INSERTION_POINT, last + 2, NULL); return 1; } extern int filePost(ip, bp, art) xvnews_post_popup_objects *ip; xvnews_xvnews_window_objects *bp; char *art; { xvnews_props_objects *pp = (xvnews_props_objects *)xv_get(bp->xvnews_window, XV_KEY_DATA, PROPS_POPUP, NULL); char *log = (char *)xv_get(pp->log_text, PANEL_VALUE, NULL); char from[80], from_line[128]; time_t clock; FILE *ifp_out; if (!strlen(log)) return 0; if (ip != NULL && !xv_get(ip->log_choice, PANEL_VALUE, NULL)) return 0; if ((ifp_out = fopen(log, "a")) == NULL) { xvnews_err(bp, "Article posted, cannot open %s to log posting!\n", log); return -1; } time(&clock); strftime(from, 80, "%a %h %e %T %Y", localtime(&clock)); sprintf(from_line, "From %s %s", (char *)cuserid(NULL), from); fprintf(ifp_out, "%s\n%s\n\n", from_line, art); fclose(ifp_out); return 1; } extern char * checkPeriods(buf, lines) char *buf; int lines; { char *c, *p, *new; if (strstr(buf, "\n.") == NULL) return buf; new = (char *)malloc(strlen(buf) + (lines + 2)); p = new; c = buf; while (*c != '\0') { if (*c == '.' && *(c - 1) == '\n') *p++ = '.'; *p++ = *c++; } *p = '\0'; free(buf); return new; } #ifndef USE_INEWS_TO_POST STATIC void errorPost(ip, message) xvnews_post_popup_objects *ip; char *message; { char error[256]; char *c = message; while(isdigit(*c++)); sprintf(error, "Server rejected article! Error: %s\n", c); xv_set(ip->post_popup, FRAME_LEFT_FOOTER, error, NULL); window_bell(ip->post_popup); } #endif STATIC char * replyAuthor(ip) xvnews_xvnews_window_objects *ip; { static char author[128]; char message[MAX_MESSAGE_LEN], *old; int status, art, row = xv_get(ip->articles_list, PANEL_LIST_FIRST_SELECTED); old = (char *)xv_get(ip->articles_list, PANEL_LIST_STRING, row); sscanf(old, "%d", &art); put_server("XHDR reply-to %d", art); status = get_server(message, sizeof(message)); if (status != OK_HEAD) { reconnect_server(); put_server("XHDR reply-to %d", art); status = get_server(message, sizeof(message)); if (status != OK_HEAD) return NULL; } get_server(message, sizeof(message)); sscanf(message, "%*d %s", author); while (*message != '.') get_server(message, sizeof(message)); if (strstr(author, "(none)") != NULL) return (char *)currentAuthor(1); return author; } extern char * newsHead(bp, flg, point) xvnews_xvnews_window_objects *bp; int flg; Textsw_index *point; { char host[64], *name; static char buff[BUFFERLEN], default_domain[] = DOMAIN; char *subject, *domain, domain_long[80], *follow; int art = 0; #ifdef linux struct utsname utsbuf; uname(&utsbuf); #endif #ifdef SVR4 sysinfo(SI_HOSTNAME, host, 32); #else gethostname(host, 32); #endif /* * Name can be the actual cuserid, or the MAIL_ALIAS as defined by * the user. Some might argue that this allows forgeries. I * laugh at them and argue that Internet allows forgeries, but * nobody has removed Internet either. */ if (!(name = (char *)getenv("MAIL_ALIAS"))) { name = cuserid(NULL); } /* Start a default new buffer */ strcpy(buff, "Distribution: \n"); if (flg == NEWS_REPLY) { /* We are doing a followup to the current article */ art = get_art_num(bp); if ((follow = get_header_field("Distribution", art))) { sprintf(buff, "Distribution: %s\n", follow); } else { sprintf(buff, "Distribution: \n"); } if ((follow = get_header_field("Followup-to", art))) { sprintf(buff, "%sNewsgroups: %s\n", buff, follow); } else { if ((follow = get_header_field("Newsgroups", art))) { sprintf(buff, "%sNewsgroups: %s\n", buff, follow); } else sprintf(buff, "%sNewsgroups: %s\n", buff, Global->group->newsgroup); } if ((follow = get_header_field("References", art))) { sprintf(buff, "%sFollowup-To: \nReferences: %s <%s>\n", buff, follow, get_messageid()); } else { sprintf(buff, "%sFollowup-To: \nReferences: <%s>\n", buff, get_messageid()); } } else { /* We are composing a new article */ if (Global->single) { sprintf(buff, "%sNewsgroups: %s\n", buff, Global->single); } else if (Global->group) sprintf(buff, "%sNewsgroups: %s\n", buff, Global->group->newsgroup); else { sprintf(buff, "%sNewsgroups: \n", buff); *point = strlen(buff); } sprintf(buff, "%sFollowup-To: \n", buff); } /* Get the domain so that we can generate From: and Reply-To: */ if ((domain = (char *)getenv("DOMAIN"))) { /* Use DOMAIN env. var. */; } else{ if (strlen(default_domain)) { domain = default_domain; } else{ /* Get the domainname from the system */ #ifdef linux strcpy(domain_long, utsbuf.domainname); #endif #ifdef SVR4 sysinfo(SI_SRPC_DOMAIN, domain_long, 32); #else getdomainname(domain_long, 64); #endif if (domain_long[0] == '+') domain_long[0] = '.'; domain = strchr(domain_long, '.'); if (domain == NULL) domain = domain_long; else ++domain; } } sprintf(buff, "%sFrom: %s@%s (%s)\nReply-To: %s@%s\n", buff, name, domain, getname(name), name, domain); /* Get the Organization: header */ if (getenv("ORGANIZATION")) sprintf(buff, "%sOrganization: %s\n", buff, getenv("ORGANIZATION")); else sprintf(buff, "%sOrganization: %s\n", buff, ORGANIZATION); #ifdef BETA #ifdef PATCHLEVEL sprintf(buff, "%sX-Newsreader: xvnews %-1.1f PL%s Beta, use only for testing please.\n", buff, VERSION, PATCHLEVEL); #else sprintf(buff, "%sX-Newsreader: xvnews %-1.1f Beta, use only for testing please.\n", buff, VERSION); #endif #endif if (flg == NEWS_REPLY) { subject = get_header_field("Subject", art); /* subject = (char *)currentSubject(bp, xv_get(bp->articles_list, PANEL_LIST_FIRST_SELECTED)); */ if (toupper(subject[0]) == 'R' && toupper(subject[1]) == 'E' && subject[2] == ':') sprintf(buff, "%sSubject: Re:%s\nSummary: \nKeywords: \n", buff, &subject[3]); else sprintf(buff, "%sSubject: Re: %s\nSummary: \nKeywords: \n", buff, subject); } else { sprintf(buff, "%sSubject: \nKeywords: \n", buff); if ((Global->group && flg != NEWS_REPLY) || Global->single) *point = strlen(buff) - 11; } if (getenv("X_NO_ARCHIVE")) sprintf(buff,"%s%s\n",buff,"X-no-archive: Yes"); sprintf(buff, "%s\n\n", buff); /* end of header */ if (flg == NEWS_REPLY) *point = strlen(buff); return buff; } extern char * addSignature(file1, file2) char *file1, *file2; { char aline[128], *sig, *result; FILE *ifp_in = NULL; struct stat statbuf; if ((ifp_in = fopen(file2 == NULL ? file1:file2, "r")) == NULL) { ifp_in = fopen(file1, "r"); stat(file1, &statbuf); } else stat(file2 == NULL ? file1:file2, &statbuf); if (ifp_in == NULL) return NULL; sig = (char *)malloc(statbuf.st_size + 2 + strlen(DEFAULT_SIGNATURE_SEPARATOR)); strcpy(sig, DEFAULT_SIGNATURE_SEPARATOR); result = sig + strlen(DEFAULT_SIGNATURE_SEPARATOR); *result = '\0'; while(fgets(aline, 127, ifp_in) != NULL) { aline[127] = '\0'; sprintf(result, "%s%s", result, aline); } fclose(ifp_in); return sig; }