@@ -109,6 +109,7 @@ struct bouncer_channel {
109109 time_t last_flush ; /*!< Last flush */
110110 unsigned int email_frequency ; /*!< Email flush frequency (0 to disable) */
111111 unsigned int interactive :1 ; /*!< Interactive flushing? */
112+ unsigned int user_mentioned :1 ; /*!< Whether user has been mentioned in channel chat since last flush */
112113 RWLIST_ENTRY (bouncer_channel ) entry ;
113114 char * data ; /* Not quite a flexible struct member, but sufficient */
114115};
@@ -439,14 +440,23 @@ static void *periodic_emailer(void *unused)
439440
440441 /* First, flush any PMs */
441442 if (TIME_TO_FLUSH (bu -> pmbc )) {
443+ if (!bu -> pmbc -> email_frequency ) {
444+ continue ; /* Don't flush if email is disabled */
445+ }
442446 if (!periodic_channel_flush (bu -> pmbc , now )) {
443447 bu -> pmbc -> last_flush = now ;
444448 }
445449 }
446450
447451 /* Now, check the channels */
448452 RWLIST_TRAVERSE (& bu -> channels , bc , entry ) {
449- if (TIME_TO_FLUSH (bc )) {
453+ if (!bc -> email_frequency ) {
454+ continue ; /* Don't flush if email is disabled */
455+ }
456+ /* We don't have an explicit frequency for email digests if mentioned in a channel,
457+ * we just use the PM digest frequency (which is presumably lower). */
458+ if (TIME_TO_FLUSH (bc ) || (bc -> user_mentioned && bu -> pmbc -> email_frequency && (bc -> last_flush < now - (60 * bu -> pmbc -> email_frequency )))) {
459+ bc -> user_mentioned = 0 ;
450460 if (!periodic_channel_flush (bc , now )) {
451461 bc -> last_flush = now ;
452462 }
@@ -806,6 +816,15 @@ static void privmsg_cb(const char *hostmask, const char *sender, const char *rec
806816 RWLIST_UNLOCK (& bouncer_users );
807817}
808818
819+ static inline int user_mentioned (const char * username , const char * msg )
820+ {
821+ char mention [64 ];
822+ /* Most IRC clients will notify the user for normal channel chat if the user's username is present in a message.
823+ * It's generally customary to mention users with "username: message" syntax, so that's what we look for here, to avoid false positives. */
824+ snprintf (mention , sizeof (mention ), "%s:" , username );
825+ return strstr (msg , username ) ? 1 : 0 ;
826+ }
827+
809828static void command_cb (const char * cb_username , enum irc_command_callback_event event , const char * cmd , const char * channel , const char * hostmask , const char * username , const char * data )
810829{
811830 struct bouncer_channel * bc ;
@@ -851,6 +870,10 @@ static void command_cb(const char *cb_username, enum irc_command_callback_event
851870 /* The bouncer client is active for this user, but this channel is not being watched. */
852871 bbs_debug (7 , "Ignoring, no bouncer channel for %s:%s\n" , cb_username , channel );
853872 } else {
873+ if (data && user_mentioned (cb_username , data )) {
874+ /* If we were mentioned in the message, then flush via email ~immediately if needed */
875+ bc -> user_mentioned = 1 ;
876+ }
854877 /* We only log if the bouncer is actually enabled.
855878 * i.e. if the user is in the channel, we don't. */
856879 if (bc -> fp ) {
@@ -1014,6 +1037,7 @@ static int join_leave(const char *username, const char *channel, int is_join)
10141037 bbs_assert (bc -> fp == NULL ); /* The log file should already be closed. */
10151038 if (bc -> interactive ) {
10161039 interactive_flush (bu , bc -> channel ); /* If interactive digest enabled, flush any messages for this channel now */
1040+ bc -> user_mentioned = 0 ;
10171041 }
10181042
10191043 bbs_mutex_unlock (& bc -> bu -> lock );
@@ -1093,6 +1117,7 @@ static int load_config(const char *filename, unsigned int userid)
10931117 bbs_config_val_set_int (cfg , "general" , "email_digest_freq" , & email_digest_freq );
10941118 if (email_digest_freq <= 0 ) {
10951119 interactive = 1 ; /* At least one or the other needs to be enabled */
1120+ email_digest_freq = 0 ; /* Negative isn't valid for the PM digest frequency, so disable */
10961121 }
10971122
10981123 RWLIST_WRLOCK (& bouncer_users );
0 commit comments