summaryrefslogtreecommitdiffstats
path: root/src/LYNews.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/LYNews.c')
-rw-r--r--src/LYNews.c509
1 files changed, 509 insertions, 0 deletions
diff --git a/src/LYNews.c b/src/LYNews.c
new file mode 100644
index 0000000..bb49289
--- /dev/null
+++ b/src/LYNews.c
@@ -0,0 +1,509 @@
+/*
+ * $LynxId: LYNews.c,v 1.62 2018/03/18 18:51:02 tom Exp $
+ */
+#include <HTUtils.h>
+#ifndef DISABLE_NEWS
+#include <HTParse.h>
+#include <HTAccess.h>
+#include <HTCJK.h>
+#include <HTAlert.h>
+#include <LYCurses.h>
+#include <LYSignal.h>
+#include <LYStructs.h>
+#include <LYUtils.h>
+#include <LYClean.h>
+#include <LYStrings.h>
+#include <LYHistory.h>
+#include <GridText.h>
+#include <LYCharSets.h>
+#include <LYNews.h>
+#include <LYEdit.h>
+
+#include <LYGlobalDefs.h>
+
+#include <LYLeaks.h>
+
+/*
+ * Global variable for async i/o.
+ */
+BOOLEAN term_message = FALSE;
+static void terminate_message(int sig);
+
+static BOOLEAN message_has_content(const char *filename,
+ BOOLEAN *nonspaces)
+{
+ FILE *fp;
+ char *buffer = NULL;
+ BOOLEAN in_headers = TRUE;
+
+ *nonspaces = FALSE;
+
+ if (!filename || (fp = fopen(filename, "r")) == NULL) {
+ CTRACE((tfp, "Failed to open file %s for reading!\n",
+ NONNULL(filename)));
+ return FALSE;
+ }
+ while (LYSafeGets(&buffer, fp) != NULL) {
+ char *cp = buffer;
+ char firstnonblank = '\0';
+
+ LYTrimNewline(cp);
+ for (; *cp; cp++) {
+ if (!firstnonblank && isgraph(UCH(*cp))) {
+ firstnonblank = *cp;
+ } else if (!isspace(UCH(*cp))) {
+ *nonspaces = TRUE;
+ }
+ }
+ if (firstnonblank && firstnonblank != '>') {
+ if (!in_headers) {
+ LYCloseInput(fp);
+ FREE(buffer);
+ return TRUE;
+ }
+ }
+ if (!firstnonblank) {
+ in_headers = FALSE;
+ }
+ }
+ FREE(buffer);
+ LYCloseInput(fp);
+ return FALSE;
+}
+
+/*
+ * This function is called from HTLoadNews() to have the user
+ * create a file with news headers and a body for posting of
+ * a new message (based on a newspost://nntp_host/newsgroups
+ * or snewspost://secure_nntp_host/newsgroups URL), or to post
+ * a followup (based on a newsreply://nntp_host/newsgroups or
+ * snewsreply://secure_nntp_host/newsgroups URL). The group
+ * or comma-separated list of newsgroups is passed without
+ * a lead slash, and followup is TRUE for newsreply or
+ * snewsreply URLs. - FM
+ */
+char *LYNewsPost(char *newsgroups,
+ int followup)
+{
+ char user_input[MAX_LINE];
+ char CJKinput[MAX_LINE];
+ char *cp = NULL;
+ const char *kp = NULL;
+ int c = 0; /* user input */
+ int len;
+ FILE *fd = NULL;
+ char my_tempfile[LY_MAXPATH];
+ FILE *fc = NULL;
+ char CJKfile[LY_MAXPATH];
+ char *postfile = NULL;
+ char *NewsGroups = NULL;
+ char *References = NULL;
+ char *org = NULL;
+ FILE *fp = NULL;
+ BOOLEAN nonempty = FALSE;
+ BOOLEAN nonspaces = FALSE;
+
+ /*
+ * Make sure a non-zero length newspost, newsreply, snewspost or snewsreply
+ * path was sent to us. - FM
+ */
+ if (isEmpty(newsgroups))
+ return (postfile);
+
+ /*
+ * Return immediately if we do get called, maybe by some quirk of HTNews.c,
+ * when we shouldn't. - kw
+ */
+ if (no_newspost)
+ return (postfile);
+
+ /*
+ * Open a temporary file for the headers and message body. - FM
+ */
+#ifdef __DJGPP__
+ if ((fd = LYOpenTemp(my_tempfile, HTML_SUFFIX, BIN_W)) == NULL)
+#else
+ if ((fd = LYOpenTemp(my_tempfile, HTML_SUFFIX, "w")) == NULL)
+#endif /* __DJGPP__ */
+ {
+ HTAlert(CANNOT_OPEN_TEMP);
+ return (postfile);
+ }
+
+ /*
+ * If we're using a Japanese display character set, open a temporary file
+ * for a conversion to JIS. - FM
+ */
+ CJKfile[0] = '\0';
+ if (current_char_set == UCGetLYhndl_byMIME("euc-jp") ||
+ current_char_set == UCGetLYhndl_byMIME("shift_jis")) {
+ if ((fc = LYOpenTemp(CJKfile, HTML_SUFFIX, "w")) == NULL) {
+ HTAlert(CANNOT_OPEN_TEMP);
+ (void) LYRemoveTemp(my_tempfile);
+ return (postfile);
+ }
+ }
+
+ /*
+ * The newsgroups could be a comma-seperated list. It need not have
+ * spaces, but deal with any that may also have been hex escaped. - FM
+ */
+ StrAllocCopy(NewsGroups, newsgroups);
+ if ((cp = strstr(NewsGroups, ";ref="))) {
+ *cp = '\0';
+ cp += 5;
+ if (*cp == '<') {
+ StrAllocCopy(References, cp);
+ } else {
+ StrAllocCopy(References, "<");
+ StrAllocCat(References, cp);
+ StrAllocCat(References, ">");
+ }
+ HTUnEscape(References);
+ if (!((cp = StrChr(References, '@')) && cp > References + 1 &&
+ isalnum(UCH(cp[1])))) {
+ FREE(References);
+ }
+ }
+ HTUnEscape(NewsGroups);
+ if (!*NewsGroups) {
+ LYCloseTempFP(fd); /* Close the temp file. */
+ goto cleanup;
+ }
+
+ /*
+ * Allow ^C to cancel the posting, i.e., don't let SIGINTs exit Lynx.
+ */
+ signal(SIGINT, terminate_message);
+ term_message = FALSE;
+
+ /*
+ * Show the list of newsgroups. - FM
+ */
+ LYclear();
+ LYmove(2, 0);
+ scrollok(LYwin, TRUE); /* Enable scrolling. */
+ LYaddstr(gettext("You will be posting to:"));
+ LYaddstr("\n\t");
+ LYaddstr(NewsGroups);
+ LYaddch('\n');
+
+ /*
+ * Get the mail address for the From header, offering personal_mail_address
+ * as default.
+ */
+ LYaddstr(gettext("\n\n Please provide your mail address for the From: header\n"));
+ sprintf(user_input, "From: %.*s", (int) sizeof(user_input) - 8,
+ NonNull(personal_mail_address));
+ if (LYGetStr(user_input, FALSE,
+ sizeof(user_input), NORECALL) < 0 ||
+ term_message) {
+ HTInfoMsg(NEWS_POST_CANCELLED);
+ LYCloseTempFP(fd); /* Close the temp file. */
+ scrollok(LYwin, FALSE); /* Stop scrolling. */
+ goto cleanup;
+ }
+ fprintf(fd, "%s\n", user_input);
+
+ /*
+ * Get the Subject header, offering the current document's title as the
+ * default if this is a followup rather than a new post. - FM
+ */
+ LYaddstr(gettext("\n\n Please provide or edit the Subject: header\n"));
+ strcpy(user_input, "Subject: ");
+ if ((followup == TRUE && nhist > 0) &&
+ (kp = HText_getTitle()) != NULL) {
+ /*
+ * Add the default subject.
+ */
+ kp = LYSkipCBlanks(kp);
+#ifdef CJK_EX /* 1998/05/15 (Fri) 09:10:38 */
+ if (HTCJK == JAPANESE) {
+ CJKinput[0] = '\0';
+ switch (kanji_code) {
+ case EUC:
+ TO_EUC((const unsigned char *) kp, (unsigned char *) CJKinput);
+ kp = CJKinput;
+ break;
+ case SJIS:
+ TO_SJIS((const unsigned char *) kp, (unsigned char *) CJKinput);
+ kp = CJKinput;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+ if (strncasecomp(kp, "Re:", 3)) {
+ strcat(user_input, "Re: ");
+ }
+ len = (int) strlen(user_input);
+ LYStrNCpy(user_input + len, kp, (int) sizeof(user_input) - len - 1);
+ }
+ cp = NULL;
+ if (LYGetStr(user_input, FALSE,
+ sizeof(user_input), NORECALL) < 0 ||
+ term_message) {
+ HTInfoMsg(NEWS_POST_CANCELLED);
+ LYCloseTempFP(fd); /* Close the temp file. */
+ scrollok(LYwin, FALSE); /* Stop scrolling. */
+ goto cleanup;
+ }
+ fprintf(fd, "%s\n", user_input);
+
+ /*
+ * Add Organization: header.
+ */
+ StrAllocCopy(cp, "Organization: ");
+ if ((org = LYGetEnv("ORGANIZATION")) != NULL) {
+ StrAllocCat(cp, org);
+ } else if ((org = LYGetEnv("NEWS_ORGANIZATION")) != NULL) {
+ StrAllocCat(cp, org);
+ }
+#ifdef UNIX
+ else if ((fp = fopen("/etc/organization", TXT_R)) != NULL) {
+ char *buffer = 0;
+
+ if (LYSafeGets(&buffer, fp) != NULL) {
+ if (user_input[0] != '\0') {
+ LYTrimNewline(buffer);
+ StrAllocCat(cp, buffer);
+ }
+ }
+ FREE(buffer);
+ LYCloseInput(fp);
+ }
+#else
+#ifdef _WINDOWS /* 1998/05/14 (Thu) 17:47:01 */
+ else {
+ char *p, fname[LY_MAXPATH];
+
+ strcpy(fname, LynxSigFile);
+ p = strrchr(fname, '/');
+ if (p != 0 && (p - fname) < sizeof(fname) - 15) {
+ strcpy(p + 1, "LYNX_ETC.TXT");
+ if ((fp = fopen(fname, TXT_R)) != NULL) {
+ if (fgets(user_input, (int) sizeof(user_input), fp) != NULL) {
+ if ((org = StrChr(user_input, '\n')) != NULL) {
+ *org = '\0';
+ }
+ if (user_input[0] != '\0') {
+ StrAllocCat(cp, user_input);
+ }
+ }
+ LYCloseInput(fp);
+ }
+ }
+ }
+#endif /* _WINDOWS */
+#endif /* !UNIX */
+ LYStrNCpy(user_input, cp, (sizeof(user_input) - 16));
+ FREE(cp);
+ LYaddstr(gettext("\n\n Please provide or edit the Organization: header\n"));
+ if (LYGetStr(user_input, FALSE,
+ sizeof(user_input), NORECALL) < 0 ||
+ term_message) {
+ HTInfoMsg(NEWS_POST_CANCELLED);
+ LYCloseTempFP(fd); /* Close the temp file. */
+ scrollok(LYwin, FALSE); /* Stop scrolling. */
+ goto cleanup;
+ }
+ fprintf(fd, "%s\n", user_input);
+
+ if (References) {
+ fprintf(fd, "References: %s\n", References);
+ }
+ /*
+ * Add Newsgroups Summary and Keywords headers.
+ */
+ fprintf(fd, "Newsgroups: %s\nSummary: \nKeywords: \n\n", NewsGroups);
+
+ /*
+ * Have the user create the message body.
+ */
+ if (!no_editor && non_empty(editor)) {
+
+ if (followup && nhist > 0) {
+ /*
+ * Ask if the user wants to include the original message.
+ */
+ if (term_message) {
+ _statusline(INC_ORIG_MSG_PROMPT);
+ } else if (HTConfirm(INC_ORIG_MSG_PROMPT) == YES) {
+ /*
+ * The 'TRUE' will add the reply ">" in front of every line.
+ * We're assuming that if the display character set is Japanese
+ * and the document did not have a CJK charset, any non-EUC or
+ * non-SJIS 8-bit characters in it where converted to 7-bit
+ * equivalents. - FM
+ */
+ print_wwwfile_to_fd(fd, FALSE, TRUE);
+ }
+ }
+ LYCloseTempFP(fd); /* Close the temp file. */
+ scrollok(LYwin, FALSE); /* Stop scrolling. */
+ if (term_message || LYCharIsINTERRUPT(c))
+ goto cleanup;
+
+ /*
+ * Spawn the user's editor on the news file.
+ */
+ edit_temporary_file(my_tempfile, "", SPAWNING_EDITOR_FOR_NEWS);
+
+ nonempty = message_has_content(my_tempfile, &nonspaces);
+
+ } else {
+ /*
+ * Use the built in line editior.
+ */
+ LYaddstr(gettext("\n\n Please enter your message below."));
+ LYaddstr(gettext("\n When you are done, press enter and put a single period (.)"));
+ LYaddstr(gettext("\n on a line and press enter again."));
+ LYaddstr("\n\n");
+ LYrefresh();
+ *user_input = '\0';
+ if (LYGetStr(user_input, FALSE,
+ sizeof(user_input), NORECALL) < 0 ||
+ term_message) {
+ HTInfoMsg(NEWS_POST_CANCELLED);
+ LYCloseTempFP(fd); /* Close the temp file. */
+ scrollok(LYwin, FALSE); /* Stop scrolling. */
+ goto cleanup;
+ }
+ while (!STREQ(user_input, ".") && !term_message) {
+ LYaddch('\n');
+ fprintf(fd, "%s\n", user_input);
+ if (!nonempty && strlen(user_input))
+ nonempty = TRUE;
+ *user_input = '\0';
+ if (LYGetStr(user_input, FALSE,
+ sizeof(user_input), NORECALL) < 0) {
+ HTInfoMsg(NEWS_POST_CANCELLED);
+ LYCloseTempFP(fd); /* Close the temp file. */
+ scrollok(LYwin, FALSE); /* Stop scrolling. */
+ goto cleanup;
+ }
+ }
+ fprintf(fd, "\n");
+ LYCloseTempFP(fd); /* Close the temp file. */
+ scrollok(LYwin, FALSE); /* Stop scrolling. */
+ }
+
+ if (nonempty) {
+ /*
+ * Confirm whether to post, and if so, whether to append the sig file.
+ * - FM
+ */
+ LYStatusLine = (LYlines - 1);
+ c = HTConfirm(POST_MSG_PROMPT);
+ LYStatusLine = -1;
+ if (c != YES) {
+ LYclear(); /* clear the screen */
+ goto cleanup;
+ }
+ } else {
+ HTAlert(gettext("Message has no original text!"));
+ if (!nonspaces
+ || HTConfirmDefault(POST_MSG_PROMPT, NO) != YES)
+ goto cleanup;
+ }
+ if ((non_empty(LynxSigFile)) && (fp = fopen(LynxSigFile, TXT_R)) != NULL) {
+ char *msg = NULL;
+
+ HTSprintf0(&msg, APPEND_SIG_FILE, LynxSigFile);
+
+ LYStatusLine = (LYlines - 1);
+ if (term_message) {
+ _user_message(APPEND_SIG_FILE, LynxSigFile);
+ } else if (HTConfirm(msg) == YES) {
+ if ((fd = LYAppendToTxtFile(my_tempfile)) != NULL) {
+ char *buffer = NULL;
+
+ fputs("-- \n", fd);
+ while (LYSafeGets(&buffer, fp) != NULL) {
+ fputs(buffer, fd);
+ }
+ LYCloseOutput(fd);
+ }
+ }
+ LYCloseInput(fp);
+ FREE(msg);
+ LYStatusLine = -1;
+ }
+ LYclear(); /* clear the screen */
+
+ /*
+ * If we are using a Japanese display character set, convert the contents
+ * of the temp file to JIS (nothing should change if it does not, in fact,
+ * contain EUC or SJIS di-bytes). Otherwise, use the temp file as is. -
+ * FM
+ */
+ if (CJKfile[0] != '\0') {
+ if ((fd = fopen(my_tempfile, TXT_R)) != NULL) {
+ char *buffer = NULL;
+
+ while (LYSafeGets(&buffer, fd) != NULL) {
+ TO_JIS((unsigned char *) buffer,
+ (unsigned char *) CJKinput);
+ fputs(CJKinput, fc);
+ }
+ LYCloseTempFP(fc);
+ StrAllocCopy(postfile, CJKfile);
+ LYCloseInput(fd);
+ (void) LYRemoveTemp(my_tempfile);
+ strcpy(my_tempfile, CJKfile);
+ CJKfile[0] = '\0';
+ } else {
+ StrAllocCopy(postfile, my_tempfile);
+ }
+ } else {
+ StrAllocCopy(postfile, my_tempfile);
+ }
+ if (!followup) {
+ /*
+ * If it's not a followup, the current document most likely is the
+ * group listing, so force a to have the article show up in the list
+ * after the posting. Note, that if it's a followup via a link in a
+ * news article, the user must do a reload manually on returning to the
+ * group listing. - FM
+ */
+ LYforce_no_cache = TRUE;
+ }
+ LYStatusLine = (LYlines - 1);
+ HTUserMsg(POSTING_TO_NEWS);
+ LYStatusLine = -1;
+
+ /*
+ * Come here to cleanup and exit.
+ */
+ cleanup:
+#ifndef VMS
+ signal(SIGINT, cleanup_sig);
+#endif /* !VMS */
+ term_message = FALSE;
+ if (!postfile)
+ (void) LYRemoveTemp(my_tempfile);
+ (void) LYRemoveTemp(CJKfile);
+ FREE(NewsGroups);
+ FREE(References);
+
+ return (postfile);
+}
+
+static void terminate_message(int sig GCC_UNUSED)
+{
+ term_message = TRUE;
+ /*
+ * Reassert the AST.
+ */
+ signal(SIGINT, terminate_message);
+#ifdef VMS
+ /*
+ * Refresh the screen to get rid of the "interrupt" message.
+ */
+ lynx_force_repaint();
+ LYrefresh();
+#endif /* VMS */
+}
+
+#endif /* not DISABLE_NEWS */