htmlout.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. /** --- BEGIN COPYRIGHT BLOCK ---
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. --- END COPYRIGHT BLOCK --- */
  38. /*
  39. * htmlout.c -- routines to output HTML elements -- HTTP gateway
  40. */
  41. #include "dsgw.h"
  42. #include "dbtdsgw.h"
  43. #define DSGW_POSTEDVARARG_NAME "name"
  44. static char*
  45. dsgw_change( char *s, dsgwsubst *changes )
  46. {
  47. auto dsgwsubst *ch;
  48. if ( changes == NULL ) return s;
  49. for ( ch = changes; ch; ch = ch->dsgwsubst_next ) {
  50. if ( strstr( s, ch->dsgwsubst_from ) ) {
  51. break;
  52. }
  53. }
  54. if ( ch != NULL ) {
  55. auto char *cs = dsgw_ch_strdup( s );
  56. for ( ch = changes; ch; ch = ch->dsgwsubst_next ) {
  57. auto const size_t from_len = strlen( ch->dsgwsubst_from );
  58. auto const size_t to_len = strlen( ch->dsgwsubst_to );
  59. auto const long change_len = to_len - from_len;
  60. auto char *p;
  61. for ( p = cs; (p = strstr( p, ch->dsgwsubst_from )) != NULL; p += to_len ) {
  62. if ( change_len ) {
  63. if ( change_len > 0 ) { /* allocate more space: */
  64. auto const size_t offset = p - cs;
  65. cs = dsgw_ch_realloc( cs, strlen( cs ) + change_len + 1 );
  66. p = cs + offset;
  67. }
  68. memmove( p + to_len, p + from_len, strlen( p + from_len ) + 1 );
  69. }
  70. if ( to_len != 0 ) {
  71. memcpy( p, ch->dsgwsubst_to, to_len );
  72. }
  73. }
  74. }
  75. return cs;
  76. }
  77. return s;
  78. }
  79. void
  80. dsgw_HTML_emits( char *s )
  81. {
  82. auto char *sc = dsgw_change( s, gc->gc_changeHTML );
  83. dsgw_emits( sc );
  84. if ( sc != s ) free( sc );
  85. }
  86. void
  87. dsgw_html_begin( char *title, int titleinbody )
  88. {
  89. static int header_done = 0;
  90. if ( !header_done ) {
  91. dsgw_emits( "<HTML>" );
  92. dsgw_head_begin();
  93. dsgw_emits( "\n" );
  94. if ( title != NULL ) {
  95. dsgw_emitf( "<TITLE>%s</TITLE>\n", title );
  96. }
  97. dsgw_emitf( "</HEAD>\n<BODY %s>\n", dsgw_html_body_colors );
  98. } else {
  99. dsgw_emits( "\n<HR>\n" );
  100. }
  101. if (( title != NULL ) && ( header_done || titleinbody )) {
  102. dsgw_emitf( "<CENTER><TABLE BORDER=\"2\" CELLPADDING=\"10\" WIDTH=100%%>\n"
  103. "<TR><TD ALIGN=\"center\" WIDTH=\"100%%\">\n<FONT SIZE=\"+2\">"
  104. "<B>%s</B></FONT></TD></TR></TABLE></CENTER>\n<P>\n", title );
  105. }
  106. header_done = 1;
  107. }
  108. void
  109. dsgw_html_end()
  110. {
  111. dsgw_emits( "</BODY></HTML>\n" );
  112. /* make sure everything has been written to the server before we exit */
  113. fflush( stdout );
  114. fflush( stderr );
  115. }
  116. /*
  117. * output a hypertext reference/URL:
  118. * if "urlprefix" != NULL, it is prepended to "url" and "url" is hex-escaped.
  119. * if "urlprefix" == NULL, "url" is assumed to be already escaped as needed.
  120. *
  121. * if "value" != NULL, any occurrence of "--value--" in "url" is replaced by
  122. * a URL-escaped version of the actual value.
  123. * if "value" == NULL, no substitution is done.
  124. *
  125. * if "label" == NULL or is of zero length, the closing ">LABEL</A>" is omitted.
  126. */
  127. void
  128. dsgw_html_href( char *urlprefix, char *url, char *label, char *value,
  129. char *extra )
  130. {
  131. char *escaped_url, *tag = "--value--";
  132. char *newlabel = NULL;
  133. int freenewlabel;
  134. if ( urlprefix == NULL ) {
  135. dsgw_emits( "<A HREF=" );
  136. escaped_url = NULL;
  137. } else {
  138. dsgw_emitf( "<A HREF=%s", urlprefix );
  139. escaped_url = dsgw_ch_malloc( 3 * strlen( url ) + 1 );
  140. *escaped_url = '\0';
  141. dsgw_strcat_escaped( escaped_url, url );
  142. url = escaped_url;
  143. }
  144. if ( value != NULL ) {
  145. dsgw_substitute_and_output( url, tag, value, 1 );
  146. } else {
  147. dsgw_emits( url );
  148. }
  149. if ( extra != NULL ) {
  150. dsgw_emits( " " );
  151. if ( value != NULL ) {
  152. dsgw_substitute_and_output( extra, tag, value, 1 );
  153. } else {
  154. dsgw_emits( extra );
  155. }
  156. }
  157. newlabel = dsgw_strdup_with_entities( label, &freenewlabel );
  158. if ( newlabel != NULL && *newlabel != '\0' ) {
  159. dsgw_emitf( ">%s</A>\n", newlabel );
  160. if ( freenewlabel ) {
  161. free( newlabel );
  162. }
  163. } else {
  164. dsgw_emits( "></A>\n" );
  165. }
  166. if ( escaped_url != NULL ) {
  167. free( escaped_url );
  168. }
  169. }
  170. void
  171. dsgw_substitute_and_output( char *s, char *tag, char *value, int escape )
  172. {
  173. char *p, *escval;
  174. escval = NULL;
  175. while ( ( p = strstr( s, tag )) != NULL ) {
  176. if ( p > s ) {
  177. dsgw_emitn( stdout, s, p - s );
  178. }
  179. if ( escape ) {
  180. if ( escval == NULL ) {
  181. escval = dsgw_strdup_escaped( value );
  182. }
  183. dsgw_emits( escval );
  184. } else {
  185. dsgw_emits( value );
  186. }
  187. s = p + strlen( tag );
  188. }
  189. if ( escval != NULL ) {
  190. free( escval );
  191. }
  192. if ( *s != '\0' ) {
  193. dsgw_emits( s );
  194. }
  195. }
  196. char *
  197. dsgw_strdup_escaped( const char *s )
  198. {
  199. char *p;
  200. p = dsgw_ch_malloc( 3 * strlen( s ) + 1 );
  201. *p = '\0';
  202. dsgw_strcat_escaped( p, s );
  203. return( p );
  204. }
  205. /* this macro was copied from libldap/tmplout.c */
  206. #define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \
  207. ( c >= '@' && c <= 'Z' ) || \
  208. ( c == '_' ) || \
  209. ( c >= 'a' && c <= 'z' ))
  210. /* this function is copied from libldap/tmplout.c:strcat_escaped */
  211. void
  212. dsgw_strcat_escaped( char *s1, const char *s2 )
  213. {
  214. unsigned char *q;
  215. char *p, *hexdig = "0123456789ABCDEF";
  216. p = s1 + strlen( s1 );
  217. for ( q = (unsigned char *)s2; *q != '\0'; ++q ) {
  218. if ( HREF_CHAR_ACCEPTABLE( *q )) {
  219. *p++ = *q;
  220. } else {
  221. *p++ = '%';
  222. *p++ = hexdig[ 0x0F & ((*(unsigned char*)q) >> 4) ];
  223. *p++ = hexdig[ 0x0F & *q ];
  224. }
  225. }
  226. *p = '\0';
  227. }
  228. #define DSGW_MAX_ENTITY_LEN 6 /* &quot; */
  229. static char *specials = "&\"<>";
  230. static char *entities[] = { "&amp;", "&quot;", "&lt;", "&gt;" };
  231. static int entitylen[] = { 5, 6, 4, 4 };
  232. char *
  233. dsgw_strdup_with_entities( char *s, int *madecopyp )
  234. {
  235. /*
  236. * If the UTF8 string "s" contains any HTML special characters, make a
  237. * duplicate where the appropriate HTML "entities" have been substituted
  238. * for the special chars. For example, "<[email protected]>" will be translated
  239. * to "&lt;[email protected]&gt;".
  240. *
  241. * If "s" does not contain any special characters, it is returned and
  242. * *madecopyp is set to 0.
  243. * Otherwise a malloc'd string is returned and *madecopyp is set to 1.
  244. */
  245. int spcount, idx;
  246. char *p, *q, *r, *d;
  247. spcount = 0;
  248. for ( p = s; *p != '\0'; LDAP_UTF8INC( p )) {
  249. if ( ((*p) & 0x80) == 0 && strchr( specials, *p ) != NULL ) {
  250. ++spcount;
  251. }
  252. }
  253. if ( spcount == 0 ) {
  254. *madecopyp = 0;
  255. return( s );
  256. }
  257. d = r = dsgw_ch_malloc( strlen( s ) + 1 + spcount * DSGW_MAX_ENTITY_LEN );
  258. for ( p = s; *p != '\0'; LDAP_UTF8INC( p )) {
  259. if ( ((*p) & 0x80) == 0 && ( q = strchr( specials, *p )) != NULL ) {
  260. idx = ( q - specials );
  261. memcpy( r, entities[ idx ], entitylen[ idx ] );
  262. r += entitylen[ idx ];
  263. } else {
  264. r += LDAP_UTF8COPY( r, p );
  265. }
  266. }
  267. *r = '\0';
  268. *madecopyp = 1;
  269. return( d );
  270. }
  271. void
  272. dsgw_form_begin( const char* name, const char* format, ... )
  273. {
  274. dsgw_emits ("<FORM method=POST");
  275. if (name) {
  276. dsgw_emitf (" name=\"%s\"", name);
  277. }
  278. if (format) {
  279. va_list argl;
  280. va_start (argl, format);
  281. dsgw_emits (" ");
  282. dsgw_emitfv (format, argl);
  283. va_end (argl);
  284. }
  285. dsgw_emits (">");
  286. dsgw_emitf("<INPUT type=hidden name=context value=\"%s\">", context);
  287. dsgw_emitf ("<INPUT type=hidden name=charset value=\"%s\">",
  288. (gc->gc_charset && *(gc->gc_charset)) ? gc->gc_charset : ISO_8859_1_ENCODING );
  289. }
  290. void
  291. dsgw_emit_cgi_var( int argc, char **argv )
  292. {
  293. char *name, *postedvalue;
  294. if (( name = get_arg_by_name( DSGW_POSTEDVARARG_NAME, argc, argv ))
  295. == NULL ) {
  296. dsgw_emitf( XP_GetClientStr(DBT_missingS_1), DSGW_POSTEDVARARG_NAME );
  297. } else if (( postedvalue = dsgw_get_cgi_var( name, DSGW_CGIVAR_OPTIONAL ))
  298. != NULL ) {
  299. dsgw_emits( postedvalue );
  300. }
  301. }
  302. void
  303. dsgw_emit_button( int argc, char **argv, const char* format, ... )
  304. {
  305. auto char *name = get_arg_by_name( DSGW_ARG_BUTTON_NAME, argc, argv );
  306. auto char *label = get_arg_by_name( DSGW_ARG_BUTTON_LABEL, argc, argv );
  307. if ( !label ) label = XP_GetClientStr( DBT_closeWindow_3 );
  308. dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\"", label );
  309. if ( name ) dsgw_emitf( " NAME=\"%s\"", name );
  310. if ( format ) {
  311. va_list argl;
  312. va_start( argl, format );
  313. dsgw_emits( " " );
  314. dsgw_emitfv( format, argl );
  315. va_end( argl );
  316. }
  317. dsgw_emits( ">" );
  318. }
  319. void
  320. dsgw_emit_alertForm ()
  321. {
  322. dsgw_form_begin ("alertForm", "action=\"%s\" target=alertWindow",
  323. DSGW_URLPREFIX_MAIN_HTTP "alert.html");
  324. dsgw_emitf ("<INPUT TYPE=hidden NAME=TITLE VALUE=\"%s\">", XP_GetClientStr(DBT_alertTitle_));
  325. dsgw_emits ("<INPUT TYPE=hidden NAME=MSG VALUE=\"\">"
  326. "</FORM>\n");
  327. }
  328. void
  329. dsgw_emit_confirmForm ()
  330. {
  331. dsgw_form_begin ("confirmForm", "action=\"%s\" target=confirmWindow",
  332. DSGW_URLPREFIX_MAIN_HTTP "confirm.html");
  333. dsgw_emitf ("<INPUT TYPE=hidden NAME=TITLE VALUE=\"%s\">", XP_GetClientStr(DBT_confirmTitle_));
  334. dsgw_emits ("<INPUT TYPE=hidden NAME=MSG VALUE=\"\">"
  335. "<INPUT TYPE=hidden NAME=YES VALUE=\"\">"
  336. "<INPUT TYPE=hidden NAME=NO VALUE=\"\">"
  337. "</FORM>\n");
  338. }
  339. static const char*
  340. defaultWindowOptions = "width=350,height=130,resizable";
  341. void
  342. dsgw_emit_alert (const char* frame, const char* windowOptions, const char* format, ...)
  343. {
  344. if (!windowOptions) windowOptions = defaultWindowOptions;
  345. dsgw_emits (" var aw = window.open(");
  346. dsgw_emits ("''");
  347. /* dsgw_quote_emits (QUOTATION_JAVASCRIPT, DSGW_URLPREFIX_MAIN_HTTP "emptyFrame.html"); */
  348. dsgw_emits ( ", 'alertWindow', ");
  349. dsgw_quote_emits (QUOTATION_JAVASCRIPT, windowOptions);
  350. dsgw_emits ( ");\n"
  351. " aw.focus();\n"
  352. " window."); /* Navigator 3 needs this */
  353. if (frame) dsgw_emitf ("%s.", frame);
  354. dsgw_emits ( "document.alertForm.MSG.value =");
  355. dsgw_quotation_begin (QUOTATION_JAVASCRIPT);
  356. if (format) {
  357. va_list argl;
  358. va_start (argl, format);
  359. dsgw_emitfv (format, argl);
  360. va_end (argl);
  361. }
  362. dsgw_quotation_end();
  363. dsgw_emits ( ";\n"
  364. " window.");
  365. if (frame) dsgw_emitf ("%s.", frame);
  366. dsgw_emits ("document.alertForm.submit();\n");
  367. }
  368. void
  369. dsgw_emit_confirm (const char* frame, const char* yes, const char* no,
  370. const char* windowOptions, int enquote, const char* format, ...)
  371. {
  372. if (!windowOptions) windowOptions = defaultWindowOptions;
  373. dsgw_emits (" cw = window.open ('', 'confirmWindow', ");
  374. dsgw_quote_emits (QUOTATION_JAVASCRIPT, windowOptions);
  375. dsgw_emits ( ");\n"
  376. " cw.focus();\n"
  377. " if (cw.opener == null) cw.opener = self;\n" /* Navigator 2 needs this */
  378. " window."); /* Navigator 3 needs this */
  379. if (frame) dsgw_emitf ("%s.", frame);
  380. dsgw_emits ( "document.confirmForm.MSG.value = ");
  381. if (enquote) dsgw_quotation_begin (QUOTATION_JAVASCRIPT);
  382. if (format) {
  383. va_list argl;
  384. va_start (argl, format);
  385. dsgw_emitfv (format, argl);
  386. va_end (argl);
  387. }
  388. if (enquote) dsgw_quotation_end();
  389. dsgw_emits ( ";\n");
  390. dsgw_emits (" window.");
  391. if (frame) dsgw_emitf ("%s.", frame);
  392. dsgw_emits ( "document.confirmForm.YES.value = ");
  393. dsgw_quote_emits (QUOTATION_JAVASCRIPT, yes ? yes : "");
  394. dsgw_emits ( ";\n");
  395. dsgw_emits (" window.");
  396. if (frame) dsgw_emitf ("%s.", frame);
  397. dsgw_emits ( "document.confirmForm.NO.value = ");
  398. dsgw_quote_emits (QUOTATION_JAVASCRIPT, no ? no : "");
  399. dsgw_emits ( ";\n");
  400. dsgw_emits (" window.");
  401. if (frame) dsgw_emitf ("%s.", frame);
  402. dsgw_emits ( "document.confirmForm.submit();\n");
  403. }