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 8699 by michael, Sun Dec 2 16:17:51 2018 UTC vs.
Revision 9802 by michael, Tue Dec 8 20:50:02 2020 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-2018 ircd-hybrid development team
5 > *  Copyright (c) 2006-2020 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 38 | Line 38
38  
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 */
41 >  CAPFL_STICKY = 1 << 0   /**< Cap may not be cleared once set */
42   };
43  
44   typedef int (*bqcmp)(const void *, const void *);
# Line 151 | Line 148 | send_caplist(struct Client *source_p,
148               const unsigned int *const set,
149               const unsigned int *const rem, const char *subcmd)
150   {
151 <  char capbuf[IRCD_BUFSIZE] = "", pfx[16];
151 >  char capbuf[IRCD_BUFSIZE] = "", pfx[4];
152    char cmdbuf[IRCD_BUFSIZE] = "";
153    unsigned int i, loc, len, pfx_len, clen;
154  
# Line 167 | Line 164 | send_caplist(struct Client *source_p,
164       * This is a little bit subtle, but just involves applying de
165       * Morgan's laws to the obvious check: We must display the
166       * capability if (and only if) it is set in \a rem or \a set, or
167 <     * if both are null and the capability is hidden.
167 >     * if both are null.
168       */
169      if (!(rem && (*rem & cap->cap)) &&
170 <        !(set && (*set & cap->cap)) &&
174 <         (rem || set || (cap->flags & CAPFL_HIDDEN)))
170 >        !(set && (*set & cap->cap)) && (rem || set))
171        continue;
172  
173      /* Build the prefix (space separator and any modifiers needed). */
# Line 181 | Line 177 | send_caplist(struct Client *source_p,
177        pfx[pfx_len++] = ' ';
178      if (rem && (*rem & cap->cap))
179        pfx[pfx_len++] = '-';
184    else
185    {
186      if (cap->flags & CAPFL_PROTO)
187        pfx[pfx_len++] = '~';
188      if (cap->flags & CAPFL_STICKY)
189        pfx[pfx_len++] = '=';
190    }
180  
181      pfx[pfx_len] = '\0';
182  
# Line 208 | Line 197 | send_caplist(struct Client *source_p,
197   }
198  
199   static void
200 < cap_ls(struct Client *source_p, const char *caplist)
200 > cap_ls(struct Client *source_p, const char *arg)
201   {
202    if (IsUnknown(source_p))  /* Registration hasn't completed; suspend it... */
203      source_p->connection->registration |= REG_NEED_CAP;
204  
205 +  if (arg && atoi(arg) >= 302)
206 +    AddFlag(source_p, FLAGS_CAP302);
207 +
208    send_caplist(source_p, NULL, NULL, "LS");  /* Send list of capabilities */
209   }
210  
211   static void
212 < cap_req(struct Client *source_p, const char *caplist)
212 > cap_req(struct Client *source_p, const char *arg)
213   {
222  const char *cl = caplist;
223  struct capabilities *cap = NULL;
214    unsigned int set = 0, rem = 0;
215 <  unsigned int cs = source_p->connection->cap_client; /* capability set */
226 <  unsigned int as = source_p->connection->cap_active; /* active set */
215 >  unsigned int cs = source_p->connection->cap;  /* Enabled capabilities */
216    int neg = 0;
217  
218    if (IsUnknown(source_p))  /* Registration hasn't completed; suspend it... */
219      source_p->connection->registration |= REG_NEED_CAP;
220  
221 <  while (cl) {  /* Walk through the capabilities list... */
222 <    if (!(cap = find_cap(&cl, &neg))  /* Look up capability... */
223 <        || (!neg && (cap->flags & CAPFL_PROHIBIT))  /* Is it prohibited? */
224 <        || (neg && (cap->flags & CAPFL_STICKY))) {  /* Is it sticky? */
221 >  /* Walk through the capabilities list... */
222 >  for (const char *cl = arg; cl; )
223 >  {
224 >    /* Look up capability... */
225 >    const struct capabilities *cap = find_cap(&cl, &neg);
226 >    if (cap == NULL ||
227 >        (neg && (cap->flags & CAPFL_STICKY)))
228 >    {
229        sendto_one(source_p, ":%s CAP %s NAK :%s", me.name,
230 <                 source_p->name[0] ? source_p->name : "*", caplist);
230 >                 source_p->name[0] ? source_p->name : "*", arg);
231        return;  /* Can't complete requested op... */
232      }
233  
# Line 244 | Line 237 | cap_req(struct Client *source_p, const c
237        rem |=  cap->cap;
238        set &= ~cap->cap;
239        cs  &= ~cap->cap;
247
248      if (!(cap->flags & CAPFL_PROTO))
249        as &= ~cap->cap;
240      }
241      else
242      {
243        rem &= ~cap->cap;
244        set |=  cap->cap;
245        cs  |=  cap->cap;
256
257      if (!(cap->flags & CAPFL_PROTO))
258        as |= cap->cap;
246      }
247    }
248  
249    /* Notify client of accepted changes and copy over results. */
250    send_caplist(source_p, &set, &rem, "ACK");
251  
252 <  source_p->connection->cap_client = cs;
266 <  source_p->connection->cap_active = as;
252 >  source_p->connection->cap = cs;
253   }
254  
255   static void
256 < cap_ack(struct Client *source_p, const char *caplist)
271 < {
272 <  const char *cl = caplist;
273 <  struct capabilities *cap = NULL;
274 <  int neg = 0;
275 <
276 <  /*
277 <   * Coming from the client, this generally indicates that the client
278 <   * is using a new backwards-incompatible protocol feature. As such,
279 <   * it does not require further response from the server.
280 <   */
281 <  while (cl)
282 <  {
283 <    /* Walk through the capabilities list... */
284 <    if (!(cap = find_cap(&cl, &neg)) ||  /* Look up capability... */
285 <        (neg ? (source_p->connection->cap_client & cap->cap) :
286 <              !(source_p->connection->cap_client & cap->cap)))  /* uh... */
287 <      continue;
288 <
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 <  }
305 < }
306 <
307 < static void
308 < cap_clear(struct Client *source_p, const char *caplist)
309 < {
310 <  unsigned int cleared = 0;
311 <
312 <  for (unsigned int ii = 0; ii < CAPAB_LIST_LEN; ++ii)
313 <  {
314 <    const struct capabilities *cap = &capab_list[ii];
315 <
316 <    /* Only clear active non-sticky capabilities. */
317 <    if (!(source_p->connection->cap_client & cap->cap) || (cap->flags & CAPFL_STICKY))
318 <      continue;
319 <
320 <    cleared |= cap->cap;
321 <    source_p->connection->cap_client &= ~cap->cap;
322 <
323 <    if (!(cap->flags & CAPFL_PROTO))
324 <      source_p->connection->cap_active &= ~cap->cap;
325 <  }
326 <
327 <  send_caplist(source_p, NULL, &cleared, "ACK");
328 < }
329 <
330 < static void
331 < cap_end(struct Client *source_p, const char *caplist)
256 > cap_end(struct Client *source_p, const char *arg)
257   {
258    if (!IsUnknown(source_p))  /* Registration has completed... */
259      return;  /* So just ignore the message... */
# Line 342 | Line 267 | cap_end(struct Client *source_p, const c
267   }
268  
269   static void
270 < cap_list(struct Client *source_p, const char *caplist)
270 > cap_list(struct Client *source_p, const char *arg)
271   {
272    /* Send the list of the client's capabilities */
273 <  send_caplist(source_p, &source_p->connection->cap_client, NULL, "LIST");
273 >  send_caplist(source_p, &source_p->connection->cap, NULL, "LIST");
274   }
275  
276   static struct subcmd
# Line 353 | Line 278 | static struct subcmd
278    const char *cmd;
279    void (*proc)(struct Client *, const char *);
280   } cmdlist[] = {
281 <  { "ACK",   cap_ack   },
282 <  { "CLEAR", cap_clear },
283 <  { "END",   cap_end   },
284 <  { "LIST",  cap_list  },
360 <  { "LS",    cap_ls    },
361 <  { "NAK",   NULL      },
362 <  { "REQ",   cap_req   }
281 >  { "END",  cap_end   },
282 >  { "LIST", cap_list  },
283 >  { "LS",   cap_ls    },
284 >  { "REQ",  cap_req   }
285   };
286  
287   static int
# Line 380 | Line 302 | subcmd_search(const char *cmd, const str
302   *      - parv[1] = CAP subcommand
303   *      - parv[2] = space-separated list of capabilities
304   */
305 < static int
305 > static void
306   m_cap(struct Client *source_p, int parc, char *parv[])
307   {
308 <  const char *subcmd = NULL, *caplist = NULL;
308 >  const char *subcmd = parv[1], *caplist = parv[2];
309    struct subcmd *cmd = NULL;
310  
389  if (EmptyString(parv[1]))  /* A subcommand is required */
390    return 0;
391
392  subcmd = parv[1];
393
394  if (parc > 2)  /* A capability list was provided */
395    caplist = parv[2];
396
311    /* Find the subcommand handler */
312    if (!(cmd = bsearch(subcmd, cmdlist,
313                        sizeof(cmdlist) / sizeof(struct subcmd),
314                        sizeof(struct subcmd), (bqcmp)subcmd_search)))
315    {
316      sendto_one_numeric(source_p, &me, ERR_INVALIDCAPCMD, subcmd);
317 <    return 0;
317 >    return;
318    }
319  
320    /* Then execute it... */
321    if (cmd->proc)
322      (cmd->proc)(source_p, caplist);
409  return 0;
323   }
324  
325   static struct Message cap_msgtab =
326   {
327    .cmd = "CAP",
328 <  .args_min = 2,
329 <  .args_max = MAXPARA,
330 <  .handlers[UNREGISTERED_HANDLER] = m_cap,
331 <  .handlers[CLIENT_HANDLER] = m_cap,
332 <  .handlers[SERVER_HANDLER] = m_ignore,
420 <  .handlers[ENCAP_HANDLER] = m_ignore,
421 <  .handlers[OPER_HANDLER] = m_cap
328 >  .handlers[UNREGISTERED_HANDLER] = { .handler = m_cap, .args_min = 2 },
329 >  .handlers[CLIENT_HANDLER] = { .handler = m_cap, .args_min = 2 },
330 >  .handlers[SERVER_HANDLER] = { .handler = m_ignore },
331 >  .handlers[ENCAP_HANDLER] = { .handler = m_ignore },
332 >  .handlers[OPER_HANDLER] = { .handler = m_cap, .args_min = 2 }
333   };
334  
335   static void

Diff Legend

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