diff --git a/doc/away-notify.txt b/doc/away-notify.txt new file mode 100644 index 00000000..f427d0da --- /dev/null +++ b/doc/away-notify.txt @@ -0,0 +1,43 @@ +away-notify client capability specification +---------------------------------------------- + +Copyright (c) 2012 Keith Buck . + +Unlimited redistribution and modification of this document is allowed +provided that the above copyright notice and this permission notice +remains in tact. + +The away-notify client capability allows a client to specify that it +would like to be notified when users are marked/unmarked as away. This +capability is referred to as 'away-notify' at capability negotiation +time. + +This capability is designed to replace polling of WHO as a more +efficient method of tracking the away state of users in a channel. The +away-notify capability both conserves bandwidth as WHO requests are +not continually sent and allows the client to be notified immediately +upon a user setting or removing their away state (as opposed to when +WHO is next polled). + +When this capability is enabled, clients will be sent an AWAY message +when a user sharing a channel with them sets or removes their away +state, as well as when a user joins and has an away message set. +(Note that AWAY will not be sent for joining users with no away +message set.) + +The format of the AWAY message is as follows: + + :nick!user@host AWAY [:message] + +If the message is present, the user (specified by the nick!user@host +mask) is going away. If the message is not present, the user is +removing their away message/state. + +To fully track the away state of users, clients should: + +1) Enable the away-notify capability at negotiation time. + +2) Execute WHO when joining a channel to capture the current away + state of all users in that channel. + +3) Update state appropriately upon receiving an AWAY message. diff --git a/include/client.h b/include/client.h index 5e2c204a..47725750 100644 --- a/include/client.h +++ b/include/client.h @@ -444,6 +444,7 @@ struct ListClient #define CLICAP_SASL 0x0002 #define CLICAP_ACCOUNT_NOTIFY 0x0004 #define CLICAP_EXTENDED_JOIN 0x0008 +#define CLICAP_AWAY_NOTIFY 0x0010 /* * flags macros. diff --git a/modules/m_away.c b/modules/m_away.c index 1cdd5ed7..9fba635d 100644 --- a/modules/m_away.c +++ b/modules/m_away.c @@ -84,6 +84,9 @@ m_away(struct Client *client_p, struct Client *source_p, int parc, const char *p sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY", use_id(source_p)); free_away(source_p); + + sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, ":%s!%s@%s AWAY", + source_p->name, source_p->username, source_p->host); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_UNAWAY, form_str(RPL_UNAWAY)); @@ -102,5 +105,9 @@ m_away(struct Client *client_p, struct Client *source_p, int parc, const char *p if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_NOWAWAY, form_str(RPL_NOWAWAY)); + sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, ":%s!%s@%s AWAY :%s", + source_p->name, source_p->username, source_p->host, + source_p->user->away); + return 0; } diff --git a/modules/m_cap.c b/modules/m_cap.c index 0530537d..81352ab3 100644 --- a/modules/m_cap.c +++ b/modules/m_cap.c @@ -72,6 +72,7 @@ static struct clicap _CLICAP("sasl", CLICAP_SASL, 0, 0), _CLICAP("account-notify", CLICAP_ACCOUNT_NOTIFY, 0, 0), _CLICAP("extended-join", CLICAP_EXTENDED_JOIN, 0, 0), + _CLICAP("away-notify", CLICAP_AWAY_NOTIFY, 0, 0), }; #define CLICAP_LIST_LEN (sizeof(clicap_list) / sizeof(struct clicap)) diff --git a/src/channel.c b/src/channel.c index 20c0dc2c..e3595d01 100644 --- a/src/channel.c +++ b/src/channel.c @@ -136,6 +136,12 @@ send_channel_join(struct Channel *chptr, struct Client *client_p) client_p->name, client_p->username, client_p->host, chptr->chname, EmptyString(client_p->user->suser) ? "*" : client_p->user->suser, client_p->info); + + /* Send away message to away-notify enabled clients. */ + if (client_p->user->away) + sendto_channel_local_with_capability_butone(client_p, ALL_MEMBERS, CLICAP_AWAY_NOTIFY, NOCAPS, chptr, + ":%s!%s@%s AWAY :%s", client_p->name, client_p->username, + client_p->host, client_p->user->away); } /* find_channel_membership() diff --git a/src/s_user.c b/src/s_user.c index ce282f2e..8892a9e6 100644 --- a/src/s_user.c +++ b/src/s_user.c @@ -1468,6 +1468,12 @@ change_nick_user_host(struct Client *target_p, const char *nick, const char *use *modeval = '\0'; } + /* Resend away message to away-notify enabled clients. */ + if (target_p->user->away) + sendto_common_channels_local_butone(target_p, CLICAP_AWAY_NOTIFY, ":%s!%s@%s AWAY :%s", + target_p->name, target_p->username, target_p->host, + target_p->user->away); + if(MyClient(target_p) && changed_case) sendto_one(target_p, ":%s!%s@%s NICK %s", target_p->name, target_p->username, target_p->host, nick);