home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / yagirc-0.51.tar.gz / yagirc-0.51.tar / yagirc-0.51 / script.c < prev    next >
C/C++ Source or Header  |  1998-05-04  |  24KB  |  1,032 lines

  1. /*
  2.  
  3.  script.c : PERL script interface
  4.  
  5.     Copyright (C) 1998 Jere Sanisalo <jeress@iname.com> and Timo Sirainen
  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
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <sys/param.h>
  25.  
  26. #ifndef HAS_BOOL
  27. #define HAS_BOOL
  28. #define bool char
  29. #endif
  30.  
  31. #include <EXTERN.h>
  32. #include <XSUB.h>
  33.  
  34. #include <glib.h>
  35.  
  36. #include "os.h"
  37. #include "txt.h"
  38. #include "irc.h"
  39. #include "script.h"
  40. #include "events.h"
  41. #include "commands.h"
  42. #include "params.h"
  43.  
  44. #undef PACKAGE
  45. #undef _
  46. #include <perl.h>
  47.  
  48. enum
  49. {
  50.     SCRIPT_EVENT_UNKNOWN,
  51.     SCRIPT_EVENT_COMMAND,
  52.     SCRIPT_EVENT_NUMERIC,
  53.     SCRIPT_EVENT_SERVERMSG,
  54.     SCRIPT_EVENT_JOIN,
  55.     SCRIPT_EVENT_PART,
  56.     SCRIPT_EVENT_PRIVMSG,
  57.     SCRIPT_EVENT_PUBMSG,
  58.     SCRIPT_EVENT_DCCMSG, /*!!*/
  59.     SCRIPT_EVENT_QUIT,
  60.     SCRIPT_EVENT_CONNECTED,
  61.     SCRIPT_EVENT_DISCONNECTED,
  62.     SCRIPT_EVENT_IRCJOIN, /*!!*/
  63.     SCRIPT_EVENT_IRCPART, /*!!*/
  64.     SCRIPT_EVENT_CTCP,
  65.     SCRIPT_EVENT_INVITE,
  66.     SCRIPT_EVENT_KICK,
  67.     SCRIPT_EVENT_MODE,
  68.     SCRIPT_EVENT_TOPIC,
  69.     SCRIPT_EVENT_ACTION,
  70. };
  71.  
  72. typedef struct
  73. {
  74.     int type;
  75.     char *name;
  76.  
  77.     int sender_pos;
  78.     int sender_host_pos;
  79. }
  80. EVENT_LIST_REC;
  81.  
  82. static EVENT_LIST_REC events[] =
  83. {
  84.     { SCRIPT_EVENT_JOIN, "JOIN", 1, 2 },
  85.     { SCRIPT_EVENT_PART, "PART", 1, 2 },
  86.     { SCRIPT_EVENT_IRCJOIN, "IRCJOIN", 1, 2 },
  87.     { SCRIPT_EVENT_IRCPART, "IRCPART", 1, 2 },
  88.     { SCRIPT_EVENT_PRIVMSG, "PRIVMSG", 1, 0 },
  89.     { SCRIPT_EVENT_PUBMSG, "PUBMSG", 1, 0 },
  90.     { SCRIPT_EVENT_DCCMSG, "DCCMSG", 1, 0 },
  91.     { SCRIPT_EVENT_ACTION, "ACTION", 1, 2 },
  92.     { SCRIPT_EVENT_QUIT, "QUIT", 1, 2 },
  93.     { SCRIPT_EVENT_SERVERMSG, "SERVERMSG", 0, 0 },
  94.     { SCRIPT_EVENT_CONNECTED, "CONNECTED", 0, 0 },
  95.     { SCRIPT_EVENT_DISCONNECTED, "DISCONNECTED", 0, 0 },
  96.     { SCRIPT_EVENT_CTCP, "CTCP", 1, 2 },
  97.     { SCRIPT_EVENT_INVITE, "INVITE", 1, 0 },
  98.     { SCRIPT_EVENT_KICK, "KICK", 1, 0 },
  99.     { SCRIPT_EVENT_MODE, "MODE", 1, 0 },
  100.     { SCRIPT_EVENT_TOPIC, "TOPIC", 1, 0 },
  101.     { 0, NULL }
  102. };
  103.  
  104. static EVENT_LIST_REC event_numeric =
  105. { SCRIPT_EVENT_NUMERIC, NULL, 1, 2 };
  106.  
  107. static EVENT_LIST_REC event_command =
  108. { SCRIPT_EVENT_COMMAND, NULL, 0, 0 };
  109.  
  110. typedef struct
  111. {
  112.     int id;
  113.     int type;
  114.     int num;
  115.     char *name;
  116.     char *spec;
  117.     char *func;
  118. }
  119. EVENT_REC;
  120.  
  121. typedef struct
  122. {
  123.     int id;
  124.     int type;
  125.     char *name;
  126.     char *spec;
  127.     char *func;
  128. }
  129. MENU_REC;
  130.  
  131. static PerlInterpreter *perl_script;
  132.  
  133. static GList *event_list;
  134. static int event_ids;
  135.  
  136. static GList *popup_menu;
  137. static int popup_ids;
  138.  
  139. static int call_perl(char *name, char *args[]);
  140. static void xs_init();
  141.  
  142. void script_init(void)
  143. {
  144.     perl_script = NULL;
  145.     event_list = NULL; event_ids = 0;
  146.     popup_menu = NULL; popup_ids = 0;
  147. }
  148.  
  149. void script_deinit(void)
  150. {
  151.     GList *tmp;
  152.  
  153.     script_event(eserver, NULL, NULL, "PRGQUIT", "");
  154.  
  155.     if(perl_script!=NULL)
  156.     {
  157.         perl_destruct(perl_script);
  158.         perl_free(perl_script);
  159.  
  160.         perl_script=NULL;
  161.     }
  162.  
  163.     if (event_list == NULL)
  164.     {
  165.         for (tmp = g_list_first(event_list); tmp != NULL; tmp = tmp->next)
  166.         {
  167.             EVENT_REC *event;
  168.  
  169.             event = (EVENT_REC *) tmp->data;
  170.             if (event->name != NULL) g_free(event->name);
  171.             g_free(event->spec);
  172.             g_free(event->func);
  173.             g_free(event);
  174.         }
  175.         g_list_free(event_list); event_list = NULL;
  176.     }
  177.  
  178.     for (tmp = g_list_first(popup_menu); tmp != NULL; tmp = tmp->next)
  179.     {
  180.         MENU_REC *menu;
  181.  
  182.         menu = (MENU_REC *) tmp->data;
  183.         g_free(menu->name);
  184.         g_free(menu->spec);
  185.         g_free(menu->func);
  186.         g_free(menu);
  187.     }
  188.     g_list_free(popup_menu); popup_menu = NULL;
  189. }
  190.  
  191. int script_load(char *name)
  192. {
  193.     char *arglist[] = { "perl", "-w", NULL, NULL };
  194.  
  195.     g_return_val_if_fail(name != NULL, RET_ERR_PARAM);
  196.  
  197.     script_deinit();
  198.  
  199.     perl_script=perl_alloc();
  200.     if(perl_script==NULL)
  201.     {
  202.         g_warning("perl_alloc() failed\n");
  203.         return RET_ERROR;
  204.     }
  205.     perl_construct(perl_script);
  206.  
  207.     arglist[2]=convhome(name);
  208.     if(perl_parse(perl_script,xs_init,2,arglist,(char **)NULL))
  209.     {
  210.         drawtext(curwin, TXT_TYPE_ERROR, IRCTXT_SCRIPT_NOT_FOUND, name);
  211.         script_deinit();
  212.         return RET_ERROR;
  213.     }
  214.     g_free(arglist[2]);
  215.  
  216.     if(perl_run(perl_script))
  217.     {
  218.         g_warning("perl_run() failed\n");
  219.         script_deinit();
  220.         return RET_ERROR;
  221.     }
  222.  
  223.     return RET_OK;
  224. }
  225.  
  226. int script_event(SERVER_REC *sendserver, char *sendnick, char *sendaddr, char *event, char *data)
  227. {
  228.     EVENT_LIST_REC *erec;
  229.     GList *tmp;
  230.     int num;
  231.     char *ptr;
  232.  
  233.     g_return_val_if_fail(event != NULL, 1);
  234.     g_return_val_if_fail(data != NULL, 1);
  235.  
  236.     if (perl_script == NULL) return 1;
  237.     if (event_list == NULL) return 1; /* there's no events grabbed.. */
  238.  
  239.     if (sscanf(event, "%d", &num) == 1)
  240.     {
  241.         /* numeric event */
  242.         erec = &event_numeric;
  243.     }
  244.     else if (sendnick == NULL)
  245.     {
  246.         /* is is a grabbed /command */
  247.         erec = &event_command;
  248.     }
  249.     else
  250.     {
  251.         /* named event.. */
  252.         if (strcasecmp(event, "PRIVMSG") == 0 && (*data == '#' || *data == '&'))
  253.         {
  254.             /* this was public message */
  255.             event = "PUBMSG";
  256.         }
  257.         ptr = strchr(data, ' ');
  258.         if (ptr != NULL && *(ptr+1) == 1)
  259.         {
  260.             /* This is a CTCP */
  261.             if (strncmp(ptr+1, "ACTION ", 7) == 0)
  262.                 event = "ACTION";
  263.             else
  264.                 event = "CTCP";
  265.         }
  266.  
  267.         erec = NULL;
  268.         for (num = 0; events[num].name != NULL; num++)
  269.         {
  270.             if (strcasecmp(event, events[num].name) == 0)
  271.             {
  272.                 erec = &events[num];
  273.                 break;
  274.             }
  275.         }
  276.         if (erec == NULL)
  277.         {
  278.             /* event wasn't recognized */
  279.             return 1;
  280.         }
  281.     }
  282.  
  283.     /* now find every function that wants this event.. */
  284.     for (tmp = g_list_first(event_list); tmp != NULL; tmp = tmp->next)
  285.     {
  286.         EVENT_REC *ev;
  287.  
  288.         ev = (EVENT_REC *) tmp->data;
  289.         if (ev->type == erec->type &&
  290.             (erec->type != SCRIPT_EVENT_NUMERIC || num == ev->num) &&
  291.             (erec->type != SCRIPT_EVENT_COMMAND || strcasecmp(ev->name, event) == 0))
  292.         {
  293.             /* found one! */
  294.             int ret, chancheck;
  295.             char *args[10], *datap, *startdata;
  296.             char *snick;
  297.  
  298.             startdata = datap = g_strdup(data);
  299.  
  300.             snick = NULL;
  301.             if (erec->sender_pos != 0)
  302.             {
  303.                 if (sendnick == NULL)
  304.                     args[erec->sender_pos-1] = "";
  305.                 else
  306.                 {
  307.                     if (sendserver == NULL)
  308.                         args[erec->sender_pos-1] = sendnick;
  309.                     else
  310.                     {
  311.                         /* nick + server id */
  312.                         snick = (char *) g_malloc(strlen(sendnick)+20);
  313.                         sprintf(snick, "%s %d", sendnick, sendserver->handle);
  314.                         args[erec->sender_pos-1] = snick;
  315.                     }
  316.                 }
  317.             }
  318.             if (erec->sender_host_pos != 0)
  319.                 args[erec->sender_host_pos-1] = sendaddr == NULL ? "" : sendaddr;
  320.  
  321.             ret = 1; /* default: call perl function */
  322.             chancheck = -1; /* default: don't check if channel name matches */
  323.             switch (ev->type)
  324.             {
  325.                 case SCRIPT_EVENT_COMMAND:
  326.                     args[0] = event_get_param(&datap); /* first parameter */
  327.                     args[1] = datap;
  328.                     args[2] = NULL;
  329.                     chancheck = 0;
  330.                     break;
  331.                 case SCRIPT_EVENT_JOIN:
  332.                     args[2] = event_get_param(&datap); /* channel */
  333.                     args[3] = NULL;
  334.                     chancheck = 2;
  335.                     break;
  336.                 case SCRIPT_EVENT_PART:
  337.                     args[2] = event_get_param(&datap); /* channel */
  338.                     args[3] = event_get_param(&datap); /* reason */
  339.                     args[4] = NULL;
  340.                     chancheck = 2;
  341.                     break;
  342.                 case SCRIPT_EVENT_QUIT:
  343.                     args[2] = ""; /* channel names where (s)he was joined.. */
  344.                     args[3] = event_get_param(&datap); /* reason */
  345.                     break;
  346.                 case SCRIPT_EVENT_PRIVMSG:
  347.                     args[2] = event_get_param(&datap); /* text */
  348.                     chancheck = 0;
  349.                     break;
  350.                 case SCRIPT_EVENT_PUBMSG:
  351.                     args[2] = event_get_param(&datap); /* channel */
  352.                     args[3] = event_get_param(&datap); /* text */
  353.                     chancheck = 2;
  354.                     break;
  355.                 case SCRIPT_EVENT_ACTION:
  356.                     args[2] = event_get_param(&datap); /* channel */
  357.                     datap += 8; /* remove "\001ACTION "*/
  358.                     ptr = strchr(datap, 1);
  359.                     if (ptr != NULL) *ptr = '\0'; /* remove last \001 */
  360.                     args[3] = event_get_param(&datap); /* data */
  361.                     chancheck = 2;
  362.                     break;
  363.                 case SCRIPT_EVENT_CTCP:
  364.                     args[2] = event_get_param(&datap); /* channel */
  365.                     datap++; /* remove first \001 */
  366.                     ptr = strchr(datap, 1);
  367.                     if (ptr != NULL) *ptr = '\0'; /* remove last \001 */
  368.                     args[3] = event_get_param(&datap); /* data */
  369.                     chancheck = 2;
  370.                     break;
  371.                 case SCRIPT_EVENT_INVITE:
  372.                     event_get_param(&datap); /* skip your name */
  373.                     args[1] = event_get_param(&datap); /* channel */
  374.                     args[2] = NULL;
  375.                     chancheck = 1;
  376.                     break;
  377.                 case SCRIPT_EVENT_KICK:
  378.                     args[1] = event_get_param(&datap); /* channel */
  379.                     args[2] = event_get_param(&datap); /* kicked nick */
  380.                     args[3] = event_get_param(&datap); /* reason */
  381.                     args[4] = NULL;
  382.                     chancheck = 1;
  383.                     break;
  384.                 case SCRIPT_EVENT_MODE:
  385.                     args[1] = event_get_param(&datap); /* channel */
  386.                     args[2] = event_get_param(&datap); /* mode */
  387.                     args[3] = NULL;
  388.                     chancheck = 1;
  389.                     break;
  390.                 case SCRIPT_EVENT_TOPIC:
  391.                     args[1] = event_get_param(&datap); /* channel */
  392.                     args[2] = event_get_param(&datap); /* topic */
  393.                     args[3] = NULL;
  394.                     chancheck = 1;
  395.                     break;
  396.                 default:
  397.                     args[1] = datap;
  398.                     args[2] = NULL;
  399.                     break;
  400.             }
  401.  
  402.             if (chancheck != -1 && *ev->spec != '\0' && strcasecmp(ev->spec, args[chancheck]) != 0)
  403.             {
  404.                 /* this event isn't supposed to be sent in this channel.. */
  405.                 ret = 0;
  406.             }
  407.  
  408.             if (ret)
  409.                 ret = !call_perl(ev->func, args);
  410.             else
  411.                 ret = 1;
  412.  
  413.             g_free(startdata);
  414.             if (snick != NULL) g_free(snick);
  415.  
  416.             if (!ret) return 0;
  417.         }
  418.     }
  419.  
  420.     return 1;
  421. }
  422.  
  423. #ifdef USE_GUI
  424. typedef struct
  425. {
  426.     MENU_REC *menu;
  427.     char *data;
  428. }
  429. SCRIPT_PARAMS_REC;
  430.  
  431. static GList *script_params = NULL;
  432.  
  433. static void script_menu(SCRIPT_PARAMS_REC *sp)
  434. {
  435.     char *args[2] = { NULL, NULL };
  436.  
  437.     args[0] = sp->data;
  438.     call_perl(sp->menu->func, args);
  439. }
  440.  
  441. void script_add_popups(GtkWidget *menu, int menutype, char *data)
  442. {
  443.     GtkWidget *smenu;
  444.     GList *tmp;
  445.  
  446.     g_return_if_fail(menu != NULL);
  447.     g_return_if_fail(data != NULL);
  448.  
  449.     for (tmp = g_list_first(script_params); tmp != NULL; tmp = tmp->next)
  450.         g_free(script_params->data);
  451.     g_list_free(script_params);
  452.  
  453.     smenu = NULL;
  454.     for (tmp = g_list_first(popup_menu); tmp != NULL; tmp = tmp->next)
  455.     {
  456.         MENU_REC *menu;
  457.  
  458.         menu = (MENU_REC *) tmp->data;
  459.         if (menu->type == menutype &&
  460.             (*menu->spec == '\0' || strcasecmp(menu->spec, data) == 0))
  461.         {
  462.             SCRIPT_PARAMS_REC *sp;
  463.  
  464.             if (smenu == NULL) smenu = gtk_menu_new();
  465.  
  466.             sp = (SCRIPT_PARAMS_REC *) g_malloc(sizeof(SCRIPT_PARAMS_REC));
  467.             sp->menu = menu;
  468.             sp->data = data;
  469.             g_list_append(script_params, sp);
  470.  
  471.             add_popup(smenu, menu->name, script_menu, sp);
  472.         }
  473.     }
  474.  
  475.     if (smenu != NULL) add_popup_sub(menu, "Script", smenu);
  476. }
  477. #endif
  478.  
  479. /* C-commands used by perl */
  480.  
  481. /*  NOTES ON PERL INTERFACE
  482. ---
  483. Types:
  484. .         IV - Integer
  485. .         NV - Double
  486. .         PV - String
  487. .         SV - Scalar
  488.  
  489. Creates new values:
  490. .         SV*  newSViv(IV);
  491. .         SV*  newSVnv(double);
  492. .         SV*  newSVpv(char*, int);
  493. .         SV*  newSVpvf(const char*, ...);
  494. .         SV*  newSVsv(SV*);
  495.  
  496. Sets the values: (length can be set to 0!)
  497. .         void  sv_setiv(SV*, IV);
  498. .         void  sv_setnv(SV*, double);
  499. .         void  sv_setpv(SV*, char*);
  500. .         void  sv_setpvn(SV*, char*, int)
  501. .         void  sv_setpvf(SV*, const char*, ...);
  502. .         void  sv_setsv(SV*, SV*);
  503.  
  504. Converts the values to C:
  505. .         SvIV(SV*)
  506. .         SvNV(SV*)
  507. .         SvPV(SV*,STRLEN len) (here the length is placed in len)
  508.  
  509. Checks if the value is TRUE:
  510. .         SvTRUE(SV*)
  511. Checks if a value is ok:
  512. .         SvOK(SV*)
  513.  
  514. Checks if the value is of a type:
  515. .         SvIOK(SV*)
  516. .         SvNOK(SV*)
  517. .         SvPOK(SV*)
  518.  
  519. .If you know the name of a scalar variable, you can get a
  520. .pointer to its SV by using the following:
  521. .         SV*  perl_get_sv("package::varname", FALSE);
  522. .This returns NULL if the variable does not exist.
  523.  
  524. Some predefined values:
  525. .         sv_no
  526. .         sv_undef
  527. .         sv_yes
  528. ---
  529. NOTE ON STRINGS!
  530.  
  531. The strings may contains NUL-characters. The last char of the strings is not
  532. necessarily a NUL, so be careful!
  533. ---
  534. XS(xxx) predefined values:
  535. .         ax - unknown
  536. .         items - Number of items (use stack ST(x) to find 'em out (x=0..items))
  537.  
  538. The XS form goes like this (the dots at the start of the line are not
  539. included):
  540. XS(name)
  541. {
  542. .         dXSARGS;
  543.  
  544. ...CODE...
  545.  
  546. ...Return method (eg. XS_RETURN_YES)...
  547. }
  548.  
  549. Return methods:
  550. .         XSRETURN(v)         - Returns with v args (must be mortal values in
  551. .                               at the start of the stack)
  552. .         XSRETURN_IV(v)
  553. .         XSRETURN_NV(v)
  554. .         XSRETURN_PV(v)
  555. .         XSRETURN_NO
  556. .         XSRETURN_YES
  557. .         XSRETURN_UNDEF
  558. .         XSRETURN_EMPTY
  559. */
  560.  
  561. static char *dup0(char *str,int len)
  562. {
  563.     char *tmp;
  564.  
  565.     g_return_val_if_fail(str != NULL, NULL);
  566.  
  567.     if(len<0) return NULL;
  568.     tmp=(char *)g_malloc(len+1);
  569.  
  570.     memcpy(tmp,str,len);
  571.     tmp[len]='\0';
  572.  
  573.     return tmp;
  574. }
  575.  
  576. #define XS_GETSTR(num,name) { char *tmp; int len; tmp=(char *)SvPV(ST(num),len); name=dup0(tmp,len); }
  577. #define XS_FREESTR(name) g_free(name);
  578.  
  579. static int call_perl(char *name, char *args[])
  580. {
  581.     dSP;
  582.     int retcount,num,i,ret;
  583.  
  584.     ENTER;
  585.     SAVETMPS;
  586.  
  587.     g_return_val_if_fail(name != NULL, 0);
  588.     g_return_val_if_fail(args != NULL, 0);
  589.  
  590.     PUSHMARK(sp);
  591.     while (*args != NULL)
  592.     {
  593.         XPUSHs(sv_2mortal(newSVpv(*args, strlen(*args))));
  594.         args++;
  595.     }
  596.     PUTBACK;
  597.     
  598.     retcount=perl_call_pv(name,G_EVAL|G_SCALAR);
  599.  
  600.     SPAGAIN;
  601.  
  602.     ret = 0;
  603.     if(SvTRUE(GvSV(errgv)))
  604.     {
  605.         void *tmp;
  606.         g_warning("perl error: %s\n",SvPV(GvSV(errgv),na));
  607.         tmp = POPs;
  608.     }
  609.     else
  610.     {
  611.         if (retcount>0) ret = POPi;
  612.         for(num=2;num<=retcount;num++) i=POPi;
  613.     }
  614.     
  615.     PUTBACK;
  616.     FREETMPS;
  617.     LEAVE;
  618.  
  619.     return ret;
  620. }
  621.  
  622. static SERVER_REC *get_server(char *chan)
  623. {
  624.     int num;
  625.  
  626.     chan = strchr(chan, ' ');
  627.     if (chan == NULL) return cserver;
  628.  
  629.     *chan++ = '\0';
  630.     if (sscanf(chan, "%d", &num) != 1) return NULL;
  631.  
  632.     return irc_get_server(num);
  633. }
  634.  
  635. XS(ircBind)
  636. {
  637.     char *event_name, *event_spec, *func_name;
  638.     EVENT_REC *event;
  639.     int tmp;
  640.  
  641.     dXSARGS;
  642.  
  643.     if(items!=3) XSRETURN_NO;
  644.  
  645.     XS_GETSTR(0, event_name);
  646.     XS_GETSTR(1, event_spec);
  647.     XS_GETSTR(2, func_name);
  648.  
  649.     event = g_malloc(sizeof(EVENT_REC));
  650.     event->id = ++event_ids;
  651.     event->type = SCRIPT_EVENT_UNKNOWN;
  652.     event->name = NULL;
  653.     event->spec = event_spec;
  654.     event->func = func_name;
  655.  
  656.     if (sscanf(event_name, "%d", &event->num) == 1)
  657.     {
  658.         /* numeric event */
  659.         event->type = SCRIPT_EVENT_NUMERIC;
  660.     }
  661.     else
  662.     {
  663.         /* named event */
  664.         strupr(event_name);
  665.         for (tmp = 0; events[tmp].name != NULL; tmp++)
  666.         {
  667.             if (strcmp(event_name, events[tmp].name) == 0)
  668.             {
  669.                 event->type = events[tmp].type;
  670.                 break;
  671.             }
  672.         }
  673.     }
  674.  
  675.     if (event->type == SCRIPT_EVENT_UNKNOWN)
  676.     {
  677.         /* unknown event */
  678.         event_ids--;
  679.         g_free(event);
  680.         XS_FREESTR(event_name);
  681.         XS_FREESTR(event_spec);
  682.         XS_FREESTR(func_name);
  683.         XSRETURN_NO;
  684.     }
  685.     XS_FREESTR(event_name);
  686.  
  687.     event_list = g_list_append(event_list, event);
  688.  
  689.     XSRETURN_IV(event->id);
  690. }
  691.  
  692. XS(ircUnBind)
  693. {
  694.     GList *tmp;
  695.     char *idstr;
  696.     int id;
  697.  
  698.     dXSARGS;
  699.  
  700.     if(items!=1) XSRETURN_NO;
  701.  
  702.     XS_GETSTR(0, idstr);
  703.     if (sscanf(idstr, "%d", &id) != 1) XSRETURN_NO;
  704.  
  705.     for (tmp = g_list_first(event_list); tmp != NULL; tmp = tmp->next)
  706.     {
  707.         EVENT_REC *event;
  708.  
  709.         event = (EVENT_REC *) tmp->data;
  710.         if (event->id == id)
  711.         {
  712.             event_list = g_list_remove(event_list, event);
  713.             XSRETURN_YES;
  714.         }
  715.     }
  716.  
  717.     XS_FREESTR(idstr);
  718.  
  719.     XSRETURN_NO;
  720. }
  721.  
  722. XS(ircBindCmd)
  723. {
  724.     char *cmd_name, *cmd_spec, *func_name;
  725.     EVENT_REC *event;
  726.  
  727.     dXSARGS;
  728.  
  729.     if(items!=3) XSRETURN_NO;
  730.  
  731.     XS_GETSTR(0, cmd_name);
  732.     XS_GETSTR(1, cmd_spec);
  733.     XS_GETSTR(2, func_name);
  734.  
  735.     event = g_malloc(sizeof(EVENT_REC));
  736.     event->id = ++event_ids;
  737.     event->type = SCRIPT_EVENT_COMMAND;
  738.     event->name = cmd_name;
  739.     event->spec = cmd_spec;
  740.     event->func = func_name;
  741.  
  742.     event_list = g_list_append(event_list, event);
  743.  
  744.     XSRETURN_IV(event->id);
  745. }
  746.  
  747. XS(ircMenuAdd)
  748. {
  749.     char *menu_type, *menu_name, *menu_spec, *func_name;
  750.     MENU_REC *menu;
  751.  
  752.     dXSARGS;
  753.  
  754.     if(items!=4) XSRETURN_NO;
  755.  
  756.     XS_GETSTR(0, menu_type);
  757.     XS_GETSTR(1, menu_name);
  758.     XS_GETSTR(2, menu_spec);
  759.     XS_GETSTR(3, func_name);
  760.  
  761.     menu = (MENU_REC *) g_malloc(sizeof(MENU_REC));
  762.     menu->id = ++popup_ids;
  763.     menu->name = menu_name;
  764.     menu->spec = menu_spec;
  765.     menu->func = func_name;
  766.  
  767.     if (strcasecmp(menu_type, "nick") == 0)
  768.         menu->type = POPUPMENU_NICK;
  769.     else if (strcasecmp(menu_type, "channel") == 0)
  770.         menu->type = POPUPMENU_CHAN;
  771.     else if (strcasecmp(menu_type, "global") == 0)
  772.         menu->type = POPUPMENU_MAIN;
  773.     else
  774.     {
  775.         /* unknown menu type */
  776.         popup_ids--;
  777.         g_free(menu);
  778.         XS_FREESTR(menu_type);
  779.         XS_FREESTR(menu_name);
  780.         XS_FREESTR(menu_spec);
  781.         XS_FREESTR(func_name);
  782.         XSRETURN_NO;
  783.     }
  784.     XS_FREESTR(menu_type);
  785.  
  786.     popup_menu = g_list_append(popup_menu, menu);
  787.  
  788.     XSRETURN_IV(menu->id);
  789. }
  790.  
  791. XS(ircMenuRemove)
  792. {
  793.     GList *tmp;
  794.     char *idstr;
  795.     int id;
  796.  
  797.     dXSARGS;
  798.  
  799.     if(items!=1) XSRETURN_NO;
  800.  
  801.     XS_GETSTR(0, idstr);
  802.     if (sscanf(idstr, "%d", &id) != 1) XSRETURN_NO;
  803.  
  804.     for (tmp = g_list_first(popup_menu); tmp != NULL; tmp = tmp->next)
  805.     {
  806.         MENU_REC *menu;
  807.  
  808.         menu = (MENU_REC *) tmp->data;
  809.         if (menu->id == id)
  810.         {
  811.             popup_menu = g_list_remove(popup_menu, menu);
  812.             XSRETURN_YES;
  813.         }
  814.     }
  815.  
  816.     XS_FREESTR(idstr);
  817.  
  818.     XSRETURN_YES;
  819. }
  820.  
  821. XS(ircMsg)
  822. {
  823.     char *channel, *text, *tmp;
  824.     SERVER_REC *old;
  825.  
  826.     dXSARGS;
  827.  
  828.     if(items!=2) XSRETURN_NO;
  829.  
  830.     XS_GETSTR(0, channel);
  831.     XS_GETSTR(1, text);
  832.  
  833.     old = cserver; cserver = get_server(channel);
  834.  
  835.     tmp = (char *) g_malloc(strlen(channel) + strlen(text)+2);
  836.     sprintf(tmp, "%s %s", channel, text);
  837.     irccmd_msg(tmp);
  838.  
  839.     cserver = old;
  840.  
  841.     XS_FREESTR(channel);
  842.     XS_FREESTR(text);
  843.  
  844.     XSRETURN_YES;
  845. }
  846.  
  847. XS(ircNotice)
  848. {
  849.     char *channel, *text, *tmp;
  850.     SERVER_REC *old;
  851.  
  852.     dXSARGS;
  853.  
  854.     if(items!=2) XSRETURN_NO;
  855.  
  856.     XS_GETSTR(0, channel);
  857.     XS_GETSTR(1, text);
  858.  
  859.     old = cserver; cserver = get_server(channel);
  860.  
  861.     tmp = (char *) g_malloc(strlen(channel) + strlen(text)+2);
  862.     sprintf(tmp, "%s %s", channel, text);
  863.     irccmd_notice(tmp);
  864.  
  865.     cserver = old;
  866.  
  867.     XS_FREESTR(channel);
  868.     XS_FREESTR(text);
  869.  
  870.     XSRETURN_YES;
  871. }
  872.  
  873. XS(ircCmd)
  874. {
  875.     char *chan, *data;
  876.     CHAN_REC *ch;
  877.  
  878.     dXSARGS;
  879.  
  880.     if(items!=2) XSRETURN_NO;
  881.  
  882.     XS_GETSTR(0, chan);
  883.     XS_GETSTR(1, data);
  884.  
  885.     ch = channel_joined(NULL, chan);
  886.     if (ch == NULL) ch = curwin->curchan;
  887.  
  888.     irc_parse_outgoing(ch, data);
  889.  
  890.     XS_FREESTR(chan);
  891.     XS_FREESTR(data);
  892.  
  893.     XSRETURN_YES;
  894. }
  895.  
  896. XS(ircText)
  897. {
  898.     char *chan, *data;
  899.     CHAN_REC *ch;
  900.  
  901.     dXSARGS;
  902.  
  903.     if(items!=2) XSRETURN_NO;
  904.  
  905.     XS_GETSTR(0, chan);
  906.     XS_GETSTR(1, data);
  907.  
  908.     ch = channel_joined(NULL, chan);
  909.     if (ch == NULL) ch = curwin->curchan;
  910.  
  911.     drawtext(ch == NULL ? curwin : ch->window, TXT_TYPE_DEFAULT, data);
  912.  
  913.     XS_FREESTR(chan);
  914.     XS_FREESTR(data);
  915.  
  916.     XSRETURN_YES;
  917. }
  918.  
  919. XS(ircCTCPSend)
  920. {
  921.     char *chan, *data, *tmp;
  922.     SERVER_REC *old;
  923.  
  924.     dXSARGS;
  925.  
  926.     if(items!=2) XSRETURN_NO;
  927.  
  928.     XS_GETSTR(0, chan);
  929.     XS_GETSTR(1, data);
  930.  
  931.     old = cserver; cserver = get_server(chan);
  932.  
  933.     tmp = (char *) g_malloc(strlen(chan)+strlen(data)+3);
  934.     sprintf(tmp, "%s %s\n", chan, data);
  935.     irccmd_ctcp(tmp);
  936.     g_free(tmp);
  937.  
  938.     cserver = old;
  939.  
  940.     XS_FREESTR(chan);
  941.     XS_FREESTR(data);
  942.  
  943.     XSRETURN_YES;
  944. }
  945.  
  946. XS(ircCTCPReply)
  947. {
  948.     char *chan, *data, *tmp;
  949.     SERVER_REC *old;
  950.  
  951.     dXSARGS;
  952.  
  953.     if(items!=2) XSRETURN_NO;
  954.  
  955.     XS_GETSTR(0, chan);
  956.     XS_GETSTR(1, data);
  957.  
  958.     old = cserver; cserver = get_server(chan);
  959.  
  960.     tmp = (char *) g_malloc(strlen(chan)+strlen(data)+3);
  961.     sprintf(tmp, "%s \001%s\001\n", chan, data);
  962.     irccmd_notice(tmp);
  963.     g_free(tmp);
  964.  
  965.     cserver = old;
  966.  
  967.     XS_FREESTR(chan);
  968.     XS_FREESTR(data);
  969.  
  970.     XSRETURN_YES;
  971. }
  972.  
  973. XS(ircServerCmd)
  974. {
  975.     SERVER_REC *serv;
  976.     char *server, *data;
  977.     int tag, ok;
  978.  
  979.     dXSARGS;
  980.  
  981.     if(items!=2) XSRETURN_NO;
  982.  
  983.     XS_GETSTR(0, server);
  984.     XS_GETSTR(1, data);
  985.  
  986.     ok = 0;
  987.     if (sscanf(server, "%d", &tag) == 1)
  988.     {
  989.         serv = irc_get_server(tag);
  990.         if (serv != NULL)
  991.             ok = irc_send_cmd(serv, data);
  992.     }
  993.  
  994.     XS_FREESTR(server);
  995.     XS_FREESTR(data);
  996.  
  997.     if (ok) XSRETURN_YES; else XSRETURN_NO;
  998. }
  999.  
  1000. XS(ircTimerCallback)
  1001. {
  1002.     /*char *func, *times;*/
  1003.  
  1004.     dXSARGS;
  1005.  
  1006.     if(items < 2) XSRETURN_NO;
  1007.  
  1008.     /*XS_GETSTR(0, func);
  1009.     XS_GETSTR(1, times);*/
  1010.  
  1011.  
  1012.     XSRETURN_YES;
  1013. }
  1014.  
  1015. static void xs_init()
  1016. {
  1017.     newXS("ircBind",ircBind,__FILE__);
  1018.     newXS("ircUnBind",ircUnBind,__FILE__);
  1019.     newXS("ircBindCmd",ircBindCmd,__FILE__);
  1020.     newXS("ircUnBindCmd",ircUnBind,__FILE__);
  1021.     newXS("ircMsg",ircMsg,__FILE__);
  1022.     newXS("ircNotice",ircNotice,__FILE__);
  1023.     newXS("ircCmd",ircCmd,__FILE__);
  1024.     newXS("ircText",ircText,__FILE__);
  1025.     newXS("ircMenuAdd",ircMenuAdd,__FILE__);
  1026.     newXS("ircMenuRemove",ircMenuRemove,__FILE__);
  1027.     newXS("ircCTCPSend",ircCTCPSend,__FILE__);
  1028.     newXS("ircCTCPReply",ircCTCPReply,__FILE__);
  1029.     newXS("ircServerCmd",ircServerCmd,__FILE__);
  1030.     newXS("ircTimerCallback",ircTimerCallback,__FILE__);
  1031. }
  1032.