2012-04-17 20:09:50 +00:00
/*
* Copyright ( c ) 2005 Atheme Development Group
* Rights to this code are documented in doc / LICENSE .
*
* This file contains the main ( ) routine .
*/
2012-10-04 05:01:29 +00:00
# include "atheme-compat.h"
2012-04-17 20:09:50 +00:00
DECLARE_MODULE_V1
(
" contrib/ircd_announceserv " , false , _modinit , _moddeinit ,
PACKAGE_STRING ,
" JD and Taros "
) ;
service_t * announcesvs ;
static void as_cmd_help ( sourceinfo_t * si , int parc , char * parv [ ] ) ;
static void account_drop_request ( myuser_t * mu ) ;
static void as_cmd_request ( sourceinfo_t * si , int parc , char * parv [ ] ) ;
static void as_cmd_waiting ( sourceinfo_t * si , int parc , char * parv [ ] ) ;
static void as_cmd_reject ( sourceinfo_t * si , int parc , char * parv [ ] ) ;
static void as_cmd_activate ( sourceinfo_t * si , int parc , char * parv [ ] ) ;
static void as_cmd_cancel ( sourceinfo_t * si , int parc , char * parv [ ] ) ;
static void write_asreqdb ( database_handle_t * db ) ;
static void db_h_ar ( database_handle_t * db , const char * type ) ;
command_t as_help = { " HELP " , N_ ( N_ ( " Displays contextual help information. " ) ) , AC_NONE , 2 , as_cmd_help , { . path = " help/help " } } ;
command_t as_request = { " REQUEST " , N_ ( " Requests new announcement. " ) , AC_AUTHENTICATED , 2 , as_cmd_request , { . path = " contrib/as_request " } } ;
command_t as_waiting = { " WAITING " , N_ ( " Lists announcements currently waiting for activation. " ) , PRIV_GLOBAL , 1 , as_cmd_waiting , { . path = " contrib/as_waiting " } } ;
command_t as_reject = { " REJECT " , N_ ( " Reject the requested announcement for the given nick. " ) , PRIV_GLOBAL , 2 , as_cmd_reject , { . path = " contrib/as_reject " } } ;
command_t as_activate = { " ACTIVATE " , N_ ( " Activate the requested announcement for a given nick. " ) , PRIV_GLOBAL , 2 , as_cmd_activate , { . path = " contrib/as_activate " } } ;
command_t as_cancel = { " CANCEL " , N_ ( " Cancels your requested announcement. " ) , AC_AUTHENTICATED , 0 , as_cmd_cancel , { . path = " contrib/as_cancel " } } ;
struct asreq_ {
2012-10-04 05:04:42 +00:00
stringref nick ;
2012-04-17 20:09:50 +00:00
char * subject ;
time_t announce_ts ;
2012-10-04 05:04:42 +00:00
stringref creator ;
2012-04-17 20:09:50 +00:00
char * text ;
} ;
typedef struct asreq_ asreq_t ;
mowgli_list_t as_reqlist ;
void _modinit ( module_t * m )
{
announcesvs = service_add ( " announceserv " , NULL ) ;
hook_add_event ( " user_drop " ) ;
hook_add_user_drop ( account_drop_request ) ;
hook_add_db_write ( write_asreqdb ) ;
db_register_type_handler ( " AR " , db_h_ar ) ;
if ( announcesvs = = NULL )
return ;
service_bind_command ( announcesvs , & as_help ) ;
service_bind_command ( announcesvs , & as_request ) ;
service_bind_command ( announcesvs , & as_waiting ) ;
service_bind_command ( announcesvs , & as_reject ) ;
service_bind_command ( announcesvs , & as_activate ) ;
service_bind_command ( announcesvs , & as_cancel ) ;
}
void _moddeinit ( module_unload_intent_t intent )
{
hook_del_user_drop ( account_drop_request ) ;
hook_del_db_write ( write_asreqdb ) ;
db_unregister_type_handler ( " AR " ) ;
if ( announcesvs ! = NULL )
{
service_unbind_command ( announcesvs , & as_help ) ;
service_unbind_command ( announcesvs , & as_request ) ;
service_unbind_command ( announcesvs , & as_waiting ) ;
service_unbind_command ( announcesvs , & as_reject ) ;
service_unbind_command ( announcesvs , & as_activate ) ;
service_unbind_command ( announcesvs , & as_cancel ) ;
service_delete ( announcesvs ) ;
announcesvs = NULL ;
}
}
static void write_asreqdb ( database_handle_t * db )
{
mowgli_node_t * n ;
MOWGLI_LIST_FOREACH ( n , as_reqlist . head )
{
asreq_t * l = n - > data ;
db_start_row ( db , " AR " ) ;
db_write_word ( db , l - > nick ) ;
db_write_word ( db , l - > subject ) ;
db_write_time ( db , l - > announce_ts ) ;
db_write_word ( db , l - > creator ) ;
db_write_str ( db , l - > text ) ;
db_commit_row ( db ) ;
}
}
static void db_h_ar ( database_handle_t * db , const char * type )
{
const char * nick = db_sread_word ( db ) ;
const char * subject = db_sread_word ( db ) ;
time_t announce_ts = db_sread_time ( db ) ;
const char * creator = db_sread_word ( db ) ;
const char * text = db_sread_str ( db ) ;
asreq_t * l = smalloc ( sizeof ( asreq_t ) ) ;
l - > nick = strshare_get ( nick ) ;
l - > creator = strshare_get ( creator ) ;
l - > subject = sstrdup ( subject ) ;
l - > announce_ts = announce_ts ;
l - > text = sstrdup ( text ) ;
mowgli_node_add ( l , mowgli_node_create ( ) , & as_reqlist ) ;
}
/* Properly remove announcement requests from the DB if an account is dropped */
static void account_drop_request ( myuser_t * mu )
{
mowgli_node_t * n ;
asreq_t * l ;
MOWGLI_LIST_FOREACH ( n , as_reqlist . head )
{
l = n - > data ;
if ( ! irccasecmp ( l - > nick , entity ( mu ) - > name ) )
{
slog ( LG_REGISTER , " ANNOUNCEREQ:DROPACCOUNT: \2 %s \2 %s \2 " , l - > nick , l - > text ) ;
mowgli_node_delete ( n , & as_reqlist ) ;
strshare_unref ( l - > nick ) ;
strshare_unref ( l - > creator ) ;
free ( l - > subject ) ;
free ( l - > text ) ;
free ( l ) ;
return ;
}
}
}
/* HELP <command> [params] */
void as_cmd_help ( sourceinfo_t * si , int parc , char * parv [ ] )
{
char * command = parv [ 0 ] ;
if ( ! command )
{
command_success_nodata ( si , _ ( " ***** \2 %s Help \2 ***** " ) , si - > service - > nick ) ;
command_success_nodata ( si , _ ( " \2 %s \2 allows users to request a network announcement. " ) , si - > service - > nick ) ;
command_success_nodata ( si , " " ) ;
command_success_nodata ( si , _ ( " For more information on a command, type: " ) ) ;
command_success_nodata ( si , " \2 /%s%s help <command> \2 " , ( ircd - > uses_rcommand = = false ) ? " msg " : " " , si - > service - > disp ) ;
command_success_nodata ( si , " " ) ;
command_help ( si , si - > service - > commands ) ;
command_success_nodata ( si , _ ( " ***** \2 End of Help \2 ***** " ) ) ;
return ;
}
/* take the command through the hash table */
help_display ( si , si - > service , command , si - > service - > commands ) ;
}
static void as_cmd_request ( sourceinfo_t * si , int parc , char * parv [ ] )
{
char * subject = parv [ 0 ] ;
char * text = parv [ 1 ] ;
2012-10-04 05:04:42 +00:00
stringref target ;
2012-04-17 20:09:50 +00:00
char * subject2 ;
char buf [ BUFSIZE ] ;
mowgli_node_t * n ;
asreq_t * l ;
if ( ! text | | ! subject )
{
command_fail ( si , fault_needmoreparams , STR_INSUFFICIENT_PARAMS , " REQUEST " ) ;
command_fail ( si , fault_needmoreparams , _ ( " Syntax: REQUEST <subject> <text> " ) ) ;
return ;
}
if ( metadata_find ( si - > smu , " private:restrict:setter " ) )
{
command_fail ( si , fault_noprivs , _ ( " You have been restricted from requesting announcements by network staff. " ) ) ;
return ;
}
target = entity ( si - > smu ) - > name ;
MOWGLI_LIST_FOREACH ( n , as_reqlist . head )
{
l = n - > data ;
if ( ! irccasecmp ( l - > nick , target ) )
{
command_fail ( si , fault_badparams , _ ( " You cannot request more than one announcement. Use CANCEL if you wish to cancel your current announcement and submit another. " ) ) ;
return ;
}
}
/* Check the subject for being too long as well. 35 chars is probably a safe limit here.
* Used here because we don ' t want users that don ' t know any better making too - long messages .
*/
if ( strlen ( subject ) > 35 )
{
command_fail ( si , fault_badparams , _ ( " Your subject is too long. Subjects need to be under 35 characters. " ) ) ;
return ;
}
/* Check if the announcement is too long or not. 450 characters is safe for our usecase */
if ( strlen ( text ) > 450 )
{
command_fail ( si , fault_badparams , _ ( " Your announcement is too long. Announcements need to be under 450 characters. " ) ) ;
return ;
}
snprintf ( buf , BUFSIZE , " %s " , text ) ;
l = smalloc ( sizeof ( asreq_t ) ) ;
l - > nick = strshare_ref ( target ) ;
l - > subject = sstrdup ( subject ) ;
l - > announce_ts = CURRTIME ; ;
l - > creator = strshare_ref ( target ) ;
l - > text = sstrdup ( buf ) ;
n = mowgli_node_create ( ) ;
mowgli_node_add ( l , n , & as_reqlist ) ;
subject2 = sstrdup ( l - > subject ) ;
/* This doesn't need to be as efficient as InfoServ, so let's just use replace() */
replace ( subject2 , BUFSIZE , " _ " , " " ) ;
command_success_nodata ( si , _ ( " You have requested the following announcement: " ) ) ;
command_success_nodata ( si , _ ( " [%s - %s] %s " ) , subject2 , l - > creator , buf ) ;
/* This is kind of hacky, and the slog will come from operserv, not announceserv.
* Still , it ' s required so the message will cut off properly , and I can ' t find a less hacky way to do it . */
logcommand ( si , CMDLOG_REQUEST , " REQUEST: " ) ;
slog ( CMDLOG_REQUEST , " [%s - %s] %s " , subject2 , l - > creator , buf ) ;
free ( subject2 ) ;
return ;
}
static void as_cmd_activate ( sourceinfo_t * si , int parc , char * parv [ ] )
{
char * nick = parv [ 0 ] ;
user_t * u ;
char * subject2 ;
char buf [ BUFSIZE ] ;
asreq_t * l ;
mowgli_node_t * n ;
if ( ! nick )
{
command_fail ( si , fault_needmoreparams , STR_INSUFFICIENT_PARAMS , " ACTIVATE " ) ;
command_fail ( si , fault_needmoreparams , _ ( " Syntax: ACTIVATE <nick> " ) ) ;
return ;
}
MOWGLI_LIST_FOREACH ( n , as_reqlist . head )
{
l = n - > data ;
if ( ! irccasecmp ( l - > nick , nick ) )
{
if ( ( u = user_find_named ( nick ) ) ! = NULL )
notice ( si - > service - > nick , u - > nick , " [auto memo] Your requested announcement has been approved. " ) ;
subject2 = sstrdup ( l - > subject ) ;
replace ( subject2 , BUFSIZE , " _ " , " " ) ;
logcommand ( si , CMDLOG_REQUEST , " ACTIVATE: \2 %s \2 " , nick ) ;
snprintf ( buf , BUFSIZE , " [%s - %s] %s " , subject2 , l - > creator , l - > text ) ;
mowgli_node_delete ( n , & as_reqlist ) ;
free ( subject2 ) ;
2012-10-04 05:04:42 +00:00
strshare_unref ( l - > nick ) ;
2012-04-17 20:09:50 +00:00
free ( l - > subject ) ;
2012-10-04 05:04:42 +00:00
strshare_unref ( l - > creator ) ;
2012-04-17 20:09:50 +00:00
free ( l - > text ) ;
free ( l ) ;
notice_global_sts ( si - > service - > me , " * " , buf ) ;
return ;
}
}
command_success_nodata ( si , _ ( " Nick \2 %s \2 not found in announce request database. " ) , nick ) ;
}
static void as_cmd_reject ( sourceinfo_t * si , int parc , char * parv [ ] )
{
char * nick = parv [ 0 ] ;
user_t * u ;
asreq_t * l ;
mowgli_node_t * n ;
if ( ! nick )
{
command_fail ( si , fault_needmoreparams , STR_INSUFFICIENT_PARAMS , " REJECT " ) ;
command_fail ( si , fault_needmoreparams , _ ( " Syntax: REJECT <nick> " ) ) ;
return ;
}
MOWGLI_LIST_FOREACH ( n , as_reqlist . head )
{
l = n - > data ;
if ( ! irccasecmp ( l - > nick , nick ) )
{
if ( ( u = user_find_named ( nick ) ) ! = NULL )
notice ( si - > service - > nick , u - > nick , " [auto memo] Your requested announcement has been rejected. " ) ;
logcommand ( si , CMDLOG_REQUEST , " REJECT: \2 %s \2 " , nick ) ;
mowgli_node_delete ( n , & as_reqlist ) ;
2012-10-04 05:04:42 +00:00
strshare_unref ( l - > nick ) ;
2012-04-17 20:09:50 +00:00
free ( l - > subject ) ;
2012-10-04 05:04:42 +00:00
strshare_unref ( l - > creator ) ;
2012-04-17 20:09:50 +00:00
free ( l - > text ) ;
free ( l ) ;
return ;
}
}
command_success_nodata ( si , _ ( " Nick \2 %s \2 not found in announcement request database. " ) , nick ) ;
}
static void as_cmd_waiting ( sourceinfo_t * si , int parc , char * parv [ ] )
{
asreq_t * l ;
mowgli_node_t * n ;
char * subject2 ;
char buf [ BUFSIZE ] ;
struct tm tm ;
MOWGLI_LIST_FOREACH ( n , as_reqlist . head )
{
l = n - > data ;
tm = * localtime ( & l - > announce_ts ) ;
strftime ( buf , BUFSIZE , TIME_FORMAT , & tm ) ;
subject2 = sstrdup ( l - > subject ) ;
replace ( subject2 , BUFSIZE , " _ " , " " ) ;
/* This needs to be two lines for cutoff purposes */
command_success_nodata ( si , " Account: \2 %s \2 , Subject: %s, Requested On: \2 %s \2 , Announcement: " ,
l - > nick , subject2 , buf ) ;
command_success_nodata ( si , " %s " , l - > text ) ;
free ( subject2 ) ;
}
command_success_nodata ( si , " End of list. " ) ;
logcommand ( si , CMDLOG_GET , " WAITING " ) ;
}
static void as_cmd_cancel ( sourceinfo_t * si , int parc , char * parv [ ] )
{
asreq_t * l ;
mowgli_node_t * n ;
2012-10-04 05:04:42 +00:00
stringref target ;
2012-04-17 20:09:50 +00:00
target = entity ( si - > smu ) - > name ;
MOWGLI_LIST_FOREACH ( n , as_reqlist . head )
{
l = n - > data ;
if ( ! irccasecmp ( l - > nick , target ) )
{
mowgli_node_delete ( n , & as_reqlist ) ;
strshare_unref ( l - > nick ) ;
strshare_unref ( l - > creator ) ;
free ( l - > subject ) ;
free ( l - > text ) ;
free ( l ) ;
command_success_nodata ( si , " Your pending announcement has been canceled. " ) ;
logcommand ( si , CMDLOG_REQUEST , " CANCEL " ) ;
return ;
}
}
command_fail ( si , fault_badparams , _ ( " You do not have a pending announcement to cancel. " ) ) ;
}
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
* vim : ts = 8
* vim : sw = 8
* vim : noexpandtab
*/