"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/types.c" (16 Nov 2011, 15928 Bytes) of archive /linux/www/links-1.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "types.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8_vs_1.03.

    1 #include "links.h"
    2 
    3 struct list_head mailto_prog = { &mailto_prog, &mailto_prog };
    4 struct list_head telnet_prog = { &telnet_prog, &telnet_prog };
    5 struct list_head tn3270_prog = { &tn3270_prog, &tn3270_prog };
    6 struct list_head mms_prog = { &mms_prog, &mms_prog };
    7 
    8 struct list_head assoc = { &assoc, &assoc };
    9 
   10 tcount get_assoc_cnt()
   11 {
   12     static tcount assoc_cnt = 0;
   13     if (!++assoc_cnt) assoc_cnt = 1;
   14     return assoc_cnt;
   15 }
   16 
   17 struct list_head extensions = { &extensions, &extensions };
   18 
   19 void delete_association(struct assoc *del)
   20 {
   21     del_from_list(del);
   22     mem_free(del->label);
   23     mem_free(del->ct);
   24     mem_free(del->prog);
   25     mem_free(del);
   26 }
   27 
   28 void delete_extension(struct extension *del)
   29 {
   30     del_from_list(del);
   31     mem_free(del->ext);
   32     mem_free(del->ct);
   33     mem_free(del);
   34 }
   35 
   36 int is_in_list(unsigned char *list, unsigned char *str, int l)
   37 {
   38     unsigned char *l2, *l3;
   39     if (!l) return 0;
   40     rep:
   41     while (*list && *list <= ' ') list++;
   42     if (!*list) return 0;
   43     for (l2 = list; *l2 && *l2 != ','; l2++) ;
   44     for (l3 = l2 - 1; l3 >= list && *l3 <= ' '; l3--) ;
   45     l3++;
   46     if (l3 - list == l && !casecmp(str, list, l)) return 1;
   47     list = l2;
   48     if (*list == ',') list++;
   49     goto rep;
   50 }
   51 
   52 unsigned char *get_content_type(unsigned char *head, unsigned char *url)
   53 {
   54     struct extension *e;
   55     struct assoc *a;
   56     unsigned char *ct, *ext, *exxt;
   57     int extl, el;
   58     if (head && (ct = parse_http_header(head, "Content-Type", NULL))) {
   59         unsigned char *s;
   60         if ((s = strchr(ct, ';'))) *s = 0;
   61         while (*ct && ct[strlen(ct) - 1] <= ' ') ct[strlen(ct) - 1] = 0;
   62         return ct;
   63     }
   64     ext = NULL, extl = 0;
   65     for (ct = url; *ct && !end_of_dir(*ct); ct++)
   66         if (*ct == '.') ext = ct + 1;
   67         else if (dir_sep(*ct)) ext = NULL;
   68     if (ext) while (ext[extl] && !dir_sep(ext[extl]) && !end_of_dir(ext[extl])) extl++;
   69     if ((extl == 3 && !casecmp(ext, "htm", 3)) ||
   70         (extl == 4 && !casecmp(ext, "html", 4))) return stracpy("text/html");
   71     foreach(e, extensions) if (is_in_list(e->ext, ext, extl)) return stracpy(e->ct);
   72     exxt = init_str(); el = 0;
   73     add_to_str(&exxt, &el, "application/x-");
   74     add_bytes_to_str(&exxt, &el, ext, extl);
   75     foreach(a, assoc) if (is_in_list(a->ct, exxt, el)) return exxt;
   76     mem_free(exxt);
   77     return !force_html ? stracpy("text/plain") : stracpy("text/html");
   78 }
   79 
   80 struct assoc *get_type_assoc(struct terminal *term, unsigned char *type)
   81 {
   82     struct assoc *a;
   83     foreach(a, assoc) if (a->system == SYSTEM_ID && (term->environment & ENV_XWIN ? a->xwin : a->cons) && is_in_list(a->ct, type, strlen(type))) return a;
   84     return NULL;
   85 }
   86 
   87 void free_types()
   88 {
   89     struct assoc *a;
   90     struct extension *e;
   91     struct protocol_program *p;
   92     foreach(a, assoc) {
   93         mem_free(a->ct);
   94         mem_free(a->prog);
   95         mem_free(a->label);
   96     }
   97     free_list(assoc);
   98     foreach(e, extensions) {
   99         mem_free(e->ext);
  100         mem_free(e->ct);
  101     }
  102     free_list(extensions);
  103     foreach(p, mailto_prog) mem_free(p->prog);
  104     free_list(mailto_prog);
  105     foreach(p, telnet_prog) mem_free(p->prog);
  106     free_list(telnet_prog);
  107     foreach(p, tn3270_prog) mem_free(p->prog);
  108     free_list(tn3270_prog);
  109     foreach(p, mms_prog) mem_free(p->prog);
  110     free_list(mms_prog);
  111 }
  112 
  113 unsigned char *ct_msg[] = {
  114     TEXT_(T_LABEL),
  115     TEXT_(T_CONTENT_TYPES),
  116     TEXT_(T_PROGRAM__IS_REPLACED_WITH_FILE_NAME),
  117 #ifdef ASSOC_BLOCK
  118     TEXT_(T_BLOCK_TERMINAL_WHILE_PROGRAM_RUNNING),
  119 #endif
  120 #ifdef ASSOC_CONS_XWIN
  121     TEXT_(T_RUN_ON_TERMINAL),
  122     TEXT_(T_RUN_IN_XWINDOW),
  123 #endif
  124     TEXT_(T_ASK_BEFORE_OPENING),
  125 };
  126 
  127 void add_ct_fn(struct dialog_data *dlg)
  128 {
  129     struct terminal *term = dlg->win->term;
  130     int max = 0, min = 0;
  131     int w, rw;
  132     int y = -1;
  133     int p = 1;
  134 #ifdef ASSOC_BLOCK
  135     p++;
  136 #endif
  137 #ifdef ASSOC_CONS_XWIN
  138     p += 2;
  139 #endif
  140     max_text_width(term, ct_msg[0], &max);
  141     min_text_width(term, ct_msg[0], &min);
  142     max_text_width(term, ct_msg[1], &max);
  143     min_text_width(term, ct_msg[1], &min);
  144     max_text_width(term, ct_msg[2], &max);
  145     min_text_width(term, ct_msg[2], &min);
  146     max_group_width(term, ct_msg + 3, dlg->items + 3, p, &max);
  147     min_group_width(term, ct_msg + 3, dlg->items + 3, p, &min);
  148     max_buttons_width(term, dlg->items + 3 + p, 2, &max);
  149     min_buttons_width(term, dlg->items + 3 + p, 2, &min);
  150     w = term->x * 9 / 10 - 2 * DIALOG_LB;
  151     if (w > max) w = max;
  152     if (w < min) w = min;
  153     if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
  154     if (w < 1) w = 1;
  155     rw = 0;
  156     dlg_format_text(NULL, term, _(ct_msg[0], term), 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
  157     y += 2;
  158     dlg_format_text(NULL, term, _(ct_msg[1], term), 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
  159     y += 2;
  160     dlg_format_text(NULL, term, _(ct_msg[2], term), 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
  161     y += 2;
  162     dlg_format_group(NULL, term, ct_msg + 3, dlg->items + 3, p, 0, &y, w, &rw);
  163     y++;
  164     dlg_format_buttons(NULL, term, dlg->items + 3 + p, 2, 0, &y, w, &rw, AL_CENTER);
  165     w = rw;
  166     dlg->xw = w + 2 * DIALOG_LB;
  167     dlg->yw = y + 2 * DIALOG_TB;
  168     center_dlg(dlg);
  169     draw_dlg(dlg);
  170     y = dlg->y + DIALOG_TB;
  171     dlg_format_text(term, term, ct_msg[0], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
  172     dlg_format_field(term, term, &dlg->items[0], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
  173     y++;
  174     dlg_format_text(term, term, ct_msg[1], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
  175     dlg_format_field(term, term, &dlg->items[1], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
  176     y++;
  177     dlg_format_text(term, term, ct_msg[2], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
  178     dlg_format_field(term, term, &dlg->items[2], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
  179     y++;
  180     dlg_format_group(term, term, ct_msg + 3, &dlg->items[3], p, dlg->x + DIALOG_LB, &y, w, NULL);
  181     y++;
  182     dlg_format_buttons(term, term, &dlg->items[3 + p], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
  183 }
  184 
  185 void update_assoc(struct assoc *new)
  186 {
  187     struct assoc *repl;
  188     if (!new->label[0] || !new->ct[0] || !new->prog[0]) return;
  189     if (new->cnt) {
  190         foreach(repl, assoc) if (repl->cnt == new->cnt) {
  191             mem_free(repl->label);
  192             mem_free(repl->ct);
  193             mem_free(repl->prog);
  194             goto replace;
  195         }
  196         return;
  197     }
  198     foreach(repl, assoc) if (!strcmp(repl->label, new->label) && !strcmp(repl->ct, new->ct) && !strcmp(repl->prog, new->prog) && repl->block == new->block && repl->cons == new->cons && repl->xwin == new->xwin && repl->ask == new->ask && repl->system == new->system) {
  199         del_from_list(repl);
  200         add_to_list(assoc, repl);
  201         return;
  202     }
  203     new->cnt = get_assoc_cnt();
  204     repl = mem_alloc(sizeof(struct assoc));
  205     add_to_list(assoc, repl);
  206     replace:
  207     repl->label = stracpy(new->label);
  208     repl->ct = stracpy(new->ct);
  209     repl->prog = stracpy(new->prog);
  210     repl->block = new->block;
  211     repl->cons = new->cons;
  212     repl->xwin = new->xwin;
  213     repl->ask = new->ask;
  214     repl->system = new->system;
  215     repl->cnt = new->cnt;
  216 }
  217 
  218 void really_del_ct(void *fcp)
  219 {
  220     tcount fc = (int)fcp;
  221     struct assoc *del;
  222     foreach(del, assoc) if (del->cnt == fc) goto ok;
  223     return;
  224     ok:
  225     delete_association(del);
  226 }
  227 
  228 void menu_del_ct(struct terminal *term, void *fcp, void *xxx2)
  229 {
  230     unsigned char *str;
  231     int l;
  232     tcount fc = (int)fcp;
  233     struct assoc *del;
  234     foreach(del, assoc) if (del->cnt == fc) goto ok;
  235     return;
  236     ok:
  237     str = init_str(), l = 0;
  238     add_to_str(&str, &l, del->ct);
  239     add_to_str(&str, &l, " -> ");
  240     add_to_str(&str, &l, del->prog);
  241     msg_box(term, getml(str, NULL), TEXT_(T_DELETE_ASSOCIATION), AL_CENTER | AL_EXTD_TEXT, TEXT_(T_DELETE_ASSOCIATION), ": ", str, "?", NULL, fcp, 2, TEXT_(T_YES), really_del_ct, B_ENTER, TEXT_(T_NO), NULL, B_ESC);
  242 }
  243 
  244 void menu_add_ct(struct terminal *term, void *fcp, void *xxx2)
  245 {
  246     int p;
  247     tcount fc = (int)fcp;
  248     struct assoc *new, *from;
  249     unsigned char *label;
  250     unsigned char *ct;
  251     unsigned char *prog;
  252     struct dialog *d;
  253     if (fc) {
  254         foreach(from, assoc) if (from->cnt == fc) goto ok;
  255         return;
  256     }
  257     from = NULL;
  258     ok:
  259     d = mem_alloc(sizeof(struct dialog) + 10 * sizeof(struct dialog_item) + sizeof(struct assoc) + 3 * MAX_STR_LEN);
  260     memset(d, 0, sizeof(struct dialog) + 10 * sizeof(struct dialog_item) + sizeof(struct assoc) + 3 * MAX_STR_LEN);
  261     new = (struct assoc *)&d->items[10];
  262     new->label = label = (unsigned char *)(new + 1);
  263     new->ct = ct = label + MAX_STR_LEN;
  264     new->prog = prog = ct + MAX_STR_LEN;
  265     if (from) {
  266         safe_strncpy(label, from->label, MAX_STR_LEN);
  267         safe_strncpy(ct, from->ct, MAX_STR_LEN);
  268         safe_strncpy(prog, from->prog, MAX_STR_LEN);
  269         new->block = from->block;
  270         new->cons = from->cons;
  271         new->xwin = from->xwin;
  272         new->ask = from->ask;
  273         new->system = from->system;
  274         new->cnt = from->cnt;
  275     } else {
  276         new->block = new->xwin = new->cons = 1;
  277         new->ask = 1;
  278         new->system = SYSTEM_ID;
  279     }
  280     d->title = TEXT_(T_ASSOCIATION);
  281     d->fn = add_ct_fn;
  282     d->refresh = (void (*)(void *))update_assoc;
  283     d->refresh_data = new;
  284     d->items[0].type = D_FIELD;
  285     d->items[0].dlen = MAX_STR_LEN;
  286     d->items[0].data = label;
  287     d->items[0].fn = check_nonempty;
  288     d->items[1].type = D_FIELD;
  289     d->items[1].dlen = MAX_STR_LEN;
  290     d->items[1].data = ct;
  291     d->items[1].fn = check_nonempty;
  292     d->items[2].type = D_FIELD;
  293     d->items[2].dlen = MAX_STR_LEN;
  294     d->items[2].data = prog;
  295     d->items[2].fn = check_nonempty;
  296     p = 3;
  297 #ifdef ASSOC_BLOCK
  298     d->items[p].type = D_CHECKBOX;
  299     d->items[p].data = (unsigned char *)&new->block;
  300     d->items[p++].dlen = sizeof(int);
  301 #endif
  302 #ifdef ASSOC_CONS_XWIN
  303     d->items[p].type = D_CHECKBOX;
  304     d->items[p].data = (unsigned char *)&new->cons;
  305     d->items[p++].dlen = sizeof(int);
  306     d->items[p].type = D_CHECKBOX;
  307     d->items[p].data = (unsigned char *)&new->xwin;
  308     d->items[p++].dlen = sizeof(int);
  309 #endif
  310     d->items[p].type = D_CHECKBOX;
  311     d->items[p].data = (unsigned char *)&new->ask;
  312     d->items[p++].dlen = sizeof(int);
  313     d->items[p].type = D_BUTTON;
  314     d->items[p].gid = B_ENTER;
  315     d->items[p].fn = ok_dialog;
  316     d->items[p++].text = TEXT_(T_OK);
  317     d->items[p].type = D_BUTTON;
  318     d->items[p].gid = B_ESC;
  319     d->items[p].text = TEXT_(T_CANCEL);
  320     d->items[p++].fn = cancel_dialog;
  321     d->items[p++].type = D_END;
  322     do_dialog(term, d, getml(d, NULL));
  323 }
  324 
  325 struct menu_item mi_no_assoc[] = {
  326     { TEXT_(T_NO_ASSOCIATIONS), "", M_BAR, NULL, NULL, 0, 0 },
  327     { NULL, NULL, 0, NULL, NULL, 0, 0 },
  328 };
  329 
  330 void menu_list_assoc(struct terminal *term, void *fn, void *xxx)
  331 {
  332     struct assoc *a;
  333     struct menu_item *mi = NULL;
  334     int n = 0;
  335     foreachback(a, assoc) if (a->system == SYSTEM_ID) {
  336         if (!mi && !(mi = new_menu(7))) return;
  337         add_to_menu(&mi, stracpy(a->label), stracpy(a->ct), "", MENU_FUNC fn, (void *)a->cnt, 0), n++;
  338     }
  339     if (!mi) do_menu(term, mi_no_assoc, xxx);
  340     else do_menu(term, mi, xxx);
  341 }
  342 
  343 unsigned char *ext_msg[] = {
  344     TEXT_(T_EXTENSION_S),
  345     TEXT_(T_CONTENT_TYPE),
  346 };
  347 
  348 void add_ext_fn(struct dialog_data *dlg)
  349 {
  350     struct terminal *term = dlg->win->term;
  351     int max = 0, min = 0;
  352     int w, rw;
  353     int y = -1;
  354     max_text_width(term, ext_msg[0], &max);
  355     min_text_width(term, ext_msg[0], &min);
  356     max_text_width(term, ext_msg[1], &max);
  357     min_text_width(term, ext_msg[1], &min);
  358     max_buttons_width(term, dlg->items + 2, 2, &max);
  359     min_buttons_width(term, dlg->items + 2, 2, &min);
  360     w = term->x * 9 / 10 - 2 * DIALOG_LB;
  361     if (w > max) w = max;
  362     if (w < min) w = min;
  363     if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
  364     if (w < 1) w = 1;
  365     rw = 0;
  366     dlg_format_text(NULL, term, ext_msg[0], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
  367     y += 2;
  368     dlg_format_text(NULL, term, ext_msg[1], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
  369     y += 2;
  370     dlg_format_buttons(NULL, term, dlg->items + 2, 2, 0, &y, w, &rw, AL_CENTER);
  371     w = rw;
  372     dlg->xw = w + 2 * DIALOG_LB;
  373     dlg->yw = y + 2 * DIALOG_TB;
  374     center_dlg(dlg);
  375     draw_dlg(dlg);
  376     y = dlg->y + DIALOG_TB;
  377     dlg_format_text(term, term, ext_msg[0], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
  378     dlg_format_field(term, term, &dlg->items[0], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
  379     y++;
  380     dlg_format_text(term, term, ext_msg[1], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
  381     dlg_format_field(term, term, &dlg->items[1], dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
  382     y++;
  383     dlg_format_buttons(term, term, &dlg->items[2], 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
  384 }
  385 
  386 void update_ext(struct extension *new)
  387 {
  388     struct extension *repl;
  389     if (!new->ext[0] || !new->ct[0]) return;
  390     if (new->cnt) {
  391         foreach(repl, extensions) if (repl->cnt == new->cnt) {
  392             mem_free(repl->ext);
  393             mem_free(repl->ct);
  394             goto replace;
  395         }
  396         return;
  397     }
  398     foreach(repl, extensions) if (!strcmp(repl->ext, new->ext) && !strcmp(repl->ct, new->ct)) {
  399         del_from_list(repl);
  400         add_to_list(extensions, repl);
  401         return;
  402     }
  403     new->cnt = get_assoc_cnt();
  404     repl = mem_alloc(sizeof(struct extension));
  405     add_to_list(extensions, repl);
  406     replace:
  407     repl->ext = stracpy(new->ext);
  408     repl->ct = stracpy(new->ct);
  409     repl->cnt = new->cnt;
  410 }
  411 
  412 void really_del_ext(void *fcp)
  413 {
  414     tcount fc = (int)fcp;
  415     struct extension *del;
  416     foreach(del, extensions) if (del->cnt == fc) goto ok;
  417     return;
  418     ok:
  419     delete_extension(del);
  420 }
  421 
  422 void menu_del_ext(struct terminal *term, void *fcp, void *xxx2)
  423 {
  424     unsigned char *str;
  425     int l;
  426     tcount fc = (int)fcp;
  427     struct extension *del;
  428     foreach(del, extensions) if (del->cnt == fc) goto ok;
  429     return;
  430     ok:
  431     str = init_str(), l = 0;
  432     add_to_str(&str, &l, del->ext);
  433     add_to_str(&str, &l, " -> ");
  434     add_to_str(&str, &l, del->ct);
  435     msg_box(term, getml(str, NULL), TEXT_(T_DELETE_EXTENSION), AL_CENTER | AL_EXTD_TEXT, TEXT_(T_DELETE_EXTENSION), " ", str, "?", NULL, fcp, 2, TEXT_(T_YES), really_del_ext, B_ENTER, TEXT_(T_NO), NULL, B_ESC);
  436 }
  437 
  438 void menu_add_ext(struct terminal *term, void *fcp, void *xxx2)
  439 {
  440     tcount fc = (int)fcp;
  441     struct extension *new, *from;
  442     unsigned char *ext;
  443     unsigned char *ct;
  444     struct dialog *d;
  445     if (fc) {
  446         foreach(from, extensions) if (from->cnt == fc) goto ok;
  447         return;
  448     }
  449     from = NULL;
  450     ok:
  451     d = mem_alloc(sizeof(struct dialog) + 5 * sizeof(struct dialog_item) + sizeof(struct extension) + 2 * MAX_STR_LEN);
  452     memset(d, 0, sizeof(struct dialog) + 5 * sizeof(struct dialog_item) + sizeof(struct extension) + 2 * MAX_STR_LEN);
  453     new = (struct extension *)&d->items[5];
  454     new->ext = ext = (unsigned char *)(new + 1);
  455     new->ct = ct = ext + MAX_STR_LEN;
  456     if (from) {
  457         safe_strncpy(ext, from->ext, MAX_STR_LEN);
  458         safe_strncpy(ct, from->ct, MAX_STR_LEN);
  459         new->cnt = from->cnt;
  460     }
  461     d->title = TEXT_(T_EXTENSION);
  462     d->fn = add_ext_fn;
  463     d->refresh = (void (*)(void *))update_ext;
  464     d->refresh_data = new;
  465     d->items[0].type = D_FIELD;
  466     d->items[0].dlen = MAX_STR_LEN;
  467     d->items[0].data = ext;
  468     d->items[0].fn = check_nonempty;
  469     d->items[1].type = D_FIELD;
  470     d->items[1].dlen = MAX_STR_LEN;
  471     d->items[1].data = ct;
  472     d->items[1].fn = check_nonempty;
  473     d->items[2].type = D_BUTTON;
  474     d->items[2].gid = B_ENTER;
  475     d->items[2].fn = ok_dialog;
  476     d->items[2].text = TEXT_(T_OK);
  477     d->items[3].type = D_BUTTON;
  478     d->items[3].gid = B_ESC;
  479     d->items[3].text = TEXT_(T_CANCEL);
  480     d->items[3].fn = cancel_dialog;
  481     d->items[4].type = D_END;
  482     do_dialog(term, d, getml(d, NULL));
  483 }
  484 
  485 struct menu_item mi_no_ext[] = {
  486     { TEXT_(T_NO_EXTENSIONS), "", M_BAR, NULL, NULL, 0, 0 },
  487     { NULL, NULL, 0, NULL, NULL, 0, 0 },
  488 };
  489 
  490 void menu_list_ext(struct terminal *term, void *fn, void *xxx)
  491 {
  492     struct extension *a;
  493     struct menu_item *mi = NULL;
  494     int n = 0;
  495     foreachback(a, extensions) {
  496         if (!mi && !(mi = new_menu(7))) return;
  497         add_to_menu(&mi, stracpy(a->ext), stracpy(a->ct), "", MENU_FUNC fn, (void *)a->cnt, 0), n++;
  498     }
  499     if (!mi) do_menu(term, mi_no_ext, xxx);
  500     else do_menu(term, mi, xxx);
  501 }
  502 
  503 void update_prog(struct list_head *l, unsigned char *p, int s)
  504 {
  505     struct protocol_program *repl;
  506     foreach(repl, *l) if (repl->system == s) {
  507         mem_free(repl->prog);
  508         goto ss;
  509     }
  510     repl = mem_alloc(sizeof(struct protocol_program));
  511     add_to_list(*l, repl);
  512     repl->system = s;
  513     ss:
  514     repl->prog = mem_alloc(MAX_STR_LEN);
  515     safe_strncpy(repl->prog, p, MAX_STR_LEN);
  516 }
  517 
  518 unsigned char *get_prog(struct list_head *l)
  519 {
  520     struct protocol_program *repl;
  521     foreach(repl, *l) if (repl->system == SYSTEM_ID) return repl->prog;
  522     update_prog(l, "", SYSTEM_ID);
  523     foreach(repl, *l) if (repl->system == SYSTEM_ID) return repl->prog;
  524     return NULL;
  525 }
  526 
  527 int is_html_type(unsigned char *ct)
  528 {
  529     return !strcasecmp(ct, "text/html") || !strcasecmp(ct, "text/x-server-parsed-html") || !casecmp(ct, "application/xhtml", strlen("application/xhtml"));
  530 }