Implement a per-connection-class default usermode option.
[ircu2.10.12-pk.git] / ircd / ircd_parser.y
index 2471248d0200458ce716b98235c1946a869b8cb4..4aa34881009607999cce85f973ea2663bb0d31b2 100644 (file)
@@ -63,7 +63,8 @@
   extern struct DenyConf*   denyConfList;
   extern struct CRuleConf*  cruleConfList;
   extern struct ServerConf* serverConfList;
-  extern struct qline     *GlobalQuarantineList;
+  extern struct s_map*      GlobalServiceMapList;
+  extern struct qline*      GlobalQuarantineList;
  
 
   int yylex(void);
   struct DenyConf *dconf;
   struct ServerConf *sconf;
   struct qline *qconf = NULL;
+  struct s_map *smap;
 
 static void parse_error(char *pattern,...) {
-       va_list vl;
-       struct VarData vd;
-       va_start(vl,pattern);
-       vd.vd_format = pattern;
-       vd.vd_args = vl;
-       sendto_opmask_butone(0, SNO_OLDSNO, "Config: %v", &vd);
-       va_end(vl);
+  static char error_buffer[1024];
+  va_list vl;
+  va_start(vl,pattern);
+  ircd_vsnprintf(NULL, error_buffer, sizeof(error_buffer), pattern, vl);
+  va_end(vl);
+  yyerror(error_buffer);
 }
+
 %}
 
 %token <text> QSTRING
