ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_cap.c
(Generate patch)

Comparing ircd-hybrid/trunk/modules/m_cap.c (file contents):
Revision 5014 by michael, Tue Dec 9 17:51:47 2014 UTC vs.
Revision 8699 by michael, Sun Dec 2 16:17:51 2018 UTC

# Line 2 | Line 2
2   *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4   *  Copyright (c) 2004 Kevin L. Mitchell <klmitch@mit.edu>
5 < *  Copyright (c) 2006-2014 ircd-hybrid development team
5 > *  Copyright (c) 2006-2018 ircd-hybrid development team
6   *
7   *  This program is free software; you can redistribute it and/or modify
8   *  it under the terms of the GNU General Public License as published by
# Line 36 | Line 36
36   #include "irc_string.h"
37  
38  
39 < #define CAPFL_HIDDEN    0x0001  /**< Do not advertize this capability */
40 < #define CAPFL_PROHIBIT  0x0002  /**< Client may not set this capability */
41 < #define CAPFL_PROTO     0x0004  /**< Cap must be acknowledged by client */
42 < #define CAPFL_STICKY    0x0008  /**< Cap may not be cleared once set */
39 > enum
40 > {
41 >  CAPFL_HIDDEN    = 1 << 0,  /**< Do not advertize this capability */
42 >  CAPFL_PROHIBIT  = 1 << 1,  /**< Client may not set this capability */
43 >  CAPFL_PROTO     = 1 << 2,  /**< Cap must be acknowledged by client */
44 >  CAPFL_STICKY    = 1 << 3   /**< Cap may not be cleared once set */
45 > };
46  
47   typedef int (*bqcmp)(const void *, const void *);
48  
# Line 55 | Line 58 | static struct capabilities
58    _CAP(CAP_UHNAMES, 0, "userhost-in-names"),
59    _CAP(CAP_MULTI_PREFIX, 0, "multi-prefix"),
60    _CAP(CAP_AWAY_NOTIFY, 0, "away-notify"),
61 <  _CAP(CAP_EXTENDED_JOIN, 0, "extended-join")
61 >  _CAP(CAP_EXTENDED_JOIN, 0, "extended-join"),
62 >  _CAP(CAP_ACCOUNT_NOTIFY, 0, "account-notify"),
63 >  _CAP(CAP_INVITE_NOTIFY, 0, "invite-notify"),
64 >  _CAP(CAP_CHGHOST, 0, "chghost")
65   #undef _CAP
66   };
67  
# Line 140 | Line 146 | find_cap(const char **caplist_p, int *ne
146   * @param[in] rem Capabalities to show as removed (with no other modifier).
147   * @param[in] subcmd Name of capability subcommand.
148   */
149 < static int
150 < send_caplist(struct Client *source_p, unsigned int set,
151 <             unsigned int rem, const char *subcmd)
149 > static void
150 > send_caplist(struct Client *source_p,
151 >             const unsigned int *const set,
152 >             const unsigned int *const rem, const char *subcmd)
153   {
154    char capbuf[IRCD_BUFSIZE] = "", pfx[16];
155    char cmdbuf[IRCD_BUFSIZE] = "";
156 <  unsigned int i, loc, len, flags, pfx_len, clen;
156 >  unsigned int i, loc, len, pfx_len, clen;
157  
158    /* Set up the buffer for the final LS message... */
159    clen = snprintf(cmdbuf, sizeof(capbuf), ":%s CAP %s %s ", me.name,
# Line 154 | Line 161 | send_caplist(struct Client *source_p, un
161  
162    for (i = 0, loc = 0; i < CAPAB_LIST_LEN; ++i)
163    {
164 <    flags = capab_list[i].flags;
164 >    const struct capabilities *cap = &capab_list[i];
165  
166      /*
167       * This is a little bit subtle, but just involves applying de
# Line 162 | Line 169 | send_caplist(struct Client *source_p, un
169       * capability if (and only if) it is set in \a rem or \a set, or
170       * if both are null and the capability is hidden.
171       */
172 <    if (!(rem && (rem & capab_list[i].cap)) &&
173 <        !(set && (set & capab_list[i].cap)) &&
174 <         (rem || set || (flags & CAPFL_HIDDEN)))
172 >    if (!(rem && (*rem & cap->cap)) &&
173 >        !(set && (*set & cap->cap)) &&
174 >         (rem || set || (cap->flags & CAPFL_HIDDEN)))
175        continue;
176  
177      /* Build the prefix (space separator and any modifiers needed). */
# Line 172 | Line 179 | send_caplist(struct Client *source_p, un
179  
180      if (loc)
181        pfx[pfx_len++] = ' ';
182 <    if (rem && (rem & capab_list[i].cap))
182 >    if (rem && (*rem & cap->cap))
183        pfx[pfx_len++] = '-';
184      else
185      {
186 <      if (flags & CAPFL_PROTO)
186 >      if (cap->flags & CAPFL_PROTO)
187          pfx[pfx_len++] = '~';
188 <      if (flags & CAPFL_STICKY)
188 >      if (cap->flags & CAPFL_STICKY)
189          pfx[pfx_len++] = '=';
190      }
191  
192      pfx[pfx_len] = '\0';
193  
194 <    len = capab_list[i].namelen + pfx_len;  /* How much we'd add... */
194 >    len = cap->namelen + pfx_len;  /* How much we'd add... */
195  
196      if (sizeof(capbuf) < (clen + loc + len + 15))
197      {
# Line 194 | Line 201 | send_caplist(struct Client *source_p, un
201      }
202  
203      loc += snprintf(capbuf + loc, sizeof(capbuf) - loc,
204 <                    "%s%s", pfx, capab_list[i].name);
204 >                    "%s%s", pfx, cap->name);
205    }
206  
207    sendto_one(source_p, "%s:%s", cmdbuf, capbuf);
201
202  return 0;  /* Convenience return */
208   }
209  
210 < static int
210 > static void
211   cap_ls(struct Client *source_p, const char *caplist)
212   {
213    if (IsUnknown(source_p))  /* Registration hasn't completed; suspend it... */
214      source_p->connection->registration |= REG_NEED_CAP;
215  
216 <  return send_caplist(source_p, 0, 0, "LS");  /* Send list of capabilities */
216 >  send_caplist(source_p, NULL, NULL, "LS");  /* Send list of capabilities */
217   }
218  
219 < static int
219 > static void
220   cap_req(struct Client *source_p, const char *caplist)
221   {
222    const char *cl = caplist;
# Line 230 | Line 235 | cap_req(struct Client *source_p, const c
235          || (neg && (cap->flags & CAPFL_STICKY))) {  /* Is it sticky? */
236        sendto_one(source_p, ":%s CAP %s NAK :%s", me.name,
237                   source_p->name[0] ? source_p->name : "*", caplist);
238 <      return 0;  /* Can't complete requested op... */
238 >      return;  /* Can't complete requested op... */
239      }
240  
241      if (neg)
# Line 255 | Line 260 | cap_req(struct Client *source_p, const c
260    }
261  
262    /* Notify client of accepted changes and copy over results. */
263 <  send_caplist(source_p, set, rem, "ACK");
263 >  send_caplist(source_p, &set, &rem, "ACK");
264  
265    source_p->connection->cap_client = cs;
266    source_p->connection->cap_active = as;
262
263  return 0;
267   }
268  
269 < static int
269 > static void
270   cap_ack(struct Client *source_p, const char *caplist)
271   {
272    const char *cl = caplist;
# Line 279 | Line 282 | cap_ack(struct Client *source_p, const c
282    {
283      /* Walk through the capabilities list... */
284      if (!(cap = find_cap(&cl, &neg)) ||  /* Look up capability... */
285 <        (neg ? (source_p->connection->cap_active & cap->cap) :
286 <              !(source_p->connection->cap_active & cap->cap)))  /* uh... */
285 >        (neg ? (source_p->connection->cap_client & cap->cap) :
286 >              !(source_p->connection->cap_client & cap->cap)))  /* uh... */
287        continue;
288  
289 <    if (neg)  /* Set or clear the active capability... */
289 >    /* Set or clear the active capability... */
290 >    if (neg)
291 >    {
292 >      if (cap->flags & CAPFL_STICKY)
293 >        continue;  /* but don't clear sticky capabilities */
294 >
295        source_p->connection->cap_active &= ~cap->cap;
296 +    }
297      else
298 +    {
299 +      if (cap->flags & CAPFL_PROHIBIT)
300 +        continue;  /* and don't set prohibited ones */
301 +
302        source_p->connection->cap_active |=  cap->cap;
303 +    }
304    }
291
292  return 0;
305   }
306  
307 < static int
307 > static void
308   cap_clear(struct Client *source_p, const char *caplist)
309   {
298  struct capabilities *cap = NULL;
310    unsigned int cleared = 0;
311  
312    for (unsigned int ii = 0; ii < CAPAB_LIST_LEN; ++ii)
313    {
314 <    cap = &capab_list[ii];
314 >    const struct capabilities *cap = &capab_list[ii];
315  
316      /* Only clear active non-sticky capabilities. */
317 <    if (!(source_p->connection->cap_active & cap->cap) || (cap->flags & CAPFL_STICKY))
317 >    if (!(source_p->connection->cap_client & cap->cap) || (cap->flags & CAPFL_STICKY))
318        continue;
319  
320      cleared |= cap->cap;
# Line 313 | Line 324 | cap_clear(struct Client *source_p, const
324        source_p->connection->cap_active &= ~cap->cap;
325    }
326  
327 <  return send_caplist(source_p, 0, cleared, "ACK");
327 >  send_caplist(source_p, NULL, &cleared, "ACK");
328   }
329  
330 < static int
330 > static void
331   cap_end(struct Client *source_p, const char *caplist)
332   {
333    if (!IsUnknown(source_p))  /* Registration has completed... */
334 <    return 0;  /* So just ignore the message... */
334 >    return;  /* So just ignore the message... */
335  
336    /* Capability negotiation is now done... */
337    source_p->connection->registration &= ~REG_NEED_CAP;
338  
339    /* If client is now done... */
340 <  if (!source_p->connection->registration)
330 <  {
340 >  if (source_p->connection->registration == 0)
341      register_local_user(source_p);
332    return 0;
333  }
334
335  return 0;  /* Can't do registration yet... */
342   }
343  
344 < static int
344 > static void
345   cap_list(struct Client *source_p, const char *caplist)
346   {
347    /* Send the list of the client's capabilities */
348 <  return send_caplist(source_p, source_p->connection->cap_client, 0, "LIST");
348 >  send_caplist(source_p, &source_p->connection->cap_client, NULL, "LIST");
349   }
350  
351   static struct subcmd
352   {
353    const char *cmd;
354 <  int (*proc)(struct Client *, const char *);
354 >  void (*proc)(struct Client *, const char *);
355   } cmdlist[] = {
356    { "ACK",   cap_ack   },
357    { "CLEAR", cap_clear },
# Line 405 | Line 411 | m_cap(struct Client *source_p, int parc,
411  
412   static struct Message cap_msgtab =
413   {
414 <  "CAP", NULL, 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
415 <  { m_cap, m_cap, m_ignore, m_ignore, m_cap, m_ignore }
414 >  .cmd = "CAP",
415 >  .args_min = 2,
416 >  .args_max = MAXPARA,
417 >  .handlers[UNREGISTERED_HANDLER] = m_cap,
418 >  .handlers[CLIENT_HANDLER] = m_cap,
419 >  .handlers[SERVER_HANDLER] = m_ignore,
420 >  .handlers[ENCAP_HANDLER] = m_ignore,
421 >  .handlers[OPER_HANDLER] = m_cap
422   };
423  
424   static void
# Line 425 | Line 437 | module_exit(void)
437  
438   struct module module_entry =
439   {
428  .node    = { NULL, NULL, NULL },
429  .name    = NULL,
440    .version = "$Revision$",
431  .handle  = NULL,
441    .modinit = module_init,
442    .modexit = module_exit,
434  .flags   = 0
443   };

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)