#define KEY_NICK "nick"
#define KEY_DB_BADCHANS "badchans"
#define KEY_HELP_CHANNEL "help_channel"
+#define KEY_PUBLIC_CHANNEL "public_channel"
#define KEY_PAGE_DEST "page_dest"
#define KEY_CMDWORD "cmdword"
#define KEY_PERSIST_LENGTH "persist_length"
#define KEY_PRIVMSG_ONLY "privmsg_only"
#define KEY_REQ_ON_JOIN "req_on_join"
#define KEY_AUTO_VOICE "auto_voice"
+#define KEY_AUTO_JOIN "auto_join"
#define KEY_AUTO_DEVOICE "auto_devoice"
#define KEY_LAST_ACTIVE "last_active"
{ "HSMSG_EXPIRATION_DONE", "%d eligible HelpServ bots have retired." },
{ "HSMSG_BAD_WEEKDAY", "I do not know which day of the week $b%s$b is." },
{ "HSMSG_WEEK_STARTS", "$b%s$b's weeks start on $b%s$b." },
+ { "HSMSG_MODSTATS_BAD_FIELD", "The specified field does not exist." },
+ { "HSMSG_MODSTATS_BAD_WEEK", "The specified week is invalid." },
+ { "HSMSG_MODSTATS_NEGATIVE", "This modification would result in a negative value." },
+ { "HSMSG_MODSTATS_SUCCESS", "$b%s$b's stats have been modified successfully." },
/* Registration */
{ "HSMSG_ILLEGAL_NICK", "$b%s$b is an illegal nick; cannot use it." },
{ "HSMSG_SET_PRIVMSGONLY", "$bPrivmsgOnly $b %s" },
{ "HSMSG_SET_REQONJOIN", "$bReqOnJoin $b %s" },
{ "HSMSG_SET_AUTOVOICE", "$bAutoVoice $b %s" },
+ { "HSMSG_SET_AUTOJOIN", "$bAutoJoin $b %s" },
{ "HSMSG_SET_AUTODEVOICE", "$bAutoDevoice $b %s" },
+ { "HSMSG_SET_PUBLICCHAN", "$bPublicChan $b %s" },
{ "HSMSG_PAGE_NOTICE", "notice" },
{ "HSMSG_PAGE_PRIVMSG", "privmsg" },
{ "HSMSG_PAGE_ONOTICE", "onotice" },
{ "HSMSG_REQ_PERSIST_PART", "Everything you tell me until you are helped (or you leave %s) will be recorded. If you part %s, your request will be lost." },
{ "HSMSG_REQ_PERSIST_HANDLE", "Everything you tell me until you are helped will be recorded." },
{ "HSMSG_REQ_MAXLEN", "Sorry, but your request has reached the maximum number of lines. Please wait to be assigned to a helper and continue explaining your request to them." },
+ { "HSMSQ_REQ_TEXT_ADDED", "Message from $b%s:$b %s" },
{ "HSMSG_REQ_FOUND_ANOTHER", "Request ID#%lu has been closed. $S detected that you also have request ID#%lu open. If you send $S a message, it will be associated with that request." },
/* Messages that are inserted into request text */
{ "HSMSG_PAGE_HELPER_GONE_2", "Request ID#%lu from $b%s$b (Not authed) $bhas been unassigned$b, as its helper, %s has %s." },
{ "HSMSG_PAGE_HELPER_GONE_3", "Request ID#%lu from an offline user (Account %s) $bhas been unassigned$b, as its helper, %s has %s." },
{ "HSMSG_PAGE_HELPER_GONE_4", "Request ID#%lu from an offline user (No account) $bhas been unassigned$b, as its helper, %s has %s." },
- { "HSMSG_PAGE_WHINE_HEADER", "$b%u unhandled request(s)$b waiting at least $b%s$b (%u total)" },
+ { "HSMSG_PAGE_WHINE_HEADER", "$b%u unhandled request(s)$b waiting at least $b%s$b (%u unhandled, %u total)" },
{ "HSMSG_PAGE_IDLE_HEADER", "$b%u users$b in %s $bidle at least %s$b:" },
{ "HSMSG_PAGE_EMPTYALERT", "$b%s has no helpers present (%u unhandled request(s))$b" },
{ "HSMSG_PAGE_ONLYTRIALALERT", "$b%s has no full helpers present (%d trial(s) present; %u unhandled request(s))$b" },
const char *reqlogfile;
unsigned long db_backup_frequency;
unsigned int expire_age;
+ unsigned long modstats_level;
char user_escape;
} helpserv_conf;
struct userNode *helpserv;
struct chanNode *helpchan;
+ struct chanNode *publicchan;
struct chanNode *page_targets[PGSRC_COUNT];
enum page_type page_types[PGSRC_COUNT];
enum notification_type notify;
/* This is a default; it can be changed on a per-request basis */
- enum persistence_type persist_types[PERSIST_T_COUNT];
+ enum persistence_length persist_lengths[PERSIST_T_COUNT];
dict_t users; /* indexed by handle */
unsigned int privmsg_only : 1;
unsigned int req_on_join : 1;
unsigned int auto_voice : 1;
+ unsigned int auto_join : 1;
unsigned int auto_devoice : 1;
unsigned int helpchan_empty : 1;
return 0; }
/* For messages going to users being helped */
-#define helpserv_msguser(target, format...) send_message_type((from_opserv ? 0 : hs->privmsg_only), (target), (from_opserv ? opserv : hs->helpserv) , ## format)
-#define helpserv_user_reply(format...) send_message_type(req->hs->privmsg_only, req->user, req->hs->helpserv , ## format)
+#if defined(GCC_VARMACROS)
+# define helpserv_msguser(target, ARGS...) send_message_type((from_opserv ? 0 : hs->privmsg_only), (target), (from_opserv ? opserv : hs->helpserv), ARGS)
+# define helpserv_user_reply(ARGS...) send_message_type(req->hs->privmsg_only, req->user, req->hs->helpserv, ARGS)
/* For messages going to helpers */
-#define helpserv_notice(target, format...) send_message((target), (from_opserv ? opserv : hs->helpserv) , ## format)
-#define helpserv_notify(helper, format...) do { struct userNode *_target; for (_target = (helper)->handle->users; _target; _target = _target->next_authed) { \
- send_message(_target, (helper)->hs->helpserv, ## format); \
+# define helpserv_notice(target, ARGS...) send_message((target), (from_opserv ? opserv : hs->helpserv), ARGS)
+# define helpserv_notify(helper, ARGS...) do { struct userNode *_target; for (_target = (helper)->handle->users; _target; _target = _target->next_authed) { \
+ if(!_target->next_authed || GetUserMode(helper->hs->helpchan, _target)) {\
+ send_message(_target, (helper)->hs->helpserv, ARGS); \
+ break; \
+ } \
+ } } while (0)
+# define helpserv_page(TYPE, ARGS...) do { \
+ int msg_type=0; struct chanNode *target=helpserv_get_page_type(hs, (TYPE), &msg_type); \
+ if (target) send_target_message(msg_type, target->name, hs->helpserv, ARGS); \
+ } while (0)
+#elif defined(C99_VARMACROS)
+# define helpserv_msguser(target, ...) send_message_type((from_opserv ? 0 : hs->privmsg_only), (target), (from_opserv ? opserv : hs->helpserv), __VA_ARGS__)
+# define helpserv_user_reply(...) send_message_type(req->hs->privmsg_only, req->user, req->hs->helpserv, __VA_ARGS__)
+/* For messages going to helpers */
+# define helpserv_notice(target, ...) send_message((target), (from_opserv ? opserv : hs->helpserv), __VA_ARGS__)
+# define helpserv_notify(helper, ...) do { struct userNode *_target; for (_target = (helper)->handle->users; _target; _target = _target->next_authed) { \
+ if(!_target->next_authed || GetUserMode(helper->hs->helpchan, _target)) {\
+ send_message(_target, (helper)->hs->helpserv, __VA_ARGS__); \
+ break; \
+ } \
} } while (0)
+# define helpserv_page(TYPE, ...) do { \
+ int msg_type=0; struct chanNode *target=helpserv_get_page_type(hs, (TYPE), &msg_type); \
+ if (target) send_target_message(msg_type, target->name, hs->helpserv, __VA_ARGS__); \
+ } while (0)
+#endif
#define helpserv_message(hs, target, id) do { if ((hs)->messages[id]) { \
if (from_opserv) \
send_message_type(4, (target), opserv, "%s", (hs)->messages[id]); \
else \
send_message_type(4 | hs->privmsg_only, (target), hs->helpserv, "%s", (hs)->messages[id]); \
} } while (0)
-#define helpserv_page(TYPE, FORMAT...) do { \
- struct chanNode *target=NULL; int msg_type=0; \
- target = hs->page_targets[TYPE]; \
- switch (hs->page_types[TYPE]) { \
- case PAGE_NOTICE: msg_type = 0; break; \
- case PAGE_PRIVMSG: msg_type = 1; break; \
- case PAGE_ONOTICE: msg_type = 2; break; \
- default: log_module(HS_LOG, LOG_ERROR, "helpserv_page() called but %s has an invalid page type %d.", hs->helpserv->nick, TYPE); \
- case PAGE_NONE: target = NULL; break; \
- } \
- if (target) send_target_message(msg_type, target->name, hs->helpserv, ## FORMAT); \
- } while (0)
#define helpserv_get_handle_info(user, text) smart_get_handle_info((from_opserv ? opserv : hs->helpserv) , (user), (text))
struct helpserv_cmd {
assert(req != NULL);
assert(reason != NULL);
- if (!(ctx = saxdb_open_context(reqlog_f)))
+ if (!reqlog_f || !(ctx = saxdb_open_context(reqlog_f)))
return;
sprintf(key, "%s-%lu-%lu", req->hs->helpserv->nick, (unsigned long)req->opened, req->id);
- if ((res = setjmp(ctx->jbuf)) != 0) {
+ if ((res = setjmp(*saxdb_jmp_buf(ctx))) != 0) {
log_module(HS_LOG, LOG_ERROR, "Unable to log helpserv request: %s.", strerror(res));
} else {
saxdb_start_record(ctx, key, 1);
saxdb_write_string(ctx, KEY_REQUEST_CLOSEREASON, reason);
saxdb_write_string_list(ctx, KEY_REQUEST_TEXT, req->text);
saxdb_end_record(ctx);
- saxdb_close_context(ctx);
- fflush(reqlog_f);
+ saxdb_close_context(ctx, 0);
}
}
+static struct chanNode *helpserv_get_page_type(struct helpserv_bot *hs, enum page_source type, int *msg_type)
+{
+ switch (hs->page_types[type]) {
+ case PAGE_NOTICE:
+ *msg_type = 0;
+ break;
+ case PAGE_PRIVMSG:
+ *msg_type = 1;
+ break;
+ case PAGE_ONOTICE:
+ *msg_type = 2;
+ break;
+ default:
+ log_module(HS_LOG, LOG_ERROR, "helpserv_page() called but %s has an invalid page type %d.", hs->helpserv->nick, type);
+ /* and fall through */
+ case PAGE_NONE:
+ return NULL;
+ }
+ return hs->page_targets[type];
+}
+
/* Searches for a request by number, nick, or account (num|nick|*account).
* As there can potentially be >1 match, it takes a reqlist. The return
* value is the "best" request found (explained in the comment block below).
static struct helpserv_request * create_request(struct userNode *user, struct helpserv_bot *hs, int from_join) {
struct helpserv_request *req = calloc(1, sizeof(struct helpserv_request));
- char lbuf[3][MAX_LINE_SIZE], unh[INTERVALLEN];
+ char lbuf[3][MAX_LINE_SIZE], req_id[INTERVALLEN];
struct helpserv_reqlist *reqlist, *hand_reqlist;
const unsigned int from_opserv = 0;
const char *fmt;
assert(req);
req->id = ++hs->last_requestid;
- sprintf(unh, "%lu", req->id);
- dict_insert(hs->requests, strdup(unh), req);
+ sprintf(req_id, "%lu", req->id);
+ dict_insert(hs->requests, strdup(req_id), req);
if (hs->id_wrap) {
unsigned long i;
sprintf(lbuf[0], fmt, req->id);
}
if (req != hs->unhandled) {
- intervalString(unh, now - hs->unhandled->opened, user->handle_info);
+ intervalString(req_id, now - hs->unhandled->opened, user->handle_info);
fmt = user_find_message(user, "HSMSG_REQ_UNHANDLED_TIME");
- sprintf(lbuf[1], fmt, unh);
+ sprintf(lbuf[1], fmt, req_id);
} else {
fmt = user_find_message(user, "HSMSG_REQ_NO_UNHANDLED");
- sprintf(lbuf[1], fmt);
+ sprintf(lbuf[1], "%s", fmt);
}
- switch (hs->persist_types[PERSIST_T_REQUEST]) {
+ switch (hs->persist_lengths[PERSIST_T_REQUEST]) {
case PERSIST_PART:
fmt = user_find_message(user, "HSMSG_REQ_PERSIST_PART");
sprintf(lbuf[2], fmt, hs->helpchan->name, hs->helpchan->name);
break;
case PERSIST_QUIT:
fmt = user_find_message(user, "HSMSG_REQ_PERSIST_QUIT");
- sprintf(lbuf[2], fmt);
+ sprintf(lbuf[2], "%s", fmt);
break;
default:
log_module(HS_LOG, LOG_ERROR, "%s has an invalid req_persist.", hs->helpserv->nick);
case PERSIST_CLOSE:
if (user->handle_info) {
fmt = user_find_message(user, "HSMSG_REQ_PERSIST_HANDLE");
- sprintf(lbuf[2], fmt);
} else {
fmt = user_find_message(user, "HSMSG_REQ_PERSIST_QUIT");
- sprintf(lbuf[2], fmt);
}
+ sprintf(lbuf[2], "%s", fmt);
break;
}
helpserv_message(hs, user, MSGTYPE_REQ_OPENED);
helpserv_msguser(user, "HSMSG_USERCMD_NO_REQUEST");
return;
}
- if ((hs->persist_types[PERSIST_T_REQUEST] == PERSIST_PART) && !GetUserMode(hs->helpchan, user)) {
- helpserv_msguser(user, "HSMSG_REQ_YOU_NOT_IN_HELPCHAN_OPEN", hs->helpchan->name);
+ if ((hs->persist_lengths[PERSIST_T_REQUEST] == PERSIST_PART) && !GetUserMode(hs->helpchan, user) && (!hs->publicchan || (hs->publicchan && !GetUserMode(hs->publicchan, user)))) {
+ if(hs->publicchan)
+ helpserv_msguser(user, "HSMSG_REQ_YOU_NOT_IN_HELPCHAN_OPEN", hs->publicchan->name);
+ else
+ helpserv_msguser(user, "HSMSG_REQ_YOU_NOT_IN_HELPCHAN_OPEN", hs->helpchan->name);
return;
}
}
req->updated = now;
- if (!hs->req_maxlen || req->text->used < hs->req_maxlen)
+ if (!hs->req_maxlen || req->text->used < hs->req_maxlen) {
+ struct userNode *likely_helper;
+
string_list_append(req->text, strdup(text));
- else
+ /* Find somebody likely to be the helper */
+ if (!req->helper)
+ likely_helper = NULL;
+ else if ((likely_helper = req->helper->handle->users) && !likely_helper->next_authed) {
+ /* only one user it could be :> */
+ } else for (likely_helper = req->helper->handle->users; likely_helper; likely_helper = likely_helper->next_authed)
+ if (GetUserMode(hs->helpchan, likely_helper))
+ break;
+
+ if(likely_helper)
+ send_target_message(1, likely_helper->nick, hs->helpserv, "HSMSQ_REQ_TEXT_ADDED", user->nick, text);
+
+ } else
helpserv_msguser(user, "HSMSG_REQ_MAXLEN");
}
struct helpserv_request *req = data;
/* Logging */
- if (shutting_down && (req->hs->persist_types[PERSIST_T_REQUEST] != PERSIST_CLOSE || !req->handle)) {
+ if (shutting_down && (req->hs->persist_lengths[PERSIST_T_REQUEST] != PERSIST_CLOSE || !req->handle)) {
helpserv_log_request(req, "srvx shutdown");
}
if (!user->handle_info)
return 0;
- if ((hs->persist_types[PERSIST_T_HELPER] == PERSIST_PART) && !GetUserMode(hs->helpchan, user)) {
+ if ((hs->persist_lengths[PERSIST_T_HELPER] == PERSIST_PART) && !GetUserMode(hs->helpchan, user)) {
struct helpserv_user *hsuser_actor = GetHSUser(hs, actor->handle_info);
if (hsuser_actor->level < HlManager) {
helpserv_notice(user, "HSMSG_REQ_YOU_NOT_IN_HELPCHAN", hs->helpchan->name);
req->helper = GetHSUser(hs, user->handle_info);
assert(req->helper);
req->assigned = now;
-
+
+ if (req->user && hs->auto_join) {
+ irc_svsjoin(hs->helpserv,req->user,hs->helpchan);
+ }
+
if (old_helper) {
helpserv_notice(user, "HSMSG_REQ_REASSIGNED", req->id, old_helper->handle->handle);
req->helper->reassigned_to[0]++;
if ((change.args[0].u.member = GetUserMode(hs->helpchan, req->user)))
mod_chanmode_announce(hs->helpserv, hs->helpchan, &change);
}
-
+
return 1;
}
return 0;
}
- if ((hs->persist_types[PERSIST_T_HELPER] == PERSIST_PART) && !GetUserMode(hs->helpchan, user) && (hs_user->level < HlManager)) {
+ if ((hs->persist_lengths[PERSIST_T_HELPER] == PERSIST_PART) && !GetUserMode(hs->helpchan, user) && (hs_user->level < HlManager)) {
helpserv_notice(user, "HSMSG_REQ_HIM_NOT_IN_HELPCHAN", targetuser->nick, hs->helpchan->name);
return 0;
}
tbl.contents[i][3] = strdup(unh_time);
}
- helpserv_page(PGSRC_ALERT, "HSMSG_PAGE_WHINE_HEADER", reqlist.used, strwhinedelay, queuesize);
+ helpserv_page(PGSRC_ALERT, "HSMSG_PAGE_WHINE_HEADER", reqlist.used, strwhinedelay, queuesize, dict_size(hs->requests));
table_send(hs->helpserv, hs->page_targets[PGSRC_ALERT]->name, 0, page_type_funcs[hs->page_types[PGSRC_ALERT]], tbl);
for (i=1; i <= reqlist.used; i++) {
free((char *)tbl.contents[i][3]);
}
#else
- helpserv_page(PGSRC_ALERT, "HSMSG_PAGE_WHINE_HEADER", reqlist.used, strwhinedelay, queuesize);
+ helpserv_page(PGSRC_ALERT, "HSMSG_PAGE_WHINE_HEADER", reqlist.used, strwhinedelay, queuesize, dict_size(hs->requests));
#endif
}
dict_insert(helpserv_bots_bychan_dict, hs->helpchan->name, botlist);
}
helpserv_botlist_append(botlist, hs);
-
return hs;
}
char *nick, *helpchan, reason[MAXLEN];
struct handle_info *handle;
- REQUIRE_PARMS(4);
+ REQUIRE_PARMS(3);
nick = argv[1];
if (!is_valid_nick(nick)) {
helpserv_notice(user, "HSMSG_ILLEGAL_NICK", nick);
}
static void helpserv_unregister(struct helpserv_bot *bot, const char *quit_fmt, const char *global_fmt, const char *actor) {
- char reason[MAXLEN], channame[CHANNELLEN], botname[NICKLEN];
+ char reason[MAXLEN], channame[CHANNELLEN], *botname;
struct helpserv_botlist *botlist;
size_t len;
helpserv_botlist_remove(botlist, bot);
if (!botlist->used)
dict_remove(helpserv_bots_bychan_dict, bot->helpchan->name);
- len = strlen(bot->helpserv->nick) + 1;
- safestrncpy(botname, bot->helpserv->nick, len);
+ botname=bot->helpserv->nick;
len = strlen(bot->helpchan->name) + 1;
safestrncpy(channame, bot->helpchan->name, len);
snprintf(reason, sizeof(reason), quit_fmt, actor);
return changed;
}
+static HELPSERV_FUNC(cmd_modstats) {
+ struct handle_info *hi;
+ struct helpserv_user *victim;
+ const char *field_name;
+ int week, mod;
+ unsigned int *field = NULL;
+ char *errptr;
+
+ REQUIRE_PARMS(5);
+ if (!oper_has_access(user, (from_opserv ? opserv : hs->helpserv), helpserv_conf.modstats_level, 0))
+ return 0;
+ if (!(hi = helpserv_get_handle_info(user, argv[1])))
+ return 0;
+ if (!(victim = GetHSUser(hs, hi))) {
+ helpserv_notice(user, "HSMSG_NOT_IN_USERLIST", hi->handle, hs->helpserv->nick);
+ return 0;
+ }
+
+ field_name = argv[2];
+ if (!strcasecmp(argv[3], "total"))
+ week = 4;
+ else if(!strcasecmp(argv[3], "current"))
+ week = 0;
+ else {
+ week = strtoul(argv[3], &errptr, 0);
+ if (*errptr != '\0') {
+ helpserv_notice(user, "HSMSG_MODSTATS_BAD_WEEK");
+ return 0;
+ }
+ }
+ mod = strtol(argv[4], NULL, 0);
+
+ if (week < 0 || week > 4) {
+ helpserv_notice(user, "HSMSG_MODSTATS_BAD_WEEK");
+ return 0;
+ }
+
+ if (!strcasecmp(field_name, "time")) {
+ if (victim->join_time && (week == 0 || week == 4)) {
+ victim->time_per_week[0] += now - victim->join_time;
+ victim->time_per_week[4] += now - victim->join_time;
+ victim->join_time = now;
+ }
+ field = victim->time_per_week;
+ }
+ else if (!strcasecmp(field_name, "picked") || !strcasecmp(field_name, "picked_up") || !strcasecmp(field_name, "reqs"))
+ field = victim->picked_up;
+ else if (!strcasecmp(field_name, "closed"))
+ field = victim->closed;
+ else if (!strcasecmp(field_name, "ra_from") || !strcasecmp(field_name, "reassigned_from"))
+ field = victim->reassigned_from;
+ else if (!strcasecmp(field_name, "ra_to") || !strcasecmp(field_name, "reassigned_to"))
+ field = victim->reassigned_to;
+ else {
+ helpserv_notice(user, "HSMSG_MODSTATS_BAD_FIELD");
+ return 0;
+ }
+
+ if (mod < 0 && mod < -(int)field[week]) {
+ helpserv_notice(user, "HSMSG_MODSTATS_NEGATIVE");
+ return 0;
+ }
+
+ field[week] += mod;
+ helpserv_notice(user, "HSMSG_MODSTATS_SUCCESS", victim->handle->handle);
+
+ return (mod != 0);
+}
+
static void set_page_target(struct helpserv_bot *hs, enum page_source idx, const char *target) {
struct chanNode *new_target, *old_target;
helpserv_notice(user, "HSMSG_INVALID_OPTION", argv[0]);
return 0;
}
- hs->persist_types[idx] = new_pers;
+ hs->persist_lengths[idx] = new_pers;
changed = 1;
}
- helpserv_notice(user, persistence_types[idx].print_name,
- user_find_message(user, persistence_lengths[hs->persist_types[idx]].print_name));
+ helpserv_notice(user, persistence_lengths[idx].print_name,
+ user_find_message(user, persistence_lengths[hs->persist_lengths[idx]].print_name));
return changed;
}
OPTION_BINARY(hs->auto_voice, "HSMSG_SET_AUTOVOICE");
}
+static HELPSERV_OPTION(opt_auto_join) {
+ OPTION_BINARY(hs->auto_join, "HSMSG_SET_AUTOJOIN");
+}
+
static HELPSERV_OPTION(opt_auto_devoice) {
OPTION_BINARY(hs->auto_devoice, "HSMSG_SET_AUTODEVOICE");
}
+static HELPSERV_OPTION(opt_publicchan) {
+ char *publicchan;
+ int changed=0;
+ if (argc > 0) {
+ publicchan = argv[0];
+ if(strcmp(publicchan, "*")) {
+ if (!IsChannelName(publicchan)) {
+ helpserv_notice(user, "HSMSG_ILLEGAL_CHANNEL", publicchan);
+ HELPSERV_SYNTAX();
+ return 0;
+ }
+ if (opserv_bad_channel(publicchan)) {
+ helpserv_notice(user, "HSMSG_ILLEGAL_CHANNEL", publicchan);
+ return 0;
+ }
+ }
+ if (!hs->publicchan || (hs->publicchan && irccasecmp(hs->publicchan->name, publicchan))) {
+ if(hs->publicchan) {
+ //there is another public chan o.O
+ //part
+ DelChannelUser(hs->helpserv, hs->publicchan, "unregistered.", 0);
+ hs->publicchan = NULL;
+ }
+ changed = 1;
+ if(strcmp(publicchan, "*")) {
+ if (!(hs->publicchan = GetChannel(publicchan))) {
+ hs->publicchan = AddChannel(publicchan, now, NULL, NULL);
+ AddChannelUser(hs->helpserv, hs->publicchan)->modes |= MODE_CHANOP;
+ } else {
+ struct mod_chanmode change;
+ mod_chanmode_init(&change);
+ change.argc = 1;
+ change.args[0].mode = MODE_CHANOP;
+ change.args[0].u.member = AddChannelUser(hs->helpserv, hs->publicchan);
+ mod_chanmode_announce(hs->helpserv, hs->publicchan, &change);
+ }
+ }
+ }
+ } else {
+ changed = 0;
+ }
+ helpserv_notice(user, "HSMSG_SET_PUBLICCHAN", (hs->publicchan) ? hs->publicchan->name : user_find_message(user,"MSG_NONE")); \
+ return changed;
+}
+
static HELPSERV_FUNC(cmd_set) {
helpserv_option_func_t *opt;
if (argc < 2) {
unsigned int i;
helpserv_option_func_t *display[] = {
- opt_pagetarget_command, opt_pagetarget_alert, opt_pagetarget_status,
+ opt_publicchan, opt_pagetarget_command, opt_pagetarget_alert, opt_pagetarget_status,
opt_pagetype, opt_alert_page_type, opt_status_page_type,
opt_greeting, opt_req_opened, opt_req_assigned, opt_req_closed,
opt_idle_delay, opt_whine_delay, opt_whine_interval,
opt_empty_interval, opt_stale_delay, opt_request_persistence,
opt_helper_persistence, opt_notification, opt_id_wrap,
- opt_req_maxlen, opt_privmsg_only, opt_req_on_join, opt_auto_voice,
+ opt_req_maxlen, opt_privmsg_only, opt_req_on_join, opt_auto_voice, opt_auto_join,
opt_auto_devoice
};
saxdb_end_record(ctx);
/* Open requests */
- if (hs->persist_types[PERSIST_T_REQUEST] == PERSIST_CLOSE) {
+ if (hs->persist_lengths[PERSIST_T_REQUEST] == PERSIST_CLOSE) {
saxdb_start_record(ctx, KEY_REQUESTS, 0);
dict_foreach(hs->requests, request_write_helper, ctx);
saxdb_end_record(ctx);
/* Other settings and state */
saxdb_write_string(ctx, KEY_HELP_CHANNEL, hs->helpchan->name);
+ if(hs->publicchan) saxdb_write_string(ctx, KEY_PUBLIC_CHANNEL, hs->publicchan->name);
slist = alloc_string_list(PGSRC_COUNT);
for (pagesrc=0; pagesrc<PGSRC_COUNT; pagesrc++) {
struct chanNode *target = hs->page_targets[pagesrc];
saxdb_write_int(ctx, interval_types[inttype].db_name, hs->intervals[inttype]);
}
for (persisttype=0; persisttype<PERSIST_T_COUNT; persisttype++) {
- const char *persist = persistence_lengths[hs->persist_types[persisttype]].db_name;
+ const char *persist = persistence_lengths[hs->persist_lengths[persisttype]].db_name;
saxdb_write_string(ctx, persistence_types[persisttype].db_name, persist);
}
saxdb_write_string(ctx, KEY_NOTIFICATION, notification_types[hs->notify].db_name);
saxdb_write_int(ctx, KEY_PRIVMSG_ONLY, hs->privmsg_only);
saxdb_write_int(ctx, KEY_REQ_ON_JOIN, hs->req_on_join);
saxdb_write_int(ctx, KEY_AUTO_VOICE, hs->auto_voice);
+ saxdb_write_int(ctx, KEY_AUTO_JOIN, hs->auto_join);
saxdb_write_int(ctx, KEY_AUTO_DEVOICE, hs->auto_devoice);
saxdb_write_int(ctx, KEY_LAST_ACTIVE, hs->last_active);
static int helpserv_bot_read(const char *key, void *data, UNUSED_ARG(void *extra)) {
struct record_data *br = data, *raw_record;
struct helpserv_bot *hs;
- char *registrar, *helpchannel_name, *str;
+ char *registrar, *helpchannel_name, *publicchannel_name, *str;
dict_t users, requests;
enum page_source pagesrc;
enum message_type msgtype;
hs = register_helpserv(key, helpchannel_name, registrar);
+ publicchannel_name = database_get_data(GET_RECORD_OBJECT(br), KEY_PUBLIC_CHANNEL, RECDB_QSTRING);
+ if (publicchannel_name) {
+ if(!IsChannelName(publicchannel_name)) {
+ log_module(HS_LOG, LOG_ERROR, "%s has an invalid channel name.", key);
+ return 0;
+ } else {
+ if (!(hs->publicchan = GetChannel(publicchannel_name))) {
+ hs->publicchan = AddChannel(publicchannel_name, now, NULL, NULL);
+ AddChannelUser(hs->helpserv, hs->publicchan)->modes |= MODE_CHANOP;
+ } else {
+ struct mod_chanmode change;
+ mod_chanmode_init(&change);
+ change.argc = 1;
+ change.args[0].mode = MODE_CHANOP;
+ change.args[0].u.member = AddChannelUser(hs->helpserv, hs->publicchan);
+ mod_chanmode_announce(hs->helpserv, hs->publicchan, &change);
+ }
+ }
+ }
raw_record = dict_find(GET_RECORD_OBJECT(br), KEY_PAGE_DEST, NULL);
switch (raw_record ? raw_record->type : RECDB_INVALID) {
case RECDB_QSTRING:
for (persisttype=0; persisttype<PERSIST_T_COUNT; persisttype++) {
str = database_get_data(GET_RECORD_OBJECT(br), persistence_types[persisttype].db_name, RECDB_QSTRING);
- hs->persist_types[persisttype] = str ? persistence_from_name(str) : PERSIST_QUIT;
+ hs->persist_lengths[persisttype] = str ? persistence_from_name(str) : PERSIST_QUIT;
}
str = database_get_data(GET_RECORD_OBJECT(br), KEY_NOTIFICATION, RECDB_QSTRING);
hs->notify = str ? notification_from_name(str) : NOTIFY_NONE;
hs->req_on_join = str ? enabled_string(str) : 0;
str = database_get_data(GET_RECORD_OBJECT(br), KEY_AUTO_VOICE, RECDB_QSTRING);
hs->auto_voice = str ? enabled_string(str) : 0;
+ str = database_get_data(GET_RECORD_OBJECT(br), KEY_AUTO_JOIN, RECDB_QSTRING);
+ hs->auto_join = str ? enabled_string(str) : 0;
str = database_get_data(GET_RECORD_OBJECT(br), KEY_AUTO_DEVOICE, RECDB_QSTRING);
hs->auto_devoice = str ? enabled_string(str) : 0;
str = database_get_data(GET_RECORD_OBJECT(br), KEY_LAST_ACTIVE, RECDB_QSTRING);
str = database_get_data(conf_node, "expiration", RECDB_QSTRING);
helpserv_conf.expire_age = ParseInterval(str ? str : "60d");
+ str = database_get_data(conf_node, "modstats_level", RECDB_QSTRING);
+ helpserv_conf.modstats_level = str ? strtoul(str, NULL, 0) : 850;
str = database_get_data(conf_node, "user_escape", RECDB_QSTRING);
helpserv_conf.user_escape = str ? str[0] : '@';
}
static struct helpserv_cmd *
-helpserv_define_func(const char *name, helpserv_func_t *func, enum helpserv_level access, long flags) {
+helpserv_define_func(const char *name, helpserv_func_t *func, enum helpserv_level level, long flags) {
struct helpserv_cmd *cmd = calloc(1, sizeof(struct helpserv_cmd));
- cmd->access = access;
+ cmd->access = level;
cmd->weight = 1.0;
cmd->func = func;
cmd->flags = flags;
hs = botlist->list[i];
if (!hs->helpserv)
continue;
- if (hs->persist_types[PERSIST_T_REQUEST] != PERSIST_PART)
+ if (hs->persist_lengths[PERSIST_T_REQUEST] != PERSIST_PART)
continue;
for (it=dict_first(hs->requests); it; it=iter_next(it)) {
struct helpserv_request *req = iter_data(it);
if (mn->user != req->user)
+ continue;
+ if (GetUserMode(hs->helpchan, mn->user)) //publicchan
continue;
if (req->text->used) {
helpserv_message(hs, mn->user, MSGTYPE_REQ_DROPPED);
for (it=dict_first(hs->requests); it; it=iter_next(it)) {
struct helpserv_request *req=iter_data(it);
- if ((hs->persist_types[PERSIST_T_HELPER] == PERSIST_PART)
+ if ((hs->persist_lengths[PERSIST_T_HELPER] == PERSIST_PART)
&& (req->helper == hs_user)) {
- char reason[CHANNELLEN + 8];
- sprintf(reason, "parted %s", mn->channel->name);
- helpserv_page_helper_gone(hs, req, reason);
+ char our_reason[CHANNELLEN + 8];
+ sprintf(our_reason, "parted %s", mn->channel->name);
+ helpserv_page_helper_gone(hs, req, our_reason);
}
}
for (i=0; i < n; i++) {
struct helpserv_request *req = reqlist->list[0];
- if ((req->hs->persist_types[PERSIST_T_REQUEST] == PERSIST_QUIT) || !req->handle) {
+ if ((req->hs->persist_lengths[PERSIST_T_REQUEST] == PERSIST_QUIT) || !req->handle) {
char buf[12];
sprintf(buf, "%lu", req->id);
for (it=dict_first(hs->requests); it; it=iter_next(it)) {
struct helpserv_request *req=iter_data(it);
- if ((hs->persist_types[PERSIST_T_HELPER] == PERSIST_QUIT) && (req->helper == hs_user)) {
+ if ((hs->persist_lengths[PERSIST_T_HELPER] == PERSIST_QUIT) && (req->helper == hs_user)) {
helpserv_page_helper_gone(hs, req, "disconnected");
}
}
if (!nicknewest || (nicknewest->opened < req->opened))
nicknewest = req;
+
if (hs->auto_voice && req->helper)
{
struct mod_chanmode change;
if ((force_greet && nicknewest) || (newest && (nicknewest == newest))) {
/* Let the user know. Either the user is forced to be greeted, or the
* above has changed which request will get their next message. */
- helpserv_msguser(user, "HSMSG_GREET_EXISTING_REQ", hs->helpchan->name, nicknewest->id);
+ //helpserv_msguser(user, "HSMSG_GREET_EXISTING_REQ", hs->helpchan->name, nicknewest->id);
}
}
if ((reqlist = dict_find(helpserv_reqs_bynick_dict, user->nick, NULL))) {
for (j=0; j < reqlist->used; j++)
- if (reqlist->list[i]->hs == hs)
+ if (reqlist->list[j]->hs == hs)
break;
if (j < reqlist->used)
continue;
struct helpserv_request *req = reqlist->list[i];
struct helpserv_bot *hs=req->hs;
- if (!old_handle || hs->persist_types[PERSIST_T_REQUEST] == PERSIST_PART || hs->persist_types[PERSIST_T_REQUEST] == PERSIST_QUIT) {
+ if (!old_handle || hs->persist_lengths[PERSIST_T_REQUEST] == PERSIST_PART || hs->persist_lengths[PERSIST_T_REQUEST] == PERSIST_QUIT) {
/* The request needs to be assigned to the new handle; either it
* only persists until part/quit (so it makes sense to keep it as
* close to the user as possible, and if it's made persistent later
if (old_handle) {
char buf[CHANNELLEN + 14];
- if (hs->persist_types[PERSIST_T_REQUEST] == PERSIST_PART) {
+ if (hs->persist_lengths[PERSIST_T_REQUEST] == PERSIST_PART) {
sprintf(buf, "part channel %s", hs->helpchan->name);
} else {
strcpy(buf, "quit irc");
}
helpserv_reqlist_append(req->parent_nick_list, req);
- if (hs->persist_types[PERSIST_T_REQUEST] == PERSIST_CLOSE)
+ if (hs->persist_lengths[PERSIST_T_REQUEST] == PERSIST_CLOSE)
helpserv_msguser(req->user, "HSMSG_REQ_WARN_UNREG", handle->handle, hs->helpchan->name, req->id);
} else {
if (handle->users) {
helpserv_define_func("BOTS", cmd_bots, HlOper, CMD_FROM_OPSERV_ONLY|CMD_IGNORE_EVENT);
helpserv_define_func("EXPIRE", cmd_expire, HlOper, CMD_FROM_OPSERV_ONLY);
helpserv_define_func("WEEKSTART", cmd_weekstart, HlTrial, CMD_NEED_BOT);
+ helpserv_define_func("MODSTATS", cmd_modstats, HlOwner, CMD_NEED_BOT);
helpserv_option_dict = dict_new();
helpserv_define_option("PAGETARGET", opt_pagetarget_command);
helpserv_define_option("PRIVMSGONLY", opt_privmsg_only);
helpserv_define_option("REQONJOIN", opt_req_on_join);
helpserv_define_option("AUTOVOICE", opt_auto_voice);
+ helpserv_define_option("AUTOJOIN", opt_auto_join);
helpserv_define_option("AUTODEVOICE", opt_auto_devoice);
+ helpserv_define_option("PUBLICCHAN", opt_publicchan);
helpserv_usercmd_dict = dict_new();
dict_insert(helpserv_usercmd_dict, "WAIT", usercmd_wait);