/* ** We store charset info in the HTParentAnchor object, for several ** "stages". (See UCDefs.h) ** A stream method is supposed to know what stage in the model it is. ** ** General model MIME -> parser -> structured -> HText ** e.g., text/html ** from HTTP: HTMIME.c -> SGML.c -> HTML.c -> GridText.c ** text/plain ** from file: HTFile.c -> HTPlain.c -> GridText.c ** ** The lock/set_by is used to lock e.g. a charset set by an explicit ** HTTP MIME header against overriding by a HTML META tag - the MIME ** header has higher priority. Defaults (from -assume_.. options etc.) ** will not override charset explicitly given by server. ** ** Some advantages of keeping this in the HTAnchor: ** - Global variables are bad. ** - Can remember a charset given by META tag when toggling to SOURCE view. ** - Can remember a charset given by <A CHARSET=...> href in another doc. ** ** We don't modify the HTParentAnchor's charset element ** here, that one will only be set when explicitly given. */ PUBLIC LYUCcharset * HTAnchor_getUCInfoStage ARGS2( HTParentAnchor *, me, int, which_stage) { if (me && !me->UCStages) { int i; int chndl = UCLYhndl_for_unspec; /* always >= 0 */ UCAnchorInfo * stages = typecalloc(UCAnchorInfo); if (stages == NULL) outofmem(__FILE__, "HTAnchor_getUCInfoStage"); for (i = 0; i < UCT_STAGEMAX; i++) { stages->s[i].C.MIMEname = ""; stages->s[i].LYhndl = -1; } if (me->charset) { chndl = UCGetLYhndl_byMIME(me->charset); if (chndl < 0) chndl = UCLYhndl_for_unrec; if (chndl < 0) /* ** UCLYhndl_for_unrec not defined :-( ** fallback to UCLYhndl_for_unspec which always valid. */ chndl = UCLYhndl_for_unspec; /* always >= 0 */ } memcpy(&stages->s[UCT_STAGE_MIME].C, &LYCharSet_UC[chndl], sizeof(LYUCcharset)); stages->s[UCT_STAGE_MIME].lock = UCT_SETBY_DEFAULT; stages->s[UCT_STAGE_MIME].LYhndl = chndl; me->UCStages = stages; } if (me) { return( &me->UCStages->s[which_stage].C); } return(NULL); }
void HTPlain_write( HTStream *me, char *s, int l ) { char *p; char *e = &s[ l ]; char c; unsigned int c_unsign; BOOLEAN chk; UCode_t code; UCode_t uck = -1; char saved_char_in = 0; p = s; for ( ; p < e; p++ ) { if ( p[0] == 8 ) { if ( HTPlain_bs_pending == 0 ) HTPlain_bs_pending = 1; // p++; else if ( HTPlain_bs_pending == 2 ) HTPlain_bs_pending = 3; } else { if ( p[0] == '_' && HTPlain_bs_pending == 0 ) { HTPlain_bs_pending = 2; HTPlain_lastraw = p[0]; } } if ( HTPlain_lastraw == 13 && p[0] == '\n' ) HTPlain_lastraw = -1; else { if ( HTPlain_bs_pending && ( 31 <= p[0] || p[0] == '\r' || p[0] == '\n' || ( p[0] != HTPlain_lastraw && HTPlain_lastraw != 95 && p[0] != '_' ) ) ) { if ( HTPlain_bs_pending > 1 ) HText_appendCharacter( &me->text, 95 ); HTPlain_bs_pending = 0; } else if ( HTPlain_bs_pending == 1 ) HTPlain_bs_pending = 0; else if ( HTPlain_bs_pending == 3 ) { if ( p[0] == '_' ) HTPlain_bs_pending = 2; else HTPlain_bs_pending = 0; } else if ( HTPlain_bs_pending == 2 ) { HText_appendCharacter( &me->text, 95 ); if ( p[0] != '_' ) HTPlain_bs_pending = 0; } else HTPlain_bs_pending = 0; HTPlain_lastraw = p[0]; if ( p[0] == '\r' ) HText_appendCharacter( &me->text, 10 ); else { code = c_unsign = c = p[0]; saved_char_in = 0; if ( me->T.decode_utf8 ) { if ( c_unsign > 127 ) { if ( 0 < me->utf_count && ( c & 192 ) == 128 ) { me->utf_char = ( me->utf_char << 6 ) | ( c & 63 ); me->utf_count = me->utf_count + -1; me->utf_buf_p[0] = c; me->utf_buf_p++; if ( me->utf_count == 0 ) { me->utf_buf_p[0] = 0; code = me->utf_char; if ( code > 0 && code <= 255 ) { c_unsign = c = code; } } } else { me->utf_buf_p[0] = c; me->utf_buf_p = me->utf_buf[1]; if ( ( p[0] & 224 ) == 192 ) { me->utf_count = 1; me->utf_char = c & 31; } else { if ( ( p[0] & 240 ) == 224 ) { me->utf_count = 2; me->utf_char = c & 15; } else { if ( ( p[0] & 248 ) == 240 ) { me->utf_count = 3; me->utf_char = c & 7; } else { if ( ( p[0] & 252 ) == 248 ) { me->utf_count = 4; me->utf_char = __MOD(c,4); } else { if ( ( p[0] & 254 ) == 252 ) { me->utf_count = 5; me->utf_char = c & 1; } else { me->utf_count = 0; me->utf_buf_p[0] = 0; me->utf_buf_p = me->utf_buf[0]; } } } } } } } else if ( 0 < me->utf_count ) { me->utf_count = 0; me->utf_buf_p = me->utf_buf[0] = 0; code = c_unsign; } else code = c_unsign; } if ( !me->T.decode_utf8 || p[0] >= 0 ) { if ( me->T.trans_to_uni && ( LYlowest_eightbit[ me->inUCLYhndl ] <= code || ( code <= 31 && code && me->T.trans_C0_to_uni ) ) ) { code = UCTransToUni( c, me->inUCLYhndl ); if ( code > 0 ) { saved_char_in = c; if ( code <= 255 ) { c_unsign = c = code; } } } else if ( code <= 31 && code && me->T.trans_C0_to_uni ) { if ( me->T.trans_from_uni ) { code = UCTransToUni( c, me->inUCLYhndl ); if ( code <= 31 ) { if ( me->T.transp ) { code = UCTransToUni( c, me->inUCLYhndl ); if ( code > 0 ) goto B103; } } B103:; saved_char_in = c; if ( code <= 255 ) { c_unsign = c = code; } } uck = -1; if ( me->T.transp ) { uck = UCTransCharStr( replace_buf, 60, c, me->inUCLYhndl, me->inUCLYhndl, 0 ); } if ( me->T.transp == 0 || uck < 0 ) { uck = UCTransCharStr( replace_buf, 60, c, me->inUCLYhndl, me->outUCLYhndl, 1 ); } if ( uck ) { if ( uck >= 0 ) { c = replace_buf[0]; if ( c && replace_buf[1] ) HText_appendText( &me->text, replace_buf ); } else { me->utf_buf[0] = 0; code = c; } me->utf_buf[0] = 0; code = c; } } else { me->utf_buf[0] = 0; code = c; } } if ( HTCJK ) HText_appendCharacter( &me->text, c ); else { if ( code > 126 && code <= 160 && ( me->T.transp || LYlowest_eightbit[ me->inUCLYhndl ] <= code ) && me->T.pass_160_173_raw ) HText_appendCharacter( &me->text, c ); else { if ( code == 173 && me->T.pass_160_173_raw ) HText_appendCharacter( &me->text, c ); else { if ( code == 160 ) HText_appendCharacter( &me->text, 32 ); else { if ( code != 173 ) { if ( ( code > 31 && code <= 126 ) || ( ( HTPassEightBitRaw || ( me->T.do_8bitraw && !me->T.trans_from_uni ) ) && LYlowest_eightbit[ me->outUCLYhndl ] <= c ) || p[0] == '\n' || p[0] == '\t' ) HText_appendCharacter( &me->text, c ); else { switch ( code ) { case 8194: case 8195: case 8201: HText_appendCharacter( &me->text, 32 ); break; default: if ( me->T.use_raw_char_in && saved_char_in ) HText_appendCharacter( &me->text, saved_char_in ); else { *(int*)&chk = 0; if ( chk ) { uck = UCTransUniChar( code, me->outUCLYhndl ); if ( uck > 31 && uck <= 255 ) { if ( WWW_TraceFlag ) { fprintf( TraceFP( ), "UCTransUniChar returned 0x%.2lX:'%c'.\n", uck, uck ); } HText_appendCharacter( &me->text, uck ); } } if ( chk && ( uck == -4 || ( me->T.repl_translated_C0 && uck > 0 && uck <= 31 ) ) ) { uck = ~UCTransUniCharStr( replace_buf, 60, code, me->outUCLYhndl, 0 ) >> 31; if ( uck ) HText_appendText( &me->text, replace_buf ); } if ( chk && code > 127 && me->T.output_utf8 ) { if ( me->utf_buf[0] ) { HText_appendText( &me->text, &me->utf_buf[0] ); me->utf_buf_p = me->utf_buf[0] = 0; } else { if ( UCConvertUniToUtf8( code, replace_buf ) & 255 ) HText_appendText( &me->text, replace_buf ); else { sprintf( replace_buf, "U%.2lX", code ); HText_appendText( &me->text, replace_buf ); } } } else { if ( ( c_unsign && (int)c_unsign < LYlowest_eightbit[ me->outUCLYhndl ] ) || ( me->T.trans_from_uni && HTPassEightBitRaw == 0 ) ) { chk = me->outUCLYhndl != UCGetLYhndl_byMIME( "us-ascii" ); if ( chk ) { uck = UCTransUniChar( code, UCGetLYhndl_byMIME( "us-ascii" ) ); if ( uck > 31 && uck <= 126 ) { c = uck; HText_appendCharacter( &me->text, c ); } } if ( chk && uck == -4 ) { uck = ~UCTransUniCharStr( replace_buf, 60, code, UCGetLYhndl_byMIME( "us-ascii" ), 0 ) >> 31; if ( uck ) HText_appendText( &me->text, replace_buf ); } if ( code == 8204 || code == 8205 ) { if ( WWW_TraceFlag ) { fprintf( TraceFP( ), "HTPlain_write: Ignoring '%ld'.\n", code ); } } else { if ( ( code == 8206 || code == 8207 ) && WWW_TraceFlag ) { fprintf( TraceFP( ), "HTPlain_write: Ignoring '%ld'.\n", code ); } } } else { if ( c_unsign && c_unsign <= 255 ) HText_appendCharacter( &me->text, c ); } } } break; } } } } } } }
/* * 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, BOOLEAN 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); 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, VISIBLE, 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, VISIBLE, 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, 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, VISIBLE, 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, VISIBLE, 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, VISIBLE, 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 ((LynxSigFile != NULL) && (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); 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) LYRemoveTemp(my_tempfile); LYRemoveTemp(CJKfile); FREE(NewsGroups); FREE(References); return (postfile); }