/*
* Copyright (c) 2004-2009 Hypertriton, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "pathnames.h"
#include "nls.h"
#include "session.h"
struct post_comment {
u_int id; /* Comment identifier */
time_t ptime; /* Time of original comment post */
time_t mtime; /* Time of last comment modification */
char author[16]; /* Author of comment */
int score; /* Moderation */
TAILQ_ENTRY(post_comment) comments;
};
struct post {
u_int id; /* Post identifier */
time_t ptime; /* Time of original post */
time_t mtime; /* Time of last modification */
char *title; /* Title of post */
char *author; /* Author of original post */
char *cats; /* Associated categories */
char *data; /* Post buffer (NULL = not resident) */
size_t len; /* Post size */
TAILQ_HEAD(,post_comment) comments;
};
enum {
TITLE_MAX = 2048,
CATS_MAX = 1024,
TEXT_MAX = 262144,
POST_ID_MAX = 5,
OP_MAX = 64
};
CGI_Application weblogApp;
CGI_Module mainModule;
struct post *posts = NULL;
unsigned int nposts = 0;
TBL *tblCategories;
int ncurrent_ents = 10;
int nrecent_ents = 20;
static void
Cleanup(void)
{
int i;
for (i = 0; i < nposts; i++) {
struct post *post = &posts[i];
struct post_comment *comm, *ncomm;
if (post->title != NULL)
free(post->title);
if (post->author != NULL)
free(post->author);
if (post->cats != NULL)
free(post->cats);
if (post->data != NULL)
free(post->data);
for (comm = TAILQ_FIRST(&post->comments);
comm != TAILQ_END(&post->comments);
comm = ncomm) {
ncomm = TAILQ_NEXT(comm, comments);
free(comm);
}
}
nposts = 0;
free(posts);
}
static void
ReadPostData(const char *dir, const char *file, char **data, size_t *lenp)
{
char path[FILENAME_MAX];
int fd;
size_t len, nRead = 0;
ssize_t rv;
strlcpy(path, dir, sizeof(path));
strlcat(path, "/", sizeof(path));
strlcat(path, file, sizeof(path));
if (*data != NULL)
free(*data);
if ((fd = open(path, O_RDONLY)) == -1) {
goto empty;
}
len = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
if (len == 0) {
close(fd);
goto empty;
}
if ((*data = (char *)malloc(len)) == NULL) {
close(fd);
goto empty;
}
while (nRead < len) {
rv = read(fd, (*data)+nRead, len-nRead);
if (rv == -1) {
if (errno == EINTR) {
continue;
}
goto empty;
}
if (rv == 0) {
goto empty;
}
nRead += rv;
}
close(fd);
if ((*data)[len-1] == '\n')
(*data)[(len--)-1] = '\0';
if (lenp != NULL)
*lenp = len;
return;
empty:
*data = NULL;
if (lenp != NULL)
*lenp = 0;
}
static void
ReadPostFromFile(const char *dir, struct post *post)
{
ReadPostData(dir, "title", &post->title, NULL);
ReadPostData(dir, "author", &post->author, NULL);
ReadPostData(dir, "cats", &post->cats, NULL);
ReadPostData(dir, "data", &post->data, &post->len);
TAILQ_INIT(&post->comments);
}
static void
ReadPosts(void)
{
struct dirent *dent;
DIR *dir;
int created = 0;
open:
if ((dir = opendir(_PATH_POSTS)) == NULL) {
if (errno == ENOENT && !created &&
mkdir(_PATH_POSTS, 0755) == 0) {
created = 1;
sleep(1);
goto open;
}
CGI_Log(LOG_ERR, "%s: %s", _PATH_POSTS, strerror(errno));
return;
}
while ((dent = readdir(dir)) != NULL) {
char postdir[FILENAME_MAX];
struct post *post;
unsigned int postid;
if (dent->d_namlen <= 2 &&
(strcmp(dent->d_name, ".") == 0 ||
strcmp(dent->d_name, "..") == 0))
continue;
postid = (int)strtol(dent->d_name, (char **)NULL, 10);
if ((postid+1) > nposts) {
nposts = postid+1;
posts = Realloc(posts, nposts*sizeof(struct post));
}
post = &posts[postid];
post->id = postid;
post->ptime = time(NULL);
post->mtime = time(NULL);
post->title = NULL;
post->author = NULL;
post->cats = NULL;
post->data = NULL;
post->len = 0;
TAILQ_INIT(&post->comments);
strlcpy(postdir, _PATH_POSTS, sizeof(postdir));
strlcat(postdir, dent->d_name, sizeof(postdir));
ReadPostFromFile(postdir, post);
}
closedir(dir);
}
static void
output_current(VAR *v, struct post *post)
{
CatS(v, "