void wiki_show_footer(HttpResponse *res) { http_response_printf(res, "%s", PAGEFOOTER); http_response_printf(res, "</body>\n" "</html>\n" ); }
void wiki_show_changes_page(HttpResponse *res) { WikiPageList **pages = NULL; int n_pages, i; wiki_show_header(res, "Changes", FALSE); pages = wiki_get_pages(&n_pages, NULL); for (i=0; i<n_pages; i++) { struct tm *pTm; char datebuf[64]; pTm = localtime(&pages[i]->mtime); strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %H:%M", pTm); http_response_printf(res, "<a href='%s'>%s</a> %s<br />\n", pages[i]->name, pages[i]->name, datebuf); } wiki_show_footer(res); http_response_send(res); exit(0); }
void wiki_show_changes_page_rss(HttpResponse *res) { WikiPageList **pages = NULL; int n_pages, i; /*char *html_clean_wikitext = NULL; char *wikitext; */ pages = wiki_get_pages(&n_pages, NULL); http_response_printf(res, "<?xml version=\"1.0\"encoding=\"ISO-8859-1\"?>\n" "<rss version=\"2.0\">\n" "<channel><title>DidiWiki Changes feed</title>\n"); for (i=0; i<n_pages; i++) { struct tm *pTm; char datebuf[64]; pTm = localtime(&pages[i]->mtime); strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %H:%M", pTm); http_response_printf(res, "<item><title>%s</title>" "<link>%s%s</link><description>" "Modified %s\n", pages[i]->name, getenv("DIDIWIKI_URL_PREFIX") ? getenv("DIDIWIKI_URL_PREFIX") : "", pages[i]->name, datebuf); /* wikitext = file_read(pages[i]->name); http_response_printf_alloc_buffer(res, strlen(wikitext)*2); html_clean_wikitext = util_htmlize(wikitext, strlen(wikitext)); wiki_print_data_as_html(res, html_clean_wikitext); */ http_response_printf(res, "</description></item>\n"); } http_response_printf(res, "</channel>\n</rss>"); http_response_send(res); exit(0); }
void wiki_show_header(HttpResponse *res, char *page_title, int want_edit) { http_response_printf(res, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" "<html xmlns='http://www.w3.org/1999/xhtml'>\n" "<head>\n" "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />\n" "<link rel='SHORTCUT ICON' href='favicon.ico' />\n" "<link media='all' href='styles.css' rel='stylesheet' type='text/css' />\n" "<title>%s</title>\n" "</head>\n" "<body>\n", page_title ); http_response_printf(res, PAGEHEADER, page_title, (want_edit) ? " ( <a href='?edit' title='Edit this wiki page contents. [alt-j]' accesskey='j'>Edit</a> ) " : "" ); }
void wiki_show_search_results_page(HttpResponse *res, char *expr) { WikiPageList **pages = NULL; int n_pages, i; if (expr == NULL || strlen(expr) == 0) { wiki_show_header(res, "Search", FALSE); http_response_printf(res, "No Search Terms supplied"); wiki_show_footer(res); http_response_send(res); exit(0); } pages = wiki_get_pages(&n_pages, expr); if (pages) { for (i=0; i<n_pages; i++) if (!strcmp(pages[i]->name, expr)) /* redirect on page name match */ wiki_redirect(res, pages[i]->name); wiki_show_header(res, "Search", FALSE); for (i=0; i<n_pages; i++) { http_response_printf(res, "<a href='%s'>%s</a><br />\n", pages[i]->name, pages[i]->name); } } else { wiki_show_header(res, "Search", FALSE); http_response_printf(res, "No matches"); } wiki_show_footer(res); http_response_send(res); exit(0); }
void wiki_show_create_page(HttpResponse *res) { wiki_show_header(res, "Create New Page", FALSE); http_response_printf(res, "%s", CREATEFORM); wiki_show_footer(res); http_response_send(res); exit(0); }
void wiki_page_forbiden(HttpResponse *res) { http_response_printf(res, "<html>\n<p>Permission denied - You need to login.</p>" "<a href='javascript:javascript:history.go(-1)'>Return to the previous page.</a>\n" "</html>\n"); http_response_set_status(res, 403, "Forbidden</"); http_response_send(res); exit(0); }
void wiki_show_edit_page(HttpResponse *res, char *wikitext, char *page) { wiki_show_header(res, page, FALSE); if (wikitext == NULL) wikitext = ""; http_response_printf(res, EDITFORM, page, wikitext); wiki_show_footer(res); http_response_send(res); exit(0); }
void wiki_show_changes_page_rss(HttpResponse *res) { WikiPageList **pages = NULL; int n_pages, i; pages = wiki_get_pages(&n_pages, NULL); http_response_set_content_type(res, "application/xhtml+xml"); http_response_printf(res, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" "<rss version=\"2.0\">\n" "<channel><title>DidiWiki Changes feed</title>\n"); for (i = 0; i < n_pages; i++) { struct tm *pTm; char datebuf[64]; pTm = localtime(&pages[i]->mtime); strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %H:%M", pTm); http_response_printf(res, "<item><title>%s</title>" "<link>%s%s</link><description>" "Modified %s\n", pages[i]->name, getenv("PORTABLEWIKI_URL_PREFIX") ? getenv("PORTABLEWIKI_URL_PREFIX") : "", pages[i]->name, datebuf); http_response_printf(res, "</description></item>\n"); } http_response_printf(res, "</channel>\n</rss>"); http_response_send(res); exit(0); }
int wiki_redirect(HttpResponse *res, char *location) { int header_len = strlen(location) + 14; char *header = alloca(sizeof(char)*header_len); snprintf(header, header_len, "Location: %s\r\n", location); http_response_append_header(res, header); http_response_printf(res, "<html>\n<p>Redirect to %s</p>\n</html>\n", location); http_response_set_status(res, 302, "Moved Temporarily"); http_response_send(res); exit(0); }
/* ** Send a reply indicating that the HTTP request was malformed */ static void malformed_request(int code, char *info) { HttpResponse *res = NULL; res = http_response_new(NULL); http_response_set_status(res, 501, "Not Implemented"); http_response_printf(res, "<html><body>Unrecognized HTTP Request Code=%i</body></html>\n", code); http_response_send(res); /* log Error */ syslog(LOG_LOCAL0|LOG_INFO, "Malformed request 501\nCode=%i\n%s\n", code,info); exit(0); }
/* Use cmd "diff" */ void wiki_show_diff_between_pages(HttpResponse *res, char *page, int mode) { FILE *fp; char line[128]; char *str_ptr; char *cmd; int val1, val2, nbln = 1, lg; char buffer[128]; char action; if (!page) exit(0); char *current = strdup(page); *strstr(current, ".prev") = '\0'; fp = fopen(page, "r"); lg = asprintf(&cmd, "diff -abB %s %s", page, current); // wiki_show_header(res, "Changes", FALSE); FILE *pipe = popen(cmd, "r"); if (!pipe) exit(0); http_response_printf(res, "<p>Current page: %s</p>\n", current); while (!feof(pipe)) { if (fgets(buffer, 128, pipe) != NULL) { /* Analyze results returned by diff */ if (strchr("<>=", buffer[0])) http_response_printf(res, "<B>%s%s</B><br>\n", buffer[0] == '>' ? "New:" : "", &buffer[1]); else if ((str_ptr = strpbrk(buffer, "acd"))) { action = *str_ptr; *str_ptr = '\0'; val1 = atoi(buffer); if ((str_ptr = strchr(buffer, ','))) val2 = atoi(str_ptr + 1); else val2 = val1; if (mode == 2) { /* Show previous page markup */ while (nbln < val2) { if (!fgets(line, 128, fp)) exit(0); http_response_printf(res, "%i:%s<br>\n", nbln, line); nbln++; } } /* Explain change */ switch (action) { case 'd': http_response_printf(res, "<B>Deleted line %i-%i:<br></B>\n", val1, val2); break; case 'a': http_response_printf(res, "<B>Added line %i-%i:<br></B>\n", val1, val2); break; case 'c': http_response_printf(res, "<B>Changed line %i-%i:<br></B>\n", val1, val2); break; } } } } if (mode == 2) { while (fgets(line, 128, fp)) { http_response_printf(res, "%i:%s<br>\n", nbln, line); nbln++; } } pclose(pipe); fclose(fp); // wiki_show_footer(res); http_response_send(res); exit(0); }
void wiki_show_changes_page(HttpResponse *res) { WikiPageList **pages = NULL; int n_pages, i, j, m, lg; char spacing[24]; char *difflink; int *table, *done; //alloc mem with n_pages char *str_ptr; // wiki_show_header(res, "Changes", FALSE); pages = wiki_get_pages(&n_pages, NULL); table = malloc((1 + n_pages) * sizeof(int)); done = malloc((1 + n_pages) * sizeof(int)); http_response_set_content_type(res, "text/html"); /* regroup file and previous file */ for (i = 0; i < n_pages + 1; i++) { done[i] = 0; table[i] = 0; } m = 0; for (i = 0; i < n_pages; i++) if (!done[i] && !strstr(pages[i]->name, ".prev.1")) { for (j = 0; j < n_pages; j++) if (!done[j] && (str_ptr = strstr(pages[j]->name, pages[i]->name)) && !strcmp(str_ptr + strlen(pages[i]->name), ".prev.1")) { table[m++] = i; table[m++] = j; done[i] = 1; done[j] = 1; break; } } /* complete with new files */ for (i = 0; i < n_pages; i++) if (!done[i]) table[m++] = i; for (j = 0; j < m; j++) { struct tm *pTm; char datebuf[64]; i = table[j]; if (strstr(pages[i]->name, ".prev.1")) { strcpy(spacing, " "); lg = asprintf(&difflink, "<a href='/#/Diff/%s'>diff</a>\n" "<a href='/#/Comp/%s'>comp</a>\n", pages[i]->name, pages[i]->name); } else { *spacing = '\0'; difflink = strdup("\0"); } pTm = localtime(&pages[i]->mtime); strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %H:%M", pTm); http_response_printf(res, "%s<a href=/#/View/%s>%s</a> %s %s<br />\n", spacing, pages[i]->name, pages[i]->name, datebuf, difflink); } http_response_printf(res, "<p>Wiki changes are also available as a " "<a href='/rss'>RSS</a> feed.\n"); // wiki_show_footer(res); http_response_send(res); free(table); free(done); exit(0); }
void wiki_handle_rest_call(HttpRequest *req, HttpResponse *res, char *func) { if (func != NULL && *func != '\0') { if (!strcmp(func, "page/get")) { char *page = http_request_param_get(req, "page"); if (page == NULL) page = http_request_get_query_string(req); if (page && (access(page, R_OK) == 0)) { http_response_printf(res, "%s", file_read(page)); http_response_send(res); return; } } else if (!strcmp(func, "page/set")) { char *wikitext = NULL, *page = NULL; if( ( (wikitext = http_request_param_get(req, "text")) != NULL) && ( (page = http_request_param_get(req, "page")) != NULL)) { file_write(page, wikitext); http_response_printf(res, "success"); http_response_send(res); return; } } else if (!strcmp(func, "page/delete")) { char *page = http_request_param_get(req, "page"); if (page == NULL) page = http_request_get_query_string(req); if (page && (unlink(page) > 0)) { http_response_printf(res, "success"); http_response_send(res); return; } } else if (!strcmp(func, "page/exists")) { char *page = http_request_param_get(req, "page"); if (page == NULL) page = http_request_get_query_string(req); if (page && (access(page, R_OK) == 0)) { http_response_printf(res, "success"); http_response_send(res); return; } } else if (!strcmp(func, "pages") || !strcmp(func, "search")) { WikiPageList **pages = NULL; int n_pages, i; char *expr = http_request_param_get(req, "expr"); if (expr == NULL) expr = http_request_get_query_string(req); pages = wiki_get_pages(&n_pages, expr); if (pages) { for (i=0; i<n_pages; i++) { struct tm *pTm; char datebuf[64]; pTm = localtime(&pages[i]->mtime); strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %H:%M", pTm); http_response_printf(res, "%s\t%s\n", pages[i]->name, datebuf); } http_response_send(res); return; } } } http_response_set_status(res, 500, "Error"); http_response_printf(res, "<html><body>Failed</body></html>\n"); http_response_send(res); return; }
void wiki_print_data_as_html(HttpResponse *res, char *raw_page_data) { char *p = raw_page_data; /* accumalates non marked up text */ char *q = NULL, *link = NULL; /* temporary scratch stuff */ char *line = NULL; int line_len; int i, j, skip_chars; /* flags, mainly for open tag states */ int bold_on = 0; int italic_on = 0; int underline_on = 0; int strikethrough_on = 0; int open_para = 0; int pre_on = 0; int table_on = 0; #define ULIST 0 #define OLIST 1 #define NUM_LIST_TYPES 2 struct { char ident; int depth; char *tag; } listtypes[] = { { '*', 0, "ul" }, { '#', 0, "ol" } }; q = p; /* p accumalates non marked up text, q is just a pointer * to the end of the current line - used by below func. */ while ( (line = get_line_from_string(&q, &line_len)) ) { int header_level = 0; char *line_start = line; int skip_to_content = 0; /* * process any initial wiki chars at line beginning */ if (pre_on && !isspace(*line) && *line != '\0') { /* close any preformatting if already on*/ http_response_printf(res, "\n</pre>\n") ; pre_on = 0; } /* Handle ordered & unordered list, code is a bit mental.. */ for (i=0; i<NUM_LIST_TYPES; i++) { /* extra checks avoid bolding */ if ( *line == listtypes[i].ident && ( *(line+1) == listtypes[i].ident || isspace(*(line+1)) ) ) { int item_depth = 0; if (listtypes[!i].depth) { for (j=0; j<listtypes[!i].depth; j++) http_response_printf(res, "</%s>\n", listtypes[!i].tag); listtypes[!i].depth = 0; } while ( *line == listtypes[i].ident ) { line++; item_depth++; } if (item_depth < listtypes[i].depth) { for (j = 0; j < (listtypes[i].depth - item_depth); j++) http_response_printf(res, "</%s>\n", listtypes[i].tag); } else { for (j = 0; j < (item_depth - listtypes[i].depth); j++) http_response_printf(res, "<%s>\n", listtypes[i].tag); } http_response_printf(res, "<li>"); listtypes[i].depth = item_depth; skip_to_content = 1; } else if (listtypes[i].depth && !listtypes[!i].depth) { /* close current list */ for (j=0; j<listtypes[i].depth; j++) http_response_printf(res, "</%s>\n", listtypes[i].tag); listtypes[i].depth = 0; } } if (skip_to_content) goto line_content; /* skip parsing any more initial chars */ /* Tables */ if (*line == '|') { if (table_on==0) http_response_printf(res, "<table class='wikitable' cellspacing='0' cellpadding='4'>\n"); line++; http_response_printf(res, "<tr><td>"); table_on = 1; goto line_content; } else { if(table_on) { http_response_printf(res, "</table>\n"); table_on = 0; } } /* pre formated */ if ( (isspace(*line) || *line == '\0')) { int n_spaces = 0; while ( isspace(*line) ) { line++; n_spaces++; } if (*line == '\0') /* empty line - para */ { if (pre_on) { http_response_printf(res, "\n") ; continue; } else if (open_para) { http_response_printf(res, "\n</p><p>\n") ; } else { http_response_printf(res, "\n<p>\n") ; open_para = 1; } } else /* starts with space so Pre formatted, see above for close */ { if (!pre_on) http_response_printf(res, "<pre>\n") ; pre_on = 1; line = line - ( n_spaces - 1 ); /* rewind so extra spaces they matter to pre */ http_response_printf(res, "%s\n", line); continue; } } else if ( *line == '=' ) { while (*line == '=') { header_level++; line++; } http_response_printf(res, "<h%d>", header_level); p = line; } else if ( *line == '-' && *(line+1) == '-' ) { /* rule */ http_response_printf(res, "<hr/>\n"); while ( *line == '-' ) line++; } line_content: /* * now process rest of the line */ p = line; while ( *line != '\0' ) { if ( *line == '!' && !isspace(*(line+1))) { /* escape next word - skip it */ *line = '\0'; http_response_printf(res, "%s", p); p = ++line; while (*line != '\0' && !isspace(*line)) line++; if (*line == '\0') continue; } else if ((link = check_for_link(line, &skip_chars)) != NULL) { http_response_printf(res, "%s", p); http_response_printf(res, "%s", link); line += skip_chars; p = line; continue; } /* TODO: Below is getting bloated and messy, need rewriting more * compactly ( and efficently ). */ else if (*line == '*') { /* Try and be smart about what gets bolded */ if (line_start != line && !is_wiki_format_char_or_space(*(line-1)) && !bold_on) { line++; continue; } if ((isspace(*(line+1)) && !bold_on)) { line++; continue; } /* bold */ *line = '\0'; http_response_printf(res, "%s%s\n", p, bold_on ? "</b>" : "<b>"); bold_on ^= 1; /* reset flag */ p = line+1; } else if (*line == '_' ) { if (line_start != line && !is_wiki_format_char_or_space(*(line-1)) && !underline_on) { line++; continue; } if (isspace(*(line+1)) && !underline_on) { line++; continue; } /* underline */ *line = '\0'; http_response_printf(res, "%s%s\n", p, underline_on ? "</u>" : "<u>"); underline_on ^= 1; /* reset flag */ p = line+1; } else if (*line == '-') { if (line_start != line && !is_wiki_format_char_or_space(*(line-1)) && !strikethrough_on) { line++; continue; } if (isspace(*(line+1)) && !strikethrough_on) { line++; continue; } /* strikethrough */ *line = '\0'; http_response_printf(res, "%s%s\n", p, strikethrough_on ? "</del>" : "<del>"); strikethrough_on ^= 1; /* reset flag */ p = line+1; } else if (*line == '/' ) { if (line_start != line && !is_wiki_format_char_or_space(*(line-1)) && !italic_on) { line++; continue; } if (isspace(*(line+1)) && !italic_on) { line++; continue; } /* crude path detection */ if (line_start != line && isspace(*(line-1)) && !italic_on) { char *tmp = line+1; int slashes = 0; /* Hack to escape out file paths */ while (*tmp != '\0' && !isspace(*tmp)) { if (*tmp == '/') slashes++; tmp++; } if (slashes > 1 || (slashes == 1 && *(tmp-1) != '/')) { line = tmp; continue; } } if (*(line+1) == '/') line++; /* escape out common '//' - eg urls */ else { /* italic */ *line = '\0'; http_response_printf(res, "%s%s\n", p, italic_on ? "</i>" : "<i>"); italic_on ^= 1; /* reset flag */ p = line+1; } } else if (*line == '|' && table_on) /* table column */ { *line = '\0'; http_response_printf(res, "%s", p); http_response_printf(res, "</td><td>\n"); p = line+1; } line++; } /* next word */ if (*p != '\0') /* accumalated text left over */ http_response_printf(res, "%s", p); /* close any html tags that could be still open */ if (listtypes[ULIST].depth) http_response_printf(res, "</li>"); if (listtypes[OLIST].depth) http_response_printf(res, "</li>"); if (table_on) http_response_printf(res, "</td></tr>\n"); if (header_level) http_response_printf(res, "</h%d>\n", header_level); else http_response_printf(res, "\n"); } /* next line */ /* clean up anything thats still open */ if (pre_on) http_response_printf(res, "</pre>\n"); /* close any open lists */ for (i=0; i<listtypes[ULIST].depth; i++) http_response_printf(res, "</ul>\n"); for (i=0; i<listtypes[OLIST].depth; i++) http_response_printf(res, "</ol>\n"); /* close any open paras */ if (open_para) http_response_printf(res, "</p>\n"); /* tables */ if (table_on) http_response_printf(res, "</table>\n"); }
void wiki_handle_http_request(HttpRequest *req) { HttpResponse *res = http_response_new(req); char *page = http_request_get_path_info(req); char *command = http_request_get_query_string(req); char *wikitext = ""; util_dehttpize(page); /* remove any encoding on the requested page name. */ if (!strcmp(page, "/")) { if (access("WikiHome", R_OK) != 0) wiki_redirect(res, "/WikiHome?create"); page = "/WikiHome"; } if (!strcmp(page, "/styles.css")) { /* Return CSS page */ http_response_set_content_type(res, "text/css"); http_response_printf(res, "%s", CssData); http_response_send(res); exit(0); } if (!strcmp(page, "/favicon.ico")) { /* Return favicon */ http_response_set_content_type(res, "image/ico"); http_response_set_data(res, FaviconData, FaviconDataLen); http_response_send(res); exit(0); } page = page + 1; /* skip slash */ if (!strncmp(page, "api/", 4)) { char *p; page += 4; for (p=page; *p != '\0'; p++) if (*p=='?') { *p ='\0'; break; } wiki_handle_rest_call(req, res, page); exit(0); } /* A little safety. issue a malformed request for any paths, * There shouldn't need to be any.. */ if (strchr(page, '/')) { http_response_set_status(res, 404, "Not Found"); http_response_printf(res, "<html><body>404 Not Found</body></html>\n"); http_response_send(res); exit(0); } if (!strcmp(page, "Changes")) { wiki_show_changes_page(res); } else if (!strcmp(page, "ChangesRss")) { wiki_show_changes_page_rss(res); } else if (!strcmp(page, "Search")) { wiki_show_search_results_page(res, http_request_param_get(req, "expr")); } else if (!strcmp(page, "Create")) { if ( (wikitext = http_request_param_get(req, "title")) != NULL) { /* create page and redirect */ wiki_redirect(res, http_request_param_get(req, "title")); } else { /* show create page form */ wiki_show_create_page(res); } } else { /* TODO: dont blindly write wikitext data to disk */ if ( (wikitext = http_request_param_get(req, "wikitext")) != NULL) { file_write(page, wikitext); } if (access(page, R_OK) == 0) /* page exists */ { wikitext = file_read(page); if (!strcmp(command, "edit")) { /* print edit page */ wiki_show_edit_page(res, wikitext, page); } else { wiki_show_page(res, wikitext, page); } } else { if (!strcmp(command, "create")) { wiki_show_edit_page(res, NULL, page); } else { char buf[1024]; snprintf(buf, 1024, "%s?create", page); wiki_redirect(res, buf); } } } }