@@ -150,6 +152,9 @@ static void parse_error(char *pattern,...) {
 %token IP
 %token FEATURES
 %token QUARANTINE
+%token PSEUDO
+%token PREPEND
+%token USERMODE
 /* and now a lot of priviledges... */
 %token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN
 %token TPRIV_KILL TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE
@@ -175,7 +180,8 @@ static void parse_error(char *pattern,...) {
 blocks: blocks block | block;
 block: adminblock | generalblock | classblock | connectblock |
        serverblock | operblock | portblock | jupeblock | clientblock |
-       killblock | cruleblock | motdblock | featuresblock | quarantineblock;
+       killblock | cruleblock | motdblock | featuresblock | quarantineblock |
+       pseudoblock | error;
 
 /* The timespec, sizespec and expr was ripped straight from
  * ircd-hybrid-7. */
@@ -250,7 +256,7 @@ expr: NUMBER
 
 jupeblock: JUPE '{' jupeitems '}' ';' ;
 jupeitems: jupeitem jupeitems | jupeitem;
-jupeitem: jupenick;
+jupeitem: jupenick | error;
 jupenick: NICK '=' QSTRING
 {
   addNickJupes(yylval.text);
@@ -258,7 +264,7 @@ jupenick: NICK '=' QSTRING
 
 generalblock: GENERAL '{' generalitems '}' ';' ;
 generalitems: generalitem generalitems | generalitem;
-generalitem: generalnumeric | generalname | generalvhost | generaldesc;
+generalitem: generalnumeric | generalname | generalvhost | generaldesc | error;
 generalnumeric: NUMERIC '=' NUMBER ';'
 {
   if (localConf.numeric == 0)
@@ -301,7 +307,7 @@ adminblock: ADMIN '{' adminitems '}'
     DupString(localConf.contact, "");
 } ';';
 adminitems: adminitems adminitem | adminitem;
-adminitem: adminlocation | admincontact;
+adminitem: adminlocation | admincontact | error;
 adminlocation: LOCATION '=' QSTRING ';'
 {
  if (localConf.location1 == NULL)
@@ -323,19 +329,22 @@ classblock: CLASS {
   tconn = 0;
   maxlinks = 0;
   sendq = 0;
+  pass = NULL;
 } '{' classitems '}'
 {
   if (name != NULL)
   {
    add_class(name, tping, tconn, maxlinks, sendq);
+   find_class(name)->default_umode = pass;
   }
   else {
    parse_error("Missing name in class block");
   }
+  pass = NULL;
 } ';';
 classitems: classitem classitems | classitem;
 classitem: classname | classpingfreq | classconnfreq | classmaxlinks |
-           classsendq;
+           classsendq | classusermode | error;
 classname: NAME '=' QSTRING ';'
 {
   MyFree(name);
@@ -357,6 +366,12 @@ classsendq: SENDQ '=' sizespec ';'
 {
   sendq = yylval.num;
 };
+classusermode: USERMODE '=' QSTRING ';'
+{
+  if (pass)
+    MyFree(pass);
+  DupString(pass, yylval.text);
+};
 
 connectblock: CONNECT
 {
@@ -393,7 +408,7 @@ connectblock: CONNECT
 }';';
 connectitems: connectitem connectitems | connectitem;
 connectitem: connectname | connectpass | connectclass | connecthost
-              | connectport;
+              | connectport | error;
 connectname: NAME '=' QSTRING ';'
 {
  MyFree(name);
@@ -440,7 +455,7 @@ serverblock: SERVER
 } ';';
 serveritems: serveritem serveritems | serveritem;
 serveritem: servername | servermask | serverhub | serverleaf |
-             serveruworld;
+             serveruworld | error;
 servername: NAME '=' QSTRING
 {
  MyFree(aconf->name);
@@ -506,7 +521,7 @@ operblock: OPER
   }
 };
 operitems: operitem | operitems operitem;
-operitem: opername | operpass | operlocal | operhost | operclass | operpriv;
+operitem: opername | operpass | operlocal | operhost | operclass | operpriv | error;
 
 opername: NAME '=' QSTRING ';'
 {
@@ -618,7 +633,7 @@ portblock: PORT {
   }
 };
 portitems: portitem portitems | portitem;
-portitem: portnumber | portvhost | portmask | portserver | porthidden;
+portitem: portnumber | portvhost | portmask | portserver | porthidden | error;
 portnumber: PORT '=' NUMBER ';'
 {
   port = yylval.num;
@@ -681,7 +696,7 @@ clientblock: CLIENT
   }
 } ';';
 clientitems: clientitem clientitems | clientitem;
-clientitem: clienthost | clientclass | clientpass | clientip;
+clientitem: clienthost | clientclass | clientpass | clientip | error;
 clientip: IP '=' QSTRING ';'
 {
   MyFree(aconf->host);
@@ -729,7 +744,7 @@ killblock: KILL
   }
 } ';';
 killitems: killitem killitems | killitem;
-killitem: killuhost | killreal | killreasonfile | killreason;
+killitem: killuhost | killreal | killreasonfile | killreason | error;
 killuhost: HOST '=' QSTRING ';'
 {
   char *u, *h;
@@ -818,7 +833,7 @@ cruleblock: CRULE
 } ';';
 
 cruleitems: cruleitem cruleitems | cruleitem;
-cruleitem: cruleserver | crulerule | cruleall;
+cruleitem: cruleserver | crulerule | cruleall | error;
 
 cruleserver: SERVER '=' QSTRING ';'
 {
@@ -853,7 +868,7 @@ motdblock: MOTD {
 } ';';
 
 motditems: motditem motditems | motditem;
-motditem: motdhost | motdfile;
+motditem: motdhost | motdfile | error;
 motdhost: HOST '=' QSTRING ';'
 {
   DupString(host, yylval.text);
@@ -921,3 +936,60 @@ quarantineitems: CHANNEL NAME '=' QSTRING ';'
 {
   DupString(qconf->reason, yylval.text);
 };
+
+pseudoblock: PSEUDO QSTRING '{'
+{
+  smap = MyCalloc(1, sizeof(struct s_map));
+  DupString(smap->command, $2);
+}
+pseudoitems '}' ';'
+{
+  if (!smap->name || !smap->services)
+  {
+    log_write(LS_CONFIG, L_ERROR, 0, "pseudo commands need a service name and list of target nicks.");
+    return 0;
+  }
+  if (register_mapping(smap))
+  {
+    smap->next = GlobalServiceMapList;
+    GlobalServiceMapList = smap;
+  }
+  else
+  {
+    struct nick_host *nh, *next;
+    for (nh = smap->services; nh; nh = next)
+    {
+      next = nh->next;
+      MyFree(nh);
+    }
+    MyFree(smap->name);
+    MyFree(smap->command);
+    MyFree(smap->prepend);
+    MyFree(smap);
+  }
+  smap = NULL;
+};
+
+pseudoitems: pseudoitem pseudoitems | pseudoitem;
+pseudoitem: pseudoname | pseudoprepend | pseudonick | error;
+pseudoname: NAME '=' QSTRING ';'
+{
+  DupString(smap->name, yylval.text);
+};
+pseudoprepend: PREPEND '=' QSTRING ';'
+{
+  DupString(smap->prepend, yylval.text);
+};
+pseudonick: NICK '=' QSTRING ';'
+{
+  char *sep = strchr(yylval.text, '@');
+
+  if (sep != NULL) {
+    size_t slen = strlen(yylval.text);
+    struct nick_host *nh = MyMalloc(sizeof(*nh) + slen);
+    memcpy(nh->nick, yylval.text, slen + 1);
+    nh->nicklen = sep - yylval.text;
+    nh->next = smap->services;
+    smap->services = nh;
+  }
+};