/*****************************************************
** _________ __ **
** \_ ___ \_____|__| _____ ________ ___ **
** / \ \/_ __ \ |/ \/ ___/_ \/ \ **
** \ \___| | \/ | | | \___ \ / ) | \ **
** \______ /__| |__|__|_| /____ \__/__| / **
** ____\/____ _ \/ ___ \/ \/ **
** \______ \ |_____ __| _/___ **
** | | _/ |\__ \/ __ | __ \ **
** | | \ |_/ __ \ / | ___/_ **
** |_____ /__/____ /_ /___ / **
** \/Antipode\/ \/ \/ **
******************************************************
** Crimson Blade Codebase (CbC) **
** (c) 2000-2002 John Bellone (Noplex) **
** Coders: Noplex, Krowe **
** http://www.crimsonblade.org **
*****************************************************/
/*
* File: news.c
* Name: Extended News (v2.81)
* Author: John 'Noplex' Bellone (john.bellone@flipsidesoftware.com)
* Terms:
* If this file is to be re-disributed; you must send an email
* to the author. All headers above the #include calls must be
* kept intact.
* Description:
* This is the extended news module; it allows for news to be
* posted in note-like format; and bringing you into a editbuffer
* instead of one-line posts. It also allows support for online
* HTML output for news to be automatically generated and included
* via a PHP; SSL; or a TXT include.
*/
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include "mud.h"
#ifdef KEY
#undef KEY
#endif
#define KEY( literal, field, value ) \
if ( !str_cmp( word, literal ) ) \
{ \
field = value; \
fMatch = TRUE; \
break; \
}
#ifdef FCLOSE
#undef FCLOSE
#endif
#define FCLOSE(fp) fclose(fp); fp=NULL;
/* locals */
static char local_buf[MAX_INPUT_LENGTH];
int top_news_type;
/* the lovely; and useful; command table */
char * news_command_table[NEWS_MAX_TYPES];
/* olc editnews command */
void do_editnews( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
if(IS_NPC(ch) || !IS_IMMORTAL(ch))
{
send_to_char( "Huh?\n\r", ch );
return;
}
set_char_color( AT_GREEN, ch );
switch( ch->substate )
{
default:
break;
case SUB_NEWS_POST:
{
NEWS *news = NULL;
news = ch->dest_buf;
STRFREE(news->post);
news->post = copy_buffer(ch);
stop_editing( ch );
ch->substate = ch->tempnum;
renumber_news();
save_news();
return;
}
break;
case SUB_NEWS_EDIT:
{
NEWS *news = NULL;
news = ch->dest_buf;
STRFREE(news->post);
news->post = copy_buffer(ch);
stop_editing( ch );
ch->substate = ch->tempnum;
renumber_news();
save_news();
return;
}
break;
}
argument = one_argument(argument, arg);
if(arg[0] == '\0' )
{
send_to_char( "Syntax: editnews addtype <name>\n\r"
" editnews addnews <type> <subject>\n\r"
" editnews removetype <number>\n\r"
" editnews removenews <type> <number>\n\r"
" editnews edittype <field> <value>\n\r"
" editnews editnews <type> <number> <new subject [optional]>\n\r"
" Fields being one of the following:\n\r"
" name header cmd_name level\n\r", ch);
return;
}
if( !str_cmp(arg, "save"))
{
renumber_news();
save_news();
send_to_char( "News saved.\n\r", ch );
return;
}
if(!str_cmp(arg, "addtype"))
{
NEWS_TYPE *type = NULL;
if(argument[0] == '\0')
{
send_to_char("Syntax: editnews addtype <name>\n\r", ch);
return;
}
if(top_news_type >= NEWS_MAX_TYPES)
{
send_to_char("There are too many news types.\n\r", ch);
return;
}
CREATE(type, NEWS_TYPE, 1);
type->name = STRALLOC(argument);
type->cmd_name = STRALLOC(argument);
type->vnum = top_news_type++;
type->level = -1;
news_command_table[type->vnum] = STRALLOC(type->cmd_name);
LINK(type, first_news_type, last_news_type, next, prev);
ch_printf( ch, "Newstype '%s' created.\n\r", argument );
return;
}
if(!str_cmp(arg, "removetype"))
{
NEWS_TYPE *type = NULL;
if(argument[0] == '\0')
{
send_to_char("Syntax: editnews removetype <name>\n\r", ch);
return;
}
if((type = figure_type(argument)) == NULL)
{
send_to_char("Invaild newstype.\n\r", ch);
return;
}
UNLINK(type, first_news_type, last_news_type, next, prev);
if(type->name)
STRFREE(type->name);
if(type->header)
STRFREE(type->header);
if(type->cmd_name)
STRFREE(type->cmd_name);
if(news_command_table[type->vnum])
STRFREE(news_command_table[type->vnum]);
if(news_command_table[type->level])
STRFREE(news_command_table[type->level]);
{
NEWS *news = NULL;
void *next;
for(news = type->first_news; news; news = next)
{
next = news->next;
UNLINK( news, type->first_news, type->last_news, next, prev );
if(news->name)
STRFREE(news->name);
if(news->title)
STRFREE(news->title);
if(news->date)
STRFREE( news->date );
if(news->post)
STRFREE( news->post );
DISPOSE(news);
}
}
DISPOSE(type);
top_news_type--;
renumber_news();
save_news();
ch_printf( ch, "Newstype '%s' removed.\n\r", argument );
return;
}
if(!str_cmp(arg, "edittype"))
{
char arg2[MAX_INPUT_LENGTH];
char arg3[MAX_INPUT_LENGTH];
NEWS_TYPE *type = NULL;
argument = one_argument(argument, arg2);
argument = one_argument(argument, arg3);
if(arg2[0] == '\0' || arg3[0] == '\0')
{
send_to_char("Syntax: editnews edittype <type> <field> <value>\n\r", ch);
send_to_char("Fields being one of the following:\n\r"
"name header cmd_name level\n\r", ch );
return;
}
if((type = figure_type(arg2)) == NULL)
{
send_to_char("Invalid newstype.\n\r", ch);
return;
}
if(!str_cmp(arg3, "cmd_name"))
{
type->cmd_name = STRALLOC(argument);
news_command_table[type->vnum] = STRALLOC(type->cmd_name);
send_to_char("Cmd_name set.\n\r", ch);
save_news();
return;
}
else if(!str_cmp(arg3, "name"))
{
type->name = STRALLOC(argument);
send_to_char("Name set.\n\r", ch);
save_news();
return;
}
else if(!str_cmp(arg3, "level"))
{
if ( argument[0] == '\0' )
{
ch_printf( ch, "%d\n\r", type->level );
return;
}
else
type->level = atoi(argument);
send_to_char("Level set.\n\r", ch);
save_news();
return;
}
else
{
send_to_char("Syntax: editnews edittype <type> <field> <value>\n\r", ch);
send_to_char("Fields being one of the following:\n\r"
"name header cmd_name level\n\r", ch );
return;
}
}
if( !str_cmp(arg, "addnews" ))
{
char arg[MAX_INPUT_LENGTH];
NEWS_TYPE *type = NULL;
NEWS *news = NULL;
argument = one_argument(argument, arg);
if(arg[0] == '\0' || argument[0] == '\0')
{
send_to_char( "Syntax: editnews addnews <type> <subject>\n\r", ch );
return;
}
if((type = figure_type(arg)) == NULL)
{
send_to_char("Invaild newstype. Use 'newstypes' to get a valid listing.\n\r", ch);
return;
}
CREATE( news, NEWS, 1 );
news->title = STRALLOC(argument);
news->name = STRALLOC(ch->name);
news->date = STRALLOC(stamp_time( ));
news->post = STRALLOC("");
/* pop character into a writing buffer */
if( ch->substate == SUB_REPEATCMD )
ch->tempnum = SUB_REPEATCMD;
else
ch->tempnum = SUB_NONE;
ch->substate = SUB_NEWS_POST;
ch->dest_buf = news;
start_editing( ch, news->post );
LINK(news, type->first_news, type->last_news, next, prev);
return;
}
if( !str_cmp(arg, "editnews"))
{
char arg2[MAX_INPUT_LENGTH];
char arg3[MAX_INPUT_LENGTH];
NEWS *news = NULL;
NEWS_TYPE *type = NULL;
argument = one_argument(argument, arg2);
argument = one_argument(argument, arg3);
if(arg2[0] == '\0')
{
send_to_char( "Syntax: editnews editnews <type> <number> <new subject [optional]>\n\r", ch );
return;
}
/* changed for new -newstype- indexing - 5/5/02 */
if((type = figure_type(arg2)) == NULL)
{
send_to_char("Invalid newstype. Use 'newstypes' to get a valid listing.\n\r", ch);
return;
}
if((news = grab_news(type, arg3)) == NULL)
{
pager_printf_color(ch, "That's not a valid news number.\n\rUse '%s' to view the valid numbers.\n\r", type->cmd_name );
return;
}
/* a changed title */
if( argument[0] != '\0' )
news->title = STRALLOC( argument );
/* new date news was edited */
news->date = STRALLOC(stamp_time( ));
/* pop character into a writing buffer */
if( ch->substate == SUB_REPEATCMD )
ch->tempnum = SUB_REPEATCMD;
else
ch->tempnum = SUB_NONE;
ch->substate = SUB_NEWS_EDIT;
ch->dest_buf = news;
start_editing( ch, news->post );
return;
}
if( !str_cmp(arg, "removenews"))
{
char arg2[MAX_INPUT_LENGTH];
NEWS *news = NULL;
NEWS_TYPE *type = NULL;
argument = one_argument(argument, arg2);
if(argument[0] == '\0' || arg2[0] == '\0')
{
send_to_char("Syntax: editnews remove <number>\n\r", ch );
return;
}
/* changed for new -newstype- indexing - 5/5/02 */
if((type = figure_type(arg2)) == NULL)
{
send_to_char("Invalid newstype. Use 'newstypes' to get a valid listing.\n\r", ch);
return;
}
if((news = grab_news(type, argument)) == NULL)
{
send_to_char( "Type 'news' to gain a list of the news numbers.\n\r", ch );
return;
}
UNLINK( news, type->first_news, type->last_news, next, prev );
if(news->name)
STRFREE( news->name );
if(news->title)
STRFREE( news->title );
if(news->date)
STRFREE( news->date );
if(news->post)
STRFREE( news->post );
DISPOSE( news );
renumber_news();
save_news();
send_to_char("News item removed.\n\r", ch );
return;
}
}
/* figure the type of a newstype by the vnum
* or by the cmd_name off the news_cmd_table -Nopey */
NEWS_TYPE *figure_type(char *str)
{
if(is_number(str))
{
NEWS_TYPE *type = NULL;
int number = atoi(str);
/* poll the list for the vnum */
for(type = first_news_type; type; type = type->next)
if(type->vnum == number)
return type;
}
else /* a cmd name */
{
NEWS_TYPE *type = NULL;
int x;
/* poll the cmd_name array for word */
for(x = 0; x < top_news_type; x++)
if(!str_cmp(str, news_command_table[x]))
{
for(type = first_news_type; type; type = type->next)
if(type->vnum == x)
return type;
}
}
return NULL;
}
/* Snatch news up from the linked list */
NEWS *grab_news(NEWS_TYPE *type, char *str)
{
NEWS *news = NULL;
for( news = type->first_news; news; news = news->next )
{
if( news->number == atoi(str))
return news;
}
return NULL;
}
/* display a full news to the character */
/* updated for the new display type 5/1/02 */
void display_news( CHAR_DATA *ch, NEWS *news, NEWS_TYPE *type )
{
pager_printf_color( ch, "\n\r&g--------------------------------------\n\r" );
pager_printf_color( ch, type->header);
pager_printf_color( ch, "&g--------------------------------------\n\r" );
pager_printf_color( ch, NEWS_HEADER_READ);
sprintf( local_buf, "&g(&W%2d&g) &W%-12s &%-11s &W%s&g\n\r", news->number, news->name, news->date, news->title );
pager_printf_color( ch, local_buf );
pager_printf_color( ch, "\n\r" );
if ( news->post[0] != '\0' )
pager_printf_color( ch, news->post );
else
pager_printf_color( ch, "&gNo further information.\n\r" );
pager_printf_color( ch, "&g--------------------------------------\n\r" );
pager_printf_color( ch, "\n\r" );
return;
}
/* renumber the news */
/* changed for new indexing - 5/5/02 */
void renumber_news(void)
{
NEWS_TYPE *type = NULL;
NEWS *news = NULL;
int x, y;
for(y = 0; y < top_news_type; y++)
if(news_command_table[y])
STRFREE(news_command_table[y]);
top_news_type = 0;
for(type = first_news_type; type; type = type->next)
{
type->vnum = top_news_type++;
news_command_table[type->vnum] = STRALLOC(type->cmd_name);
x = 0;
for(news = type->first_news; news; news = news->next)
{
x++;
news->number = x;
news->type = type->vnum;
}
}
return;
}
/* save the linked list */
/* changed for new indexing - 5/5/02 */
void save_news(void)
{
NEWS *news = NULL;
NEWS_TYPE *type = NULL;
FILE *fp = NULL;
char filename[256];
sprintf( filename, "%s%s", SYSTEM_DIR, NEWS_FILE );
if((fp = fopen(filename, "w")) == NULL)
{
perror("save_news(): cannot open file");
return;
}
for(type = first_news_type; type; type = type->next)
{
fprintf(fp, "#NEWSTYPE\n");
fprintf(fp, "Name %s~\n", type->name);
fprintf(fp, "Cmd_Name %s~\n", type->cmd_name);
fprintf(fp, "Header %s~\n", type->header);
fprintf(fp, "Vnum %d\n", type->vnum);
fprintf(fp, "Level %d\n", type->level);
fprintf(fp, "End\n");
for(news = type->first_news; news; news = news->next)
{
fprintf( fp, "#NEWS\n" );
fprintf( fp, "Title %s~\n", news->title );
fprintf( fp, "Name %s~\n", news->name );
fprintf( fp, "Date %s~\n", news->date );
fprintf( fp, "Type %d\n", news->type);
fprintf( fp, "POST %s~\n", news->post );
fprintf( fp, "End\n" );
}
}
/*
if(sysdata.news_html_path && sysdata.news_html_path[0] != '\0' && sysdata.max_html_news > 0)
write_html_news( );
*/
FCLOSE(fp);
return;
}
/* load the linked list from disk */
void load_news(void)
{
FILE *fp = NULL;
char filename[256];
sprintf( filename, "%s%s", SYSTEM_DIR, NEWS_FILE );
if((fp = fopen(filename, "r")) == NULL)
{
perror("load_news(): cannot open file");
return;
}
for( ; ; )
{
NEWS_TYPE *type = NULL;
NEWS *news = NULL;
char *word;
char letter;
letter = fread_letter(fp);
if(letter == '*')
{
fread_to_eol(fp);
continue;
}
if(letter != '#')
{
bug("load_news(): # not found");
break;
}
word = fread_word(fp);
if(!str_cmp(word, "NEWS"))
{
CREATE( news, NEWS, 1 );
news->type = -1;
fread_news(news, fp);
link_news_to_type(news);
continue;
}
/* added for new indexing - 5/5/02 */
else if(!str_cmp(word, "NEWSTYPE"))
{
CREATE(type, NEWS_TYPE, 1);
fread_news_type(type, fp);
LINK(type, first_news_type, last_news_type, next, prev);
continue;
}
if(!str_cmp(word, "END"))
break;
else
{
bug("load_news(): unknown section %s", word);
continue;
}
}
FCLOSE(fp);
renumber_news();
return;
}
/* added for new indexing - 5/5/02 - Nopey */
/* adds the news to to the correct newstype */
void link_news_to_type(NEWS *news)
{
NEWS_TYPE *type = NULL;
sprintf(local_buf, "%d", news->type);
if((type = figure_type(local_buf)) == NULL)
{
bug("link_news_to_type(): invaild news->type %d", news->type);
return;
}
LINK(news, type->first_news, type->last_news, next, prev);
return;
}
void fread_news( NEWS *news, FILE *fp )
{
char *word;
bool fMatch;
for( ; ; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = FALSE;
switch(UPPER(word[0]))
{
case '*':
fread_to_eol(fp);
break;
case 'D':
KEY( "Date", news->date, fread_string(fp));
break;
case 'E':
if(!str_cmp(word, "END"))
{
if(!news->name)
news->name = STRALLOC("Unknown");
if(!news->date)
{
news->date = STRALLOC(stamp_time( ));
}
if(!news->title)
news->title = STRALLOC("News Post");
if(news->type <= -1)
news->type = 0;
return;
}
break;
case 'N':
KEY( "Name", news->name, fread_string(fp));
break;
case 'P':
if(!str_cmp(word, "POST"))
{
fMatch = TRUE;
news->post = fread_string(fp);
break;
}
break;
case 'T':
KEY( "Title", news->title, fread_string(fp));
KEY("Type", news->type, fread_number(fp));
break;
}
if(!fMatch)
bug("fread_news(): no match: %s", word);
}
}
/* added for new index - 5/5/02 - Nopey */
void fread_news_type( NEWS_TYPE *type, FILE *fp )
{
char *word;
bool fMatch;
for( ; ; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = FALSE;
switch(UPPER(word[0]))
{
case '*':
fread_to_eol(fp);
break;
case 'C':
KEY( "Cmd_Name", type->cmd_name, fread_string(fp));
break;
case 'E':
if(!str_cmp(word, "END"))
{
if(!type->name)
type->name = STRALLOC("Unknown");
return;
}
break;
case 'H':
KEY("Header", type->header, fread_string(fp));
break;
case 'L':
KEY( "Level", type->level, fread_number(fp));
break;
case 'N':
KEY( "Name", type->name, fread_string(fp));
break;
case 'V':
KEY( "Vnum", type->vnum, fread_number(fp));
break;
}
if(!fMatch)
bug("fread_news_type(): no match: %s", word);
}
}
/* stamp date in mm/dd/yy. return string */
char *stamp_time(void)
{
static char buf[128];
struct tm *time;
time = localtime(¤t_time);
strftime(buf, sizeof(buf), "%x", time);
return buf;
}
#ifdef NOHTMLISON
/*
* html the news up! -Nopey
*/
void write_html_news(void)
{
FILE *fp = NULL;
char filename[256];
sprintf(filename, "%s%s", sysdata.news_html_path, NEWS_INCLUDE_FILE);
if((fp = fopen(filename, "w")) == NULL)
{
bug("write_html_news(): cannot open %s for writing", filename);
return;
}
snarf_news(fp);
FCLOSE(fp);
return;
}
/*
* rip it apart! =\ -Nopey
*/
void snarf_news(FILE *fp)
{
NEWS *news = NULL;
int x = 0;
char buf[1024];
for(news = last_news; x < sysdata.max_html_news; news = news->prev)
{
x++;
fprintf(fp, "<div align='center'>");
fprintf(fp, "\n<table width='399' border='1' height='56' bgcolor='#990000'>" );
sprintf(buf, "\n<tr><td><font face='Arial, Helvetica, sans-serif' size='2'>%s</font></tr></td><tr><td><font size='1' face='Arial, Helvetica, sans-serif' color='#FFFFFF'>[</font><font color='#FFFFFF' size='2'>%s</font><font size='1' color='#FFFFFF'>]</font>", news->title, news->name );
fprintf(fp, buf);
fprintf(fp, "\n<font size='1'><font face='Arial, Helvetica, sans-serif'>[<b><font size='2' color='#FFFFFF'>" );
sprintf(buf, "\n%s\n\r</font></b>]</font></font></td></tr><tr><td height='2' bgcolor='#000000'>", news->date );
fprintf(fp, buf);
sprintf(buf, "\n<p><font face='Arial, Helvetica, sans-serif' size='2' color='#FFFFFF'>%s</font><p></td></tr></table></div>", news->post );
fprintf(fp, buf);
fprintf(fp, "</div>");
}
/* this must stay here -- line below */
fprintf(fp, "\n<center><font size='2' face='Arial, Helvetica, sans-serif' color='#FFFFFF'>Extended News v2.5 written by: <a href='mailto:noplex@crimsonblade.org'>Noplex</a>; <a href='http://www.crimsonblade.org/snippets/' target='new'>Get your copy here!</a></font></center>\n\r");
fprintf(fp, "<pre><center>Page last written: %s</center></pre>", ctime(¤t_time));
return;
}
#endif
/* news command hook; interp.c -Nopey */
bool news_cmd_hook(CHAR_DATA *ch, char *cmd, char *argument)
{
int x = 0;
for(x = 0; x < top_news_type; x++)
if(!str_cmp(cmd, news_command_table[x]))
{
NEWS_TYPE *type = NULL;
sprintf(local_buf, "%d", x);
if((type = figure_type(local_buf)) == NULL)
{
bug("news_cmd_hook(): cannot find type for cmd %s", cmd);
return FALSE;
}
if ( get_trust( ch ) < type->level )
return FALSE;
display_news_type(ch, type, argument);
return TRUE;
}
return FALSE;
}
/*
* display the news entry from the command hook -Nopey
*/
void display_news_type(CHAR_DATA *ch, NEWS_TYPE *type, char *argument)
{
if(!type->first_news)
{
send_to_char_color("&gThere are currently no news items for this news type.\n\r", ch);
return;
}
if(argument[0] == '\0' || !str_cmp(argument, "all"))
{
bool all_news = FALSE;
NEWS *news = NULL;
int x = type->last_news->number, y = NEWS_VIEW;
int skipper = (x-y);
if(!str_cmp(argument, "all"))
all_news = TRUE;
pager_printf_color( ch, "\n\r&g--------------------------------------\n\r" );
if(type->header)
pager_printf_color(ch, type->header);
pager_printf_color( ch, "&g--------------------------------------\n\r" );
pager_printf_color(ch, NEWS_HEADER_ALL);
for(news = type->first_news; news; news = news->next)
{
if(!all_news)
{
if(skipper > -1)
{
skipper--;
continue;
}
}
sprintf( local_buf, "&g(&W%2d&g) &W%-12s &%-11s &W%s&g\n\r", news->number, news->name, news->date, news->title );
pager_printf_color(ch, local_buf);
}
if(!all_news)
{
if ( type->last_news->number == 1 )
pager_printf_color( ch, "&g\n\rThere is one news item.\n\r" );
else if ( type->last_news->number > NEWS_VIEW - 1 )
pager_printf_color( ch, "\n\r&gThere are &w%d&g total items, the oldest of which are not listed here.\n\rUse '&w%s all&g' to list them all.&g\n\r", type->last_news->number, type->cmd_name );
else
pager_printf_color( ch, "\n\r&gThere are &w%d&g total items.\n\r", type->last_news->number );
pager_printf_color( ch, "\n\r&gTo read individual items type '&w%s <number>&g'.\n\r", type->cmd_name );
return;
}
pager_printf_color( ch, "\n\r&gTo read individual items type '&w%s <number>&g'.\n\r", type->cmd_name );
}
{
NEWS *news = NULL;
if((news = grab_news(type, argument)) == NULL)
{
if( str_cmp( argument, "all" ) )
send_to_char_color( "&g\n\rThat's not a news post number.\n\rUse '&wnews&g' to view them.\n\r", ch );
return;
}
display_news(ch, news, type);
return;
}
}