blines patch for ircu
=====================

This is some random b:lines patch for ircu2.10.11.07 I believe. I
garbled it up somewhere on the net and put it up here in case anyone
needs it.
I am NEITHER author NOR do I provide support for this in any way.
If you are the author, please contact me for removal or so I can add the
info.

I do not know how well this patch works or whether it is stable or
secure to use.
The b:lines allow you to set alias commands to ease the use of services
for your users, i.e. they can type /authserv instead of /msg authserv in
clients that forward unknown commands to the server.

Have fun.


Nei


diff -urp cvs/include/ircd_features.h blines/include/ircd_features.h
--- cvs/include/ircd_features.h	2004-09-02 14:35:06.000000000 +0200
+++ blines/include/ircd_features.h	2004-12-27 21:12:31.000000000 +0100
@@ -148,6 +148,7 @@ enum Feature {
   FEAT_HIS_MAP,
   FEAT_HIS_LINKS,
   FEAT_HIS_TRACE,
+  FEAT_HIS_STATS_b,
   FEAT_HIS_STATS_l,
   FEAT_HIS_STATS_c,
   FEAT_HIS_STATS_g,
diff -urp cvs/include/numeric.h blines/include/numeric.h
--- cvs/include/numeric.h	2004-09-02 14:35:06.000000000 +0200
+++ blines/include/numeric.h	2004-12-27 21:12:31.000000000 +0100
@@ -112,6 +112,7 @@ extern const struct Numeric* get_error_n
 	RPL_STATSGLINE	     227	   Dalnet 
 	RPL_STATSVLINE	     227	   unreal */
 #define RPL_STATSQLINE       228        /* Undernet extension */
+#define RPL_STATSBLINE	     229	/* PGPN extension! -akl */
 
 #define RPL_SERVICEINFO      231	/* unused */
 #define RPL_ENDOFSERVICES    232	/* unused */
diff -urp cvs/include/s_conf.h blines/include/s_conf.h
--- cvs/include/s_conf.h	2004-09-02 14:35:06.000000000 +0200
+++ blines/include/s_conf.h	2004-12-27 21:12:31.000000000 +0100
@@ -148,6 +148,13 @@ enum AuthorizationCheckResult {
   ACR_BAD_SOCKET
 };
 
+struct svcline {
+  struct svcline *next;
+  char *cmd;
+  char *target;
+  char *prepend;
+};
+
 struct qline {
   struct qline *next;
   char *chname;
@@ -189,6 +196,7 @@ extern struct tm        motd_tm;
 extern struct MotdItem* motd;
 extern struct MotdItem* rmotd;
 extern struct TRecord*  tdata;
+extern struct svcline*  GlobalServicesList;
 extern struct qline*	GlobalQuarantineList;
 extern struct sline*	GlobalSList;
 
@@ -223,6 +231,8 @@ extern int find_kill(struct Client *cptr
 extern int find_restrict(struct Client *cptr);
 extern struct MotdItem* read_motd(const char* motdfile);
 extern char* find_quarantine(const char* chname);
+extern void conf_add_svcline(const char * const* fields, int count);
+extern void clear_svclines(void);
 extern void conf_add_sline(const char* const* fields, int count);
 extern void clear_slines(void);
 extern int str2prefix(char *s, struct prefix *p);
diff -urp cvs/include/s_user.h blines/include/s_user.h
--- cvs/include/s_user.h	2004-09-02 14:35:06.000000000 +0200
+++ blines/include/s_user.h	2004-12-27 21:12:31.000000000 +0100
@@ -106,6 +106,8 @@ extern unsigned int umode_make_snomask(u
                                        int what);
 extern int send_supported(struct Client *cptr);
 
+extern int lsc(struct Client *cptr, const char *target, const char *prepend, const char *servicename, int parc, char* parv[]);
+
 #define NAMES_ALL 1 /* List all users in channel */
 #define NAMES_VIS 2 /* List only visible users in non-secret channels */
 #define NAMES_EON 4 /* Add an 'End Of Names' reply to the end */
diff -urp cvs/ircd/ircd_features.c blines/ircd/ircd_features.c
--- cvs/ircd/ircd_features.c	2004-09-02 14:35:07.000000000 +0200
+++ blines/ircd/ircd_features.c	2004-12-27 21:12:32.000000000 +0100
@@ -355,6 +355,7 @@ static struct FeatureDesc {
   F_B(HIS_MAP, 0, 1, 0),
   F_B(HIS_LINKS, 0, 1, 0),
   F_B(HIS_TRACE, 0, 1, 0),
+  F_B(HIS_STATS_b, 0, 1, 0),
   F_B(HIS_STATS_l, 0, 1, 0),
   F_B(HIS_STATS_c, 0, 1, 0),
   F_B(HIS_STATS_g, 0, 1, 0),
diff -urp cvs/ircd/parse.c blines/ircd/parse.c
--- cvs/ircd/parse.c	2004-09-02 14:35:07.000000000 +0200
+++ blines/ircd/parse.c	2004-12-27 21:12:31.000000000 +0100
@@ -825,6 +825,7 @@ static struct Message *msg_tree_parse_cl
   unsigned char q = (0xdf & (unsigned char)*cmd) - 'A';
   if (q > 25 || !(mtree = root->pointers[q]))
     return NULL;
+
   for (;;)
   {
     q = 0xdf & (unsigned char)*++cmd;
@@ -850,6 +851,7 @@ int parse_client(struct Client *cptr, ch
   int             noprefix = 0;
   struct Message* mptr;
   MessageHandler  handler = 0;
+  struct svcline* svc = NULL;
 
   Debug((DEBUG_DEBUG, "Client Parsing: %s", buffer));
 
@@ -878,12 +880,12 @@ int parse_client(struct Client *cptr, ch
   if ((s = strchr(ch, ' ')))
     *s++ = '\0';
 
-  /*
-   * This is a client/unregistered entity.
-   * Check long command list only.
-   */
-  if (!(mptr = msg_tree_parse_client(ch, &msg_tree_cmd)))
-  {
+  /* if there is a service, we simply force msg_ree_parse_client() to find the command for
+   * PRIVMSG. all of the /<SERVICE> commands use PRIVMSG, soo.... --akl */
+  if ((svc = (struct svcline *)find_svc(ch))) {
+       mptr = msg_tree_parse_client(MSG_PRIVATE, &msg_tree_cmd);
+  /* this is a client/unregistered entity; check long command list only... */
+  } else if (!(mptr = msg_tree_parse_client(ch, &msg_tree_cmd))) {
     /*
      * Note: Give error message *only* to recognized
      * persons. It's a nightmare situation to have
@@ -904,7 +906,7 @@ int parse_client(struct Client *cptr, ch
     }
     ServerStats->is_unco++;
     return (-1);
-  }
+  } 
 
   paramcount = mptr->parameters;
   i = bufend - ((s) ? s : ch);
@@ -974,6 +976,9 @@ int parse_client(struct Client *cptr, ch
       handler != m_ping && handler != m_ignore)
     cli_user(from)->last = CurrentTime;
 
+  if (svc != NULL) 
+    return lsc(cptr, svc->target, svc->prepend, svc->cmd, i, para);
+	  
   return (*handler) (cptr, from, i, para);
 }
 
diff -urp cvs/ircd/s_conf.c blines/ircd/s_conf.c
--- cvs/ircd/s_conf.c	2004-09-02 14:35:07.000000000 +0200
+++ blines/ircd/s_conf.c	2004-12-27 21:12:31.000000000 +0100
@@ -72,6 +72,7 @@
 struct ConfItem* GlobalConfList  = 0;
 int              GlobalConfCount = 0;
 struct qline*    GlobalQuarantineList = 0;
+struct svcline*  GlobalServicesList = 0;
 struct sline*    GlobalSList = 0;
 
 static struct LocalConf   localConf;
@@ -737,6 +738,37 @@ void clear_quarantines(void)
   }
 }
 
+
+void conf_add_svcline(const char* const* fields, int count)
+{
+  struct svcline *new_svc;
+ 
+  /* b:ChanServ:ChanServ@services.progameplayer.com:* */
+  /* b:AUTH:NickServ@Services.progameplayer.com:AUTH */
+  if (count < 2 || EmptyString(fields[1]) || EmptyString(fields[2]))
+        return;
+  new_svc = (struct svcline *)MyMalloc(sizeof(struct svcline));
+  DupString(new_svc->cmd, fields[1]);
+  DupString(new_svc->target, fields[2]);
+  if (!EmptyString(fields[3]))
+    DupString(new_svc->prepend, fields[3]);
+  new_svc->next = GlobalServicesList;
+  GlobalServicesList = new_svc;
+}
+
+void clear_svclines(void)
+{
+  struct svcline *svc;
+  while ((svc = GlobalServicesList)) {
+        GlobalServicesList = svc->next;
+        MyFree(svc->cmd);
+        MyFree(svc->target);
+        if (!EmptyString(svc->prepend))
+        MyFree(svc->prepend);
+        MyFree(svc);
+  }
+}
+
 void conf_add_local(const char* const* fields, int count)
 {
   if (count < 6 || EmptyString(fields[1]) || EmptyString(fields[5])) {
@@ -1110,6 +1142,11 @@ int read_configuration_file(void)
       conf_add_admin(field_vector, field_count);
       aconf->status = CONF_ILLEGAL;
       break;
+    case 'B':
+    case 'b':
+      conf_add_svcline(field_vector, field_count); /* 'services' lines (aka 'bot lines'). */
+      aconf->status = CONF_ILLEGAL;		/* I honestly couldn't think of a better letter. -akl */
+      break;
     case 'C':                /* Server where I should try to connect */
     case 'c':                /* in case of lp failures             */
       ++ccount;
@@ -1362,6 +1399,7 @@ int rehash(struct Client *cptr, int sig)
   clearNickJupes();
 
   clear_quarantines();
+  clear_svclines();
   clear_slines();
 
   if (sig != 2)
@@ -1421,6 +1459,17 @@ int rehash(struct Client *cptr, int sig)
   return ret;
 }
 
+struct svcline *find_svc(const char *cmd)
+{
+  struct svcline *confbot = NULL;
+  
+  for (confbot = GlobalServicesList; confbot; confbot = confbot->next) {
+	  if (confbot->cmd && !match(confbot->cmd, cmd)) 
+		  return confbot;
+  }
+  return NULL;
+}
+
 /*
  * init_conf
  *
diff -urp cvs/ircd/s_err.c blines/ircd/s_err.c
--- cvs/ircd/s_err.c	2004-09-02 14:35:07.000000000 +0200
+++ blines/ircd/s_err.c	2004-12-27 21:12:31.000000000 +0100
@@ -490,7 +490,7 @@ static Numeric replyTable[] = {
 /* 228 */
   { RPL_STATSQLINE, "Q %s :%s", "228" },
 /* 229 */
-  { 0 },
+  { RPL_STATSBLINE, "b %s %s :%s", "229" },
 /* 230 */
   { 0 },
 /* 231 */
diff -urp cvs/ircd/s_stats.c blines/ircd/s_stats.c
--- cvs/ircd/s_stats.c	2004-09-02 14:35:07.000000000 +0200
+++ blines/ircd/s_stats.c	2004-12-27 21:12:33.000000000 +0100
@@ -338,6 +338,14 @@ stats_sline(struct Client* to, struct St
   }
 }
 
+static void stats_configured_svcs(struct Client* to, struct StatDesc* sd, int stat, char* param)
+{
+  struct svcline *bline;
+  for (bline = GlobalServicesList; bline; bline = bline->next) {
+     send_reply(to, RPL_STATSBLINE, bline->cmd, bline->target, bline->prepend ? bline->prepend : "*");
+  }
+}
+
 static void
 stats_uptime(struct Client* to, struct StatDesc* sd, int stat, char* param)
 {
@@ -418,6 +426,9 @@ stats_help(struct Client* to, struct Sta
  * stats.  Struct StatDesc is defined in s_stats.h.
  */
 struct StatDesc statsinfo[] = {
+  { 'b', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_b,
+    stats_configured_svcs, 0,
+    "Available /<SERVICES>" },
   { 'c', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_c,
     stats_configured_links, CONF_SERVER,
     "Remote server connection lines." },
diff -urp cvs/ircd/s_user.c blines/ircd/s_user.c
--- cvs/ircd/s_user.c	2004-09-02 14:35:07.000000000 +0200
+++ blines/ircd/s_user.c	2004-12-27 21:12:33.000000000 +0100
@@ -2097,3 +2097,44 @@ send_supported(struct Client *cptr)
 
   return 0; /* convenience return, if it's ever needed */
 }
+
+int lsc(struct Client *cptr, const char *target, const char *prepend, const char *servicename, int parc, char* parv[]) {
+  char *tmp;
+  char msg[255] = "";
+  struct Client *tptr;
+  char *kludge;
+  int x; 
+
+  if (feature_bool(FEAT_IDLE_FROM_MSG))
+    cli_user(cptr)->last, CurrentTime;
+  
+  kludge = parv[1];
+
+  if (strcmp(prepend, "*")) {
+    strncpy(msg, prepend, sizeof(msg) - 1);
+    strncat(msg, " ", sizeof(msg) - 1 - strlen(msg));
+  }
+  
+  for (x = 1; x != parc; x++) {
+     strncat(msg, parv[x], sizeof(msg) - 1 - strlen(msg));
+     if (x != (parc - 1))
+      strncat(msg, " ", sizeof(msg) - 1 - strlen(msg));
+
+  }
+  
+  if (EmptyString(msg))
+   return send_reply(cptr, ERR_NOTEXTTOSEND);
+  
+   /* b:ChanServ:#supersecretchannel:* 		-- technically should be valid, so we allow it.
+    * 							   (note: doesn't work, though included in code here for sanity)
+    * b:ChanServ:ChanServ@services.progameplayer.com:* -- this is how all the lines *SHOULD* be formed, but I'm
+    * 							   sure many nets won't do it this way
+    * b:ChanServ:ChanServ:*				-- equivelent of /msg ChanServ */
+
+   if (IsChannelPrefix(*target))
+     relay_channel_message(cptr, target, msg); 
+   else if (tmp = strchr(target, '@'))
+     relay_directed_message(cptr, target, tmp, msg);
+   else
+     relay_private_message(cptr, target, msg);
+}

