Implement the netsplit batch type.
This also lays the groundwork for the netjoin batch type, but that isn't implemented yet. I don't like how some of this is implemented but it'll have to do for now... Compile tested, needs more testing.
This commit is contained in:
parent
4f2b9a4fd1
commit
2373891299
8 changed files with 346 additions and 1 deletions
47
include/batch.h
Normal file
47
include/batch.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/* ircd/batch.h - batch management
|
||||||
|
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice is present in all copies.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdinc.h"
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BATCH_NETSPLIT,
|
||||||
|
BATCH_NETJOIN,
|
||||||
|
BATCH_LAST,
|
||||||
|
} batch_type;
|
||||||
|
|
||||||
|
/* Used for netsplits/netjoins */
|
||||||
|
struct Batch
|
||||||
|
{
|
||||||
|
batch_type batch; /* Type of batch */
|
||||||
|
char id[8]; /* Id of batch */
|
||||||
|
void *data; /* Batch-specific data */
|
||||||
|
void *pdata; /* Private data */
|
||||||
|
int parc; /* Batch parameter count */
|
||||||
|
char **parv; /* Batch parameters */
|
||||||
|
|
||||||
|
rb_dlink_node node;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Batch *start_batch(batch_type batch, void *data, int parc, ...);
|
||||||
|
void finish_batch(struct Batch *batch_p);
|
||||||
|
|
||||||
|
struct Batch *find_batch(batch_type batch, void *data);
|
|
@ -68,6 +68,7 @@ extern unsigned int CLICAP_USERHOST_IN_NAMES;
|
||||||
extern unsigned int CLICAP_CAP_NOTIFY;
|
extern unsigned int CLICAP_CAP_NOTIFY;
|
||||||
extern unsigned int CLICAP_CHGHOST;
|
extern unsigned int CLICAP_CHGHOST;
|
||||||
extern unsigned int CLICAP_ECHO_MESSAGE;
|
extern unsigned int CLICAP_ECHO_MESSAGE;
|
||||||
|
extern unsigned int CLICAP_BATCH;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: this is kind of ugly, but this allows us to have backwards
|
* XXX: this is kind of ugly, but this allows us to have backwards
|
||||||
|
|
|
@ -21,6 +21,7 @@ endif
|
||||||
libircd_la_SOURCES = \
|
libircd_la_SOURCES = \
|
||||||
authproc.c \
|
authproc.c \
|
||||||
bandbi.c \
|
bandbi.c \
|
||||||
|
batch.c \
|
||||||
cache.c \
|
cache.c \
|
||||||
capability.c \
|
capability.c \
|
||||||
channel.c \
|
channel.c \
|
||||||
|
|
202
ircd/batch.c
Normal file
202
ircd/batch.c
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
/* ircd/batch.c - batch management
|
||||||
|
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice is present in all copies.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdinc.h"
|
||||||
|
#include "batch.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "s_serv.h"
|
||||||
|
#include "send.h"
|
||||||
|
#include "channel.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "s_assert.h"
|
||||||
|
#include "rb_radixtree.h"
|
||||||
|
|
||||||
|
/* Multiple batches may be in progress for each slot. */
|
||||||
|
rb_dlink_list batches[BATCH_LAST];
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
generate_batch_id(char *ptr, size_t len)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
const char batchchars[65] =
|
||||||
|
"\0._0123456789" /* Zero-indexed */
|
||||||
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
len--; /* Room for \0 */
|
||||||
|
for(i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
char r;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
r = batchchars[rand() & 0x7F]; /* random int between 0-64 */
|
||||||
|
|
||||||
|
if(r == '\0' && i > 3)
|
||||||
|
/* We have enough chars */
|
||||||
|
goto end;
|
||||||
|
} while(r == '\0');
|
||||||
|
|
||||||
|
ptr[i] = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
ptr[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Batch *
|
||||||
|
start_batch(batch_type batch, void *data, int parc, ...)
|
||||||
|
{
|
||||||
|
struct Batch *batch_p = rb_malloc(sizeof(struct Batch));
|
||||||
|
|
||||||
|
batch_p->batch = batch;
|
||||||
|
generate_batch_id(batch_p->id, sizeof(batch_p->id));
|
||||||
|
batch_p->data = data;
|
||||||
|
batch_p->parc = parc;
|
||||||
|
if(parc > 0)
|
||||||
|
{
|
||||||
|
/* Get the argument list */
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
batch_p->parv = rb_malloc(sizeof(char *) * parc);
|
||||||
|
|
||||||
|
va_start(args, parc);
|
||||||
|
for(size_t i = 0; i < parc; i++)
|
||||||
|
batch_p->parv[i] = va_arg(args, char *);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Batch-type specific processing */
|
||||||
|
switch(batch)
|
||||||
|
{
|
||||||
|
case BATCH_NETSPLIT:
|
||||||
|
case BATCH_NETJOIN:
|
||||||
|
{
|
||||||
|
/* Build list of channels affected by the batch */
|
||||||
|
rb_dlink_list *clist;
|
||||||
|
rb_radixtree_iteration_state iter;
|
||||||
|
struct Channel *chptr;
|
||||||
|
|
||||||
|
batch_p->pdata = clist = rb_malloc(sizeof(rb_dlink_list));
|
||||||
|
|
||||||
|
/* Look for channels we need to send the batch to */
|
||||||
|
RB_RADIXTREE_FOREACH(chptr, &iter, channel_tree)
|
||||||
|
{
|
||||||
|
rb_dlink_node *ptr;
|
||||||
|
|
||||||
|
if(rb_dlink_list_length(&chptr->locmembers) == 0)
|
||||||
|
/* They're all remotes, so don't send a batch */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Hunt for members in the channel from the target server
|
||||||
|
* If we find one, send the channel a BATCH message */
|
||||||
|
RB_DLINK_FOREACH(ptr, chptr->members.head)
|
||||||
|
{
|
||||||
|
struct Client *client_p = ptr->data;
|
||||||
|
|
||||||
|
if(client_p->from == data)
|
||||||
|
{
|
||||||
|
rb_dlinkAddAlloc(rb_strdup(chptr->chname), clist);
|
||||||
|
sendto_channel_local_with_capability(ALL_MEMBERS, CLICAP_BATCH, NOCAPS,
|
||||||
|
chptr, ":%s BATCH +%s %s %s",
|
||||||
|
me.name,
|
||||||
|
batch == BATCH_NETSPLIT ? "netsplit" : "netjoin",
|
||||||
|
batch_p->parv[0], batch_p->parv[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s_assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_dlinkAdd(batch_p, &batch_p->node, &batches[batch]);
|
||||||
|
|
||||||
|
return batch_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
finish_batch(struct Batch *batch_p)
|
||||||
|
{
|
||||||
|
if(batch_p == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Batch type-specific processing */
|
||||||
|
switch(batch_p->batch)
|
||||||
|
{
|
||||||
|
case BATCH_NETSPLIT:
|
||||||
|
case BATCH_NETJOIN:
|
||||||
|
{
|
||||||
|
rb_dlink_list *clist = batch_p->pdata;
|
||||||
|
rb_dlink_node *ptr, *nptr;
|
||||||
|
|
||||||
|
RB_DLINK_FOREACH_SAFE(ptr, nptr, clist->head)
|
||||||
|
{
|
||||||
|
struct Channel *chptr = find_channel(ptr->data);
|
||||||
|
|
||||||
|
if(chptr != NULL) /* Shouldn't be but just in case... */
|
||||||
|
{
|
||||||
|
sendto_channel_local_with_capability(ALL_MEMBERS, CLICAP_BATCH, NOCAPS,
|
||||||
|
chptr, ":%s BATCH -%s %s %s",
|
||||||
|
me.name,
|
||||||
|
batch_p->batch == BATCH_NETSPLIT ? "netsplit" : "netjoin",
|
||||||
|
batch_p->parv[0], batch_p->parv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_free(ptr->data);
|
||||||
|
rb_dlinkDestroy(ptr, clist);
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_free(clist);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s_assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free all the strings */
|
||||||
|
for(size_t i = 0; i < (batch_p->parc - 1); i++)
|
||||||
|
rb_free(batch_p->parv[i]);
|
||||||
|
|
||||||
|
rb_free(batch_p->parv);
|
||||||
|
|
||||||
|
rb_dlinkDelete(&batch_p->node, &batches[batch_p->batch]);
|
||||||
|
rb_free(batch_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Batch *
|
||||||
|
find_batch(batch_type batch, void *data)
|
||||||
|
{
|
||||||
|
rb_dlink_node *ptr;
|
||||||
|
|
||||||
|
RB_DLINK_FOREACH(ptr, batches[batch].head)
|
||||||
|
{
|
||||||
|
struct Batch *batch_p = ptr->data;
|
||||||
|
|
||||||
|
if(batch_p->data == data)
|
||||||
|
return batch_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -53,6 +53,7 @@
|
||||||
#include "sslproc.h"
|
#include "sslproc.h"
|
||||||
#include "wsproc.h"
|
#include "wsproc.h"
|
||||||
#include "s_assert.h"
|
#include "s_assert.h"
|
||||||
|
#include "batch.h"
|
||||||
|
|
||||||
#define DEBUG_EXITED_CLIENTS
|
#define DEBUG_EXITED_CLIENTS
|
||||||
|
|
||||||
|
@ -1385,14 +1386,25 @@ exit_remote_server(struct Client *client_p, struct Client *source_p, struct Clie
|
||||||
static char comment1[(HOSTLEN*2)+2];
|
static char comment1[(HOSTLEN*2)+2];
|
||||||
static char newcomment[BUFSIZE];
|
static char newcomment[BUFSIZE];
|
||||||
struct Client *target_p;
|
struct Client *target_p;
|
||||||
|
struct Batch *batch_p;
|
||||||
|
|
||||||
if(ConfigServerHide.flatten_links)
|
if(ConfigServerHide.flatten_links)
|
||||||
|
{
|
||||||
strcpy(comment1, "*.net *.split");
|
strcpy(comment1, "*.net *.split");
|
||||||
|
|
||||||
|
/* rb_strdup since they are later freed */
|
||||||
|
batch_p = start_batch(BATCH_NETSPLIT, source_p, 2,
|
||||||
|
rb_strdup("*.net"), rb_strdup("*.split"));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcpy(comment1, source_p->servptr->name);
|
strcpy(comment1, source_p->servptr->name);
|
||||||
strcat(comment1, " ");
|
strcat(comment1, " ");
|
||||||
strcat(comment1, source_p->name);
|
strcat(comment1, source_p->name);
|
||||||
|
|
||||||
|
batch_p = start_batch(BATCH_NETSPLIT, source_p, 2,
|
||||||
|
rb_strdup(source_p->servptr->name),
|
||||||
|
rb_strdup(source_p->name));
|
||||||
}
|
}
|
||||||
if (IsPerson(from))
|
if (IsPerson(from))
|
||||||
snprintf(newcomment, sizeof(newcomment), "by %s: %s",
|
snprintf(newcomment, sizeof(newcomment), "by %s: %s",
|
||||||
|
@ -1430,6 +1442,7 @@ exit_remote_server(struct Client *client_p, struct Client *source_p, struct Clie
|
||||||
#else
|
#else
|
||||||
rb_dlinkAddAlloc(source_p, &dead_list);
|
rb_dlinkAddAlloc(source_p, &dead_list);
|
||||||
#endif
|
#endif
|
||||||
|
finish_batch(batch_p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1463,6 +1476,7 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
|
||||||
static char comment1[(HOSTLEN*2)+2];
|
static char comment1[(HOSTLEN*2)+2];
|
||||||
static char newcomment[BUFSIZE];
|
static char newcomment[BUFSIZE];
|
||||||
unsigned int sendk, recvk;
|
unsigned int sendk, recvk;
|
||||||
|
struct Batch *batch_p;
|
||||||
|
|
||||||
rb_dlinkDelete(&source_p->localClient->tnode, &serv_list);
|
rb_dlinkDelete(&source_p->localClient->tnode, &serv_list);
|
||||||
rb_dlinkFindDestroy(source_p, &global_serv_list);
|
rb_dlinkFindDestroy(source_p, &global_serv_list);
|
||||||
|
@ -1493,12 +1507,18 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
|
||||||
close_connection(source_p);
|
close_connection(source_p);
|
||||||
|
|
||||||
if(ConfigServerHide.flatten_links)
|
if(ConfigServerHide.flatten_links)
|
||||||
|
{
|
||||||
strcpy(comment1, "*.net *.split");
|
strcpy(comment1, "*.net *.split");
|
||||||
|
batch_p = start_batch(BATCH_NETSPLIT, source_p, 2,
|
||||||
|
rb_strdup("*.net"), rb_strdup("*.split"));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcpy(comment1, source_p->servptr->name);
|
strcpy(comment1, source_p->servptr->name);
|
||||||
strcat(comment1, " ");
|
strcat(comment1, " ");
|
||||||
strcat(comment1, source_p->name);
|
strcat(comment1, source_p->name);
|
||||||
|
batch_p = start_batch(BATCH_NETSPLIT, source_p, 2,
|
||||||
|
rb_strdup(source_p->servptr->name), rb_strdup(source_p->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(source_p->serv != NULL)
|
if(source_p->serv != NULL)
|
||||||
|
@ -1520,6 +1540,7 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
|
||||||
|
|
||||||
SetDead(source_p);
|
SetDead(source_p);
|
||||||
rb_dlinkAddAlloc(source_p, &dead_list);
|
rb_dlinkAddAlloc(source_p, &dead_list);
|
||||||
|
finish_batch(batch_p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,7 @@ unsigned int CLICAP_USERHOST_IN_NAMES;
|
||||||
unsigned int CLICAP_CAP_NOTIFY;
|
unsigned int CLICAP_CAP_NOTIFY;
|
||||||
unsigned int CLICAP_CHGHOST;
|
unsigned int CLICAP_CHGHOST;
|
||||||
unsigned int CLICAP_ECHO_MESSAGE;
|
unsigned int CLICAP_ECHO_MESSAGE;
|
||||||
|
unsigned int CLICAP_BATCH;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize our builtin capability table. --nenolod
|
* initialize our builtin capability table. --nenolod
|
||||||
|
@ -147,6 +148,7 @@ init_builtin_capabs(void)
|
||||||
CLICAP_CAP_NOTIFY = capability_put(cli_capindex, "cap-notify", NULL);
|
CLICAP_CAP_NOTIFY = capability_put(cli_capindex, "cap-notify", NULL);
|
||||||
CLICAP_CHGHOST = capability_put(cli_capindex, "chghost", NULL);
|
CLICAP_CHGHOST = capability_put(cli_capindex, "chghost", NULL);
|
||||||
CLICAP_ECHO_MESSAGE = capability_put(cli_capindex, "echo-message", NULL);
|
CLICAP_ECHO_MESSAGE = capability_put(cli_capindex, "echo-message", NULL);
|
||||||
|
CLICAP_BATCH = capability_put(cli_capindex, "batch", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CNCB serv_connect_callback;
|
static CNCB serv_connect_callback;
|
||||||
|
|
|
@ -9,6 +9,7 @@ auto_load_moddir=@moduledir@/autoload
|
||||||
|
|
||||||
auto_load_mod_LTLIBRARIES = \
|
auto_load_mod_LTLIBRARIES = \
|
||||||
cap_account_tag.la \
|
cap_account_tag.la \
|
||||||
|
cap_batch.la \
|
||||||
cap_server_time.la \
|
cap_server_time.la \
|
||||||
chm_nocolour.la \
|
chm_nocolour.la \
|
||||||
chm_noctcp.la \
|
chm_noctcp.la \
|
||||||
|
|
70
modules/cap_batch.c
Normal file
70
modules/cap_batch.c
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* charybdis: an advanced ircd.
|
||||||
|
* cap_batch.c: implement the batch IRCv3.2 capability
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice is present in all copies.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdinc.h"
|
||||||
|
#include "modules.h"
|
||||||
|
#include "hook.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "ircd.h"
|
||||||
|
#include "send.h"
|
||||||
|
#include "s_conf.h"
|
||||||
|
#include "s_user.h"
|
||||||
|
#include "s_serv.h"
|
||||||
|
#include "numeric.h"
|
||||||
|
#include "chmode.h"
|
||||||
|
#include "batch.h"
|
||||||
|
#include "inline/stringops.h"
|
||||||
|
|
||||||
|
static const char cap_batch_desc[] =
|
||||||
|
"Provides the batch client capability";
|
||||||
|
|
||||||
|
static void cap_batch_process(hook_data *);
|
||||||
|
|
||||||
|
mapi_hfn_list_av1 cap_batch_hfnlist[] = {
|
||||||
|
{ "outbound_msgbuf", (hookfn) cap_batch_process },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
cap_batch_process(hook_data *data)
|
||||||
|
{
|
||||||
|
struct MsgBuf *msgbuf = data->arg1;
|
||||||
|
struct Client *client_p = data->client;
|
||||||
|
struct Batch *batch_p;
|
||||||
|
|
||||||
|
if(rb_strcasecmp(msgbuf->cmd, "quit") == 0)
|
||||||
|
{
|
||||||
|
if(!IsClient(client_p) || MyConnect(client_p))
|
||||||
|
/* Remote users only please */
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Now find our batch... */
|
||||||
|
if((batch_p = find_batch(BATCH_NETSPLIT, client_p->from)) == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Boom */
|
||||||
|
msgbuf_append_tag(msgbuf, "batch", batch_p->id, CLICAP_BATCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_MODULE_AV2(cap_batch, NULL, NULL, NULL, NULL, cap_batch_hfnlist, NULL, NULL, cap_batch_desc);
|
Loading…
Reference in a new issue