diff options
author | berkeviktor@aol.com <berkeviktor@aol.com> | 2011-02-28 18:59:32 +0100 |
---|---|---|
committer | berkeviktor@aol.com <berkeviktor@aol.com> | 2011-02-28 18:59:32 +0100 |
commit | d03d6e606b40157d910ddf99ab018156abeb8ef0 (patch) | |
tree | 1f2b148661fb688ae0863b361e49f19672dbe685 /plugins | |
parent | ad7ea4b77e059880ef8f7cb05fe2aa2cdcc217fb (diff) |
add wdk changes to named branch
Diffstat (limited to 'plugins')
54 files changed, 7658 insertions, 9 deletions
diff --git a/plugins/checksum/checksum.c b/plugins/checksum/checksum.c new file mode 100644 index 00000000..170daa5b --- /dev/null +++ b/plugins/checksum/checksum.c @@ -0,0 +1,351 @@ +/* XChat-WDK + * Copyright (c) 2010-2011 Berke Viktor. + * + * Use of OpenSSL SHA256 interface: http://adamlamers.com/?p=5 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <openssl/sha.h> + +#include "xchat-plugin.h" + +#define BUFSIZE 32768 +#define DEFAULT_MAX_HASH_SIZE 268435456 /* default size is 256 MB */ +#define FILE_BUF_SIZE 512 + +#ifndef snprintf +#define snprintf _snprintf +#endif +#ifndef stat64 +#define stat64 _stat64 +#endif + +static xchat_plugin *ph; /* plugin handle */ +static int config_fail; /* variable for config availability */ + +static void +sha256_hash_string (unsigned char hash[SHA256_DIGEST_LENGTH], char outputBuffer[65]) +{ + int i; + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) + { + sprintf (outputBuffer + (i * 2), "%02x", hash[i]); + } + outputBuffer[64] = 0; +} + +static void +sha256 (char *string, char outputBuffer[65]) +{ + int i; + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256_CTX sha256; + + SHA256_Init (&sha256); + SHA256_Update (&sha256, string, strlen (string)); + SHA256_Final (hash, &sha256); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) + { + sprintf (outputBuffer + (i * 2), "%02x", hash[i]); + } + outputBuffer[64] = 0; +} + +static int +sha256_file (char *path, char outputBuffer[65]) +{ + int bytesRead; + unsigned char *buffer; + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256_CTX sha256; + + FILE *file = fopen (path, "rb"); + if (!file) + { + return -534; + } + + SHA256_Init (&sha256); + buffer = malloc (BUFSIZE); + bytesRead = 0; + + if (!buffer) + { + return ENOMEM; + } + + while ((bytesRead = fread (buffer, 1, BUFSIZE, file))) + { + SHA256_Update (&sha256, buffer, bytesRead); + } + + SHA256_Final (hash, &sha256); + sha256_hash_string (hash, outputBuffer); + + fclose (file); + free (buffer); + return 0; +} + +static void +init () +{ + /* check whether the config file exists, if it doesn't, try to create it */ + FILE * file_in; + FILE * file_out; + char buffer[FILE_BUF_SIZE]; + + config_fail = 0; + snprintf (buffer, sizeof (buffer), "%s/checksum.conf", xchat_get_info (ph, "xchatdirfs")); + + if ((file_in = fopen (buffer, "r")) == NULL) + { + if ((file_out = fopen (buffer, "w")) == NULL) + { + config_fail = 1; + } else + { + fprintf (file_out, "%llu\n", (unsigned long long) DEFAULT_MAX_HASH_SIZE); + fclose (file_out); + } + } else + { + fclose (file_in); + } + + /* nasty easter egg: if FILE_BUF_SIZE is set to 1024 and you build for x86, you can do fclose () + at the end of init (), which is plain wrong as it will only work if fopen () != 0. */ +} + +static unsigned long long +get_max_hash_size () +{ + FILE * file_in; + char buffer[FILE_BUF_SIZE]; + unsigned long long max_hash_size; + + if (config_fail) + { + return (unsigned long long) DEFAULT_MAX_HASH_SIZE; + } else + { + snprintf (buffer, sizeof (buffer), "%s/checksum.conf", xchat_get_info (ph, "xchatdirfs")); + file_in = fopen (buffer, "r"); + fscanf (file_in, "%llu", &max_hash_size); + + fclose (file_in); + return max_hash_size; + } +} + +static void +print_size () +{ + unsigned long long size; + char suffix[3]; + + size = get_max_hash_size (); + + if (size >= 1073741824) + { + size /= 1073741824; + snprintf (suffix, sizeof (suffix), "GB"); + } else if (size >= 1048576) + { + size /= 1048576; + snprintf (suffix, sizeof (suffix), "MB"); + } else if (size >= 1024) + { + size /= 1024; + snprintf (suffix, sizeof (suffix), "kB"); + } else + { + snprintf (suffix, sizeof (suffix), "B"); + } + xchat_printf (ph, "File size limit for checksums: %llu %s\n", size, suffix); +} + +static void +increase_max_hash_size () +{ + unsigned long long size; + FILE * file_out; + char buffer[FILE_BUF_SIZE]; + + if (config_fail) + { + xchat_printf (ph, "Config file is unavailable, falling back to the default value\n"); + print_size (); + } else + { + size = get_max_hash_size (); + if (size <= ULLONG_MAX/2) + { + size *= 2; + } + + snprintf (buffer, sizeof (buffer), "%s/checksum.conf", xchat_get_info (ph, "xchatdirfs")); + file_out = fopen (buffer, "w"); + fprintf (file_out, "%llu\n", size); + fclose (file_out); + print_size (); + } +} + +static void +decrease_max_hash_size () +{ + unsigned long long size; + FILE * file_out; + char buffer[FILE_BUF_SIZE]; + + if (config_fail) + { + xchat_printf (ph, "Config file is unavailable, falling back to the default value\n"); + print_size (); + } else + { + size = get_max_hash_size (); + if (size >= 2) + { + size /= 2; + } + + snprintf (buffer, sizeof (buffer), "%s/checksum.conf", xchat_get_info (ph, "xchatdirfs")); + file_out = fopen (buffer, "w"); + fprintf (file_out, "%llu\n", size); + fclose (file_out); + print_size (); + } +} + +static int +dccrecv_cb (char *word[], void *userdata) +{ + int result; + struct stat64 buffer; /* buffer for storing file info */ + char sum[65]; /* buffer for checksum */ + + result = stat64 (word[2], &buffer); + if (result == 0) /* stat returns 0 on success */ + { + if (buffer.st_size <= get_max_hash_size ()) + { + sha256_file (word[2], sum); /* word[2] is the full filename */ + /* try to print the checksum in the privmsg tab of the sender */ + xchat_set_context (ph, xchat_find_context (ph, NULL, word[3])); + xchat_printf (ph, "SHA-256 checksum for %s (local): %s\n", word[1], sum); + } else + { + xchat_set_context (ph, xchat_find_context (ph, NULL, word[3])); + xchat_printf (ph, "SHA-256 checksum for %s (local): (size limit reached, no checksum calculated, you can increase it with /CHECKSUM INC)\n", word[1]); + } + } else + { + xchat_printf (ph, "File access error\n"); + } + + return XCHAT_EAT_NONE; +} + +static int +dccoffer_cb (char *word[], void *userdata) +{ + int result; + struct stat64 buffer; /* buffer for storing file info */ + char sum[65]; /* buffer for checksum */ + + result = stat64 (word[3], &buffer); + if (result == 0) /* stat returns 0 on success */ + { + if (buffer.st_size <= get_max_hash_size ()) + { + sha256_file (word[3], sum); /* word[3] is the full filename */ + xchat_commandf (ph, "quote PRIVMSG %s :SHA-256 checksum for %s (remote): %s", word[2], word[1], sum); + } else + { + xchat_set_context (ph, xchat_find_context (ph, NULL, word[3])); + xchat_printf (ph, "quote PRIVMSG %s :SHA-256 checksum for %s (remote): (size limit reached, no checksum calculated)", word[2], word[1]); + } + } else + { + xchat_printf (ph, "File access error\n"); + } + + return XCHAT_EAT_NONE; +} + +static void +checksum (char *word[], void *userdata) +{ + if (!stricmp ("GET", word[2])) + { + print_size (); + } else if (!stricmp ("INC", word[2])) + { + increase_max_hash_size (); + } else if (!stricmp ("DEC", word[2])) + { + decrease_max_hash_size (); + } else + { + xchat_printf (ph, "Usage: /CHECKSUM GET|INC|DEC\n"); + xchat_printf (ph, " GET - print the maximum file size to be hashed\n"); + xchat_printf (ph, " INC - double the maximum file size to be hashed\n"); + xchat_printf (ph, " DEC - halve the maximum file size to be hashed\n"); + } +} + +int +xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg) +{ + ph = plugin_handle; + + *plugin_name = "Checksum"; + *plugin_desc = "Calculate checksum for DCC file transfers"; + *plugin_version = "2.0"; + + init (); + + xchat_hook_command (ph, "CHECKSUM", XCHAT_PRI_NORM, checksum, "Usage: /CHECKSUM GET|INC|DEC", 0); + xchat_hook_print (ph, "DCC RECV Complete", XCHAT_PRI_NORM, dccrecv_cb, NULL); + xchat_hook_print (ph, "DCC Offer", XCHAT_PRI_NORM, dccoffer_cb, NULL); + + xchat_print (ph, "Checksum plugin loaded\n"); + return 1; +} + +int +xchat_plugin_deinit (void) +{ + xchat_print (ph, "Checksum plugin unloaded\n"); + return 1; +} diff --git a/plugins/checksum/makefile.mak b/plugins/checksum/makefile.mak new file mode 100644 index 00000000..ec8e0455 --- /dev/null +++ b/plugins/checksum/makefile.mak @@ -0,0 +1,18 @@ +include "..\..\src\makeinc.mak" + +all: checksum.obj checksum.def + link $(LDFLAGS) $(LIBS) /dll /out:xcchecksum.dll /def:checksum.def checksum.obj + +checksum.def: + echo EXPORTS > checksum.def + echo xchat_plugin_init >> checksum.def + echo xchat_plugin_deinit >> checksum.def + +checksum.obj: checksum.c makefile.mak + cl $(CFLAGS) /I.. checksum.c + +clean: + del *.obj + del *.dll + del *.exp + del *.lib diff --git a/plugins/ewc/COPYING b/plugins/ewc/COPYING new file mode 100644 index 00000000..4362b491 --- /dev/null +++ b/plugins/ewc/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/plugins/ewc/ewc.c b/plugins/ewc/ewc.c new file mode 100644 index 00000000..78e7e9ac --- /dev/null +++ b/plugins/ewc/ewc.c @@ -0,0 +1,231 @@ +/* +EasyWinampControl - A Winamp "What's playing" plugin for Xchat +Copyright (C) Yann HAMON & contributors + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "xchat-plugin.h" +#include <windows.h> + +static xchat_plugin *ph; /* plugin handle */ +static int enable = 1; + +// For example, circularstrstr("winamp", "pwi", 3) would return 5 (the index of p) +int circularstrstr(char* a, char* b, int nb) +{ + int equal = 1; + int length; + int pos=-1; + int i, j; + + length = strlen(a); + + for (i=0; i<length && pos == -1; ++i) { + equal = 1; + for (j=0; j<nb;j++) { + if (a[(i+j)%length] != b[j]) + equal = 0; + } + if (equal == 1) + pos = i; + } + + return pos; +} + +void GetCurrentSongsName(HWND hwndWinamp, char* title, int titlesize) +{ + int pos; + char *title2; + int i, j=0; + int length; + char *p; + + GetWindowText(hwndWinamp, title, titlesize); + length = strlen(title); + + if ((pos = circularstrstr(title, "- Winamp ***", 12)) != -1) { + // The option "scroll song title in taskbar" is on + title2 = (char*) malloc (titlesize*sizeof(char)); + + for (i=(pos+12)%length; i!=pos; i=(i+1)%length) + title2[j++] = title[i]; + + title2[j] = '\0'; + + p = title2; + while (p<title2+titlesize && *p != '.') + p++; + p+=2; // Delete the . and the following white space + + strcpy(title, p); + free(title2); + } + else { + p = title; + while (p<title+titlesize && *p != '.') + p++; + p+=2; // Delete the . and the following white space + if (p<title+titlesize) + strncpy(title, p, titlesize-(p-title)); + + // Delete the trailing "- winamp" + p = title + titlesize - 1; + while (p>title && *p != '-') p--; + *p = '\0'; + } +} + + +// Controlling winamp +static int wcmd_cb(char *word[], char *word_eol[], void *userdata) +{ + // Everything's here : http://winamp.com/nsdn/winamp2x/dev/sdk/api.php + // The previous url seems dead, see http://forums.winamp.com/showthread.php?threadid=180297 + HWND hwndWinamp = NULL; + + if ((hwndWinamp = FindWindow("Winamp v1.x",NULL)) == NULL) { + xchat_print(ph, "Winamp's window not found - Is winamp really running?\n"); + } + else { + if (strcmp(word[1], "") == 0) + xchat_print(ph, "Usage: wcmd [command]\n"); + else if (strcmp(word[2], "next") == 0) { + xchat_print(ph, "Loading next song...\n"); + SendMessage (hwndWinamp, WM_COMMAND, 40048, 0); + } + else if (strcmp(word[2], "prev") == 0) { + xchat_print(ph, "Loading previous song...\n"); + SendMessage (hwndWinamp, WM_COMMAND, 40044, 0); + } + else if (strcmp(word[2], "play") == 0) { + xchat_print(ph, "Playin'...\n"); + SendMessage (hwndWinamp, WM_COMMAND, 40045, 0); + } + else if (strcmp(word[2], "stop") == 0) { + xchat_print(ph, "Winamp stopped!...\n"); + SendMessage (hwndWinamp, WM_COMMAND, 40047, 0); + } + else if (strcmp(word[2], "pause") == 0) { + SendMessage (hwndWinamp, WM_COMMAND, 40046, 0); + } + } + + return XCHAT_EAT_ALL; +} + + +// Display current song +static int wp_cb(char *word[], char *word_eol[], void *userdata) +{ + HWND hwndWinamp = NULL; + int bitrate, length, elapsed, minutes, seconds, eminutes, eseconds, samplerate, nbchannels; + char elapsedtime[7]; + char totaltime[7]; + char this_title[1024]; + + if ((hwndWinamp = FindWindow("Winamp v1.x",NULL)) == NULL) + xchat_print(ph, "Winamp's window not found - Is winamp really running?\n"); + else { + //Winamp's running + // Seems buggy when winamp2's agent is running, and winamp not (or winamp3) -> crashes xchat. + SendMessage(hwndWinamp, WM_USER, (WPARAM)0, (LPARAM)125); + + if ((samplerate = SendMessage(hwndWinamp, WM_USER, (WPARAM)0, (LPARAM)126)) == 0) { + xchat_print(ph, "Could not get current song's samplerate... !?\n"); + return XCHAT_EAT_ALL; + } + if ((bitrate = SendMessage(hwndWinamp, WM_USER, (WPARAM)1, (LPARAM)126)) == 0) { + xchat_print(ph, "Could not get current song's bitrate... !?\n"); + return XCHAT_EAT_ALL; + } + if ((nbchannels = SendMessage(hwndWinamp, WM_USER, (WPARAM)2, (LPARAM)126)) == 0) { + xchat_print(ph, "Could not get the number of channels... !?\n"); + return XCHAT_EAT_ALL; + } + if ((length = SendMessage(hwndWinamp, WM_USER, (WPARAM)1, (LPARAM)105)) == 0) { + // Could be buggy when streaming audio or video, returned length is unexpected; + // How to detect is Winamp is streaming, and display ??:?? in that case? + xchat_print(ph, "Could not get current song's length... !?\n"); + return XCHAT_EAT_ALL; + } + else { + minutes = length/60; + seconds = length%60; + + if (seconds>9) + wsprintf(totaltime, "%d:%d", minutes, seconds); + else + wsprintf(totaltime, "%d:0%d", minutes, seconds); + } + if ((elapsed = SendMessage(hwndWinamp, WM_USER, (WPARAM)0, (LPARAM)105)) == 0) { + xchat_print(ph, "Could not get current song's elapsed time... !?\n"); + return XCHAT_EAT_ALL; + } + else { + eminutes = (elapsed/1000)/60; /* kinda stupid sounding, but e is for elapsed */ + eseconds = (elapsed/1000)%60; + + if (eseconds>9) + wsprintf(elapsedtime, "%d:%d", eminutes, eseconds); + else + wsprintf(elapsedtime, "%d:0%d", eminutes, eseconds); + } + + if ((bitrate = SendMessage(hwndWinamp, WM_USER, (WPARAM)1, (LPARAM)126)) == 0) { + xchat_print(ph, "Could not get current song's bitrate... !?\n"); + return XCHAT_EAT_ALL; + } + + GetCurrentSongsName(hwndWinamp, this_title, 1024); + + xchat_commandf(ph, "dispcurrsong %d %d %d %s %s %s", samplerate, bitrate, nbchannels, elapsedtime, totaltime, this_title); + } + + return XCHAT_EAT_ALL; /* eat this command so xchat and other plugins can't process it */ +} + + + +int xchat_plugin_init(xchat_plugin *plugin_handle, + char **plugin_name, + char **plugin_desc, + char **plugin_version, + char *arg) +{ + /* we need to save this for use with any xchat_* functions */ + ph = plugin_handle; + + *plugin_name = "EasyWinampControl"; + *plugin_desc = "Some commands to remotely control winamp"; + *plugin_version = "1.2"; + + xchat_hook_command(ph, "wp", XCHAT_PRI_NORM, wp_cb, + "Usage: wp", 0); + + xchat_hook_command(ph, "wcmd", XCHAT_PRI_NORM, wcmd_cb, + "Usage: wcmd [play|pause|stop|prev|next]", 0); + + xchat_print(ph, "EasyWinampControl plugin loaded\n"); + + return 1; /* return 1 for success */ +} + +int xchat_plugin_deinit(void) +{ + xchat_print(ph, "EasyWinampControl plugin unloaded\n"); + return 1; +} diff --git a/plugins/ewc/makefile.mak b/plugins/ewc/makefile.mak new file mode 100644 index 00000000..9b9f21c1 --- /dev/null +++ b/plugins/ewc/makefile.mak @@ -0,0 +1,18 @@ +include "..\..\src\makeinc.mak" + +all: ewc.obj ewc.def + link $(LDFLAGS) $(LIBS) /dll /out:xcewc.dll /def:ewc.def ewc.obj + +ewc.def: + echo EXPORTS > ewc.def + echo xchat_plugin_init >> ewc.def + echo xchat_plugin_deinit >> ewc.def + +ewc.obj: ewc.c makefile.mak + cl $(CFLAGS) ewc.c + +clean: + del *.obj + del *.dll + del *.exp + del *.lib diff --git a/plugins/lua/lua.c b/plugins/lua/lua.c new file mode 100644 index 00000000..9574fd4d --- /dev/null +++ b/plugins/lua/lua.c @@ -0,0 +1,1882 @@ +/* + * X-Chat 2.0 LUA Plugin + * + * Copyright (c) 2007 Hanno Hecker + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +/* + * $Id: lua.c 91 2007-06-09 18:44:03Z vetinari $ + * $Revision: 91 $ + * $Date: 2007-06-09 20:44:03 +0200 (Szo, 09 jún. 2007) $ + */ +/* + * TODO: + * * compile (was OK)/run on IRIX + * ? localize error msgs? ... maybe later + * ? make xchat.print() like print() which does an tostring() on + * everything it gets? + * ? add /LUA -s <code>? ... add a new script from cmdline... this state + * is not removed after the pcall(), but prints a name, which may + * be used to unload this virtual script. ... no xchat_register(), + * xchat_init() should be needed + * ... don't disable xchat.hook_* for this + * ? timer name per state/script and not per plugin? + */ +#define LXC_NAME "Lua" +#define LXC_DESC "Lua scripting interface" +#define LXC_VERSION "0.7 (r91)" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "../../src/common/dirent.h" +#include <errno.h> +#include <ctype.h> + +#ifdef _WIN32 +#include <direct.h> /* for getcwd */ +#endif + +#if !( defined(_WIN32) || defined(LXC_XCHAT_GETTEXT) ) +# include <libintl.h> +#endif + +#ifndef PATH_MAX /* hurd */ +# define PATH_MAX 1024 +#endif + +#include <lua.h> +#include <lauxlib.h> +#include <lualib.h> + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#include "xchat-plugin.h" + +static xchat_plugin *ph; /* plugin handle */ + +#define LXC_STRIP_COLOR 1 +#define LXC_STRIP_ATTR 2 +#define LXC_STRIP_ALL (LXC_STRIP_COLOR|LXC_STRIP_ATTR) + +/* registered hooks */ +struct lxc_hooks { + const char *name; + xchat_hook *hook; + struct lxc_hooks *next; +}; + +/* single linked list of all lua states^Wscripts ;-) */ +struct lxc_States { + lua_State *state; /* the lua state of the script */ + char file[PATH_MAX+1]; /* the file name of the script */ + struct lxc_hooks *hooks; /* all hooks this script registered */ + void *gui; /* the gui entry in windows->plugins and scripts... */ + struct lxc_States *next; +}; + +static struct lxc_States *lxc_states = NULL; + +/* user/script supplied data for a callback */ +struct lxc_userdata { + int idx; /* table index */ + int type; /* lua type: */ + const char *string; /* only strings, ... */ + double num; /* numbers and booleans are supported */ + struct lxc_userdata *next; +}; + +/* callback data */ +struct lxc_cbdata { + lua_State *state; + const char *func; + xchat_hook *hook; /* timer ... */ + struct lxc_userdata *data; +}; + +static char lxc_event_name[1024] = "\0"; + +static int lxc_run_hook(char *word[], char *word_eol[], void *data); +static int lxc_run_print(char *word[], void *data); +static int lxc_run_timer(void *data); + +static int lxc_hook_command(lua_State *L); +static int lxc_hook_server(lua_State *L); +static int lxc_hook_print(lua_State *L); +static int lxc_event(lua_State *L); +static int lxc_hook_timer(lua_State *L); +static int lxc_unhook(lua_State *L); + +static int lxc_command(lua_State *L); +static int lxc_print(lua_State *L); +static int lxc_emit_print(lua_State *L); +static int lxc_send_modes(lua_State *L); +static int lxc_find_context(lua_State *L); +static int lxc_get_context(lua_State *L); +static int lxc_get_info(lua_State *L); +static int lxc_get_prefs(lua_State *L); +static int lxc_set_context(lua_State *L); +static int lxc_nickcmp(lua_State *L); + +static int lxc_list_get(lua_State *L); +static int lxc_list_fields(lua_State *L); +static int lxc_gettext(lua_State *L); + +static int lxc_bits(lua_State *L); + +static luaL_reg lxc_functions[] = { + {"hook_command", lxc_hook_command }, +/* TODO: + {"hook_fd", lxc_hook_fd }, +*/ + {"hook_print", lxc_hook_print }, + {"hook_server", lxc_hook_server }, + {"hook_timer", lxc_hook_timer }, + {"unhook", lxc_unhook }, + + {"event", lxc_event }, + + {"command", lxc_command }, + {"print", lxc_print }, + {"emit_print", lxc_emit_print }, + {"send_modes", lxc_send_modes }, + {"find_context", lxc_find_context }, + {"get_context", lxc_get_context }, + {"get_info", lxc_get_info }, + {"get_prefs", lxc_get_prefs }, + {"set_context", lxc_set_context }, + + {"nickcmp", lxc_nickcmp }, + + {"list_get", lxc_list_get }, + {"list_fields", lxc_list_fields }, + + {"gettext", lxc_gettext}, +/* helper function for bit flags */ + {"bits", lxc_bits }, + {NULL, NULL} +}; + +static struct { + const char *name; + long value; +} lxc_consts[] = { + {"EAT_NONE", XCHAT_EAT_NONE}, + {"EAT_XCHAT", XCHAT_EAT_XCHAT}, + {"EAT_PLUGIN", XCHAT_EAT_PLUGIN}, + {"EAT_ALL", XCHAT_EAT_ALL}, + +/* unused until hook_fd is done + {"FD_READ", XCHAT_FD_READ}, + {"FD_WRITE", XCHAT_FD_WRITE}, + {"FD_EXCEPTION", XCHAT_FD_EXCEPTION}, + {"FD_NOTSOCKET", XCHAT_FD_NOTSOCKET}, + */ + + {"PRI_HIGHEST", XCHAT_PRI_HIGHEST}, + {"PRI_HIGH", XCHAT_PRI_HIGH}, + {"PRI_NORM", XCHAT_PRI_NORM}, + {"PRI_LOW", XCHAT_PRI_LOW}, + {"PRI_LOWEST", XCHAT_PRI_LOWEST}, + + /* for: clean = xchat.strip(dirty, xchat.STRIP_ALL) */ + {"STRIP_COLOR", LXC_STRIP_COLOR}, + {"STRIP_ATTR", LXC_STRIP_ATTR}, + {"STRIP_ALL", LXC_STRIP_ALL}, + + /* for xchat.commandf("GUI COLOR %d", xchat.TAB_HILIGHT) */ + {"TAB_DEFAULT", 0}, + {"TAB_NEWDATA", 1}, + {"TAB_NEWMSG", 2}, + {"TAB_HILIGHT", 3}, + + {NULL, 0} +}; + + +#ifdef DEBUG +static void stackDump (lua_State *L, const char *msg) { + int i, t; + int top = lua_gettop(L); + + fprintf(stderr, "%s\n", msg); + for (i = 1; i <= top; i++) { /* repeat for each level */ + t = lua_type(L, i); + switch (t) { + + case LUA_TSTRING: /* strings */ + fprintf(stderr, "`%s'", lua_tostring(L, i)); + break; + + case LUA_TBOOLEAN: /* booleans */ + fprintf(stderr, lua_toboolean(L, i) ? "true" : "false"); + break; + + case LUA_TNUMBER: /* numbers */ + fprintf(stderr, "%g", lua_tonumber(L, i)); + break; + + default: /* other values */ + fprintf(stderr, "%s", lua_typename(L, t)); + break; + + } + fprintf(stderr, " "); /* put a separator */ + } + fprintf(stderr, "\n"); /* end the listing */ +} +#endif /* DEBUG */ + +static int lxc__newindex(lua_State *L) +{ + int i; + const char *name = lua_tostring(L, 2); + + luaL_getmetatable(L, "xchat"); /* 4 */ + + lua_pushnil(L); /* 5 */ + while (lua_next(L, 4) != 0) { + if ((lua_type(L, -2) == LUA_TSTRING) + && strcmp("__index", lua_tostring(L, -2)) == 0) + break; /* now __index is 5, table 6 */ + lua_pop(L, 1); + } + + lua_pushnil(L); + while (lua_next(L, 6) != 0) { + if ((lua_type(L, -2) == LUA_TSTRING) + && strcmp(name, lua_tostring(L, -2)) == 0) { + for (i=0; lxc_consts[i].name; i++) { + if (strcmp(name, lxc_consts[i].name) == 0) { + luaL_error(L, + "`xchat.%s' is a readonly constant", lua_tostring(L, 2)); + return 0; + } + } + } + lua_pop(L, 1); + } + + lua_pushvalue(L, 2); + lua_pushvalue(L, 3); + lua_rawset(L, 6); + + lua_settop(L, 1); + return 0; +} + +static int luaopen_xchat(lua_State *L) +{ + int i; +/* + * wrappers for xchat.printf() and xchat.commandf() + * ... xchat.strip + */ +#define LXC_WRAPPERS "function xchat.printf(...)\n" \ + " xchat.print(string.format(unpack(arg)))\n" \ + "end\n" \ + "function xchat.commandf(...)\n" \ + " xchat.command(string.format(unpack(arg)))\n" \ + "end\n" \ + "function xchat.strip(str, flags)\n" \ + " if flags == nil then\n" \ + " flags = xchat.STRIP_ALL\n" \ + " end\n" \ + " local bits = xchat.bits(flags)\n" \ + " if bits[1] then\n" \ + " str = string.gsub(\n" \ + " string.gsub(str, \"\\3%d%d?,%d%d?\", \"\"),\n" \ + " \"\\3%d%d?\", \"\")\n" \ + " end\n" \ + " if bits[2] then\n" \ + " -- bold, beep, reset, reverse, underline\n" \ + " str = string.gsub(str,\n" \ + " \"[\\2\\7\\15\\22\\31]\", \"\")\n" \ + " end\n" \ + " return str\n" \ + "end\n" + +#if defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM >= 501) + luaL_register(L, "xchat", lxc_functions); + (void)luaL_dostring(L, LXC_WRAPPERS); +#else + luaL_openlib(L, "xchat", lxc_functions, 0); + lua_dostring(L, LXC_WRAPPERS); +#endif + + luaL_newmetatable(L, "xchat"); + + lua_pushliteral(L, "__index"); + lua_newtable(L); + + lua_pushstring(L, "ARCH"); +#ifdef _WIN32 + lua_pushstring(L, "Windows"); +#else + lua_pushstring(L, "Unix"); +#endif + lua_settable(L, -3); /* add to table __index */ + + for (i=0; lxc_consts[i].name; i++) { + lua_pushstring(L, lxc_consts[i].name); + lua_pushnumber(L, lxc_consts[i].value); + lua_settable(L, -3); /* add to table __index */ + } + lua_settable(L, -3); /* add to metatable */ + + lua_pushliteral(L, "__newindex"); + lua_pushcfunction(L, lxc__newindex); + lua_settable(L, -3); +/* + lua_pushliteral(L, "__metatable"); + lua_pushstring(L, "nothing to see here, move along"); + lua_settable(L, -3); +*/ + lua_setmetatable(L, -2); + lua_pop(L, 1); + return 1; +} + +lua_State *lxc_new_state() +{ +#if defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM >= 501) + lua_State *L = luaL_newstate(); /* opens Lua */ + luaL_openlibs(L); +#else + lua_State *L = lua_open(); /* opens Lua */ + luaopen_base(L); /* opens the basic library */ + luaopen_table(L); /* opens the table library */ + luaopen_io(L); /* opens the I/O library */ + luaopen_string(L); /* opens the string lib. */ + luaopen_math(L); /* opens the math lib. */ +#endif + + luaopen_xchat(L); + return L; +} + +static int +lxc_load_file(const char *script) +{ + lua_State *L; + struct lxc_States *state; /* pointer to lua states list */ + struct lxc_States *st; /* pointer to lua states list */ + + L = lxc_new_state(); + state = malloc(sizeof(struct lxc_States)); + if (state == NULL) { + xchat_printf(ph, "malloc() failed: %s\n", strerror(errno)); + lua_close(L); + return 0; + } + + state->state = L; + snprintf(state->file, PATH_MAX, script); + state->next = NULL; + state->hooks = NULL; + state->gui = NULL; + + if (luaL_loadfile(L, script) || lua_pcall(L, 0, 0, 0)) { + xchat_printf(ph, "Lua plugin: error loading script %s", + lua_tostring(L, -1)); + lua_close(L); + free(state); + return 0; + } + + if (!lxc_states) + lxc_states = state; + else { + st = lxc_states; + while (st->next) + st = st->next; + st->next = state; + } + + return 1; +} + +static void +lxc_autoload_from_path(const char *path) +{ + DIR *dir; + struct dirent *ent; + char *file; + int len; + /* xchat_printf(ph, "loading from %s\n", path); */ + dir = opendir(path); + if (dir) { + while ((ent = readdir(dir))) { + len = strlen(ent->d_name); + if (len > 4 && strcasecmp(".lua", ent->d_name + len - 4) == 0) { + file = malloc(len + strlen(path) + 2); + if (file == NULL) { + xchat_printf(ph, "lxc_autoload_from_path(): malloc failed: %s", + strerror(errno)); + break; + } + sprintf(file, "%s/%s", path, ent->d_name); + (void)lxc_load_file((const char *)file); + free(file); + } + } + closedir(dir); + } +} + +void lxc_unload_script(struct lxc_States *state) +{ + struct lxc_hooks *hooks, *h; + struct lxc_cbdata *cb; + struct lxc_userdata *ud, *u; + lua_State *L = state->state; + + lua_pushstring(L, "xchat_unload"); + lua_gettable(L, LUA_GLOBALSINDEX); + if (lua_type(L, -1) == LUA_TFUNCTION) { + if (lua_pcall(L, 0, 0, 0)) { + xchat_printf(ph, "Lua plugin: error while unloading script %s", + lua_tostring(L, -1)); + lua_pop(L, 1); + } + } + + if (state->gui) + xchat_plugingui_remove(ph, state->gui); + state->gui = NULL; + + hooks = state->hooks; + while (hooks) { + h = hooks; + hooks = hooks->next; + + cb = xchat_unhook(ph, h->hook); + if (cb) { + ud = cb->data; + while (ud) { + u = ud; + ud = ud->next; + free(u); + } + free(cb); + } + + free(h); + } + lua_close(state->state); +} + + +static int lxc_cb_load(char *word[], char *word_eol[], void *userdata) +{ + int len; + struct lxc_States *state; + lua_State *L; + const char *name, *desc, *vers; + const char *xdir = ""; + char *buf; + char file[PATH_MAX+1]; + struct stat *st; + + if (word_eol[2][0] == 0) + return XCHAT_EAT_NONE; + + buf = malloc(PATH_MAX + 1); + if (!buf) { + xchat_printf(ph, "malloc() failed: %s\n", strerror(errno)); + return XCHAT_EAT_NONE; + } + + st = malloc(sizeof(struct stat)); + if (!st) { + xchat_printf(ph, "malloc() failed: %s\n", strerror(errno)); + free(buf); + return XCHAT_EAT_NONE; + } + + len = strlen(word[2]); + if (len > 4 && strcasecmp (".lua", word[2] + len - 4) == 0) { +#ifdef WIN32 + if (strrchr(word[2], '\\') != NULL) +#else + if (strrchr(word[2], '/') != NULL) +#endif + strncpy(file, word[2], PATH_MAX); + else { + if (stat(word[2], st) == 0) + xdir = getcwd(buf, PATH_MAX); + else { + xdir = xchat_get_info(ph, "xchatdirfs"); + if (!xdir) /* xchatdirfs is new for 2.0.9, will fail on older */ + xdir = xchat_get_info (ph, "xchatdir"); + } + snprintf(file, PATH_MAX, "%s/%s", xdir, word[2]); + } + + if (lxc_load_file((const char *)file) == 0) { + free(st); + free(buf); + return XCHAT_EAT_ALL; + } + + state = lxc_states; + while (state) { + if (state->next == NULL) { + L = state->state; + + lua_pushstring(L, "xchat_register"); + lua_gettable(L, LUA_GLOBALSINDEX); + if (lua_pcall(L, 0, 3, 0)) { + xchat_printf(ph, "Lua plugin: error registering script %s", + lua_tostring(L, -1)); + lua_pop(L, 1); + free(st); + free(buf); + return XCHAT_EAT_ALL; + } + + name = lua_tostring(L, -3); + desc = lua_tostring(L, -2); + vers = lua_tostring(L, -1); + lua_pop(L, 4); /* func + 3 ret value */ + state->gui = xchat_plugingui_add(ph, state->file, + name, desc, vers, NULL + ); + + lua_pushstring(L, "xchat_init"); + lua_gettable(L, LUA_GLOBALSINDEX); + if (lua_type(L, -1) != LUA_TFUNCTION) + lua_pop(L, 1); + else { + if (lua_pcall(L, 0, 0, 0)) { + xchat_printf(ph, + "Lua plugin: error calling xchat_init() %s", + lua_tostring(L, -1)); + lua_pop(L, 1); + } + } + free(st); + free(buf); + return XCHAT_EAT_ALL; + } + state = state->next; + } + } + free(st); + free(buf); + return XCHAT_EAT_NONE; +} + +static int lxc_cb_unload(char *word[], char *word_eol[], void *userdata) +{ + int len; + struct lxc_States *state; + struct lxc_States *prev = NULL; + char *file; + + if (word_eol[2][0] == 0) + return XCHAT_EAT_NONE; + + len = strlen(word[2]); + if (len > 4 && strcasecmp(".lua", word[2] + len - 4) == 0) { + state = lxc_states; + while (state) { + /* + * state->file is the full or relative path, always with a '/' inside, + * even if loaded via '/LOAD script.lua'. So strrchr() will never + * be NULL. + * ... we just inspect the script name w/o path to see if it's the + * right one to unload + */ + file = strrchr(state->file, '/') + 1; + if ((strcmp(state->file, word[2]) == 0) + || (strcasecmp(file, word[2]) == 0)) { + lxc_unload_script(state); + if (prev) + prev->next = state->next; + else + lxc_states = state->next; + xchat_printf(ph, "Lua script %s unloaded", file); + free(state); + return XCHAT_EAT_ALL; + } + prev = state; + state = state->next; + } + } + return XCHAT_EAT_NONE; +} + +static int lxc_cb_lua(char *word[], char *word_eol[], void *userdata) +{ + lua_State *L = lxc_new_state(); + if (word[2][0] == '\0') { + xchat_printf(ph, "LUA: Usage: /LUA LUA_CODE... execute LUA_CODE"); + return XCHAT_EAT_ALL; + } + if (luaL_loadbuffer(L, word_eol[2], strlen(word_eol[2]), "/LUA")) { + xchat_printf(ph, "LUA: error loading line %s", lua_tostring(L, -1)); + lua_pop(L, 1); + } + +#define LXC_HOOK_DISABLE "xchat.hook_command = nil\n" \ + "xchat.hook_server = nil\n" \ + "xchat.hook_print = nil\n" \ + "xchat.hook_timer = nil\n" + +#if defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM >= 501) + (void)luaL_dostring(L, LXC_HOOK_DISABLE); +#else + lua_dostring(L, LXC_HOOK_DISABLE); +#endif + + if (lua_pcall(L, 0, 0, 0)) { + xchat_printf(ph, "LUA: error executing line %s", lua_tostring(L, -1)); + lua_pop(L, 1); + } + + lua_close(L); + return XCHAT_EAT_ALL; +} + +int xchat_plugin_init(xchat_plugin *plugin_handle, + char **plugin_name, + char **plugin_desc, + char **plugin_version, + char *arg) +{ + struct lxc_States *state; + lua_State *L; + const char *xdir; + const char *name, *desc, *vers; + /* we need to save this for use with any xchat_* functions */ + ph = plugin_handle; + + /* tell xchat our info */ + *plugin_name = LXC_NAME; + *plugin_desc = LXC_DESC; + *plugin_version = LXC_VERSION; + + xchat_hook_command(ph, "LOAD", XCHAT_PRI_NORM, lxc_cb_load, NULL, NULL); + xchat_hook_command(ph, "UNLOAD", XCHAT_PRI_NORM, lxc_cb_unload, NULL, NULL); + xchat_hook_command(ph, "LUA", XCHAT_PRI_NORM, lxc_cb_lua, "Usage: LUA <code>, executes <code> in a new lua state", NULL); + + xdir = xchat_get_info(ph, "xchatdirfs"); + if (!xdir) /* xchatdirfs is new for 2.0.9, will fail on older */ + xdir = xchat_get_info (ph, "xchatdir"); + + lxc_autoload_from_path(xdir); + + if (!lxc_states) /* no scripts loaded */ + return 1; + + state = lxc_states; + while (state) { + L = state->state; + lua_pushstring(L, "xchat_register"); + lua_gettable(L, LUA_GLOBALSINDEX); + if (lua_pcall(L, 0, 3, 0)) { + xchat_printf(ph, "Lua plugin: error registering script %s", + lua_tostring(L, -1)); + lua_pop(L, 1); + state = state->next; + continue; + } + + name = lua_tostring(L, -3); + desc = lua_tostring(L, -2); + vers = lua_tostring(L, -1); + lua_pop(L, 4); /* func + 3 ret value */ + state->gui = xchat_plugingui_add(ph, state->file, name, desc, vers, NULL); + + lua_pushstring(L, "xchat_init"); + lua_gettable(L, LUA_GLOBALSINDEX); + if (lua_type(L, -1) != LUA_TFUNCTION) + lua_pop(L, 1); + else { + if (lua_pcall(L, 0, 0, 0)) { + xchat_printf(ph, "Lua plugin: error calling xchat_init() %s", + lua_tostring(L, -1)); + lua_pop(L, 1); + } + } + state = state->next; + } + xchat_printf(ph, "Lua interface (v%s) loaded", LXC_VERSION); + return 1; +} + +int xchat_plugin_deinit(xchat_plugin *plug_handle) +{ + struct lxc_States *state, *st; + + state = lxc_states; + while (state) { + lxc_unload_script(state); + xchat_printf(ph, "Lua script %s unloaded", state->file); + st = state; + state = state->next; + free(st); + } + xchat_printf(plug_handle, "Lua plugin v%s removed", LXC_VERSION); + return 1; +} + +/* + * lua: func_name(word, word_eol, data) + * desc: your previously hooked callback function for hook_command() and + * hook_server(), you must return one of the xchat.EAT_* constants + * ret: none + * args: + * * word (table): the incoming line split into words (max 32) + * * word_eol (table): + * for both see + * http://xchat.org/docs/plugin20.html#word + * * data (table): the data table you passed to the hook_command() / + * hook_server() as 5th arg + */ +static int lxc_run_hook(char *word[], char *word_eol[], void *data) +{ + struct lxc_cbdata *cb = data; + lua_State *L = cb->state; + struct lxc_userdata *ud = cb->data; + struct lxc_userdata *u; + int i; + lua_pushstring(L, cb->func); + lua_gettable(L, LUA_GLOBALSINDEX); + + strcpy(lxc_event_name, word[0]); + lua_newtable(L); + for (i=1; i<=31 && word[i][0]; i++) { + lua_pushnumber(L, i); + lua_pushstring(L, word[i]); + lua_settable(L, -3); + } + + lua_newtable(L); + for (i=1; i<=31 && word_eol[i][0]; i++) { + lua_pushnumber(L, i); + lua_pushstring(L, word_eol[i]); + lua_settable(L, -3); + } + + lua_newtable(L); + u = ud; + while (u) { + lua_pushnumber(L, u->idx); + switch (u->type) { + case LUA_TSTRING: + lua_pushstring(L, u->string); + break; + case LUA_TNUMBER: + lua_pushnumber(L, u->num); + break; + case LUA_TBOOLEAN: + lua_pushboolean(L, (((int)u->num == 0) ? 0 : 1)); + break; + default: /* LUA_TNIL or others */ + lua_pushnil(L); + break; + } + lua_settable(L, -3); + u = u->next; + } + + if (lua_pcall(L, 3, 1, 0)) { + xchat_printf(ph, "failed to call callback for '%s': %s", + word[1], lua_tostring(L, -1) + ); + lua_pop(L, 1); + return XCHAT_EAT_NONE; + } + + if (lua_type(L, -1) != LUA_TNUMBER) { + xchat_printf(ph, "callback for '%s' did not return number...", word[1]); + return XCHAT_EAT_NONE; + } + + i = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + return i; +} + +static int lxc_get_userdata(int pos, struct lxc_cbdata *cb) +{ + struct lxc_userdata *ud, *u; + lua_State *L = cb->state; + int i, t; + + t = lua_type(L, pos); + if (t == LUA_TNIL) + return 1; + if (t != LUA_TTABLE) + return 0; + + i = 1; + while (1) { + lua_pushnumber(L, i); + lua_gettable(L, -2); + + t = lua_type(L, -1); + if (t == LUA_TNIL) { + lua_pop(L, 1); + break; + } + + ud = malloc(sizeof(struct lxc_userdata)); + if (!ud) { + xchat_printf(ph, "lxc_get_userdata(): failed to malloc: %s", + strerror(errno)); + if (cb->data != NULL) { + ud = cb->data; + while (ud) { + u = ud; + ud = ud->next; + free(u); + } + } + /* free(cb); NO! */ + lua_pushnil(L); + return 0; + } + ud->idx = i; + ud->next = NULL; + switch (t) { + case LUA_TSTRING: + ud->string = lua_tostring(L, -1); + ud->type = LUA_TSTRING; + break; + case LUA_TNUMBER: + ud->num = lua_tonumber(L, -1); + ud->type = LUA_TNUMBER; + break; + case LUA_TBOOLEAN: + ud->num = (double)lua_toboolean(L, -1); + ud->type = LUA_TBOOLEAN; + break; + default: + ud->type = LUA_TNIL; + break; + } + lua_pop(L, 1); + + if (cb->data == NULL) + cb->data = ud; + else { + u = cb->data; + while (u->next) + u = u->next; + u->next = ud; + } + i++; + } /* END while (1) */ + return 1; +} + +/* + * lua: xchat.hook_command(name, func_name, prio, help_str, data) + * desc: Adds a new /command. This allows your program to handle commands + * entered at the input box. To capture text without a "/" at the start + * (non-commands), you may hook a special name of "". i.e + * xchat.hook_command( "", ...) + * Starting from version 2.6.8, commands hooked that begin with a + * period ('.') will be hidden in /HELP and /HELP -l. + * ret: true... or false if something went wrong while registering hook + * args: + * * name (string): the name of the new command + * * func_name (string): the lua function to be called when command is + * entered + * * prio (number): use one of the xchat.PRIO_* + * * help_str (string): help for the new command... use nil for no help + * * data (table): table with strings, numbers and booleans, which will + * be passed to func_name as last argument. + */ +static int lxc_hook_command(lua_State *L) +{ + xchat_hook *hook; + const char *help, *command, *func; + double prio; + struct lxc_hooks *hooks, *h; + struct lxc_States *st; + struct lxc_cbdata *cb; + + + if (lua_gettop(L) < 5) /* expand to five args if necessary */ + lua_settop(L, 5); + + cb = malloc(sizeof(struct lxc_cbdata)); + if (!cb) { + xchat_printf(ph, "lxc_hook_command(): failed to malloc: %s", + strerror(errno)); + lua_pushboolean(L, 0); + return 1; + } + + cb->state = L; + cb->data = NULL; + + command = luaL_checkstring(L, 1); + func = luaL_checkstring(L, 2); + cb->func = func; + cb->hook = NULL; + + if (lua_type(L, 3) == LUA_TNIL) + prio = XCHAT_PRI_NORM; + else + prio = luaL_checknumber(L, 3); + + if (lua_type(L, 4) == LUA_TSTRING) { + help = luaL_checkstring(L, 4); + if (strlen(help) == 0) + help = NULL; + } + else + help = NULL; + + if (lxc_get_userdata(5, cb) == 0) + lua_pushboolean(L, 0); + else { + h = malloc(sizeof(struct lxc_hooks)); + if (!h) { + xchat_printf(ph, "lxc_hook_command(): failed to malloc: %s", + strerror(errno)); + lua_pushboolean(L, 0); + return 1; + } + hook = xchat_hook_command(ph, command, prio, lxc_run_hook, help, cb); + h->hook = hook; + h->name = command; + h->next = NULL; + st = lxc_states; + while (st) { + if (st->state == L) { + if (!st->hooks) + st->hooks = h; + else { + hooks = st->hooks; + while (hooks->next) + hooks = hooks->next; + hooks->next = h; + } + break; + } + st = st->next; + } + lua_pushboolean(L, 1); + } + return 1; +} + +/* + * lua: func_name(word, data) + * desc: your previously hooked callback function for hook_print(), + * you must return one of the xchat.EAT_* constants + * ret: none + * args: + * * word (table): the incoming line split into words (max 32) + * (see http://xchat.org/docs/plugin20.html#word) + * * data (table): the data table you passed to the hook_print() / + * as 4th arg + */ +static int lxc_run_print(char *word[], void *data) +{ + struct lxc_cbdata *cb = data; + lua_State *L = cb->state; + int i; + + lua_pushstring(L, cb->func); + lua_gettable(L, LUA_GLOBALSINDEX); + + strcpy(lxc_event_name, word[0]); + lua_newtable(L); + for (i=1; i<=31 && word[i][0]; i++) { + lua_pushnumber(L, i); + lua_pushstring(L, word[i]); + lua_settable(L, -3); + } + + if (lua_pcall(L, 1, 1, 0)) { + xchat_printf(ph, "failed to call callback for '%s': %s", + word[1], lua_tostring(L, -1)); + lua_pop(L, 1); + return 0; + } + + if (lua_type(L, -1) != LUA_TNUMBER) { + xchat_printf(ph, "callback for '%s' didn't return number...", word[1]); + return XCHAT_EAT_NONE; + } + i = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + return i; +} + +/* + * lua: xchat.hook_print(name, func_name, prio, data) + * desc: Registers a function to trap any print events. The event names may + * be any available in the "Advanced > Text Events" window. There are + * also some extra "special" events you may hook using this function, + * see: http://xchat.org/docs/plugin20.html#xchat_hook_print + * ret: true... or false if something went wrong while registering hook + * args: + * * name (string): the name of the new command + * * prio (number): use one of the xchat.PRIO_* + * * func_name (string): the lua function to be called when command is + * entered + * * data (table): table with strings, numbers and booleans, which will + * be passed to func_name as last argument. + */ +static int lxc_hook_print(lua_State *L) +{ + xchat_hook *hook; + struct lxc_hooks *hooks, *h; + struct lxc_States *st; + struct lxc_cbdata *cb = malloc(sizeof(struct lxc_cbdata)); + const char *name, *func; + double prio; + + if (!cb) { + luaL_error(L, "lxc_hook_print(): failed to malloc: %s", strerror(errno)); + return 0; + } + + if (lua_gettop(L) < 4) /* expand to 4 args if necessary */ + lua_settop(L, 4); + + name = luaL_checkstring(L, 1); + func = luaL_checkstring(L, 2); + if (lua_type(L, 3) == LUA_TNIL) + prio = XCHAT_PRI_NORM; + else + prio = luaL_checknumber(L, 3); + + cb->state = L; + cb->func = func; + cb->data = NULL; + cb->hook = NULL; + + if (lxc_get_userdata(4, cb) == 0) + lua_pushboolean(L, 0); + else { + h = malloc(sizeof(struct lxc_hooks)); + if (!h) { + xchat_printf(ph, "lxc_hook_print(): failed to malloc: %s", + strerror(errno)); + lua_pushboolean(L, 0); + return 1; + } + hook = xchat_hook_print(ph, name, prio, lxc_run_print, cb); + h->hook = hook; + h->name = name; + h->next = NULL; + st = lxc_states; + while (st) { + if (st->state == L) { + if (!st->hooks) + st->hooks = h; + else { + hooks = st->hooks; + while (hooks->next) + hooks = hooks->next; + hooks->next = h; + } + break; + } + st = st->next; + } + lua_pushboolean(L, 1); + } + return 1; +} + +/* + * lua: xchat.hook_server(name, func_name, prio, data) + * desc: Registers a function to be called when a certain server event + * occurs. You can use this to trap PRIVMSG, NOTICE, PART, a server + * numeric etc... If you want to hook every line that comes from the + * IRC server, you may use the special name of "RAW LINE". + * ret: true... or false if something went wrong while registering + * args: + * * name (string): the event name / numeric (yes, also as a string) + * * prio (number): one of the xchat.PRIO_* constants + * * func_name (string): the function to be called, when the event + * happens + * * data (table)... see xchat.hook_command() + */ +static int lxc_hook_server(lua_State *L) +{ + xchat_hook *hook; + struct lxc_hooks *hooks, *h; + struct lxc_States *st; + const char *name, *func; + double prio; + + struct lxc_cbdata *cb = malloc(sizeof(struct lxc_cbdata)); + if (!cb) { + xchat_printf(ph, "lxc_hook_server(): failed to malloc: %s", + strerror(errno)); + lua_pushnil(L); + return 1; + } + + if (lua_gettop(L) < 4) /* expand to 4 args if necessary */ + lua_settop(L, 4); + + name = luaL_checkstring(L, 1); + func = luaL_checkstring(L, 2); + if (lua_type(L, 3) == LUA_TNIL) + prio = XCHAT_PRI_NORM; + else + prio = luaL_checknumber(L, 3); + + cb->state = L; + cb->func = func; + cb->data = NULL; + cb->hook = NULL; + + if (lxc_get_userdata(4, cb) == 0) + lua_pushboolean(L, 0); + else { + h = malloc(sizeof(struct lxc_hooks)); + if (!h) { + xchat_printf(ph, "lxc_hook_server(): failed to malloc: %s", + strerror(errno)); + lua_pushboolean(L, 0); + return 1; + } + hook = xchat_hook_server(ph, name, prio, lxc_run_hook, cb); + h->hook = hook; + h->name = name; + h->next = NULL; + st = lxc_states; + while (st) { + if (st->state == L) { + if (!st->hooks) + st->hooks = h; + else { + hooks = st->hooks; + while (hooks->next) + hooks = hooks->next; + hooks->next = h; + } + break; + } + st = st->next; + } + lua_pushboolean(L, 1); + } + return 1; +} + +/* + * lua: xchat.hook_timer(timeout, func_name, data) + * desc: Registers a function to be called every "timeout" milliseconds. + * ret: true (or false on error while registering) + * args: + * * timeout (number): Timeout in milliseconds (1000 is 1 second). + * * func_name (string): Callback function. This will be called + * every "timeout" milliseconds. + * * data (table): see xchat.hook_command() + */ + +static unsigned long long lxc_timer_count = 0; + +static int lxc_hook_timer(lua_State *L) +{ + xchat_hook *hook; + struct lxc_hooks *hooks, *h; + struct lxc_States *st; + double timeout; + const char *func; + char name[32]; + + struct lxc_cbdata *cb = malloc(sizeof(struct lxc_cbdata)); + if (!cb) { + luaL_error(L, "lxc_hook_timer(): failed to malloc: %s", strerror(errno)); + lua_pushnil(L); + return 1; + } + + if (lua_gettop(L) < 3) /* expand to 3 args if necessary */ + lua_settop(L, 3); + + timeout = luaL_checknumber(L, 1); + func = luaL_checkstring(L, 2); + + cb->state = L; + cb->func = func; + cb->data = NULL; + + if (lxc_get_userdata(3, cb) == 0) + lua_pushnil(L); + else { + h = malloc(sizeof(struct lxc_hooks)); + if (!h) { + luaL_error(L, "lxc_hook_timer(): failed to malloc: %s", + strerror(errno)); + return 0; + } + hook = xchat_hook_timer(ph, timeout, lxc_run_timer, cb); + cb->hook = hook; + h->hook = hook; + h->next = NULL; + snprintf(name, 31, "timer%llu", lxc_timer_count++); + h->name = name; + lua_pushstring(L, name); + + st = lxc_states; + while (st) { + if (st->state == L) { + if (!st->hooks) + st->hooks = h; + else { + hooks = st->hooks; + while (hooks->next) + hooks = hooks->next; + hooks->next = h; + } + break; + } + st = st->next; + } + } + return 1; +} + +static void lxc_unhook_timer(lua_State *L, xchat_hook *hook) +{ + struct lxc_States *state; + struct lxc_hooks *hooks, *h, *prev_hook; + struct lxc_cbdata *cb; + struct lxc_userdata *ud, *u; + + prev_hook = NULL; + state = lxc_states; + while (state) { + if (state->state == L) { + hooks = state->hooks; + while (hooks) { + if (hooks->hook == hook) { + h = hooks; + if (prev_hook) + prev_hook->next = hooks->next; + else + state->hooks = hooks->next; + + cb = xchat_unhook(ph, h->hook); + if (cb) { + ud = cb->data; + while (ud) { + u = ud; + ud = ud->next; + free(u); + } + free(cb); + } + + free(h); + return; + } + prev_hook = hooks; + hooks = hooks->next; + } + break; + } + state = state->next; + } +} + +/* + * lua: func_name(data) + * desc: the callback function for the registered timer hook, return + * true to keep this timer going, false to stop it + * ret: none + * args: + * * data (table): the table you gave the hook_timer() as last + * argument + */ + static int lxc_run_timer(void *data) +{ + int ret; + struct lxc_cbdata *cb = data; + xchat_hook *hook = cb->hook; + lua_State *L = cb->state; + + lua_pushstring(L, cb->func); + lua_gettable(L, LUA_GLOBALSINDEX); + + if (lua_pcall(L, 0, 1, 0)) { + xchat_printf(ph, "failed to call timer callback for '%s': %s", + cb->func, lua_tostring(L, -1)); + lua_pop(L, 1); + lxc_unhook_timer(L, hook); + return 0; + } + + if (lua_type(L, -1) != LUA_TBOOLEAN) { + xchat_printf(ph, + "timer callback for '%s' didn't return a boolean", cb->func); + lua_pop(L, 1); + lxc_unhook_timer(L, hook); + return 0; + } + + ret = (lua_toboolean(L, -1) == 0) ? 0 : 1; + lua_pop(L, 1); + + if (ret == 0) + lxc_unhook_timer(L, hook); + + return ret; +} + +/* + * lua: xchat.unhook(name) + * desc: unhooks a previously hooked hook + * ret: true if the hook existed, else false.. + * args: + * * name (string): name of a registered hook (e.g. with + * xchat.hook_command("whois", ... ) you would unhook "whois" + * ... see timer warnings... there's currently just one "timer" + * to unhook + */ +static int lxc_unhook(lua_State *L) +{ + struct lxc_States *state; + struct lxc_hooks *hooks, *h, *prev_hook; + struct lxc_cbdata *cb; + struct lxc_userdata *ud, *u; + int done = 0; + const char *name = luaL_checkstring(L, 1); + + prev_hook = NULL; + state = lxc_states; + while (state) { + if (state->state == L) { + hooks = state->hooks; + while (hooks) { + if (strcasecmp(hooks->name, name) == 0) { + h = hooks; + if (prev_hook) + prev_hook->next = hooks->next; + else + state->hooks = hooks->next; + + cb = xchat_unhook(ph, h->hook); + if (cb) { + ud = cb->data; + while (ud) { + u = ud; + ud = ud->next; + free(u); + } + free(cb); + } + + free(h); + done = 1; + break; + } + prev_hook = hooks; + hooks = hooks->next; + } + break; + } + state = state->next; + } + lua_pushboolean(L, done); + return 1; +} + +static int lxc_event(lua_State *L) +{ + lua_pushstring(L, lxc_event_name); + return 1; +} + +/* + * lua: xchat.command(command) + * desc: executes a command as if it were typed in xchat's input box. + * ret: none + * args: + * * command (string): command to execute, without the forward slash "/". + */ +static int lxc_command(lua_State *L) +{ + const char *command = luaL_checkstring(L, 1); + xchat_command(ph, command); + return 0; +} + +/* + * lua: xchat.print(text) + * desc: Prints some text to the current tab/window. + * ret: none + * args: + * * text (string): the text to print + */ +static int lxc_print(lua_State *L) +{ + const char *txt = luaL_checkstring(L, 1); + // FIXME? const char *txt = lua_tostring(L, 1); + xchat_print(ph, txt); + return 0; +} + +/* + * lua: xchat.emit_print(event, text, [text2, ...]) + * desc: Generates a print event. This can be any event found in the + * Preferences > Advanced > Text Events window. The vararg parameter + * list MUST be no longer than four (4) parameters. + * Special care should be taken when calling this function inside a + * print callback (from xchat.hook_print()), as not to cause endless + * recursion. + * ret: true on success, false on error + * args: + * * event (string): the event name from the references > Advanced > + * Text Events window + * * text (string) + * text2 (string) + * ... (string(s)): + * parameters for the given event + */ +static int lxc_emit_print(lua_State *L) +{ + + int n = lua_gettop(L); + const char *text[5]; + const char *event; + int i = 2; + + if (n > 6) + luaL_error(L, "too many arguments to xchat.emit_print()"); + + event = luaL_checkstring(L, 1); + while (i <= n) { + text[i-2] = luaL_checkstring(L, i); + i++; + } + switch (n-1) { + case 0: + i = xchat_emit_print(ph, event, NULL); + break; + case 1: + i = xchat_emit_print(ph, event, text[0], NULL); + break; + case 2: + i = xchat_emit_print(ph, event, text[0], text[1], NULL); + break; + case 3: + i = xchat_emit_print(ph, event, text[0], text[1], text[2], NULL); + break; + case 4: + i = xchat_emit_print(ph, event, text[0], text[1], text[2], text[3], NULL); + break; + } + lua_pushboolean(L, (i == 0) ? 0 : 1); + return 1; +} + +/* + * lua: xchat.send_modes(targets, sign, mode [, modes_per_line]) + * desc: Sends a number of channel mode changes to the current channel. + * For example, you can Op a whole group of people in one go. It may + * send multiple MODE lines if the request doesn't fit on one. Pass 0 + * for modes_per_line to use the current server's maximum possible. + * This function should only be called while in a channel context. + * ret: none + * args: + * * targets (table): list of names + * * sign (string): mode sign, i.e. "+" or "-", only the first char of + * this is used (currently unchecked if it's really "+" or "-") + * * mode (string): mode char, i.e. "o" for opping, only the first + * char of this is used (currently unchecked, what char) + * * modes_per_line (number): [optional] number of modes per line + */ +static int lxc_send_modes(lua_State *L) +{ + int i = 1; + const char *name, *mode, *sign; + const char *targets[4096]; + int num = 0; /* modes per line */ + + if (!lua_istable(L, 1)) { + luaL_error(L, + "xchat.send_modes(): first argument is not a table: %s", + lua_typename(L, lua_type(L, 1))); + return 0; + } + + while (1) { + lua_pushnumber(L, i); /* push index on stack */ + lua_gettable(L, 1); /* and get the element @ index */ + if (lua_isnil(L, -1)) { /* end of table */ + lua_pop(L, 1); + break; + } + + if (lua_type(L, -1) != LUA_TSTRING) { /* oops, something wrong */ + luaL_error(L, + "lua: xchat.send_modes(): table element #%d not a string: %s", + i, lua_typename(L, lua_type(L, -1))); + lua_pop(L, 1); + return 0; + } + + name = lua_tostring(L, -1); + if (name == NULL) { /* this should not happen, but... */ + lua_pop(L, 1); + break; + } + + targets[i-1] = name; + lua_pop(L, 1); /* take index from stack */ + ++i; + } + + sign = luaL_checkstring(L, 2); + if (sign[0] == '\0' || sign[1] != '\0') { + luaL_error(L, "argument #2 (mode sign) does not have length 1"); + return 0; + } + if ((sign[0] != '+') && (sign[0] != '-')) { + luaL_error(L, "argument #2 (mode sign) is not '+' or '-'"); + return 0; + } + + mode = luaL_checkstring(L, 3); + if (mode[0] == '\0' || mode[1] != '\0') { + luaL_error(L, "argument #3 (mode char) does not have length 1"); + return 0; + } + if (!isalpha((int)mode[0]) || !isascii((int)mode[0])) { + luaL_error(L, "argument #3 is not a valid mode character"); + return 0; + } + + if (lua_gettop(L) == 4) + num = luaL_checknumber(L, 4); + + xchat_send_modes(ph, targets, i-1, num, sign[0], mode[0]); + return 0; +} + +/* + * lua: xchat.find_context(srv, chan) + * desc: Finds a context based on a channel and servername. If servname is nil, + * it finds any channel (or query) by the given name. If channel is nil, + * it finds the front-most tab/window of the given servname. If nil is + * given for both arguments, the currently focused tab/window will be + * returned. + * Changed in 2.6.1. If servname is nil, it finds the channel (or query) + * by the given name in the same server group as the current context. + * If that doesn't exists then find any by the given name. + * ret: context number (DON'T modify) + * args: + * * srv (string or nil): server name + * * chan (string or nil): channel / query name + */ +static int lxc_find_context(lua_State *L) +{ + const char *srv, *chan; + long ctx; + xchat_context *ptr; + + if (lua_type(L, 1) == LUA_TSTRING) { + srv = lua_tostring(L, 1); + if (srv[0] == '\0') + srv = NULL; + } + else + srv = NULL; + + if (lua_type(L, 2) == LUA_TSTRING) { + chan = lua_tostring(L, 2); + if (chan[0] == '\0') + chan = NULL; + } + else + chan = NULL; + + ptr = xchat_find_context(ph, srv, chan); + ctx = (long)ptr; +#ifdef DEBUG + fprintf(stderr, "find_context(): %#lx\n", (long)ptr); +#endif + lua_pushnumber(L, (double)ctx); + return 1; +} + +/* + * lua: xchat.get_context() + * desc: Returns the current context for your plugin. You can use this later + * with xchat_set_context. + * ret: context number ... DON'T modifiy + * args: none + */ +static int lxc_get_context(lua_State *L) +{ + long ptr; + xchat_context *ctx = xchat_get_context(ph); + ptr = (long)ctx; +#ifdef DEBUG + fprintf(stderr, "get_context(): %#lx\n", ptr); +#endif + lua_pushnumber(L, (double)ptr); + return 1; +} + +/* + * lua: xchat.get_info(id) + * desc: Returns information based on your current context. + * ret: the requested string or nil on error + * args: + * * id (string): the wanted information + */ +static int lxc_get_info(lua_State *L) +{ + const char *id = luaL_checkstring(L, 1); + const char *value = xchat_get_info(ph, id); + if (value == NULL) + lua_pushnil(L); + else + lua_pushstring(L, value); + return 1; +} + +/* + * lua: xchat.get_prefs(name) + * desc: Provides xchat's setting information (that which is available + * through the /set command). A few extra bits of information are + * available that don't appear in the /set list, currently they are: + * * state_cursor: Current input-box cursor position (characters, + * not bytes). Since 2.4.2. + * *id: Unique server id. Since 2.6.1. + * ret: returns the string/number/boolean for the given config var + * or nil on error + * args: + * * name (string): the wanted setting's name + */ +static int lxc_get_prefs(lua_State *L) +{ + int i; + const char *str; + const char *name = luaL_checkstring(L, 1); + /* + * luckily we can store anything in a lua var... this makes the + * xchat lua api more user friendly ;-) + */ + switch (xchat_get_prefs(ph, name, &str, &i)) { + case 0: /* request failed */ + lua_pushnil(L); + break; + case 1: + lua_pushstring(L, str); + break; + case 2: + lua_pushnumber(L, (double)i); + break; + case 3: + lua_pushboolean(L, i); + break; + default: /* doesn't happen if xchat's C-API doesn't change ;-) */ + lua_pushnil(L); + break; + } + return 1; +} + +/* + * lua: xchat.set_context(ctx) + * desc: Changes your current context to the one given. + * ret: true or false + * args: + * * ctx (number): the context (e.g. from xchat.get_context()) + */ +static int lxc_set_context(lua_State *L) +{ + double ctx = luaL_checknumber(L, 1); +#ifdef DEBUG + fprintf(stderr, "set_context(): %#lx\n", (long)ctx); +#endif + xchat_context *xc = (void *)(long)ctx; + lua_pushboolean(L, xchat_set_context(ph, xc)); + return 1; +} + +/* + * lua: xchat.nickcmp(name1, name2) + * desc: Performs a nick name comparision, based on the current server + * connection. This might be a RFC1459 compliant string compare, or + * plain ascii (in the case of DALNet). Use this to compare channels + * and nicknames. The function works the same way as strcasecmp. + * ret: number ess than, equal to, or greater than zero if name1 is found, + * respectively, to be less than, to match, or be greater than name2. + * args: + * * name1 (string): nick or channel name + * * name2 (string): nick or channel name + */ +static int lxc_nickcmp(lua_State *L) +{ + const char *n1 = luaL_checkstring(L, 1); + const char *n2 = luaL_checkstring(L, 2); + lua_pushnumber(L, (double)xchat_nickcmp(ph, n1, n2)); + return 1; +} + +/* + * lua: xchat.list_get(name) + * desc: http://xchat.org/docs/plugin20.html#lists :) + * time_t values are stored as number => e.g. + * os.date("%Y-%m-%d, %H:%M:%S", time_t_value) + * pointers (channel -> context) as number... untested if this works + * ret: table with tables with all keys=Name, value=(Type)... or nil on error + * args: + * * name (string): the wanted list + */ +static int lxc_list_get(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + int i; /* item index */ + int l; /* list index */ + const char *str; + double num; + time_t date; + long ptr; + const char *const *fields = xchat_list_fields(ph, name); + xchat_list *list = xchat_list_get(ph, name); + + if (!list) { + lua_pushnil(L); + return 1; + } + lua_newtable(L); + /* this is like the perl plugin does it ;-) */ + l = 1; + while (xchat_list_next(ph, list)) { + i = 0; + lua_pushnumber(L, l); + lua_newtable(L); + while (fields[i] != NULL) { + switch (fields[i][0]) { + case 's': + str = xchat_list_str(ph, list, fields [i] + 1); + lua_pushstring(L, fields[i]+1); + if (str != NULL) + lua_pushstring(L, str); + else + lua_pushnil(L); + lua_settable(L, -3); + break; + case 'p': + ptr = (long)xchat_list_str(ph, list, fields [i] + 1); + num = (double)ptr; + lua_pushstring(L, fields[i]+1); + lua_pushnumber(L, num); + lua_settable(L, -3); + break; + case 'i': + num = (double)xchat_list_int(ph, list, fields[i] + 1); + lua_pushstring(L, fields[i]+1); + lua_pushnumber(L, num); + lua_settable(L, -3); + break; + case 't': + date = xchat_list_time(ph, list, fields[i] + 1); + lua_pushstring(L, fields[i]+1); + lua_pushnumber(L, (double)date); + lua_settable(L, -3); + break; + } + i++; + } + lua_settable(L, -3); + l++; + } + xchat_list_free(ph, list); + return 1; +} + +/* + * lua: xchat.list_fields(name) + * desc: returns the possible keys for name as table + * ret: table ;-> + * args: + * * name (string): name of the wanted list ("channels", "dcc", + * "ignore", "notify", "users") + */ +static int lxc_list_fields(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + const char *const *fields = xchat_list_fields(ph, name); + int i; + + lua_newtable(L); + i = 0; + while (fields[i] != NULL) { + lua_pushnumber(L, i); + /* first char is the type ... */ + lua_pushstring(L, fields[i]+1); + lua_settable(L, -3); + } + return 1; +} + +/* + * lua: xchat.gettext(str) + * desc: + */ +static int lxc_gettext(lua_State *L) +{ +#if defined(_WIN32) || defined(LXC_XCHAT_GETTEXT) + lua_pushstring(L, xchat_gettext(ph, luaL_checkstring(L, 1))); +#else + const char *dom; + const char *msgid = luaL_checkstring(L, 1); + if (lua_type(L,2) == LUA_TSTRING) + dom = lua_tostring(L, 2); + else + dom = "xchat"; + lua_pushstring(L, dgettext(dom, msgid)); +#endif + return 1; +} + +/* + * lua: xchat.bits(flags) + * desc: returns a table of booleans if the bit at index (err... index-1) is + * set + * ret: table of booleans + * args: + * * flags (number) + */ +static int lxc_bits(lua_State *L) +{ + int flags = luaL_checknumber(L, 1); + int i; + lua_pop(L, 1); + lua_newtable(L); + for (i=0; i<16; i++) { /* at time of writing, the highest index was 9 ... */ + lua_pushnumber(L, i+1); + lua_pushboolean(L, ((1<<i) & flags) == 0 ? 0 : 1); + lua_settable(L, -3); + } + return 1; +} +/* + * vim: ts=3 noexpandtab + */ diff --git a/plugins/lua/makefile.mak b/plugins/lua/makefile.mak new file mode 100644 index 00000000..fbc94072 --- /dev/null +++ b/plugins/lua/makefile.mak @@ -0,0 +1,20 @@ +include "..\..\src\makeinc.mak" + +DIRENTLIB = ..\..\src\common\dirent.lib + +all: lua.obj lua.def + link $(LDFLAGS) $(LIBS) /dll /out:xclua.dll $(LUALIB).lib $(DIRENTLIB) /def:lua.def lua.obj + +lua.def: + echo EXPORTS > lua.def + echo xchat_plugin_init >> lua.def + echo xchat_plugin_deinit >> lua.def + +lua.obj: lua.c makefile.mak + cl $(CFLAGS) /I.. /Dsnprintf=g_snprintf lua.c + +clean: + del *.obj + del *.dll + del *.exp + del *.lib diff --git a/plugins/makefile.mak b/plugins/makefile.mak new file mode 100644 index 00000000..d15c7f84 --- /dev/null +++ b/plugins/makefile.mak @@ -0,0 +1,66 @@ +all: + @cd checksum + @-$(MAKE) /nologo /s /f makefile.mak $@ + @cd ..\lua + @-$(MAKE) /nologo /s /f makefile.mak $@ + @cd ..\mpcinfo + @-$(MAKE) /nologo /s /f makefile.mak $@ + @cd ..\python + @-$(MAKE) /nologo /s /f makefile.mak $@ + @cd ..\tcl + @-$(MAKE) /nologo /s /f makefile.mak $@ + @cd ..\upd + @-$(MAKE) /nologo /s /f makefile.mak $@ +# @cd ..\xdcc +# @-$(MAKE) /nologo /s /f makefile.mak $@ + @cd ..\xtray + @-$(MAKE) /nologo /s /f makefile.mak $@ + @cd ..\winamp + @-$(MAKE) /nologo /s /f makefile.mak $@ + +clean: + @del checksum\*.def + @del checksum\*.dll + @del checksum\*.exp + @del checksum\*.lib + @del checksum\*.obj + @del lua\*.def + @del lua\*.dll + @del lua\*.exp + @del lua\*.lib + @del lua\*.obj + @del mpcinfo\*.def + @del mpcinfo\*.dll + @del mpcinfo\*.exp + @del mpcinfo\*.lib + @del mpcinfo\*.obj + @del python\*.def + @del python\*.dll + @del python\*.exp + @del python\*.lib + @del python\*.obj + @del tcl\*.def + @del tcl\*.dll + @del tcl\*.exp + @del tcl\*.lib + @del tcl\*.obj + @del upd\*.def + @del upd\*.dll + @del upd\*.exp + @del upd\*.lib + @del upd\*.obj +# @del xdcc\*.def +# @del xdcc\*.dll +# @del xdcc\*.exp +# @del xdcc\*.lib +# @del xdcc\*.obj + @del xtray\*.def + @del xtray\*.dll + @del xtray\*.exp + @del xtray\*.lib + @del xtray\*.obj + @del winamp\*.def + @del winamp\*.dll + @del winamp\*.exp + @del winamp\*.lib + @del winamp\*.obj diff --git a/plugins/mpcinfo/functions.c b/plugins/mpcinfo/functions.c new file mode 100644 index 00000000..ed0632d4 --- /dev/null +++ b/plugins/mpcinfo/functions.c @@ -0,0 +1,167 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* +typedef int (*MYPROC)(HWND,HWND,char*,char*,BOOL,BOOL); + +int dllProc(char *name, char *data){ + HINSTANCE hinstLib; + hinstLib = LoadLibrary("mpcinfo"); + //MYPROC proc; + int res; + if (hinstLib != NULL){ + //proc = ; + if ((MYPROC) GetProcAddress(hinstLib, name)!=NULL){ + res=(MYPROC)(NULL,NULL,data,NULL,TRUE,TRUE); + } + else{fprintf(stderr,"can't get proc: %s\n",name);res=-2;} + } + else{fprintf(stderr,"can't access dll\n");return -1;} + FreeLibrary(hinstLib); + return res; +} +*/ + +/* +int dllProc(char *name, char *data) +{ + static HMODULE lib = NULL; + if (!lib) + { + lib = LoadLibraryA ("mpcinfo"); + if (!lib) + { + return FALSE; + } + FreeLibrary (lib); + } + + return TRUE; +} +*/ + +char *split(char *text, char seperator){ + //if (DEBUG==1) putlog("splitting"); + int i;int pos=-1; + for (i=0;i<strlen(text);i++){ + if (text[i]==seperator){pos=i;i=strlen(text)+1;} + } + if (pos==-1) return text; + text[pos]=0; + return &(text[pos+1]); +} + +int endsWith(char *text, char *suffix){ + char *tmp=strstr(text,suffix); + if (tmp==NULL) return 0; + if (strlen(tmp)==strlen(suffix)) return 1; + return 0; +} + +int inStr(char *s1, int sl1, char *s2){ + //if (DEBUG==1) putlog("checking instr"); + int i;int j; + for(i=0;i<sl1-strlen(s2);i++){ + for (j=0;j<strlen(s2);j++){ + if (s1[i+j]!=s2[j]) j=strlen(s2)+2; + } + if (j==strlen(s2)) return i; + } + return -1; +} + +static char *subString(char *text, int first, int length, int spcKill){ +//if (DEBUG==1) putlog("creating substring"); + char *ret=(char*) calloc (length+1,sizeof(char)); //malloc(sizeof(char)*(length+1)); + int i; + ret[length]=0; + for (i=0;i<length;i++){ + ret[i]=text[i+first]; + //if (ret[i]==0) ret[i]='0'; + } + if (spcKill==1){ + for (i=length-1;i>=0;i--){ + if (ret[i]==32) ret[i]=0; + else i=-1; + } + } + //if (DEBUG==1) putlog("substring created"); + return ret; +} + +static char *substring(char *text, int first, int length){return subString(text,first,length,0);} + + +char *readLine(FILE *f){ + //if (DEBUG==1) putlog("reading line from file"); + char *buffer=(char*)calloc(1024,sizeof(char)); //malloc(sizeof(char)*1024); + int pos=0; + int cc=0; + while((cc!=EOF)&&(pos<1024)&&(cc!=10)){ + cc=fgetc(f); + if ((cc!=10)&&(cc!=13)){ + if (cc==EOF) buffer[pos]=0; + else buffer[pos]=(char)cc;pos++; + } + } + if (buffer[pos]==EOF) xchat_printf(ph,"EOF: %i\n",pos); + return buffer; +} + +char *toUpper(char *text){ + //if (DEBUG==1) putlog("converting text to upper case"); + char *ret=(char*) calloc(strlen(text)+1,sizeof(char)); + int i; + for (i=0;i<strlen(text);i++) ret[i]=toupper(text[i]); + ret[strlen(text)]=0; + //if (DEBUG==1) putlog("uc done"); + return ret; +} + +static char *str3cat(char *s1, char *s2, char *s3){ + //if (DEBUG==1) putlog("cating 3 strings"); + char *ret=(char*)calloc(strlen(s1)+strlen(s2)+strlen(s3)+1,sizeof(char)); + strcpy(ret,s1);strcat(ret,s2);strcat(ret,s3); + ret[strlen(s1)+strlen(s2)+strlen(s3)]=0; + //if (DEBUG==1) putlog("strings cated"); + return ret; +} + +char *replace(char *text, char *from, char *to){ + //if (DEBUG==1) putlog("replacing"); + char *ret=(char*)calloc( strlen(text)+(strlen(to)-strlen(from)),sizeof(char)); + char *left; + char *right; + int pos=inStr(text,strlen(text),from); + if (pos!=-1){ + left=substring(text,0,pos); + right=substring(text,pos+strlen(from),strlen(text)-(pos+strlen(from))); + ret=str3cat(left,to,right); + return replace(ret,from,to); + } + //if (DEBUG==1) putlog("replaced"); + return text; +} + +char *intReplaceF(char *text, char *from, int to, char *form){ + //if (DEBUG==1) putlog("replaceF"); + char *buffer=(char*) calloc(16,sizeof(char)); + sprintf(buffer,form,to); + //if (DEBUG==1) putlog("replaceF done"); + return replace(text,from,buffer); +} + +char *intReplace(char *text, char *from, int to){return intReplaceF(text,from,to,"%i");} diff --git a/plugins/mpcinfo/makefile.mak b/plugins/mpcinfo/makefile.mak new file mode 100644 index 00000000..4a8a2763 --- /dev/null +++ b/plugins/mpcinfo/makefile.mak @@ -0,0 +1,18 @@ +include "..\..\src\makeinc.mak" + +all: mpcinfo.obj mpcinfo.def + link $(LDFLAGS) $(LIBS) /dll /out:xcmpcinfo.dll /def:mpcinfo.def mpcinfo.obj + +mpcinfo.def: + echo EXPORTS > mpcinfo.def + echo xchat_plugin_init >> mpcinfo.def + echo xchat_plugin_deinit >> mpcinfo.def + +mpcinfo.obj: mpcinfo.c makefile.mak + cl $(CFLAGS) $(GLIB) /I.. mpcinfo.c + +clean: + del *.obj + del *.dll + del *.exp + del *.lib diff --git a/plugins/mpcinfo/mp3Info.c b/plugins/mpcinfo/mp3Info.c new file mode 100644 index 00000000..f75ba9c4 --- /dev/null +++ b/plugins/mpcinfo/mp3Info.c @@ -0,0 +1,361 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +//#include <stdio.h> +#include <sys/stat.h> +//#include "functions.c" + +struct tagInfo{ + int mode; + int cbr; + int bitrate; + unsigned int freq; + char *artist; + char *title; + char *album; + char *comment; + char *genre; + //int genre; + //int track; +}; + +static int RATES[2][3][15]={ + {//mpeg2 + {-1,8,16,24,32,64,80,56,64,128,160,112,128,256,320},//layer3 (V2) + {-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384},//layer2 (V2) + {-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448},//layer1 (V2) + }, + {//mpeg1 + {-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320},//layer3 (V1) + {-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384},//layer2 (V1) + {-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448},//layer1 (V1) + }}; +static int FREQS[2][4]={{22050,24000,16000,-1},{44100,48000,32000,-1}}; +//static double FRATES[]={38.5,32.5,27.8,0.0}; + +static char GENRES[][50]={"Blues","Classic Rock","Country","Dance","Disco","Funk","Grunge","Hip-Hop","Jazz","Metal", +"New Age","Oldies","Other","Pop","R&B","Rap","Reggae","Rock","Techno","Industrial", +"Alternative","Ska","Death Metal","Pranks","Soundtrack","Euro-Techno","Ambient","Trip-Hop","Vocal","Jazz+Funk", +"Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound Clip","Gospel","Noise", +"AlternRock","Bass","Soul","Punk","Space","Meditative","Instrumental Pop","Instrumental Rock","Ethnic","Gothic", +"Darkwave","Techno-Industrial","Electronic","Pop-Folk","Eurodance","Dream","Southern Rock","Comedy","Cult","Gangsta", +"Top 40","Christian Rap","Pop/Funk","Jungle","Native American","Cabaret","New Wave","Psychadelic","Rave","Showtunes", +"Trailer","Lo-Fi","Tribal","Acid Punk","Acid Jazz","Polka","Retro","Musical","Rock & Roll","Hard Rock", + +//################## END OF OFFICIAL ID3 TAGS, WINAMP TAGS BELOW ######################################## + +"Folk","Folk/Rock","National Folk","Swing","Fast Fusion","Bebob","Latin","Revival","Celtic","Bluegrass", +"Avantgarde","Gothic Rock","Progressive Rock","Psychedelic Rock","Symphonic Rock","Slow Rock","Big Band","Chorus","Easy Listening","Acoustic", +"Humour","Speech","Chanson","Opera","Chamber Music","Sonata","Symphony","Booty Bass","Primus","Porn Groove", +"Satire","Slow Jam","Club","Tango","Samba","Folklore","Ballad","Poweer Ballad","Rhytmic Soul","Freestyle", +"Duet","Punk Rock","Drum Solo","A Capela","Euro-House","Dance Hall", + +//################## FOUND AT http://en.wikipedia.org/wiki/ID3 ########################################### + +"Goa","Drum & Bass","Club-House","Hardcore", +"Terror","Indie","BritPop","Negerpunk","Polsk Punk","Beat","Christian Gangsta Rap","Heavy Metal","Black Metal","Crossover", +"Contemporary Christian","Christian Rock","Merengue","Salsa","Thrash Metal","Anime","JPop","Synthpop" + +}; + +static char MODES [][13]={"Stereo","Joint-Stereo","Dual-Channel","Mono"}; + +int iPow(int x, int y){return (int)(pow((double)x,(double) y));} + +int str2int(char *text){ + //if (DEBUG==1) putlog("converting string to int"); + int i; + int ret=0; + for (i=1;i<=strlen(text);i++){ + if ((text[strlen(text)-i]>57)||(text[strlen(text)-i]<48)){ + xchat_printf(ph,"invalid char in string: %i",text[strlen(text)-i]); + return 255; + } + ret+=((int)text[strlen(text)-i]-48)*iPow(10,i-1); + } + //xchat_printf(ph, "str2int(%s)=%i",text,ret); + //if (DEBUG==1) putlog("int converted"); + return ret; +} +/* +static int getSize(char *file){ + //if (DEBUG==1) putlog("reading filesize"); + struct stat info; + if (stat(file,&info)!=0) return -1; + return info.st_size; +}*/ +/* +int inStr(char *s1, int sl1, char *s2){ + //if (DEBUG==1) putlog("checking instr"); + int i;int j; + for(i=0;i<sl1-strlen(s2);i++){ + for (j=0;j<strlen(s2);j++){ + if (s1[i+j]!=s2[j]) j=strlen(s2)+2; + } + if (j==strlen(s2)) return i; + } + return -1; +} + +static char *subString(char *text, int first, int length, int spcKill){ +//if (DEBUG==1) putlog("creating substring"); + char *ret=(char*) calloc (length+1,sizeof(char)); //malloc(sizeof(char)*(length+1)); + ret[length]=0;int i; + for (i=0;i<length;i++){ + ret[i]=text[i+first]; + //if (ret[i]==0) ret[i]='0'; + } + if (spcKill==1){ + for (i=length-1;i>=0;i--){ + if (ret[i]==32) ret[i]=0; + else i=-1; + } + } + //if (DEBUG==1) putlog("substring created"); + return ret; +} + +static char *substring(char *text, int first, int length){return subString(text,first,length,0);} //1 +*/ + +static char *tagExtract(char *tag, int tagLen, char* info){ +//if (DEBUG==1) putlog("extracting tag"); + int pos, len, i; + pos=inStr(tag,tagLen,info); +//xchat_printf(ph,"pos=%i",pos); + if (pos==-1) return "";//NULL; + //printf("position of %s = %i\n",info,pos); + len=0; + //for (i=pos;i<pos+10;i++)printf("tag[%i]=%i \n",i,tag[i]); + for (i=0;i<4;i++) { + len+=tag[pos+strlen(info)+i]*iPow(255,3-i); + } + //printf("Tag-Length: %i\n",len); + if (strcmp("COMM",info)!=0) return substring(tag,pos+7+strlen(info),len-1);//11 + return substring(tag,pos+7+strlen(info),len-1);//11 + //char *ct=substring(tag,pos+7+strlen(info),len-1);//11 + //return substring(ct,strlen(ct)+1,len-1-strlen(ct)); //<-- do not understand, what i did here :( + +} + +struct tagInfo readID3V1(char *file){ +//if (DEBUG==1) putlog("reading ID3V1"); + FILE *f; + struct tagInfo ret; + int res, i, c, val; + char *tag; + char *id; + char *tmp; + tag = (char*) malloc(sizeof(char)*129); + ret.artist=NULL; + f=fopen(file,"rb"); + if (f==NULL){ + xchat_print(ph,"file not found while trying to read id3v1"); + //if (DEBUG==1) putlog("file not found while trying to read id3v1"); + return ret; + } + //int offset=getSize(file)-128; + res=fseek(f,-128,SEEK_END); + if (res!=0) {printf("seek failed\n");fclose(f);return ret;} + //long int pos=ftell(f); + //printf("position= %li\n",pos); + for (i=0;i<128;i++) { + c=fgetc(f); + if (c==EOF) {xchat_printf(ph,"read ID3V1 failed\n");fclose(f);return ret;} + tag[i]=(char)c; + } + fclose(f); + //printf("tag readed: \n"); + id=substring(tag,0,3); + //printf("header: %s\n",id); + if (strcmp(id,"TAG")!=0){xchat_printf(ph,"no id3 v1 found\n");return ret;} + ret.title=subString(tag,3,30,1); + ret.artist=subString(tag,33,30,1); + ret.album=subString(tag,63,30,1); + ret.comment=subString(tag,97,30,1); + tmp=substring(tag,127,1); + //ret.genre=substring(tag,127,1); + + val=(int)tmp[0]; + if (val<0)val+=256; + //xchat_printf(ph, "tmp[0]=%i (%i)",val,tmp[0]); + if ((val<148)&&(val>=0)) + ret.genre=GENRES[val];//#############changed + else { + ret.genre="unknown"; + //xchat_printf(ph, "tmp[0]=%i (%i)",val,tmp[0]); + } + //xchat_printf(ph, "tmp: \"%s\" -> %i",tmp,tmp[0]); + //xchat_printf(ph,"genre \"%s\"",ret.genre); + //if (DEBUG==1) putlog("id3v1 extracted"); + return ret; +} + +char *extractID3Genre(char *tag){ + //if (DEBUG==1) putlog("extracting id3 genre"); + if (tag[strlen(tag)-1]==')'){ + tag[strlen(tag)-1]=0; + tag=&tag[1]; + return GENRES[str2int(tag)]; + //return tag; + } + else{ + int i; + //xchat_print(ph, "Using 2 criteria"); + for (i=0;i<strlen(tag);i++){ + if (tag[i]==')'){ tag=&tag[i]+1;return tag;} + //return tag; + } + } + return "[152] failed"; +} + +struct tagInfo readID3V2(char *file){ +//if (DEBUG==1) putlog("reading id3v2"); + FILE *f; + int i, c, len; + char header[10]; + char *tag; + struct tagInfo ret; + + f = fopen(file,"rb"); + //xchat_printf(ph,"file :%s",file); + if (f==NULL) + { + xchat_print(ph,"file not found whilt trying to read ID3V2"); + //if (DEBUG==1)putlog("file not found while trying to read ID3V2"); + return ret; + } + + ret.artist=NULL; + for (i=0;i<10;i++){ + c=fgetc(f); + if (c==EOF){ + //putlog("found eof while reading id3v2"); + return ret; + } + header[i]=(char)c; + } + if (strstr(header,"ID3")==header){ + //xchat_printf(ph,"found id3v2\n"); + len=0; + for (i=6;i<10;i++) len+=(int)header[i]*iPow(256,9-i); + + //char *tag=(char*)malloc(sizeof(char)*len); + tag=(char*) calloc(len,sizeof(char)); //malloc(sizeof(char)*len); + for (i=0;i<len;i++){c=fgetc(f);tag[i]=(char)c;} +//xchat_printf(ph,"tag length: %i\n",len); +//xchat_printf(ph,"tag: %s\n",tag); + fclose(f); + ret.comment=tagExtract(tag,len,"COMM"); +//xchat_printf(ph,"Comment: %s\n",ret.comment); + ret.genre=tagExtract(tag,len,"TCON"); + //if (strcmp(ret.genre,"(127)")==0) ret.genre="unknown"; +//xchat_printf(ph, "ret.genre = %s",ret.genre); + if ((ret.genre!=NULL)&&(ret.genre[0]=='(')) ret.genre=extractID3Genre(ret.genre); +//xchat_printf(ph,"genre: %s\n",ret.genre); + ret.title=tagExtract(tag,len,"TIT2"); +//xchat_printf(ph,"Title: %s\n",ret.title); + ret.album=tagExtract(tag,len,"TALB"); +//xchat_printf(ph,"Album: %s\n",ret.album); + ret.artist=tagExtract(tag,len,"TPE1"); +//xchat_printf(ph,"Artist: %s\n",ret.artist); + } + else{fclose(f);printf("no id3v2 tag found\n"); return ret;} + //printf("id2v2 done\n"); + //if (DEBUG==1) putlog("id3v2 readed"); + return ret; +} + +struct tagInfo readHeader(char *file){ +//if (DEBUG==1) putlog("reading header"); + FILE *f; + //int buffer[5120]; + int versionB, layerB, bitrateB, freqB, modeB; + int header[4]; + int count=0; + int cc=0; + struct tagInfo info; + info.artist=NULL; + + f = fopen(file,"rb"); + if (f==NULL) + { + xchat_print(ph,"file not found while trying to read mp3 header"); + //if (DEBUG==1) putlog("file not found while trying to read mp3 header"); + return info; + } + //struct tagInfo tagv2 + + info=readID3V2(file); + //struct tagInfo tagv1;//=readID3V1(file); + //if (tagv2.artist!=NULL){info=tagv2;} + //else { + if (info.artist==NULL){ + //printf("searching for id3v1\n"); + //tagv1=readID3V1(file); + info=readID3V1(file); //##################### + } + /* + if (tagv1.artist!=NULL){ + //printf("Artist: %s\nTitle: %s\nAlbum: %s\nComment: %s\nGenre: %s\n",tagv1.artist,tagv1.title,tagv1.album,tagv1.comment,tagv1.genre); + info=tagv1; + } + */ + while ((count<5120)&&(cc!=EOF)&&(cc!=255)) {cc=fgetc(f);count++;} + if ((cc==EOF)||(count==5119)) printf("no header found\n"); + else { + //printf("located header at %i\n",count); + header[0]=255; + for (count=1;count<4;count++){ + header[count]=fgetc(f); + //printf("header[%i]=%i\n",count,header[count]); + } + versionB=(header[1]&8)>>3; + layerB=(header[1]&6)>>1; + bitrateB=(header[2]&240)>>4; //4 + freqB=(header[2]&12)>>2;//2 + modeB=(header[3]&192)>>6;//6 + //printf("Mpeg: %i\nLayer: %i\nBitrate: %i\nFreq: %i\nMode: %i\n",versionB, layerB, bitrateB, freqB, modeB); + //int Bitrate=RATES[versionB][layerB-1][bitrateB]; + //int Freq=FREQS[versionB][freqB]; + info.bitrate=RATES[versionB][layerB-1][bitrateB]; + info.freq=FREQS[versionB][freqB]; + info.mode=modeB; + } + fclose(f); + //if (DEBUG==1) putlog("header readed"); + return info; +} +/* +static void printMp3Info(char *file){ + //printf("\nScanning Mp3-File for Informations: %s\n",file); + //printf("size:\t%10d byte\n",getSize(file)); + struct tagInfo info =readHeader(file); + printf("%s | %10d",file,getSize(file)); + if (info.bitrate>0){ + //printf("Bitrate: %i\nFreq: %i\nMode: %s\n",info.bitrate,info.freq,MODES[info.mode]); + printf(" | %i kbps | %i kHz | %s",info.bitrate,info.freq,MODES[info.mode]); + //if (info.artist!=NULL) printf("\nArtist: %s\nTitle: %s\nAlbum: %s\nComment: %s\nGenre: %s\n",info.artist,info.title,info.album,info.comment,info.genre); + if (info.artist!=NULL) { + printf("| %s | %s | %s | %s | %s",info.artist,info.title,info.album,info.comment,info.genre); + //printf("| %s ",info.title);//,info.title,info.album,info.comment,info.genre + } + } + printf("\n"); + +} +*/ diff --git a/plugins/mpcinfo/mpcInfo.c b/plugins/mpcinfo/mpcInfo.c new file mode 100644 index 00000000..e467e516 --- /dev/null +++ b/plugins/mpcinfo/mpcInfo.c @@ -0,0 +1,149 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +//static int DEBUG=0; +static char *VERSION="0.0.6"; + +#include <windows.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#include "xchat-plugin.h" +static xchat_plugin *ph; + +#include "functions.c" +#include "mp3Info.c" +#include "oggInfo.c" +#include "theme.c" + +static int print_themes (char *word[], char *word_eol[], void *userdata){ + printThemes(); + return XCHAT_EAT_ALL; +} + +static int mpc_themeReload(char *word[], char *word_eol[], void *userdata){ + themeInit(); + loadThemes(); + return XCHAT_EAT_ALL; +} + +static int mpc_tell(char *word[], char *word_eol[], void *userdata){ + char *tTitle, *zero, *oggLine, *line; + struct tagInfo info; + HWND hwnd = FindWindow("MediaPlayerClassicW",NULL); + if (hwnd==0) {xchat_command(ph, randomLine(notRunTheme));return XCHAT_EAT_ALL;} + + tTitle=(char*)malloc(sizeof(char)*1024); + GetWindowText(hwnd, tTitle, 1024); + zero=strstr(tTitle," - Media Player Classic"); + if (zero!=NULL) zero[0]=0; + else xchat_print(ph,"pattern not found"); + + if ((tTitle[1]==':')&&(tTitle[2]=='\\')){ + //xchat_print(ph,"seams to be full path"); + if (endsWith(tTitle,".mp3")==1){ + //xchat_print(ph,"seams to be a mp3 file"); + info = readHeader(tTitle); + + if ((info.artist!=NULL)&&(strcmp(info.artist,"")!=0)){ + char *mode=MODES[info.mode]; + //xchat_printf(ph,"mode: %s\n",mode); + char *mp3Line=randomLine(mp3Theme); + mp3Line=replace(mp3Line,"%art",info.artist); + mp3Line=replace(mp3Line,"%tit",info.title); + mp3Line=replace(mp3Line,"%alb",info.album); + mp3Line=replace(mp3Line,"%com",info.comment); + mp3Line=replace(mp3Line,"%gen",info.genre); + //mp3Line=replace(mp3Line,"%time",pos); + //mp3Line=replace(mp3Line,"%length",len); + //mp3Line=replace(mp3Line,"%ver",waVers); + //mp3Line=intReplace(mp3Line,"%br",br); + //mp3Line=intReplace(mp3Line,"%frq",frq); + + mp3Line=intReplace(mp3Line,"%br",info.bitrate); + mp3Line=intReplace(mp3Line,"%frq",info.freq); + mp3Line=replace(mp3Line,"%mode",mode); + //mp3Line=replace(mp3Line,"%size",size); + //mp3Line=intReplace(mp3Line,"%perc",perc); + //mp3Line=replace(mp3Line,"%plTitle",title); + mp3Line=replace(mp3Line,"%file",tTitle); + xchat_command(ph, mp3Line); + return XCHAT_EAT_ALL; + } + } + if (endsWith(tTitle,".ogg")==1){ + xchat_printf(ph,"Ogg detected\n"); + info = getOggHeader(tTitle); + if (info.artist!=NULL){ + char *cbr; + if (info.cbr==1) cbr="CBR"; else cbr="VBR"; + oggLine=randomLine(oggTheme); + //if (cue==1) oggLine=cueLine; + //xchat_printf(ph,"ogg-line: %s\n",oggLine); + oggLine=replace(oggLine,"%art",info.artist); + oggLine=replace(oggLine,"%tit",info.title); + oggLine=replace(oggLine,"%alb",info.album); + oggLine=replace(oggLine,"%com",info.comment); + oggLine=replace(oggLine,"%gen",info.genre); + //oggLine=replace(oggLine,"%time",pos); + //oggLine=replace(oggLine,"%length",len); + //oggLine=replace(oggLine,"%ver",waVers); + oggLine=intReplace(oggLine,"%chan",info.mode); + oggLine=replace(oggLine,"%cbr",cbr); + oggLine=intReplace(oggLine,"%br",info.bitrate/1000);//br); + oggLine=intReplace(oggLine,"%frq",info.freq); + //oggLine=replace(oggLine,"%size",size); + //oggLine=intReplace(oggLine,"%perc",perc); + //oggLine=replace(oggLine,"%plTitle",title); + oggLine=replace(oggLine,"%file",tTitle); + xchat_command(ph, oggLine); + return XCHAT_EAT_ALL; + } + } + } + line=randomLine(titleTheme); + line=replace(line,"%title", tTitle); + xchat_command(ph,line); + return XCHAT_EAT_ALL; +} + +int xchat_plugin_init(xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg){ + ph = plugin_handle; + *plugin_name = "mpcInfo"; + *plugin_desc = "Information-Script for Media Player Classic"; + *plugin_version=VERSION; + + xchat_hook_command(ph, "mpc", XCHAT_PRI_NORM, mpc_tell,"no help text", 0); + xchat_hook_command(ph, "mpc_themes", XCHAT_PRI_NORM, print_themes,"no help text", 0); + xchat_hook_command(ph, "mpc_reloadthemes", XCHAT_PRI_NORM, mpc_themeReload,"no help text", 0); + xchat_command (ph, "MENU -ietc\\music.png ADD \"Window/Display Current Song (MPC)\" \"MPC\""); + + themeInit(); + loadThemes(); + xchat_printf(ph, "%s %s plugin loaded\n",*plugin_name, VERSION); + + return 1; +} + +int +xchat_plugin_deinit (void) +{ + xchat_command (ph, "MENU DEL \"Window/Display Current Song (MPC)\""); + xchat_print (ph, "mpcInfo plugin unloaded\n"); + return 1; +} diff --git a/plugins/mpcinfo/oggInfo.c b/plugins/mpcinfo/oggInfo.c new file mode 100644 index 00000000..83c2beb5 --- /dev/null +++ b/plugins/mpcinfo/oggInfo.c @@ -0,0 +1,122 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +static int getOggInt(char *buff, int beg, int bytes){ +//if (DEBUG==1) putlog("getOggInt"); + int ret=0; + int i; + for (i=0;i<bytes;i++){ + if (buff[i+beg]>=0) ret+=buff[i+beg]*iPow(256,i);else ret+=(256+buff[i+beg])*iPow(256,i); + //printf("[%i]=%i\n",i,buff[i+beg]); + } + return ret; +} + +static char *upperStr(char *text){ +//if (DEBUG==1) putlog("converting text to uc"); + //printf("upperStr(%s)\n",text); + int i; + char *ret=(char*) malloc(sizeof(char)*(strlen(text)+1)); + ret[strlen(text)]=0; + for (i=0;i<strlen(text);i++) ret[i]=toupper(text[i]); + //printf("Result: %s\n",ret); + return ret; +} + +struct tagInfo getOggHeader(char *file){ +//if (DEBUG==1) putlog("reading ogg header"); + char header[4096]; + int i, c; + int h1pos, h3pos, maxBr, nomBr, minBr, pos, count, tagLen; + char *sub; + char *name; + char *val; + char *HEADLOC1, *HEADLOC3, *HEADLOC5; + FILE *f; + struct tagInfo info; + + info.artist=NULL; + f = fopen(file,"rb"); + if (f==NULL){ + xchat_print(ph,"file not found while trying to read ogg header"); + //if (DEBUG==1) putlog("file not found while trying to read ogg header"); + return info; + } + + for (i=0;i<4095;i++) {c=fgetc(f);header[i]=(char)c;} + fclose(f); + HEADLOC1="_vorbis"; + HEADLOC1[0]=1; + HEADLOC3="_vorbis"; + HEADLOC3[0]=3; + HEADLOC5="_vorbis"; + HEADLOC5[0]=5; + h1pos=inStr(header,4096,HEADLOC1); + h3pos=inStr(header,4096,HEADLOC3); + //int h5pos=inStr(header,4096,HEADLOC5); //not needed + + //printf("loc1: %i\n",h1pos);printf("loc3: %i\n",h3pos);printf("loc5: %i\n",h5pos); + maxBr=getOggInt(header,h1pos+7+9,4); + nomBr=getOggInt(header,h1pos+7+13,4); + minBr=getOggInt(header,h1pos+7+17,4); + info.freq=getOggInt(header,h1pos+7+5,4); + info.mode=header[h1pos+7+4]; + info.bitrate=nomBr; + if (((maxBr==nomBr)&&(nomBr=minBr))||((minBr==0)&&(maxBr==0))||((minBr=-1)&&(maxBr=-1)) )info.cbr=1;else info.cbr=0; + printf("bitrates: %i|%i|%i\n",maxBr,nomBr,minBr); + printf("freq: %i\n",info.freq); + pos=h3pos+7; + pos+=getOggInt(header,pos,4)+4; + count=getOggInt(header,pos,4); + //printf("tags: %i\n",count); + pos+=4; + + info.artist=NULL;info.title=NULL;info.album=NULL;info.comment=NULL;info.genre=NULL; + for (i=0;i<count;i++){ + tagLen=getOggInt(header,pos,4); + //printf("taglength: %i\n",tagLen); + sub=substring(header,pos+4,tagLen); + name=upperStr(substring(sub,0,inStr(sub,tagLen,"="))); + val=substring(sub,inStr(sub,tagLen,"=")+1,tagLen-inStr(sub,tagLen,"=")-1); + //printf("Tag: %s\n",sub); + //printf("Name: %s\n",name); + //printf("value: %s\n",val); + if (strcmp(name,"ARTIST")==0) info.artist=val; + if (strcmp(name,"TITLE")==0) info.title=val; + if (strcmp(name,"ALBUM")==0) info.album=val; + if (strcmp(name,"GENRE")==0) info.genre=val; + if (strcmp(name,"COMMENT")==0) info.comment=val; + pos+=4+tagLen; + } + if (info.artist==NULL) info.artist=""; + if (info.album==NULL) info.album =""; + if (info.title==NULL) info.title=""; + if (info.genre==NULL) info.genre=""; + if (info.comment==NULL) info.comment=""; + + printf("Artist: %s\nTitle: %s\nAlbum: %s\n",info.artist,info.title, info.album); + printf("Genre: %s\nComment: %s\nMode: %i\nCBR: %i\n",info.genre,info.comment,info.mode,info.cbr); + //if (DEBUG==1) putlog("ogg header readed"); + return info; +} + +/* +void printOggInfo(char *file){ + printf("Scanning Ogg-File for Informations: %s\n",file); + printf("size:\t%10d byte\n",getSize(file)); + struct tagInfo info = getOggHeader(file); +} +*/ diff --git a/plugins/mpcinfo/theme.c b/plugins/mpcinfo/theme.c new file mode 100644 index 00000000..000c00b1 --- /dev/null +++ b/plugins/mpcinfo/theme.c @@ -0,0 +1,136 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <time.h> + +struct theme{ + int size; + char **line; +}; + +static struct theme notRunTheme; +static struct theme titleTheme; +static struct theme mp3Theme; +static struct theme oggTheme; + + +void themeInit(){ + //if (DEBUG==1) putlog("init theme"); + /*mp3Theme.size=0;oggTheme.size=0;cueTheme.size=0;streamTheme.size=0;etcTheme.size=0; + stopTheme.size=0;pauseTheme.size=0;*/ + + notRunTheme.size=0;titleTheme.size=0; + srand((unsigned int)time((time_t *)NULL)); + //if (DEBUG==1) putlog("theme init done"); +} + +void printTheme(struct theme data){ + int i; + for (i=0;i<data.size;i++) xchat_printf(ph,"line[%i]=%s\n",i,data.line[i]); +} + +void printThemes(){ + xchat_printf(ph,"\nNotRun-Theme:\n");printTheme(notRunTheme); + xchat_printf(ph,"\nMP3-Theme:\n");printTheme(mp3Theme); + xchat_printf(ph,"\nOGG-Theme:\n");printTheme(oggTheme); + xchat_printf(ph,"\nTitle-Theme:\n");printTheme(titleTheme); +} + +void cbFix(char *line){ + //if (DEBUG==1) putlog("cbfix"); + int i, j; + for (i=0;i<strlen(line);i++){ + if (line[i]=='%'){ + if ((line[i+1]=='C')||(line[i+1]=='B')||(line[i+1]=='U')||(line[i+1]=='O')||(line[i+1]=='R')){ + if(line[i+1]=='C') line[i]=3; + if(line[i+1]=='B') line[i]=2; + if(line[i+1]=='U') line[i]=37; + if(line[i+1]=='O') line[i]=17; + if(line[i+1]=='R') line[i]=26; + + for (j=i+1;j<strlen(line)-1;j++) line[j]=line[j+1]; + line[strlen(line)-1]=0; + } + } + } + //if (DEBUG==1) putlog("cbfix done"); +} + +struct theme themeAdd(struct theme data, char *info){ + //if (DEBUG==1) putlog("adding theme"); + struct theme ret; + char **newLine=(char **)calloc(data.size+1,sizeof(char*)); + int i; + for (i=0;i<data.size;i++) newLine[i]=data.line[i]; + cbFix(info); + newLine[data.size]=info; + ret.line=newLine;ret.size=data.size+1; + //if (DEBUG==1) putlog("theme added"); + return ret; +} + +void loadThemes(){ + char *hDir, *hFile, *line, *val; + FILE *f; + xchat_print(ph,"loading themes\n"); + hDir=(char*)calloc(1024,sizeof(char)); + strcpy(hDir,xchat_get_info(ph,"xchatdirfs")); + hFile=str3cat(hDir,"\\","mpcInfo.theme.txt"); + f = fopen(hFile,"r"); + if(f==NULL) + { + xchat_print(ph,"no theme in homedir, checking global theme"); + f=fopen("mpcInfo.theme.txt","r"); + } + //xchat_printf(ph,"file_desc: %p\n",f); + if (f==NULL) xchat_print(ph, "no theme found, using hardcoded\n"); + else { + if (f > 0) + { + line=" "; + } else + { + line="\0"; + } + + while (line[0]!=0) + { + line=readLine(f); + val=split(line,'='); + printf("line: %s\n",line); + printf("val: %s\n",val); + if (strcmp(toUpper(line),"OFF_LINE")==0) notRunTheme=themeAdd(notRunTheme,val); + if (strcmp(toUpper(line),"TITLE_LINE")==0) titleTheme=themeAdd(titleTheme,val); + if (strcmp(toUpper(line),"MP3_LINE")==0) mp3Theme=themeAdd(mp3Theme,val); + if (strcmp(toUpper(line),"OGG_LINE")==0) mp3Theme=themeAdd(oggTheme,val); + } + fclose(f); + xchat_print(ph, "theme loaded successfull\n"); + } + if (notRunTheme.size==0) notRunTheme=themeAdd(notRunTheme,"say Media Player Classic not running"); + if (titleTheme.size==0) titleTheme=themeAdd(titleTheme,"say Playing %title in Media Player Classic"); + if (mp3Theme.size==0) mp3Theme=themeAdd(mp3Theme,"me listens to %art with %tit from %alb [%gen|%br kbps|%frq kHz|%mode] in Media Player Classic "); + if (oggTheme.size==0) oggTheme=themeAdd(oggTheme,"me listens to %art with %tit from %alb [%gen|%br kbps|%frq kHz|%chan channels] in Media Player Classic "); + //mp3Theme=themeAdd(mp3Theme,"me listens to %art with %tit from %alb [%time|%length|%perc%|%br kbps|%frq kHz|%mode] in Media Player Classic "); +} + +int rnd(int max){ + return rand()%max; +} + +char *randomLine(struct theme data){ + return data.line[rnd(data.size)]; +} diff --git a/plugins/perl/makefile-510.mak b/plugins/perl/makefile-510.mak new file mode 100644 index 00000000..60f6b2dc --- /dev/null +++ b/plugins/perl/makefile-510.mak @@ -0,0 +1,30 @@ +include "..\..\src\makeinc.mak" + +DIRENTLIB = ..\..\src\common\dirent.lib +TARGET = $(PERL510OUTPUT) + +all: $(TARGET) + +perl.def: + echo EXPORTS > perl.def + echo xchat_plugin_init >> perl.def + echo xchat_plugin_deinit >> perl.def + echo xchat_plugin_get_info >> perl.def + +perl.obj: perl.c + $(CC) $(CFLAGS) perl.c $(GLIB) /I$(PERL510PATH) /I.. /DPERL_DLL=\"$(PERL510LIB).dll\" + +perl.c: xchat.pm.h + +xchat.pm.h: lib/Xchat.pm lib/IRC.pm + perl.exe generate_header + +$(TARGET): perl.obj perl.def + $(LINK) /DLL /out:$(TARGET) perl.obj $(LDFLAGS) $(PERL510LIB).lib /libpath:$(PERL510PATH) /DELAYLOAD:$(PERL510LIB).dll $(DIRENTLIB) DELAYIMP.LIB user32.lib shell32.lib advapi32.lib /def:perl.def + +clean: + @del $(TARGET) + @del *.obj + @del perl.def + @del *.lib + @del *.exp diff --git a/plugins/perl/makefile-512.mak b/plugins/perl/makefile-512.mak new file mode 100644 index 00000000..e4887ff9 --- /dev/null +++ b/plugins/perl/makefile-512.mak @@ -0,0 +1,30 @@ +include "..\..\src\makeinc.mak" + +DIRENTLIB = ..\..\src\common\dirent.lib +TARGET = $(PERL512OUTPUT) + +all: $(TARGET) + +perl.def: + echo EXPORTS > perl.def + echo xchat_plugin_init >> perl.def + echo xchat_plugin_deinit >> perl.def + echo xchat_plugin_get_info >> perl.def + +perl.obj: perl.c + $(CC) $(CFLAGS) perl.c $(GLIB) /I$(PERL512PATH) /I.. /DPERL_DLL=\"$(PERL512LIB).dll\" + +perl.c: xchat.pm.h + +xchat.pm.h: lib/Xchat.pm lib/IRC.pm + perl.exe generate_header + +$(TARGET): perl.obj perl.def + $(LINK) /DLL /out:$(TARGET) perl.obj $(LDFLAGS) $(PERL512LIB).lib /libpath:$(PERL512PATH) /DELAYLOAD:$(PERL512LIB).dll $(DIRENTLIB) DELAYIMP.LIB user32.lib shell32.lib advapi32.lib /def:perl.def + +clean: + @del $(TARGET) + @del *.obj + @del perl.def + @del *.lib + @del *.exp diff --git a/plugins/perl/perl.c b/plugins/perl/perl.c index a29ce65a..761566f9 100644 --- a/plugins/perl/perl.c +++ b/plugins/perl/perl.c @@ -22,12 +22,15 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> -#include <dirent.h> #ifdef ENABLE_NLS #include <locale.h> #endif #ifdef WIN32 #include <windows.h> +#define _INC_DIRENT +#include "../../src/common/dirent.h" +#else +#include <dirent.h> #endif #undef PACKAGE @@ -1342,7 +1345,11 @@ perl_load_file (char *filename) if (GetLastError () == ERROR_BAD_EXE_FORMAT) /* http://forum.xchat.org/viewtopic.php?t=3277 */ thread_mbox ("Cannot use this " PERL_DLL "\n\n" +#ifdef _WIN64 + "64-bit ActivePerl is required."); +#else "32-bit ActivePerl is required."); +#endif else { /* a lot of people install this old version */ lib = LoadLibraryA ("perl56.dll"); @@ -1357,7 +1364,7 @@ perl_load_file (char *filename) thread_mbox ("Cannot open " PERL_DLL "\n\n" "You must have ActivePerl " PERL_REQUIRED_VERSION " installed in order to\n" "run perl scripts.\n\n" - "http://www.activestate.com/ActivePerl/\n\n" + "http://www.activestate.com/activeperl/downloads\n\n" "Make sure perl's bin directory is in your PATH."); } } diff --git a/plugins/python/makefile.mak b/plugins/python/makefile.mak new file mode 100644 index 00000000..8cbba3f5 --- /dev/null +++ b/plugins/python/makefile.mak @@ -0,0 +1,25 @@ +include "..\..\src\makeinc.mak" + +DIRENTLIB = ..\..\src\common\dirent.lib +TARGET = $(PYTHONOUTPUT) + +all: $(TARGET) + +python.def: + echo EXPORTS > python.def + echo xchat_plugin_init >> python.def + echo xchat_plugin_deinit >> python.def + echo xchat_plugin_get_info >> python.def + +python.obj: python.c + $(CC) $(CFLAGS) /I.. /Dusleep=_sleep /DPATH_MAX=255 python.c $(GLIB) /I$(PYTHONPATH)\include /DPYTHON_DLL=\"$(PYTHONLIB).dll\" + +$(TARGET): python.obj python.def + $(LINK) /dll /out:$(TARGET) $(LDFLAGS) python.obj /libpath:$(PYTHONPATH)\libs $(PYTHONLIB).lib $(DIRENTLIB) $(LIBS) /def:python.def + +clean: + del $(TARGET) + del *.obj + del python.def + del *.lib + del *.exp diff --git a/plugins/python/python.c b/plugins/python/python.c index fd682082..55adf989 100644 --- a/plugins/python/python.c +++ b/plugins/python/python.c @@ -53,10 +53,10 @@ #include <glib.h> #include <string.h> -#include <unistd.h> #include <stdlib.h> #include <sys/types.h> -#include <dirent.h> +#include "../../src/common/dirent.h" +#include "../../config.h" #include "xchat-plugin.h" #include "Python.h" @@ -68,7 +68,7 @@ #ifdef WIN32 #undef WITH_THREAD /* Thread support locks up xchat on Win32. */ -#define VERSION "0.8/2.4" /* Linked to python24.dll */ +#define VERSION "0.8/2.7" /* Linked to python27.dll */ #else #define VERSION "0.8" #endif diff --git a/plugins/tcl/makefile.mak b/plugins/tcl/makefile.mak new file mode 100644 index 00000000..c88f5c4f --- /dev/null +++ b/plugins/tcl/makefile.mak @@ -0,0 +1,22 @@ +include "..\..\src\makeinc.mak" + +TARGET = $(TCLOUTPUT) + +all: $(TARGET) + +tcl.def: + echo EXPORTS > tcl.def + echo xchat_plugin_init >> tcl.def + echo xchat_plugin_deinit >> tcl.def + echo xchat_plugin_get_info >> tcl.def + +tclplugin.obj: tclplugin.c + $(CC) $(CFLAGS) /I.. tclplugin.c /I$(TCLPATH)\include /DTCL_DLL=\"$(TCLLIB).dll\" + +$(TARGET): tclplugin.obj tcl.def + $(LINK) /dll /out:$(TARGET) $(LDFLAGS) tclplugin.obj /libpath:$(TCLPATH)\lib $(TCLLIB).lib /delayload:$(TCLLIB).dll delayimp.lib /def:tcl.def + +clean: + del $(TARGET) + del *.obj + del tcl.def diff --git a/plugins/tcl/tclplugin.c b/plugins/tcl/tclplugin.c index 17dc7556..1f9b33e7 100644 --- a/plugins/tcl/tclplugin.c +++ b/plugins/tcl/tclplugin.c @@ -32,8 +32,6 @@ static char RCSID[] = "$Id: tclplugin.c,v 1.64 2010/03/10 04:24:16 mooooooo Exp #include <windows.h> #define bzero(mem, sz) memset((mem), 0, (sz)) #define bcopy(src, dest, count) memmove((dest), (src), (count)) -#else -#include <unistd.h> #endif #include "xchat-plugin.h" @@ -2221,7 +2219,7 @@ int xchat_plugin_init(xchat_plugin * plugin_handle, char **plugin_name, char **p #ifdef WIN32 lib = LoadLibraryA(TCL_DLL); if (!lib) { - xchat_print(ph, "You must have ActiveTCL installed in order to run Tcl scripts.\n" "http://aspn.activestate.com/ASPN/Tcl/\n" "Make sure Tcl's bin directory is in your PATH.\n\n"); + xchat_print(ph, "You must have ActiveTCL 8.5 installed in order to run Tcl scripts.\n" "http://www.activestate.com/activetcl/downloads\n" "Make sure Tcl's bin directory is in your PATH.\n\n"); return 0; } FreeLibrary(lib); diff --git a/plugins/upd/makefile.mak b/plugins/upd/makefile.mak new file mode 100644 index 00000000..34b54cb8 --- /dev/null +++ b/plugins/upd/makefile.mak @@ -0,0 +1,18 @@ +include "..\..\src\makeinc.mak" + +all: upd.obj upd.def + link $(LDFLAGS) $(LIBS) /dll /out:xcupd.dll /def:upd.def upd.obj + +upd.def: + echo EXPORTS > upd.def + echo xchat_plugin_init >> upd.def + echo xchat_plugin_deinit >> upd.def + +upd.obj: upd.c makefile.mak + cl $(CFLAGS) $(GLIB) /I.. upd.c + +clean: + del *.obj + del *.dll + del *.exp + del *.lib diff --git a/plugins/upd/upd.c b/plugins/upd/upd.c new file mode 100644 index 00000000..001cd9d2 --- /dev/null +++ b/plugins/upd/upd.c @@ -0,0 +1,111 @@ +/* XChat-WDK + * Copyright (c) 2010-2011 Berke Viktor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <windows.h> +#include <wininet.h> + +#include "xchat-plugin.h" + +static xchat_plugin *ph; /* plugin handle */ + +static char* +check_version () +{ + HINTERNET hINet, hFile; + hINet = InternetOpen ("Update Checker", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + + if (!hINet) + { + return "Unknown"; + } + + hFile = InternetOpenUrl (hINet, "http://xchat-wdk.googlecode.com/hg/version.txt", NULL, 0, 0, 0); + + if (hFile) + { + static char buffer[1024]; + DWORD dwRead; + while (InternetReadFile (hFile, buffer, 1023, &dwRead)) + { + if (dwRead == 0) + { + break; + } + buffer[dwRead] = 0; + } + + InternetCloseHandle (hFile); + return buffer; + } + + InternetCloseHandle (hINet); + return "Unknown"; +} + +static void +print_version () +{ + char *version = check_version (); + + if (strcmp (version, xchat_get_info (ph, "wdk_version")) == 0) + { + xchat_printf (ph, "You have the latest version of XChat-WDK installed!\n"); + } + else if (strcmp (version, "Unknown") == 0) + { + xchat_printf (ph, "Unable to check for XChat-WDK updates!\n"); + } + else + { + xchat_printf (ph, "An XChat-WDK update is available! You can download it from here:\nhttp://xchat-wdk.googlecode.com/files/XChat-WDK%%20%s.exe\n", version); + } +} + +int +xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg) +{ + ph = plugin_handle; + + *plugin_name = "Update Checker"; + *plugin_desc = "Plugin for checking for XChat-WDK updates"; + *plugin_version = "1.2"; + + xchat_hook_command (ph, "UPDCHK", XCHAT_PRI_NORM, print_version, 0, 0); + xchat_command (ph, "MENU -ietc\\download.png ADD \"Help/Check for Updates\" \"UPDCHK\""); + + xchat_print (ph, "Update Checker plugin loaded\n"); + print_version (); + + return 1; /* return 1 for success */ +} + +int +xchat_plugin_deinit (void) +{ + xchat_command (ph, "MENU DEL \"Help/Check for updates\""); + xchat_print (ph, "Update Checker plugin unloaded\n"); + return 1; +} diff --git a/plugins/winamp/makefile.mak b/plugins/winamp/makefile.mak new file mode 100644 index 00000000..79adf87e --- /dev/null +++ b/plugins/winamp/makefile.mak @@ -0,0 +1,18 @@ +include "..\..\src\makeinc.mak" + +all: winamp.obj winamp.def + link $(LDFLAGS) $(LIBS) /dll /out:xcwinamp.dll /def:winamp.def winamp.obj + +winamp.def: + echo EXPORTS > winamp.def + echo xchat_plugin_init >> winamp.def + echo xchat_plugin_deinit >> winamp.def + +winamp.obj: winamp.c makefile.mak + cl $(CFLAGS) /I.. winamp.c + +clean: + del *.obj + del *.dll + del *.exp + del *.lib diff --git a/plugins/winamp/winamp.c b/plugins/winamp/winamp.c new file mode 100644 index 00000000..7201a875 --- /dev/null +++ b/plugins/winamp/winamp.c @@ -0,0 +1,189 @@ +/********************* Winamp Plugin 0.3****************************** + * + * Distribution: GPL + * + * Originally written by: Leo - leo.nard@free.fr + * Modified by: SilvereX - SilvereX@karklas.mif.vu.lt + * Modified again by: Derek Buitenhuis - daemon404@gmail.com + * Modified yet again by: Berke Viktor - berkeviktor@aol.com + *********************************************************************/ + +#include "windows.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "xchat-plugin.h" + +#define PLAYING 1 +#define PAUSED 3 + +static xchat_plugin *ph; /* plugin handle */ + +BOOL winamp_found = FALSE; + +int status = 0; + +/* Slightly modified from X-Chat's log_escape_strcpy */ +static char * +song_strcpy (char *dest, char *src) +{ + while (*src) + { + *dest = *src; + dest++; + src++; + + if (*src == '%') + { + dest[0] = '%'; + dest++; + } + } + + dest[0] = 0; + return dest - 1; +} + +static int +winamp(char *word[], char *word_eol[], void *userdata) +{ + +char current_play[2048], *p; +char p_esc[2048]; +char cur_esc[2048]; +char truc[2048]; +HWND hwndWinamp = FindWindow("Winamp v1.x",NULL); + + if (hwndWinamp) + { + { + if (!stricmp("PAUSE", word[2])) + { + if (SendMessage(hwndWinamp,WM_USER, 0, 104)) + { + SendMessage(hwndWinamp, WM_COMMAND, 40046, 0); + + if (SendMessage(hwndWinamp, WM_USER, 0, 104) == PLAYING) + xchat_printf(ph, "Winamp: playing"); + else + xchat_printf(ph, "Winamp: paused"); + } + } + else + if (!stricmp("STOP", word[2])) + { + SendMessage(hwndWinamp, WM_COMMAND, 40047, 0); + xchat_printf(ph, "Winamp: stopped"); + } + else + if (!stricmp("PLAY", word[2])) + { + SendMessage(hwndWinamp, WM_COMMAND, 40045, 0); + xchat_printf(ph, "Winamp: playing"); + } + else + + if (!stricmp("NEXT", word[2])) + { + SendMessage(hwndWinamp, WM_COMMAND, 40048, 0); + xchat_printf(ph, "Winamp: next playlist entry"); + } + else + + if (!stricmp("PREV", word[2])) + { + SendMessage(hwndWinamp, WM_COMMAND, 40044, 0); + xchat_printf(ph, "Winamp: previous playlist entry"); + } + else + + if (!stricmp("START", word[2])) + { + SendMessage(hwndWinamp, WM_COMMAND, 40154, 0); + xchat_printf(ph, "Winamp: playlist start"); + } + + else + + if (!word_eol[2][0]) + { + GetWindowText(hwndWinamp, current_play, sizeof(current_play)); + + if (strchr(current_play, '-')) + { + + p = current_play + strlen(current_play) - 8; + while (p >= current_play) + { + if (!strnicmp(p, "- Winamp", 8)) break; + p--; + } + + if (p >= current_play) p--; + + while (p >= current_play && *p == ' ') p--; + *++p=0; + + + p = strchr(current_play, '.') + 1; + + song_strcpy(p_esc, p); + song_strcpy(cur_esc, current_play); + + if (p) + { + sprintf(truc, "me is now playing:%s", p_esc); + } + else + { + sprintf(truc, "me is now playing:%s", cur_esc); + } + + xchat_commandf(ph, truc); + + } + else xchat_print(ph, "Winamp: Nothing being played."); + } + else + xchat_printf(ph, "Usage: /WINAMP [PAUSE|PLAY|STOP|NEXT|PREV|START]\n"); + } + + } + else + { + xchat_print(ph, "Winamp not found.\n"); + } + return XCHAT_EAT_ALL; +} + +int +xchat_plugin_init(xchat_plugin *plugin_handle, + char **plugin_name, + char **plugin_desc, + char **plugin_version, + char *arg) +{ + /* we need to save this for use with any xchat_* functions */ + ph = plugin_handle; + + *plugin_name = "Winamp"; + *plugin_desc = "Winamp plugin for XChat"; + *plugin_version = "0.5"; + + xchat_hook_command (ph, "WINAMP", XCHAT_PRI_NORM, winamp, "Usage: /WINAMP [PAUSE|PLAY|STOP|NEXT|PREV|START] - control Winamp or show what's currently playing", 0); + xchat_command (ph, "MENU -ietc\\music.png ADD \"Window/Display Current Song (Winamp)\" \"WINAMP\""); + + xchat_print (ph, "Winamp plugin loaded\n"); + + return 1; /* return 1 for success */ +} + +int +xchat_plugin_deinit(void) +{ + xchat_command (ph, "MENU DEL \"Window/Display Current Song (Winamp)\""); + xchat_print (ph, "Winamp plugin unloaded\n"); + return 1; +} diff --git a/plugins/xdcc/makefile.mak b/plugins/xdcc/makefile.mak new file mode 100644 index 00000000..0a12347e --- /dev/null +++ b/plugins/xdcc/makefile.mak @@ -0,0 +1,18 @@ +include "..\..\src\makeinc.mak" + +all: xdcc.obj xdcc.def + link $(LDFLAGS) $(LIBS) /dll /out:xcxdcc.dll /def:xdcc.def xdcc.obj + +xdcc.def: + echo EXPORTS > xdcc.def + echo xchat_plugin_init >> xdcc.def + echo xchat_plugin_deinit >> xdcc.def + +xdcc.obj: xdcc.c makefile.mak + cl $(CFLAGS) $(GLIB) /I.. xdcc.c + +clean: + del *.obj + del *.dll + del *.exp + del *.lib diff --git a/plugins/xdcc/xdcc.c b/plugins/xdcc/xdcc.c index 147a3c33..a8fda540 100644 --- a/plugins/xdcc/xdcc.c +++ b/plugins/xdcc/xdcc.c @@ -2,11 +2,11 @@ #include <glib.h> #include <string.h> -#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include "xchat-plugin.h" +#include "../../src/common/xchat.h" static xchat_plugin *ph; /* plugin handle */ diff --git a/plugins/xtray/bitmaps/sd.bmp b/plugins/xtray/bitmaps/sd.bmp new file mode 100644 index 00000000..9d6b7f95 --- /dev/null +++ b/plugins/xtray/bitmaps/sd.bmp Binary files differdiff --git a/plugins/xtray/callbacks.cpp b/plugins/xtray/callbacks.cpp new file mode 100644 index 00000000..636c114e --- /dev/null +++ b/plugins/xtray/callbacks.cpp @@ -0,0 +1,734 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _WIN32_IE 0x0601 + +#include <windows.h> +#include <stdio.h> +#include <commctrl.h> +#include <tchar.h> +#include "utility.h" +#include "plugin.h" +#include "xtray.h" +#include "xchat.h" +#include "callbacks.h" +#include "resource.h" +#include "sdTray.h" +#include "sdAlerts.h" + +HWND g_hPrefTabEvents; +HWND g_hPrefTabSettings; +HWND g_hPrefTabAlerts; +HWND g_hPrefTabAbout; +bool g_bCanQuit; +int g_iIsActive = 1; + + +BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) +{ + TCHAR szTitle[10]; + GetWindowText(hWnd, szTitle, 9); + + if(_tcsstr(szTitle, _T("XChat ["))) + { + g_hXchatWnd = hWnd; + return false; + } + + return true; +} + +/***********************************************************************************************/ +/******* our xchat event call back, get the name and info for each event and save it ***********/ +/******* for our alerts later ***********/ +/***********************************************************************************************/ +int event_cb(char *word[], void *userdata) +{ + int iEvent = (int)userdata; + + if(iEvent > 10 && iEvent != 21) + return XCHAT_EAT_NONE; + + /***************************************************************************************/ + /***** if the window is minimized or if we're allowed to show alerts when its not **/ + /***** and if the option to show the specified alert is true and if we're even **/ + /***** allowed to show alerts at all then we show them (a bit confusing but it works) **/ + /***************************************************************************************/ + if(((g_iIsActive == 0) || !(g_dwPrefs & (1<<PREF_OSBWM))) && (g_dwPrefs & (1<<PREF_AMAE)) && (g_dwPrefs & (1<<iEvent))) + { + /*********************************/ + /*********** Our Buffers *********/ + /*********************************/ + char szInfo[512]; + char szName[64]; + DWORD dwInfoFlags; + int iTime = g_iTime*1000; + char *szTemp = NULL; + + if(g_dwPrefs & (1<<PREF_KAOI)) + { + iTime = 0; + } + + switch(iEvent) + { + case CHAN_HILIGHT: + _snprintf(szInfo, 512, "%s:\r\n%s", word[1], word[2]); + _snprintf(szName, 64, "Hilight"); + dwInfoFlags = NIIF_INFO; + break; + case CHAN_MESSAGE: + _snprintf(szInfo, 512, "%s:\r\n%s", word[1], word[2]); + _snprintf(szName, 64, "Channel Message"); + dwInfoFlags = NIIF_INFO; + break; + case CHAN_TOPIC_CHANGE: + _snprintf(szInfo, 512, "%s has changed the topic to %s", word[1], word[2]); + _snprintf(szName, 64, "Topic Change: %s", word[3]); + dwInfoFlags = NIIF_INFO; + break; + case CHAN_INVITE: + _snprintf(szInfo, 512, "%s has invited you into %s", word[1], word[2]); + _snprintf(szName, 64, "Invite"); + dwInfoFlags = NIIF_INFO; + break; + case CHAN_KICKED: + _snprintf(szInfo, 512, "Kicked from %s by %s:\r\n%s", word[2], word[3], word[4]); + _snprintf(szName, 64, "Kick"); + dwInfoFlags = NIIF_WARNING; + break; + case CHAN_BANNED: + _snprintf(szInfo, 512, "Cannot join #%s You are banned.", word[1]); + _snprintf(szName, 64, "Banned"); + dwInfoFlags = NIIF_WARNING; + break; + case CTCP_GENERIC: + _snprintf(szInfo, 512, "%s:\r\nCTCP %s", word[2], word[1]); + _snprintf(szName, 64, "CTCP"); + dwInfoFlags = NIIF_INFO; + break; + case PMSG_RECEIVE: + _snprintf(szInfo, 512, "%s:\r\n%s", word[1], word[2]); + _snprintf(szName, 64, "Private Message"); + dwInfoFlags = NIIF_INFO; + break; + case SERV_DISCONNECT: + _snprintf(szInfo, 512, "Disconnected\r\nError: %s", word[1]); + _snprintf(szName, 64, "Disconnect"); + dwInfoFlags = NIIF_ERROR; + break; + case SERV_KILLED: + _snprintf(szInfo, 512, "Killed(%s(%s))", word[1], word[2]); + _snprintf(szName, 64, "Server Admin has killed you"); + dwInfoFlags = NIIF_ERROR; + break; + case SERV_NOTICE: + _snprintf(szInfo, 512, "Notice:\r\n%s: %s", word[1], word[2]); + _snprintf(szName, 64, "Notice"); + dwInfoFlags = NIIF_INFO; + break; + case 11: + _snprintf(szInfo, 512, ":\r\n%s: %s", word[1], word[2]); + _snprintf(szName, 64, "Notice"); + dwInfoFlags = NIIF_INFO; + break; + } + + /**************************************************************************************/ + /***** Use windows instead of balloons, and if its a window should we keep it open ****/ + /***** indefinately? ****/ + /**************************************************************************************/ + szTemp = xchat_strip_color(szInfo); + + if(g_dwPrefs & (1<<PREF_UWIOB)) + { + sdSystemAlert((HINSTANCE)g_hInstance, IDD_ALERT, szTemp, szName, iTime); + } + else + { + ShowBalloon(g_hXchatWnd, 1, szTemp, szName, iTime, dwInfoFlags); + } + + free(szTemp); + } + + if(g_dwPrefs & (1<<PREF_BLINK)) + { + BlinkIcon(g_hXchatWnd, 1, g_hIcons[0], g_hIcons[(iEvent+1)], 700, 5); + + } + + /***********************************/ + /***** pass the events to xchat ****/ + /***********************************/ + return XCHAT_EAT_NONE; +} + +int command_cb(char *word[], char *word_eol[], void *userdata) +{ + char szInfo[512]; + char *szTemp = NULL; + int iTime = g_iTime*1000; + + _snprintf(szInfo, 512, word_eol[2]); + szTemp = xchat_strip_color(szInfo); + + if(g_dwPrefs & (1<<PREF_KAOI)) + { + iTime = 0; + } + + if(((g_iIsActive == 0) || !(g_dwPrefs & (1<<PREF_OSBWM))) && (g_dwPrefs & (1<<PREF_AMAE))) + { + if(g_dwPrefs & (1<<PREF_UWIOB)) + { + sdSystemAlert((HINSTANCE)g_hInstance, IDD_ALERT, szTemp, "Alert", iTime); + } + else + { + ShowBalloon(g_hXchatWnd, 1, szTemp, "Alert", iTime, NIIF_INFO); + } + } + + free(szTemp); + + return XCHAT_EAT_ALL; +} + +LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch(msg) + { + case WM_CLOSE: + { + if((g_dwPrefs & (1<<PREF_MIOC)) && (g_bCanQuit == false)) + { + /*******************************************/ + /**** to autoaway or not to autoaway... ***/ + /*******************************************/ + if(g_dwPrefs & (1<<PREF_AOM)) + { + xchat_globally_away(g_szAway); + } + + /**************************************************/ + /**** Win32 API call to hide the window and **/ + /**** save the fact that its minimized for later **/ + /**************************************************/ + g_iIsActive = 0; + ShowWindow(hWnd, SW_HIDE); + + return 0; + } + else + { + if(g_hPrefDlg != NULL) + { + DestroyWindow(g_hPrefDlg); + } + + StopBlink(hWnd, 1, g_hIcons[0]); + + if(sdAlertNum()) + { + sdCloseAlerts(); + HoldClose(); + return 0; + } + } + } + break; + case WM_SIZE: + { + /******************************************/ + /***** User wants to minimize xChat, ******/ + /***** are we allowed to go to tray? ******/ + /******************************************/ + if((g_dwPrefs & (1<<PREF_TOT)) && (wparam == SIZE_MINIMIZED)) + { + /*******************************************/ + /**** to autoaway or not to autoaway... ***/ + /*******************************************/ + if(g_dwPrefs & (1<<PREF_AOM)) + { + xchat_globally_away(g_szAway); + } + + /**************************************************/ + /**** Win32 API call to hide the window and **/ + /**** save the fact that its minimized for later **/ + /**************************************************/ + g_iIsActive = 0; + ShowWindow(hWnd, SW_HIDE); + } + } + break; + /**********************************/ + /*** user clicked the tray icon ***/ + /**********************************/ + case WM_TRAYMSG: + { + switch(lparam) + { + case WM_LBUTTONDOWN: + { + if(!g_iIsActive) + { + /*********************************************************/ + /*** 0: its hiden, restore it and show it, if autoaway ***/ + /*** is on, set us as back ***/ + /*********************************************************/ + SendMessage(hWnd, WM_SYSCOMMAND, SC_RESTORE, 0); + SetForegroundWindow(hWnd); + g_iIsActive = 1; + + if(g_dwPrefs & (1<<PREF_AOM)) + { + xchat_globally_back(); + } + } + else + { + SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); + } + } + break; + case WM_RBUTTONDOWN: + { + /******************************************/ + /*** user wants to see the menu find out **/ + /*** where the mouse is and show it **/ + /******************************************/ + POINT pt; + int iRet; + + GetCursorPos(&pt); + SetForegroundWindow(hWnd); + + ModifyMenu(g_hTrayMenu, 2, (MF_POPUP | MF_BYPOSITION), (UINT)setServerMenu(), _T("Away")); + + Sleep(175); + + iRet = TrackPopupMenuEx(g_hTrayMenu, (TPM_RETURNCMD | TPM_LEFTALIGN), pt.x, pt.y, hWnd, NULL); + + /***********************************/ + /*** nRet is the users selection, **/ + /*** process it **/ + /***********************************/ + sdTrayProc(hWnd, iRet); + } + break; + } + } + break; + default: + { + /*****************************************************/ + /*** the taskbar has been restarted, re-add our icon */ + /*****************************************************/ + if(msg == RegisterWindowMessage(_T("TaskbarCreated"))) + { + char szVersion[64]; + _snprintf(szVersion, 64, "XChat-WDK [%s]", xchat_get_info(ph, "version")); + AddIcon(g_hXchatWnd, 1, g_hIcons[0], szVersion, (NIF_ICON | NIF_MESSAGE | NIF_TIP), WM_TRAYMSG); + } + } + break; + } + + return CallWindowProc(g_hOldProc, hWnd, msg, wparam, lparam); +} + +/****************************************************/ +/*** process messages from the tray menu ************/ +/****************************************************/ +LRESULT CALLBACK sdTrayProc(HWND hWnd, int msg) +{ + switch(msg) + { + case ACT_EXIT: + { + g_bCanQuit = true; + PostMessage(hWnd, WM_CLOSE, 0, 0); + } + break; + case ACT_RESTORE: + { + /***********************************************/ + /** user wants us to restore the xchat window **/ + /** and of autoaway is on, set as back **/ + /***********************************************/ + SendMessage(g_hXchatWnd, WM_SYSCOMMAND, SC_RESTORE, 0); + SetForegroundWindow(hWnd); + + if((!g_iIsActive) && (g_dwPrefs & (1<<PREF_AOM))) + { + xchat_globally_back(); + g_iIsActive = 1; + } + } + break; + case ACT_SETTINGS: + { + ShowWindow(g_hPrefDlg, SW_SHOW); + } + break; + case ACT_AWAY: + { + xchat_globally_away(g_szAway); + } + break; + case ACT_BACK: + { + xchat_globally_back(); + } + break; + default: + { + if(msg > 0) + { + xchat_set_context(ph, xchat_find_server(msg-1)); + + if(!xchat_get_info(ph, "away")) + { + xchat_away(g_szAway); + } + else + { + xchat_back(); + } + } + } + break; + } + + return 1; +} + +int CALLBACK PrefProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + TCITEM tci1; + TCITEM tci2; + TCITEM tci3; + TCITEM tci4; + + tci1.mask = TCIF_TEXT; + tci1.pszText = _T("Settings"); + tci1.cchTextMax = strlen("Settings"); + SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_INSERTITEM, 0, (LPARAM)&tci1); + + tci2.mask = TCIF_TEXT; + tci2.pszText = _T("Alerts"); + tci2.cchTextMax = strlen("Alerts"); + SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_INSERTITEM, 1, (LPARAM)&tci2); + + tci3.mask = TCIF_TEXT; + tci3.pszText = _T("Events"); + tci3.cchTextMax = strlen("Events"); + SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_INSERTITEM, 2, (LPARAM)&tci3); + + tci4.mask = TCIF_TEXT; + tci4.pszText = _T("About"); + tci4.cchTextMax = strlen("About"); + SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_INSERTITEM, 3, (LPARAM)&tci4); + + + /***********************************************************************************/ + /***********************************************************************************/ + /***********************************************************************************/ + + g_hPrefTabSettings = CreateDialog((HINSTANCE)g_hInstance, + MAKEINTRESOURCE(IDD_SETTINGS), + hWnd, + (DLGPROC)SettingsProc); + SetDialog(g_hPrefTabSettings, IDD_SETTINGS); + + g_hPrefTabAlerts = CreateDialog((HINSTANCE)g_hInstance, + MAKEINTRESOURCE(IDD_ALERTS), + hWnd, + (DLGPROC)AlertsProc); + SetDialog(g_hPrefTabAlerts, IDD_ALERTS); + + g_hPrefTabEvents = CreateDialog((HINSTANCE)g_hInstance, + MAKEINTRESOURCE(IDD_EVENTS), + hWnd, + (DLGPROC)EventsProc); + SetDialog(g_hPrefTabEvents, IDD_EVENTS); + + g_hPrefTabAbout = CreateDialog((HINSTANCE)g_hInstance, + MAKEINTRESOURCE(IDD_ABOUT), + hWnd, + (DLGPROC)AboutProc); + } + break; + case WM_SHOWWINDOW: + { + if(wparam) + { + SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_SETCURSEL, 0, 0); + ShowWindow(g_hPrefTabSettings, SW_SHOW); + ShowWindow(g_hPrefTabAlerts, SW_HIDE); + ShowWindow(g_hPrefTabEvents, SW_HIDE); + ShowWindow(g_hPrefTabAbout, SW_HIDE); + } + } + break; + case WM_NOTIFY: + { + NMHDR *pData = (NMHDR *)lparam; + + switch(pData->code) + { + case TCN_SELCHANGE: + { + switch(SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_GETCURSEL, 0, 0)) + { + case 0: + { + ShowWindow(g_hPrefTabSettings, SW_SHOW); + ShowWindow(g_hPrefTabAlerts, SW_HIDE); + ShowWindow(g_hPrefTabEvents, SW_HIDE); + ShowWindow(g_hPrefTabAbout, SW_HIDE); + } + break; + case 1: + { + ShowWindow(g_hPrefTabSettings, SW_HIDE); + ShowWindow(g_hPrefTabAlerts, SW_SHOW); + ShowWindow(g_hPrefTabEvents, SW_HIDE); + ShowWindow(g_hPrefTabAbout, SW_HIDE); + } + break; + case 2: + { + ShowWindow(g_hPrefTabSettings, SW_HIDE); + ShowWindow(g_hPrefTabAlerts, SW_HIDE); + ShowWindow(g_hPrefTabEvents, SW_SHOW); + ShowWindow(g_hPrefTabAbout, SW_HIDE); + } + break; + case 3: + { + ShowWindow(g_hPrefTabSettings, SW_HIDE); + ShowWindow(g_hPrefTabAlerts, SW_HIDE); + ShowWindow(g_hPrefTabEvents, SW_HIDE); + ShowWindow(g_hPrefTabAbout, SW_SHOW); + } + break; + } + } + break; + } + } + break; + case WM_CLOSE: + { + ShowWindow(g_hPrefTabEvents, SW_HIDE); + ShowWindow(g_hPrefTabSettings, SW_HIDE); + ShowWindow(g_hPrefTabAlerts, SW_HIDE); + ShowWindow(g_hPrefTabAbout, SW_HIDE); + ShowWindow(hWnd, SW_HIDE); + return TRUE; + } + break; + case WM_COMMAND: + { + switch(wparam) + { + case IDC_PREF_OK: + { + CheckPrefs(g_hPrefTabEvents, IDD_EVENTS); + CheckPrefs(g_hPrefTabSettings, IDD_SETTINGS); + CheckPrefs(g_hPrefTabAlerts, IDD_ALERTS); + + SavePrefs(0); + + ShowWindow(g_hPrefTabEvents, SW_HIDE); + ShowWindow(g_hPrefTabSettings, SW_HIDE); + ShowWindow(g_hPrefTabAlerts, SW_HIDE); + ShowWindow(g_hPrefTabAbout, SW_HIDE); + ShowWindow(hWnd, SW_HIDE); + return TRUE; + } + break; + case IDC_PREF_CANCEL: + { + ShowWindow(g_hPrefTabEvents, SW_HIDE); + ShowWindow(g_hPrefTabSettings, SW_HIDE); + ShowWindow(g_hPrefTabAlerts, SW_HIDE); + ShowWindow(g_hPrefTabAbout, SW_HIDE); + ShowWindow(hWnd, SW_HIDE); + return TRUE; + } + break; + case IDC_PREF_APPLY: + { + CheckPrefs(g_hPrefTabEvents, IDD_EVENTS); + CheckPrefs(g_hPrefTabSettings, IDD_SETTINGS); + CheckPrefs(g_hPrefTabAlerts, IDD_ALERTS); + + SavePrefs(0); + return FALSE; + } + break; + } + } + break; + case WM_DESTROY: + { + SendMessage(g_hPrefTabEvents, WM_CLOSE, 0, 0); + SendMessage(g_hPrefTabSettings, WM_CLOSE, 0, 0); + SendMessage(g_hPrefTabAbout, WM_CLOSE, 0, 0); + SendMessage(g_hPrefTabAlerts, WM_CLOSE, 0, 0); + } + break; + } + + return FALSE; +} + +/****************************************************/ +/****************************************************/ +/****************************************************/ +LRESULT CALLBACK AlertsProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch(msg) + { + case WM_CLOSE: + { + DestroyWindow(hWnd); + return TRUE; + break; + } + break; + case WM_COMMAND: + { + switch(LOWORD(wparam)) + { + case PREF_AMAE: + { + SetToggle(hWnd, PREF_OSBWM, PREF_AMAE, TRUE); + SetToggle(hWnd, PREF_UWIOB, PREF_AMAE, TRUE); + SetToggle(hWnd, PREF_KAOI, PREF_AMAE, TRUE); + + if(IsDlgButtonChecked(hWnd, PREF_AMAE)) + { + SetToggle(hWnd, IDC_ALERT_HOTKEY, PREF_UWIOB, TRUE); + SetToggle(hWnd, IDC_ALERT_HOTKEY_TEXT, PREF_UWIOB, TRUE); + SetToggle(hWnd, IDC_ALERT_TIME, PREF_KAOI, FALSE); + SetToggle(hWnd, IDC_ALERT_TIME_TEXT, PREF_KAOI, FALSE); + } + else + { + SetToggle(hWnd, IDC_ALERT_HOTKEY, PREF_AMAE, TRUE); + SetToggle(hWnd, IDC_ALERT_HOTKEY_TEXT, PREF_AMAE, TRUE); + SetToggle(hWnd, IDC_ALERT_TIME, PREF_AMAE, TRUE); + SetToggle(hWnd, IDC_ALERT_TIME_TEXT, PREF_AMAE, TRUE); + } + } + break; + case PREF_UWIOB: + { + SetToggle(hWnd, IDC_ALERT_HOTKEY, PREF_UWIOB, TRUE); + SetToggle(hWnd, IDC_ALERT_HOTKEY_TEXT, PREF_UWIOB, TRUE); + } + break; + case PREF_KAOI: + { + SetToggle(hWnd, IDC_ALERT_TIME, PREF_KAOI, FALSE); + SetToggle(hWnd, IDC_ALERT_TIME_TEXT, PREF_KAOI, FALSE); + } + break; + } + break; + } + } + + return FALSE; +} + +/****************************************************/ +/****************************************************/ +/****************************************************/ +LRESULT CALLBACK AboutProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(msg == WM_CLOSE) + { + DestroyWindow(hWnd); + return true; + } + + return FALSE; +} + +/*****************************************************/ +/** Process the events for our event dialog **********/ +/*****************************************************/ +LRESULT CALLBACK EventsProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(msg == WM_CLOSE) + { + DestroyWindow(hWnd); + return true; + } + + return FALSE; +} + +/*****************************************************/ +/** Process the events for our settings dialog this **/ +/** is alot more complicated because options are **/ +/** enabled/disabled based on the state of others **/ +/*****************************************************/ +LRESULT CALLBACK SettingsProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(msg == WM_CLOSE) + { + DestroyWindow(hWnd); + return true; + } + + return FALSE; +} + +/*****************************************************/ +/** this is the hotkey message processing function **/ +/** this window is always open and ready to be told **/ +/** if someone has hit the hotkey, if they did, we **/ +/** need to close out all of the tray alerts, for **/ +/** this I wrote sdCloseAlerts, more info there **/ +/*****************************************************/ +LRESULT CALLBACK HotKeyProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(msg == WM_CLOSE) + { + DestroyWindow(hWnd); + return true; + } + else if(msg == WM_HOTKEY) + { + sdCloseAlerts(); + } + + return FALSE; +} + diff --git a/plugins/xtray/callbacks.h b/plugins/xtray/callbacks.h new file mode 100644 index 00000000..99cbae74 --- /dev/null +++ b/plugins/xtray/callbacks.h @@ -0,0 +1,37 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_CALLBACKS_H +#define _H_CALLBACKS_H + +int event_cb (char *word[], void *userdata); +int command_cb (char *word[], char *word_eol[], void *userdata); + +LRESULT CALLBACK WindowProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +BOOL CALLBACK EnumWindowsProc (HWND hWnd, LPARAM lParam); +LRESULT CALLBACK sdTrayProc (HWND hwnd, int msg); + +LRESULT CALLBACK AlertProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +LRESULT CALLBACK HotKeyProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +LRESULT CALLBACK EventsProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +LRESULT CALLBACK AboutProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +LRESULT CALLBACK AlertsProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +LRESULT CALLBACK SettingsProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +int CALLBACK PrefProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); + +#endif \ No newline at end of file diff --git a/plugins/xtray/icons/banned.ico b/plugins/xtray/icons/banned.ico new file mode 100644 index 00000000..fef8df8c --- /dev/null +++ b/plugins/xtray/icons/banned.ico Binary files differdiff --git a/plugins/xtray/icons/chan_msg.ico b/plugins/xtray/icons/chan_msg.ico new file mode 100644 index 00000000..793d050e --- /dev/null +++ b/plugins/xtray/icons/chan_msg.ico Binary files differdiff --git a/plugins/xtray/icons/disconnected.ico b/plugins/xtray/icons/disconnected.ico new file mode 100644 index 00000000..9063e7e3 --- /dev/null +++ b/plugins/xtray/icons/disconnected.ico Binary files differdiff --git a/plugins/xtray/icons/highlight-1-3.ico b/plugins/xtray/icons/highlight-1-3.ico new file mode 100644 index 00000000..a759145b --- /dev/null +++ b/plugins/xtray/icons/highlight-1-3.ico Binary files differdiff --git a/plugins/xtray/icons/highlight.ico b/plugins/xtray/icons/highlight.ico new file mode 100644 index 00000000..625cca9a --- /dev/null +++ b/plugins/xtray/icons/highlight.ico Binary files differdiff --git a/plugins/xtray/icons/kicked.ico b/plugins/xtray/icons/kicked.ico new file mode 100644 index 00000000..845a74e1 --- /dev/null +++ b/plugins/xtray/icons/kicked.ico Binary files differdiff --git a/plugins/xtray/icons/priv_msg-1-2-2.ico b/plugins/xtray/icons/priv_msg-1-2-2.ico new file mode 100644 index 00000000..7941ff77 --- /dev/null +++ b/plugins/xtray/icons/priv_msg-1-2-2.ico Binary files differdiff --git a/plugins/xtray/icons/sd.ico b/plugins/xtray/icons/sd.ico new file mode 100644 index 00000000..ca179621 --- /dev/null +++ b/plugins/xtray/icons/sd.ico Binary files differdiff --git a/plugins/xtray/icons/server_notice.ico b/plugins/xtray/icons/server_notice.ico new file mode 100644 index 00000000..ff765d87 --- /dev/null +++ b/plugins/xtray/icons/server_notice.ico Binary files differdiff --git a/plugins/xtray/icons/xchat.ico b/plugins/xtray/icons/xchat.ico new file mode 100644 index 00000000..73247fd0 --- /dev/null +++ b/plugins/xtray/icons/xchat.ico Binary files differdiff --git a/plugins/xtray/makefile.mak b/plugins/xtray/makefile.mak new file mode 100644 index 00000000..d1f8d295 --- /dev/null +++ b/plugins/xtray/makefile.mak @@ -0,0 +1,37 @@ +include "..\..\src\makeinc.mak" + +TARGET = xtray.dll + +TRAY_OBJECTS = \ +callbacks.obj \ +sdAlerts.obj \ +sdTray.obj \ +utility.obj \ +xchat.obj \ +xtray.obj + +CPPFLAGS = $(CPPFLAGS) /D_STL70_ /D_STATIC_CPPLIB /EHsc /DUNICODE /D_UNICODE + +all: $(TRAY_OBJECTS) $(TARGET) + +xtray.def: + echo EXPORTS > xtray.def + echo xchat_plugin_init >> xtray.def + echo xchat_plugin_deinit >> xtray.def + +.cpp.obj: + $(CC) $(CPPFLAGS) /c $< + +res: + rc /nologo resource.rc + +$(TARGET): $(TRAY_OBJECTS) xtray.def res + $(LINK) /DLL /out:$(TARGET) $(LDFLAGS) $(TRAY_OBJECTS) ntstc_msvcrt.lib $(LIBS) /def:xtray.def resource.res + +clean: + del $(TARGET) + del *.obj + del xtray.def + del resource.res + del *.lib + del *.exp diff --git a/plugins/xtray/plugin.h b/plugins/xtray/plugin.h new file mode 100644 index 00000000..50b0de21 --- /dev/null +++ b/plugins/xtray/plugin.h @@ -0,0 +1,335 @@ +/* You can distribute this header with your plugins for easy compilation */ +#ifndef XCHAT_PLUGIN_H +#define XCHAT_PLUGIN_H + +#include <time.h> + +#define XCHAT_IFACE_MAJOR 1 +#define XCHAT_IFACE_MINOR 9 +#define XCHAT_IFACE_MICRO 11 +#define XCHAT_IFACE_VERSION ((XCHAT_IFACE_MAJOR * 10000) + \ + (XCHAT_IFACE_MINOR * 100) + \ + (XCHAT_IFACE_MICRO)) + +#define XCHAT_PRI_HIGHEST 127 +#define XCHAT_PRI_HIGH 64 +#define XCHAT_PRI_NORM 0 +#define XCHAT_PRI_LOW (-64) +#define XCHAT_PRI_LOWEST (-128) + +#define XCHAT_FD_READ 1 +#define XCHAT_FD_WRITE 2 +#define XCHAT_FD_EXCEPTION 4 +#define XCHAT_FD_NOTSOCKET 8 + +#define XCHAT_EAT_NONE 0 /* pass it on through! */ +#define XCHAT_EAT_XCHAT 1 /* don't let xchat see this event */ +#define XCHAT_EAT_PLUGIN 2 /* don't let other plugins see this event */ +#define XCHAT_EAT_ALL (XCHAT_EAT_XCHAT|XCHAT_EAT_PLUGIN) /* don't let anything see this event */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xchat_plugin xchat_plugin; +typedef struct _xchat_list xchat_list; +typedef struct _xchat_hook xchat_hook; +#ifndef PLUGIN_C +typedef struct _xchat_context xchat_context; +#endif + +#ifndef PLUGIN_C +struct _xchat_plugin +{ + /* these are only used on win32 */ + xchat_hook *(*xchat_hook_command) (xchat_plugin *ph, + const char *name, + int pri, + int (*callback) (char *word[], char *word_eol[], void *user_data), + const char *help_text, + void *userdata); + xchat_hook *(*xchat_hook_server) (xchat_plugin *ph, + const char *name, + int pri, + int (*callback) (char *word[], char *word_eol[], void *user_data), + void *userdata); + xchat_hook *(*xchat_hook_print) (xchat_plugin *ph, + const char *name, + int pri, + int (*callback) (char *word[], void *user_data), + void *userdata); + xchat_hook *(*xchat_hook_timer) (xchat_plugin *ph, + int timeout, + int (*callback) (void *user_data), + void *userdata); + xchat_hook *(*xchat_hook_fd) (xchat_plugin *ph, + int fd, + int flags, + int (*callback) (int fd, int flags, void *user_data), + void *userdata); + void *(*xchat_unhook) (xchat_plugin *ph, + xchat_hook *hook); + void (*xchat_print) (xchat_plugin *ph, + const char *text); + void (*xchat_printf) (xchat_plugin *ph, + const char *format, ...); + void (*xchat_command) (xchat_plugin *ph, + const char *command); + void (*xchat_commandf) (xchat_plugin *ph, + const char *format, ...); + int (*xchat_nickcmp) (xchat_plugin *ph, + const char *s1, + const char *s2); + int (*xchat_set_context) (xchat_plugin *ph, + xchat_context *ctx); + xchat_context *(*xchat_find_context) (xchat_plugin *ph, + const char *servname, + const char *channel); + xchat_context *(*xchat_get_context) (xchat_plugin *ph); + const char *(*xchat_get_info) (xchat_plugin *ph, + const char *id); + int (*xchat_get_prefs) (xchat_plugin *ph, + const char *name, + const char **string, + int *integer); + xchat_list * (*xchat_list_get) (xchat_plugin *ph, + const char *name); + void (*xchat_list_free) (xchat_plugin *ph, + xchat_list *xlist); + const char * const * (*xchat_list_fields) (xchat_plugin *ph, + const char *name); + int (*xchat_list_next) (xchat_plugin *ph, + xchat_list *xlist); + const char * (*xchat_list_str) (xchat_plugin *ph, + xchat_list *xlist, + const char *name); + int (*xchat_list_int) (xchat_plugin *ph, + xchat_list *xlist, + const char *name); + void * (*xchat_plugingui_add) (xchat_plugin *ph, + const char *filename, + const char *name, + const char *desc, + const char *version, + char *reserved); + void (*xchat_plugingui_remove) (xchat_plugin *ph, + void *handle); + int (*xchat_emit_print) (xchat_plugin *ph, + const char *event_name, ...); + int (*xchat_read_fd) (xchat_plugin *ph, + void *src, + char *buf, + int *len); + time_t (*xchat_list_time) (xchat_plugin *ph, + xchat_list *xlist, + const char *name); + char *(*xchat_gettext) (xchat_plugin *ph, + const char *msgid); + void (*xchat_send_modes) (xchat_plugin *ph, + const char **targets, + int ntargets, + int modes_per_line, + char sign, + char mode); + char *(*xchat_strip) (xchat_plugin *ph, + const char *str, + int len, + int flags); + void (*xchat_free) (xchat_plugin *ph, + void *ptr); +}; +#endif + + + +xchat_hook * +xchat_hook_command (xchat_plugin *ph, + const char *name, + int pri, + int (*callback) (char *word[], char *word_eol[], void *user_data), + const char *help_text, + void *userdata); + +xchat_hook * +xchat_hook_server (xchat_plugin *ph, + const char *name, + int pri, + int (*callback) (char *word[], char *word_eol[], void *user_data), + void *userdata); + +xchat_hook * +xchat_hook_print (xchat_plugin *ph, + const char *name, + int pri, + int (*callback) (char *word[], void *user_data), + void *userdata); + +xchat_hook * +xchat_hook_timer (xchat_plugin *ph, + int timeout, + int (*callback) (void *user_data), + void *userdata); + +xchat_hook * +xchat_hook_fd (xchat_plugin *ph, + int fd, + int flags, + int (*callback) (int fd, int flags, void *user_data), + void *userdata); + +void * +xchat_unhook (xchat_plugin *ph, + xchat_hook *hook); + +void +xchat_print (xchat_plugin *ph, + const char *text); + +void +xchat_printf (xchat_plugin *ph, + const char *format, ...); + +void +xchat_command (xchat_plugin *ph, + const char *command); + +void +xchat_commandf (xchat_plugin *ph, + const char *format, ...); + +int +xchat_nickcmp (xchat_plugin *ph, + const char *s1, + const char *s2); + +int +xchat_set_context (xchat_plugin *ph, + xchat_context *ctx); + +xchat_context * +xchat_find_context (xchat_plugin *ph, + const char *servname, + const char *channel); + +xchat_context * +xchat_get_context (xchat_plugin *ph); + +const char * +xchat_get_info (xchat_plugin *ph, + const char *id); + +int +xchat_get_prefs (xchat_plugin *ph, + const char *name, + const char **string, + int *integer); + +xchat_list * +xchat_list_get (xchat_plugin *ph, + const char *name); + +void +xchat_list_free (xchat_plugin *ph, + xchat_list *xlist); + +const char * const * +xchat_list_fields (xchat_plugin *ph, + const char *name); + +int +xchat_list_next (xchat_plugin *ph, + xchat_list *xlist); + +const char * +xchat_list_str (xchat_plugin *ph, + xchat_list *xlist, + const char *name); + +int +xchat_list_int (xchat_plugin *ph, + xchat_list *xlist, + const char *name); + +time_t +xchat_list_time (xchat_plugin *ph, + xchat_list *xlist, + const char *name); + +void * +xchat_plugingui_add (xchat_plugin *ph, + const char *filename, + const char *name, + const char *desc, + const char *version, + char *reserved); + +void +xchat_plugingui_remove (xchat_plugin *ph, + void *handle); + +int +xchat_emit_print (xchat_plugin *ph, + const char *event_name, ...); + +char * +xchat_gettext (xchat_plugin *ph, + const char *msgid); + +void +xchat_send_modes (xchat_plugin *ph, + const char **targets, + int ntargets, + int modes_per_line, + char sign, + char mode); + +char * +xchat_strip (xchat_plugin *ph, + const char *str, + int len, + int flags); + +void +xchat_free (xchat_plugin *ph, + void *ptr); + +#if !defined(PLUGIN_C) && defined(WIN32) +#ifndef XCHAT_PLUGIN_HANDLE +#define XCHAT_PLUGIN_HANDLE (ph) +#endif +#define xchat_hook_command ((XCHAT_PLUGIN_HANDLE)->xchat_hook_command) +#define xchat_hook_server ((XCHAT_PLUGIN_HANDLE)->xchat_hook_server) +#define xchat_hook_print ((XCHAT_PLUGIN_HANDLE)->xchat_hook_print) +#define xchat_hook_timer ((XCHAT_PLUGIN_HANDLE)->xchat_hook_timer) +#define xchat_hook_fd ((XCHAT_PLUGIN_HANDLE)->xchat_hook_fd) +#define xchat_unhook ((XCHAT_PLUGIN_HANDLE)->xchat_unhook) +#define xchat_print ((XCHAT_PLUGIN_HANDLE)->xchat_print) +#define xchat_printf ((XCHAT_PLUGIN_HANDLE)->xchat_printf) +#define xchat_command ((XCHAT_PLUGIN_HANDLE)->xchat_command) +#define xchat_commandf ((XCHAT_PLUGIN_HANDLE)->xchat_commandf) +#define xchat_nickcmp ((XCHAT_PLUGIN_HANDLE)->xchat_nickcmp) +#define xchat_set_context ((XCHAT_PLUGIN_HANDLE)->xchat_set_context) +#define xchat_find_context ((XCHAT_PLUGIN_HANDLE)->xchat_find_context) +#define xchat_get_context ((XCHAT_PLUGIN_HANDLE)->xchat_get_context) +#define xchat_get_info ((XCHAT_PLUGIN_HANDLE)->xchat_get_info) +#define xchat_get_prefs ((XCHAT_PLUGIN_HANDLE)->xchat_get_prefs) +#define xchat_list_get ((XCHAT_PLUGIN_HANDLE)->xchat_list_get) +#define xchat_list_free ((XCHAT_PLUGIN_HANDLE)->xchat_list_free) +#define xchat_list_fields ((XCHAT_PLUGIN_HANDLE)->xchat_list_fields) +#define xchat_list_str ((XCHAT_PLUGIN_HANDLE)->xchat_list_str) +#define xchat_list_int ((XCHAT_PLUGIN_HANDLE)->xchat_list_int) +#define xchat_list_time ((XCHAT_PLUGIN_HANDLE)->xchat_list_time) +#define xchat_list_next ((XCHAT_PLUGIN_HANDLE)->xchat_list_next) +#define xchat_plugingui_add ((XCHAT_PLUGIN_HANDLE)->xchat_plugingui_add) +#define xchat_plugingui_remove ((XCHAT_PLUGIN_HANDLE)->xchat_plugingui_remove) +#define xchat_emit_print ((XCHAT_PLUGIN_HANDLE)->xchat_emit_print) +#define xchat_gettext ((XCHAT_PLUGIN_HANDLE)->xchat_gettext) +#define xchat_send_modes ((XCHAT_PLUGIN_HANDLE)->xchat_send_modes) +#define xchat_strip ((XCHAT_PLUGIN_HANDLE)->xchat_strip) +#define xchat_free ((XCHAT_PLUGIN_HANDLE)->xchat_free) +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/plugins/xtray/resource.h b/plugins/xtray/resource.h new file mode 100644 index 00000000..b8008c2c --- /dev/null +++ b/plugins/xtray/resource.h @@ -0,0 +1,47 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define IDD_ALERTS 104 +#define IDD_EVENTS 105 +#define IDD_SETTINGS 106 +#define IDD_ALERT 107 +#define IDD_PREF 108 +#define IDD_ABOUT 109 +#define IDR_TRAY_MENU 110 +#define ICO_XCHAT 111 +#define ICO_BANNED 112 +#define ICO_CHANMSG 113 +#define ICO_DISCONNECTED 114 +#define ICO_HIGHLIGHT 115 +#define ICO_KICKED 116 +#define ICO_PMSG 117 +#define ICO_SNOTICE 118 +#define IDB_SD_LOGO 119 +#define IDC_PREF_OK 1014 +#define IDC_PREF_CANCEL 1015 +#define IDC_PREF_APPLY 1016 +#define IDC_AWAY_MSG 1017 +#define IDC_ALERT_TIME 1018 +#define IDC_TAB_CONTROL 1019 +#define IDC_ALERT_HOTKEY 1020 +#define IDC_ALERT_MSG 1021 +#define IDC_ALERT_HOTKEY_TEXT 1022 +#define IDC_ALERT_TIME_TEXT 1023 +#define ACT_EXIT 40001 +#define ACT_SETTINGS 40002 +#define ACT_AWAY 40003 +#define ACT_BACK 40004 +#define ACT_RESTORE 40005 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 120 +#define _APS_NEXT_COMMAND_VALUE 40006 +#define _APS_NEXT_CONTROL_VALUE 1024 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/xtray/resource.rc b/plugins/xtray/resource.rc new file mode 100644 index 00000000..906cf591 --- /dev/null +++ b/plugins/xtray/resource.rc @@ -0,0 +1,309 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_EVENTS DIALOGEX 8, 20, 216, 143 +STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CHILD +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + GROUPBOX "XChat Events",IDC_STATIC,5,5,205,77 + CONTROL "Banned",4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,18,49,10 + CONTROL "Kicked",5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,32,49,10 + CONTROL "Killed",8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,46,49,10 + CONTROL "Disconnect",10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,60,49,10 + CONTROL "Private Message",7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,70,18,69,10 + CONTROL "Channel Message",21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,70,32,69,10 + CONTROL "Highlight",1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,70,46,69,10 + CONTROL "CTCP",6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,70,60,69,10 + CONTROL "Topic Change",3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,18,55,10 + CONTROL "Server Notice",9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,32,55,10 + CONTROL "Invite",2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,46,55,10 +END + +IDD_SETTINGS DIALOGEX 8, 20, 216, 143 +STYLE DS_SETFONT | WS_CHILD +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + GROUPBOX "Options",IDC_STATIC,5,5,205,135 + CONTROL "Auto away on minimize",11,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,16,60,100,10 + CONTROL "Minimize XChat to the system tray",12,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,18,133,10 + CONTROL "Minimize to the tray instead of closing",17,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,32,174,9 + EDITTEXT IDC_AWAY_MSG,33,86,169,50,ES_AUTOHSCROLL + LTEXT "Away Msg:",IDC_STATIC,27,72,35,8 + CONTROL "Remove XChat from the taskbar (only show in tray)", + 20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,46,191,9 +END + +IDD_ALERT DIALOGEX 0, 0, 151, 28 +STYLE DS_LOCALEDIT | DS_SETFONT | DS_NOIDLEMSG | DS_CENTER | WS_CAPTION | + WS_SYSMENU +EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_ACCEPTFILES | WS_EX_TOOLWINDOW +CAPTION "Event Name" +FONT 8, "Tahoma", 0, 0, 0x1 +BEGIN + LTEXT "Event Text",IDC_ALERT_MSG,3,0,147,27 +END + +IDD_PREF DIALOGEX 0, 0, 233, 190 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "X-Tray Preferences" +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "Ok",IDC_PREF_OK,57,173,50,14 + PUSHBUTTON "Cancel",IDC_PREF_CANCEL,115,173,50,14 + PUSHBUTTON "Apply",IDC_PREF_APPLY,175,173,50,14 + CONTROL "Tab1",IDC_TAB_CONTROL,"SysTabControl32",0x0,7,7,218,159 +END + +IDD_ABOUT DIALOGEX 8, 20, 216, 143 +STYLE DS_SETFONT | WS_CHILD +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + CONTROL 119,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN | + WS_BORDER,3,6,88,81 + CTEXT "X-Tray\r\nBy: Michael Hotaling\r\n www.SinisterDevelopments.com", + IDC_STATIC,95,33,118,30 + LTEXT "Folken\r\nBasket\r\nDonatzsky\r\nDaemon404",IDC_STATIC, + 15,103,64,33 + GROUPBOX "Special Thanks To:",IDC_STATIC,3,91,89,50 + GROUPBOX "Version Information:",IDC_STATIC,101,92,109,49 + LTEXT "1.2.4",IDC_STATIC,170,105,33,8,0,WS_EX_RIGHT + LTEXT "Compiled In: ",IDC_STATIC,110,117,54,8 + LTEXT "2011",IDC_STATIC,170,117,33,8,0,WS_EX_RIGHT + LTEXT "Version Number:",IDC_STATIC,110,105,54,8 +END + +IDD_ALERTS DIALOGEX 8, 20, 216, 143 +STYLE DS_SETFONT | WS_CHILD +FONT 8, "Tahoma", 0, 0, 0x0 +BEGIN + GROUPBOX "Alerts",IDC_STATIC,5,5,205,117 + CONTROL "Only show alerts while minimized",14,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,27,46,117,10 + CONTROL "Use tray alerts to notify me about events",13,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,32,152,10 + CONTROL "Use window instead of balloons",15,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,27,60,141,11 + EDITTEXT IDC_ALERT_TIME,137,101,61,12,ES_AUTOHSCROLL | ES_NUMBER, + WS_EX_RIGHT + LTEXT "Show alert for x seconds:",IDC_ALERT_TIME_TEXT,40,103, + 83,9 + CONTROL "Alert Hotkey",IDC_ALERT_HOTKEY,"msctls_hotkey32", + WS_BORDER | WS_TABSTOP,137,74,61,13 + LTEXT "Close all alerts hotkey:",IDC_ALERT_HOTKEY_TEXT,39,75, + 76,10 + CONTROL "Leave alerts open indefinately",16,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,27,88,115,11 + CONTROL "Blink Icon to alert me about events",18,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,18,127,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_EVENTS, DIALOG + BEGIN + BOTTOMMARGIN, 56 + END + + IDD_SETTINGS, DIALOG + BEGIN + BOTTOMMARGIN, 66 + END + + IDD_ALERT, DIALOG + BEGIN + RIGHTMARGIN, 150 + BOTTOMMARGIN, 26 + END + + IDD_PREF, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 232 + TOPMARGIN, 7 + BOTTOMMARGIN, 176 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 209 + TOPMARGIN, 7 + BOTTOMMARGIN, 136 + END + + IDD_ALERTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 208 + TOPMARGIN, 7 + BOTTOMMARGIN, 136 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "xtray.h\0" +END + +4 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,2,4,0 + PRODUCTVERSION 1,2,4,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "SinisterDevelopments" + VALUE "FileDescription", "X-Tray" + VALUE "FileVersion", "1, 2, 4, 0" + VALUE "InternalName", "X-Tray" + VALUE "LegalCopyright", "Copyright © 2005" + VALUE "OriginalFilename", "xtray.dll" + VALUE "ProductName", "X-Tray - XChat Win32 System Tray Plugin" + VALUE "ProductVersion", "1, 2, 4, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_TRAY_MENU MENU +BEGIN + POPUP "TRAY" + BEGIN + MENUITEM "Restore", ACT_RESTORE + MENUITEM SEPARATOR + MENUITEM "Away", 65535 + MENUITEM "Settings", ACT_SETTINGS + MENUITEM SEPARATOR + MENUITEM "Exit", ACT_EXIT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +ICO_XCHAT ICON "icons\\xchat.ico" +ICO_BANNED ICON "icons\\banned.ico" +ICO_CHANMSG ICON "icons\\chan_msg.ico" +ICO_HIGHLIGHT ICON "icons\\highlight.ico" +ICO_KICKED ICON "icons\\kicked.ico" +ICO_PMSG ICON "icons\\priv_msg-1-2-2.ico" +ICO_SNOTICE ICON "icons\\server_notice.ico" +ICO_DISCONNECTED ICON "icons\\disconnected.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_SD_LOGO BITMAP "bitmaps\\sd.bmp" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +xtray.h +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/xtray/sdAlerts.cpp b/plugins/xtray/sdAlerts.cpp new file mode 100644 index 00000000..5e042806 --- /dev/null +++ b/plugins/xtray/sdAlerts.cpp @@ -0,0 +1,109 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <windows.h> +#include <winuser.h> +#include <stdio.h> +#include "utility.h" +#include "resource.h" +#include "sdAlerts.h" + +int g_iAlerts = 0; + +void sdSystemAlert(HINSTANCE hModule, UINT uiDialog, char *szMsg, char *szName, unsigned int iTime) +{ + TCHAR wszMsg[256]; + TCHAR wszName[64]; + + HWND hDialog; + RECT rcWorkArea, rcDlg; + int ixPos, iyPos; + int iNumPerCol; + + hDialog = CreateDialog(hModule, MAKEINTRESOURCE(uiDialog), NULL, (DLGPROC)sdAlertProc); + + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0); + GetWindowRect(hDialog, &rcDlg); + + iNumPerCol = ((rcWorkArea.bottom - rcWorkArea.top) / (rcDlg.bottom - rcDlg.top)); + ixPos = rcWorkArea.right - (rcDlg.right - rcDlg.left) + 1; + iyPos = rcWorkArea.bottom - (rcDlg.bottom - rcDlg.top); + + if((g_iAlerts >= iNumPerCol) && (iNumPerCol > 0)) + { + ixPos -= ((g_iAlerts / iNumPerCol) * (rcDlg.right - rcDlg.left)); + iyPos -= ((g_iAlerts - (iNumPerCol * (g_iAlerts / iNumPerCol))) * (rcDlg.bottom - rcDlg.top)); + } + else + { + iyPos -= (g_iAlerts * (rcDlg.bottom - rcDlg.top)); + } + SetWindowPos(hDialog, HWND_TOPMOST, ixPos, iyPos, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); + + ConvertString(szName, wszName, 64); + ConvertString(szMsg, wszMsg, 256); + + SetWindowText(hDialog, wszName); + SetDlgItemText(hDialog, IDC_ALERT_MSG, wszMsg); + ShowWindow(hDialog, SW_SHOWNA); + + if(iTime > 0) + { + SetTimer(hDialog, 1, iTime, NULL); + } + + g_iAlerts++; +} + +void sdCloseAlerts() +{ + PostMessage(HWND_BROADCAST, RegisterWindowMessage(TEXT("xTray:CloseAllAlertWindows")), 0, 0); +} + +LRESULT CALLBACK sdAlertProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch(msg) + { + case WM_CLOSE: + if(g_iAlerts > 0){ g_iAlerts--; } + DestroyWindow(hwnd); + return TRUE; + break; + case WM_TIMER: + if(g_iAlerts > 0){ g_iAlerts--; } + AnimateWindow(hwnd, 600, AW_SLIDE | AW_HIDE | AW_VER_POSITIVE); + DestroyWindow(hwnd); + return TRUE; + break; + default: + if(msg == RegisterWindowMessage(TEXT("xTray:CloseAllAlertWindows"))) + { + if(g_iAlerts > 0){ g_iAlerts--; } + DestroyWindow(hwnd); + return TRUE; + } + break; + } + + return FALSE; +} + +int sdAlertNum() +{ + return g_iAlerts; +} \ No newline at end of file diff --git a/plugins/xtray/sdAlerts.h b/plugins/xtray/sdAlerts.h new file mode 100644 index 00000000..cd45a05b --- /dev/null +++ b/plugins/xtray/sdAlerts.h @@ -0,0 +1,26 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_SDALERTS_H +#define _H_SDALERTS_H + +void sdSystemAlert (HINSTANCE, UINT, char *, char *, UINT); +LRESULT CALLBACK sdAlertProc (HWND, UINT, WPARAM, LPARAM); +int sdAlertNum (); +void sdCloseAlerts (); +#endif \ No newline at end of file diff --git a/plugins/xtray/sdTray.cpp b/plugins/xtray/sdTray.cpp new file mode 100644 index 00000000..3a91a61b --- /dev/null +++ b/plugins/xtray/sdTray.cpp @@ -0,0 +1,207 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define _WIN32_IE 0x601 +#include <windows.h> +#include <stdio.h> +#include <tchar.h> +#include "sdTray.h" +#include "utility.h" + +HANDLE hThread; +iBlink *tData = NULL; + +int AddIcon(HWND hwnd, UINT id, HICON hicon, char *szTip, unsigned short flags, unsigned int cbMsg) +{ + NOTIFYICONDATA nidata; + + nidata.cbSize = NOTIFYICONDATA_V2_SIZE; + nidata.hIcon = hicon; + nidata.hWnd = hwnd; + nidata.uCallbackMessage = cbMsg; + nidata.uFlags = flags; + nidata.uID = id; + + if(szTip != NULL) + { + TCHAR *szTemp = new TCHAR[64]; + + ConvertString(szTip, szTemp, 64); + _tcsncpy(nidata.szTip, szTemp, 64); + + delete[] szTemp; + } + + return Shell_NotifyIcon(NIM_ADD, &nidata); +} + +int RemoveIcon(HWND hwnd, UINT id) +{ + if(hThread != NULL) + { + TerminateThread(hThread, 0); + hThread = NULL; + + delete tData; + } + + NOTIFYICONDATA nidata; + + nidata.cbSize = NOTIFYICONDATA_V2_SIZE; + nidata.hWnd = hwnd; + nidata.uID = id; + + return Shell_NotifyIcon(NIM_DELETE, &nidata); +} + +int SetIcon(HWND hwnd, UINT id, HICON hicon) +{ + NOTIFYICONDATA nidata; + + nidata.cbSize = NOTIFYICONDATA_V2_SIZE; + nidata.hWnd = hwnd; + nidata.uID = id; + nidata.hIcon = hicon; + nidata.uFlags = NIF_ICON; + + return Shell_NotifyIcon(NIM_MODIFY, &nidata); +} + +int SetTooltip(HWND hwnd, UINT id, char *szTip) +{ + NOTIFYICONDATA nidata; + + nidata.cbSize = NOTIFYICONDATA_V2_SIZE; + nidata.hWnd = hwnd; + nidata.uID = id; + nidata.uFlags = NIF_TIP; + + if(szTip != NULL) + { + TCHAR *szTemp = new TCHAR[64]; + ConvertString(szTip, szTemp, 64); + _tcsncpy(nidata.szTip, szTemp, 64); + delete[] szTemp; + } + + return Shell_NotifyIcon(NIM_MODIFY, &nidata); +} + +int ShowBalloon(HWND hwnd, UINT id, char *szInfo, char *szTitle, UINT time, UINT infoFlags) +{ + NOTIFYICONDATA nidata; + + nidata.cbSize = NOTIFYICONDATA_V2_SIZE; + nidata.hWnd = hwnd; + nidata.uID = id; + nidata.uFlags = NIF_INFO; + nidata.dwInfoFlags = infoFlags; + + if(time > 0) + nidata.uTimeout = time; + else + nidata.uTimeout = 500000; + + if(szInfo != NULL) + { + TCHAR *szTemp = new TCHAR[255]; + + ConvertString(szInfo, szTemp, 251); + szTemp[250] = 0; + + if(strlen(szInfo) > 255) + { + _sntprintf(szTemp, 255, _T("%s..."), szTemp); + } + _tcsncpy(nidata.szInfo, szTemp, 255); + + delete[] szTemp; + } + if(szTitle != NULL) + { + TCHAR *wszTitle = new TCHAR[64]; + ConvertString(szTitle, wszTitle, 64); + _tcsncpy(nidata.szInfoTitle, wszTitle, 64); + delete[] wszTitle; + } + + return Shell_NotifyIcon(NIM_MODIFY, &nidata); +} + + +DWORD WINAPI BlinkThread(LPVOID lpParam) +{ + NOTIFYICONDATA nidata; + + nidata.cbSize = NOTIFYICONDATA_V2_SIZE; + nidata.hWnd = tData->hwnd; + nidata.uID = tData->id; + nidata.uFlags = NIF_ICON; + + for(UINT i = 0; i < tData->num; i++) + { + nidata.hIcon = tData->hBlink; + Shell_NotifyIcon(NIM_MODIFY, &nidata); + + Sleep(tData->time); + + nidata.hIcon = tData->hBase; + Shell_NotifyIcon(NIM_MODIFY, &nidata); + + Sleep(tData->time); + } + + delete tData; + hThread = NULL; + + return 0; +} + +int BlinkIcon(HWND hwnd, UINT id, HICON hBase, HICON hBlink, UINT time, UINT num) +{ + if(hThread != NULL) + { + StopBlink(hwnd, id, hBase); + } + + DWORD dwThreadID; + tData = new iBlink; + + tData->hwnd = hwnd; + tData->id = id; + tData->hBase = hBase; + tData->hBlink = hBlink; + tData->time = time; + tData->num = num; + + hThread = CreateThread(NULL, 0, BlinkThread, tData, 0, &dwThreadID); + + return 0; +} + +void StopBlink(HWND hwnd, UINT id, HICON hBase) +{ + if(hThread != NULL) + { + TerminateThread(hThread, 0); + hThread = NULL; + + delete tData; + } + + SetIcon(hwnd, id, hBase); +} \ No newline at end of file diff --git a/plugins/xtray/sdTray.h b/plugins/xtray/sdTray.h new file mode 100644 index 00000000..68469fe0 --- /dev/null +++ b/plugins/xtray/sdTray.h @@ -0,0 +1,39 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_SDTRAY_H +#define _H_SDTRAY_H + +int AddIcon (HWND, UINT, HICON, char *, unsigned short, UINT); +int ShowBalloon (HWND, UINT, char *, char *, UINT, UINT); +int BlinkIcon (HWND, UINT, HICON, HICON, UINT, UINT); +int SetTooltip (HWND, UINT, char *); +int SetIcon (HWND, UINT, HICON); +void StopBlink (HWND, UINT, HICON); +int RemoveIcon (HWND, UINT); + +typedef struct IBLINK +{ + HICON hBase; + HICON hBlink; + HWND hwnd; + UINT id; + UINT time; + UINT num; +}iBlink; +#endif \ No newline at end of file diff --git a/plugins/xtray/utility.cpp b/plugins/xtray/utility.cpp new file mode 100644 index 00000000..60f3f2f0 --- /dev/null +++ b/plugins/xtray/utility.cpp @@ -0,0 +1,563 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <windows.h> +#include <stdio.h> +#include <commctrl.h> +#include <tchar.h> +#include "utility.h" +#include "plugin.h" +#include "xtray.h" +#include "callbacks.h" +#include "resource.h" + +TCHAR BACKUP_INI_FILE[] = _T(".\\plugins\\config\\xtray.conf"); +struct HOTKEY g_hHotKey; + +void SavePrefs(int iDlg) +{ + /**************************************************************************************************/ + /********** allocate space for our string, and then set it to the currently logged on user ********/ + /**************************************************************************************************/ + DWORD dBuff = 257; + TCHAR szUser[257]; + + GetUserName(szUser, &dBuff); + + /**************************************************************************************************/ + /*********************** Test if the file exists, If it doesn't, Create It ************************/ + /**************************************************************************************************/ + TCHAR XTRAY_INI_FILE[1024]; + +#ifdef UNICODE + char temp[1024]; + TCHAR TEMP_INI_FILE[1024]; + + _snprintf(temp, 1024, "%s\\xtray.conf", xchat_get_info(ph, "xchatdir")); + ConvertString(temp, TEMP_INI_FILE, 1024); + + // ok this one is really ugly + // it checks to see if the file exists in two locations + // X-Chat default config dir, if that fails it trys xchat\plugins\config + // if neither one exists it tries to create it in + // X-Chat default config dir, if that fails it trys xchat\plugins\config + // In either case it writes \xFF\xFE to the file ( on creation ) + // so that we can save unicode away messages WritePrivateProfile doesn't + // do this for us, though I think it really should + + if(FileExists(TEMP_INI_FILE)) + { + _tcscpy(XTRAY_INI_FILE, TEMP_INI_FILE); + } + else + { + if(FileExists(BACKUP_INI_FILE)) + { + _tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE); + } + else + { + HANDLE xTemp; + DWORD dwBytesTemp; + + if(xTemp = CreateFile(TEMP_INI_FILE, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL)) + { + if(GetLastError() != ERROR_ALREADY_EXISTS) + { + WriteFile(xTemp, _T("\xFF\xFE"), 4, &dwBytesTemp, NULL); + } + CloseHandle(xTemp); + } + + if(FileExists(TEMP_INI_FILE)) + { + _tcscpy(XTRAY_INI_FILE, TEMP_INI_FILE); + } + else + { + HANDLE xBackup; + DWORD dwBytesBackup; + + if(xBackup = CreateFile(TEMP_INI_FILE, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL)) + { + if(GetLastError() != ERROR_ALREADY_EXISTS) + { + WriteFile(xBackup, _T("\xFF\xFE"), 4, &dwBytesBackup, NULL); + } + + CloseHandle(xBackup); + } + + if(FileExists(BACKUP_INI_FILE)) + { + _tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE); + } + } + } + } + +#else + _tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE); +#endif + + WritePrivateProfileInt(szUser, _T("SETTINGS"), g_dwPrefs, XTRAY_INI_FILE); + WritePrivateProfileInt(szUser, _T("AOT"), g_iTime, XTRAY_INI_FILE); + WritePrivateProfileInt(szUser, _T("KEY"), g_hHotKey.key, XTRAY_INI_FILE); + WritePrivateProfileInt(szUser, _T("MOD"), g_hHotKey.mod, XTRAY_INI_FILE); + WritePrivateProfileString(szUser, _T("AWAY"), g_szAway, XTRAY_INI_FILE); +} + +void LoadPrefs() +{ + /**************************************************************************************************/ + /*********************** Our Settings Section *****************************************************/ + /**************************************************************************************************/ + DWORD dBuff = 257; + TCHAR szUser[257]; + + GetUserName(szUser, &dBuff); + + /**************************************************************************************************/ + /*********************** Test if the file exists, If it doesn't, Create It ************************/ + /**************************************************************************************************/ + TCHAR XTRAY_INI_FILE[1024]; + +#ifdef UNICODE + char temp[1024]; + TCHAR TEMP_INI_FILE[1024]; + + _snprintf(temp, 1024, "%s\\xtray.conf", xchat_get_info(ph, "xchatdir")); + ConvertString(temp, TEMP_INI_FILE, 1024); + + if(FileExists(TEMP_INI_FILE)) + { + _tcscpy(XTRAY_INI_FILE, TEMP_INI_FILE); + } + else + { + if(FileExists(BACKUP_INI_FILE)) + { + _tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE); + } + else + { + HANDLE xTemp; + DWORD dwBytesTemp; + + if(xTemp = CreateFile(TEMP_INI_FILE, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL)) + { + if(GetLastError() != ERROR_ALREADY_EXISTS) + { + WriteFile(xTemp, _T("\xFF\xFE"), 4, &dwBytesTemp, NULL); + } + + CloseHandle(xTemp); + } + + if(FileExists(TEMP_INI_FILE)) + { + _tcscpy(XTRAY_INI_FILE, TEMP_INI_FILE); + } + else + { + HANDLE xBackup; + DWORD dwBytesBackup; + + if(xBackup = CreateFile(TEMP_INI_FILE, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL)) + { + if(GetLastError() != ERROR_ALREADY_EXISTS) + { + WriteFile(xBackup, _T("\xFF\xFE"), 4, &dwBytesBackup, NULL); + } + + CloseHandle(xBackup); + } + + if(FileExists(BACKUP_INI_FILE)) + { + _tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE); + } + } + } + } + +#else + _tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE); +#endif + + /**************************************************************************************************/ + /*************************** Get the value for each of our preferances ****************************/ + /**************************************************************************************************/ + g_dwPrefs = GetPrivateProfileInt(szUser, _T("SETTINGS"), 0, XTRAY_INI_FILE); + + // backwards compatability + // also allows us to set defaults if its a new installation + // disable topic change, channel message and server notice by default + if(g_dwPrefs == 0) + { + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("HILIGHT"), 1, XTRAY_INI_FILE)<<1); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("INVITE"), 1, XTRAY_INI_FILE)<<2); + /* g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("TOPIC"), 1, XTRAY_INI_FILE)<<3); */ + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("BANNED"), 1, XTRAY_INI_FILE)<<4); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("KICKED"), 1, XTRAY_INI_FILE)<<5); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("CTCP"), 1, XTRAY_INI_FILE)<<6); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("PMSG"), 1, XTRAY_INI_FILE)<<7); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("KILLED"), 1, XTRAY_INI_FILE)<<8); + /* g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("NOTICE"), 1, XTRAY_INI_FILE)<<9); */ + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("DISCONNECT"), 1, XTRAY_INI_FILE)<<10); + + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("AOM"), 0, XTRAY_INI_FILE)<<11); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("TOT"), 1, XTRAY_INI_FILE)<<12); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("AMAE"), 1, XTRAY_INI_FILE)<<13); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("OSBWM"), 0, XTRAY_INI_FILE)<<14); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("UWIOB"), 0, XTRAY_INI_FILE)<<15); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("KAOI"), 0, XTRAY_INI_FILE)<<16); + g_dwPrefs |= (GetPrivateProfileInt(szUser, _T("MIOC"), 0, XTRAY_INI_FILE)<<17); + } + + g_hHotKey.key = GetPrivateProfileInt(szUser, _T("KEY"), 84, XTRAY_INI_FILE); + g_hHotKey.mod = GetPrivateProfileInt(szUser, _T("MOD"), (MOD_CONTROL | MOD_SHIFT), XTRAY_INI_FILE); + g_iTime = GetPrivateProfileInt(szUser, _T("AOT"), 5, XTRAY_INI_FILE); + + GetPrivateProfileString(szUser, _T("AWAY"), _T(""), g_szAway, 1024, XTRAY_INI_FILE); + + /**************************************************************************************************/ + /******************************** Register our hotkey with windows ********************************/ + /**************************************************************************************************/ + if(g_dwPrefs & (1<<PREF_UWIOB)) + { + RegisterHotKey(g_hHotkeyWnd, 1, g_hHotKey.mod, g_hHotKey.key); + } +} + +void CheckPrefs(HWND hwnd, int iDlg) +{ + /**************************************************************************************************/ + /**************** save the preferances based on the checkmarks/options ****************************/ + /**************************************************************************************************/ + switch(iDlg) + { + case IDD_EVENTS: + { + SetOption(hwnd, CHAN_HILIGHT, CHAN_HILIGHT); + SetOption(hwnd, CHAN_INVITE, CHAN_INVITE); + SetOption(hwnd, CHAN_TOPIC_CHANGE, CHAN_TOPIC_CHANGE); + SetOption(hwnd, CHAN_BANNED, CHAN_BANNED); + SetOption(hwnd, CHAN_KICKED, CHAN_KICKED); + SetOption(hwnd, CTCP_GENERIC, CTCP_GENERIC); + SetOption(hwnd, PMSG_RECEIVE, PMSG_RECEIVE); + SetOption(hwnd, SERV_KILLED, SERV_KILLED); + SetOption(hwnd, SERV_NOTICE, SERV_NOTICE); + SetOption(hwnd, SERV_DISCONNECT, SERV_DISCONNECT); + SetOption(hwnd, CHAN_MESSAGE, CHAN_MESSAGE); + } + break; + case IDD_ALERTS: + { + SetOption(hwnd, PREF_AMAE, PREF_AMAE); + SetOption(hwnd, PREF_OSBWM, PREF_OSBWM); + SetOption(hwnd, PREF_UWIOB, PREF_UWIOB); + SetOption(hwnd, PREF_KAOI, PREF_KAOI); + SetOption(hwnd, PREF_BLINK, PREF_BLINK); + + /**************************************************************************/ + /**************************************************************************/ + /**************************************************************************/ + TCHAR tTime[512]; + + GetWindowText(GetDlgItem(hwnd, IDC_ALERT_TIME), tTime, 511); + + g_iTime = _tstoi(tTime); + + /**************************************************************************/ + /**************** Get our Hotkey and save it **********/ + /**************** then remove the old hotkey and add the new one **********/ + /**************************************************************************/ + DWORD hHotkey; + hHotkey = SendDlgItemMessage(hwnd, IDC_ALERT_HOTKEY, HKM_GETHOTKEY, 0, 0); + + g_hHotKey.key = LOBYTE(hHotkey); + g_hHotKey.mod = HIBYTE(hHotkey); + + if(IsDlgButtonChecked(hwnd, PREF_UWIOB) == BST_CHECKED) + { + UnregisterHotKey(g_hHotkeyWnd, 1); + RegisterHotKey(g_hHotkeyWnd, 1, g_hHotKey.mod, g_hHotKey.key); + } + else + { + UnregisterHotKey(g_hHotkeyWnd, 1); + } + + /*************************************************************************/ + /*********** Get and save the away msg and alert time ********************/ + /*************************************************************************/ + } + break; + case IDD_SETTINGS: + { + SetOption(hwnd, PREF_AOM, PREF_AOM); + SetOption(hwnd, PREF_TOT, PREF_TOT); + SetOption(hwnd, PREF_MIOC, PREF_MIOC); + SetOption(hwnd, PREF_DNSIT, PREF_DNSIT); + + GetDlgItemText(hwnd, IDC_AWAY_MSG, g_szAway, 511); + + if(g_dwPrefs & (1<<PREF_DNSIT)) + { + DWORD dwStyle; + dwStyle = GetWindowLong(g_hXchatWnd, GWL_STYLE); + dwStyle |= (1<<WS_CHILD); + SetWindowLongPtr(g_hXchatWnd, GWL_STYLE, (LONG_PTR)dwStyle); + SetWindowLongPtr(g_hXchatWnd, GWL_HWNDPARENT, (LONG_PTR)g_hHotkeyWnd); + } + else + { + DWORD dwStyle; + dwStyle = GetWindowLong(g_hXchatWnd, GWL_STYLE); + dwStyle &= ~(1<<WS_CHILD); + SetWindowLongPtr(g_hXchatWnd, GWL_STYLE, (LONG_PTR)dwStyle); + SetWindowLongPtr(g_hXchatWnd, GWL_HWNDPARENT, NULL); + } + } + break; + } +} + +void SetDialog(HWND hwnd, int iDlg) +{ + switch(iDlg) + { + case IDD_EVENTS: + { + SetCheck(hwnd, CHAN_HILIGHT, CHAN_HILIGHT); + SetCheck(hwnd, CHAN_INVITE, CHAN_INVITE); + SetCheck(hwnd, CHAN_TOPIC_CHANGE, CHAN_TOPIC_CHANGE); + SetCheck(hwnd, CHAN_BANNED, CHAN_BANNED); + SetCheck(hwnd, CHAN_KICKED, CHAN_KICKED); + SetCheck(hwnd, CTCP_GENERIC, CTCP_GENERIC); + SetCheck(hwnd, PMSG_RECEIVE, PMSG_RECEIVE); + SetCheck(hwnd, SERV_KILLED, SERV_KILLED); + SetCheck(hwnd, SERV_NOTICE, SERV_NOTICE); + SetCheck(hwnd, SERV_DISCONNECT, SERV_DISCONNECT); + SetCheck(hwnd, CHAN_MESSAGE, CHAN_MESSAGE); + } + break; + case IDD_SETTINGS: + { + SetCheck(hwnd, PREF_TOT, PREF_TOT); + SetCheck(hwnd, PREF_MIOC, PREF_MIOC); + SetCheck(hwnd, PREF_AOM, PREF_AOM); + SetCheck(hwnd, PREF_DNSIT, PREF_DNSIT); + + SetDlgItemText(hwnd, IDC_AWAY_MSG, g_szAway); + } + break; + case IDD_ALERTS: + { + + SetCheck(hwnd, PREF_BLINK, PREF_BLINK); + SetCheck(hwnd, PREF_OSBWM, PREF_OSBWM); + SetCheck(hwnd, PREF_UWIOB, PREF_UWIOB); + SetCheck(hwnd, PREF_KAOI, PREF_KAOI); + + /**********************************************************/ + /**********************************************************/ + /**********************************************************/ + if(SetCheck(hwnd, PREF_AMAE, PREF_AMAE) == false) + { + SetToggle(hwnd, PREF_OSBWM, PREF_AMAE, TRUE); + SetToggle(hwnd, PREF_UWIOB, PREF_AMAE, TRUE); + SetToggle(hwnd, PREF_KAOI, PREF_AMAE, TRUE); + SetToggle(hwnd, IDC_ALERT_TIME, PREF_AMAE, TRUE); + SetToggle(hwnd, IDC_ALERT_TIME_TEXT, PREF_AMAE, TRUE); + SetToggle(hwnd, IDC_ALERT_HOTKEY, PREF_AMAE, TRUE); + SetToggle(hwnd, IDC_ALERT_HOTKEY_TEXT, PREF_AMAE, TRUE); + } + else + { + + SetToggle(hwnd, IDC_ALERT_HOTKEY, PREF_UWIOB, TRUE); + SetToggle(hwnd, IDC_ALERT_HOTKEY_TEXT, PREF_UWIOB, TRUE); + SetToggle(hwnd, IDC_ALERT_TIME, PREF_KAOI, FALSE); + SetToggle(hwnd, IDC_ALERT_TIME_TEXT, PREF_KAOI, FALSE); + } + + /**********************************************************/ + /**********************************************************/ + /**********************************************************/ + TCHAR tTime[255]; + SendDlgItemMessage(hwnd, IDC_ALERT_TIME, WM_SETTEXT, 0, (LPARAM)_itot(g_iTime, tTime, 10)); + SendDlgItemMessage(hwnd, IDC_ALERT_HOTKEY, HKM_SETHOTKEY, MAKEWORD(g_hHotKey.key, g_hHotKey.mod), 0); + } + break; + } +} + +int SetCheck(HWND hDialog, unsigned int uiCheckBox, unsigned int uiPref) +{ + if((g_dwPrefs & (1<<uiPref))) + { + CheckDlgButton(hDialog, uiCheckBox, BST_CHECKED); + return 1; + } + else + { + CheckDlgButton(hDialog, uiCheckBox, BST_UNCHECKED); + return 0; + } + + return 0; +} + +int SetToggle(HWND hDialog, unsigned int uiCheckBox, unsigned int uiTestbox, bool offeqoff) +{ + /**************************************************************************************************/ + /*********************** if(true) then if option is off turn toggle off ***************************/ + /*********************** if(false) then if option is off turn toggle on ***************************/ + /**************************************************************************************************/ + if(offeqoff) + { + if(IsDlgButtonChecked(hDialog, uiTestbox) == BST_CHECKED) + { + EnableWindow(GetDlgItem(hDialog, uiCheckBox), TRUE); + return 1; + } + else + { + EnableWindow(GetDlgItem(hDialog, uiCheckBox), FALSE); + return 0; + } + } + else + { + if(IsDlgButtonChecked(hDialog, uiTestbox) == BST_CHECKED) + { + EnableWindow(GetDlgItem(hDialog, uiCheckBox), FALSE); + return 1; + } + else + { + EnableWindow(GetDlgItem(hDialog, uiCheckBox), TRUE); + return 0; + } + } + + return 0; +} + +int SetOption(HWND hDialog, unsigned int uiCheckBox, unsigned int uiPref) +{ + if(IsDlgButtonChecked(hDialog, uiCheckBox) == BST_CHECKED) + { + g_dwPrefs |= (1<<uiPref); + } + else + { + g_dwPrefs &= ~(1<<uiPref); + } + + return (g_dwPrefs & (1<<uiPref)); +} + +int WritePrivateProfileIntA(char *szSection, char *szItem, int iData, char *szPath) +{ + char szData[33]; + itoa(iData, szData, 10); + return WritePrivateProfileStringA(szSection, szItem, szData, szPath); +} + +int WritePrivateProfileIntW(wchar_t *wszSection, wchar_t *wszItem, int iData, wchar_t *wszPath) +{ + wchar_t wszData[33]; + _itow(iData, wszData, 10); + return WritePrivateProfileStringW(wszSection, wszItem, wszData, wszPath); +} + +// For cleanup ( Closing windows and the such ) +void HoldClose() +{ + HANDLE hcThread; + DWORD dwThreadID; + hcThread = CreateThread(NULL, 0, HoldCloseThread, 0, 0, &dwThreadID); +} + +DWORD WINAPI HoldCloseThread(LPVOID lpParam) +{ + Sleep(1000); + PostMessage(g_hXchatWnd, WM_CLOSE, 0, 0); + return 0; +} + +bool FileExists(TCHAR *file) +{ + HANDLE hTemp = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + int nRet = GetLastError(); + CloseHandle(hTemp); + + if(nRet == 0) + { + return true; + } + else + { + return false; + } + + return false; +} + +void ConvertString(const char *in, wchar_t *out, int size) +{ + MultiByteToWideChar(CP_UTF8, 0, in, -1, out, size); +} + +void ConvertString(const wchar_t *in, char *out, int size) +{ + WideCharToMultiByte(CP_UTF8, 0, in, (size - 1), out, size, NULL, NULL); +} + +void ConvertString(const char *in, char *out, int size) +{ + strncpy(out, in, size); +} + +void ErrorDebug(LPTSTR lpszFunction) +{ + TCHAR szBuf[80]; + LPVOID lpMsgBuf; + DWORD dw = GetLastError(); + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL ); + + _stprintf(szBuf, + _T("%s failed with error %d: %s"), + lpszFunction, dw, lpMsgBuf); + + MessageBox(NULL, szBuf, _T("Error"), MB_OK); + + LocalFree(lpMsgBuf); +} + diff --git a/plugins/xtray/utility.h b/plugins/xtray/utility.h new file mode 100644 index 00000000..ce3d541c --- /dev/null +++ b/plugins/xtray/utility.h @@ -0,0 +1,52 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_UTILITY_H +#define _H_UTILITY_H + +int SetOption (HWND, unsigned int, unsigned int); +int SetCheck (HWND, unsigned int, unsigned int); +int SetToggle (HWND, unsigned int, unsigned int, bool); +void ErrorDebug (LPTSTR lpszFunction); +void SetDialog (HWND, int); +void CheckPrefs (HWND, int); +bool FileExists (TCHAR *); +DWORD WINAPI HoldCloseThread (LPVOID); +void SavePrefs (int); +void LoadPrefs (); +void HoldClose (); + +void ConvertString(const char *in, wchar_t *out, int size); +void ConvertString(const wchar_t *in, char *out, int size); +void ConvertString(const char *in, char *out, int size); + +int WritePrivateProfileIntA(char *, char *, int, char *); +int WritePrivateProfileIntW(wchar_t *, wchar_t *, int, wchar_t *); + +#ifdef UNICODE +#define WritePrivateProfileInt WritePrivateProfileIntW +#else +#define WritePrivateProfileInt WritePrivateProfileIntA +#endif + +struct HOTKEY +{ + WORD key; + WORD mod; +}; +#endif \ No newline at end of file diff --git a/plugins/xtray/xchat.cpp b/plugins/xtray/xchat.cpp new file mode 100644 index 00000000..581970f1 --- /dev/null +++ b/plugins/xtray/xchat.cpp @@ -0,0 +1,319 @@ +/* X-Tray + * Copyright (C) 1998, 2005 Peter Zelezny, Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <windows.h> +#include <vector> +#include <algorithm> +#include <stdio.h> +#include <tchar.h> +#include "plugin.h" +#include "xtray.h" +#include "resource.h" +#include "xchat.h" +#include "utility.h" + +// from util.c of xchat source code ( slightly modified to fit X-Tray Syntax ) +char *xchat_strip_color (char *text) +{ + int nc = 0; + int i = 0; + int col = 0; + int len = strlen(text); + char *new_str = (char *)malloc(len + 2); + + while (len > 0) + { + if ((col && isdigit(*text) && (nc < 2)) || (col && isdigit(*(text+1)) && (nc < 3) && (*text == ','))) + { + nc++; + + if(*text == ',') + { + nc = 0; + } + } + else + { + col = 0; + + switch (*text) + { + case '\003': /*ATTR_COLOR: */ + { + col = 1; + nc = 0; + } + break; + case '\007': /*ATTR_BEEP: */ + case '\017': /*ATTR_RESET: */ + case '\026': /*ATTR_REVERSE: */ + case '\002': /*ATTR_BOLD: */ + case '\037': /*ATTR_UNDERLINE: */ + break; + default: + { + new_str[i] = *text; + i++; + } + break; + } + } + + text++; + len--; + } + + new_str[i] = 0; + + return new_str; +} + +void check_special_chars (char *cmd) +{ + int occur = 0; + int len = strlen (cmd); + int i = 0, j = 0; + char *buf; + + if (!len) + return; + + buf = (char *)malloc (len + 1); + + if (buf) + { + while (cmd[j]) + { + switch (cmd[j]) + { + case '%': + { + occur++; + + switch (cmd[j + 1]) + { + case 'R': + buf[i] = '\026'; + break; + case 'U': + buf[i] = '\037'; + break; + case 'B': + buf[i] = '\002'; + break; + case 'C': + buf[i] = '\003'; + break; + case 'O': + buf[i] = '\017'; + break; + case '%': + buf[i] = '%'; + break; + default: + buf[i] = '%'; + j--; + break; + } + + j++; + } + break; + default: + { + buf[i] = cmd[j]; + } + break; + } + + j++; + i++; + } + + buf[i] = 0; + + if (occur) + strcpy (cmd, buf); + + free (buf); + } +} + +void xchat_globally_away(TCHAR *tszAway) +{ + char szTemp[512]; + char szAway[512]; + + ConvertString(tszAway, szAway, 512); + _snprintf(szTemp, 512, "ALLSERV AWAY %s\0", szAway); + check_special_chars(szTemp); + xchat_exec(szTemp); +} + +void xchat_away(TCHAR *tszAway) +{ + char szTemp[512]; + char szAway[512]; + + ConvertString(tszAway, szAway, 512); + _snprintf(szTemp, 512, szAway); + check_special_chars(szTemp); + xchat_commandf(ph, "AWAY %s\0", szTemp); +} + +void xchat_globally_back() +{ + std::vector<int> xs; + std::vector<int>::iterator xsi; + xchat_list *xl = xchat_list_get(ph, "channels"); + + if(xl) + { + while(xchat_list_next(ph, xl)) + { + xsi = std::find(xs.begin(), xs.end(), xchat_list_int(ph, xl, "id")); + + if((xsi == xs.end()) && + ((strlen(xchat_list_str(ph, xl, "server")) > 0) || + (strlen(xchat_list_str(ph, xl, "channel")) > 0))) + { + xs.push_back(xchat_list_int(ph, xl, "id")); + xchat_set_context(ph, (xchat_context *)xchat_list_str(ph, xl, "context")); + xchat_back(); + } + } + + xchat_list_free(ph, xl); + } +} + + + +void xchat_back() +{ + if(xchat_get_info(ph, "away")) + { + xchat_command(ph, "BACK"); + } +} + +HMENU setServerMenu() +{ + HMENU sTemp = CreateMenu(); + TCHAR wszServer[128]; + TCHAR wszNick[128]; + TCHAR wszMenuEntry[256]; + + std::vector<int> xs; + std::vector<int>::iterator xsi; + xchat_list *xl = xchat_list_get(ph, "channels"); + + AppendMenu(sTemp, MF_STRING, ACT_AWAY, _T("Set Globally Away")); + AppendMenu(sTemp, MF_STRING, ACT_BACK, _T("Set Globally Back")); + AppendMenu(sTemp, MF_SEPARATOR, 0, NULL); + + if(xl) + { + while(xchat_list_next(ph, xl)) + { + xsi = std::find(xs.begin(), xs.end(), xchat_list_int(ph, xl, "id")); + + if( (xsi == xs.end()) && + ((strlen(xchat_list_str(ph, xl, "server")) > 0) || + (strlen(xchat_list_str(ph, xl, "channel")) > 0))) + { + xchat_set_context(ph, (xchat_context *)xchat_list_str(ph, xl, "context")); + xs.push_back(xchat_list_int(ph, xl, "id")); + + char *network = _strdup(xchat_list_str(ph, xl, "network")); + char *server = _strdup(xchat_list_str(ph, xl, "server")); + char *nick = _strdup(xchat_get_info(ph, "nick")); + + if(network != NULL) + { + ConvertString(network, wszServer, 128); + } + else + { + ConvertString(server, wszServer, 128); + } + + if(server != NULL) + { + ConvertString(nick, wszNick, 128); + _sntprintf(wszMenuEntry, 256, _T("%s @ %s\0"), wszNick, wszServer); + + if(!xchat_get_info(ph, "away")) + { + AppendMenu(sTemp, MF_STRING, (xchat_list_int(ph, xl, "id") + 1), wszMenuEntry); + } + else + { + AppendMenu(sTemp, (MF_CHECKED | MF_STRING), (xchat_list_int(ph, xl, "id") + 1), wszMenuEntry); + } + } + + free(network); + free(server); + free(nick); + } + } + + xchat_list_free(ph, xl); + } + + return sTemp; +} + +struct _xchat_context *xchat_find_server(int find_id) +{ + xchat_context *xc; + xchat_list *xl = xchat_list_get(ph, "channels"); + int id; + + if(!xl) + return NULL; + + while(xchat_list_next(ph, xl)) + { + id = xchat_list_int(ph, xl, "id"); + + if(id == -1) + { + return NULL; + } + else if(id == find_id) + { + xc = (xchat_context *)xchat_list_str(ph, xl, "context"); + + xchat_list_free(ph, xl); + + return xc; + } + } + + xchat_list_free(ph, xl); + + return NULL; +} + +void xchat_exec(char *command) +{ + xchat_set_context(ph, xchat_find_context(ph, NULL, NULL)); + xchat_command(ph, command); +} \ No newline at end of file diff --git a/plugins/xtray/xchat.h b/plugins/xtray/xchat.h new file mode 100644 index 00000000..76452aeb --- /dev/null +++ b/plugins/xtray/xchat.h @@ -0,0 +1,32 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _H_XCHAT_H +#define _H_XCHAT_H + +void xchat_exec (char *); +char *xchat_strip_color (char *); +void xchat_parse (char *); +struct _xchat_context *xchat_find_server (int); +void xchat_globally_away (TCHAR *); +void xchat_away (TCHAR *); +void xchat_globally_back (); +void xchat_back (); +HMENU setServerMenu (); + +#endif \ No newline at end of file diff --git a/plugins/xtray/xtray.cpp b/plugins/xtray/xtray.cpp new file mode 100644 index 00000000..a7c8c8bd --- /dev/null +++ b/plugins/xtray/xtray.cpp @@ -0,0 +1,219 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _WIN32_IE 0x0601 + +#include <windows.h> +#include <list> +#include <string> +#include <shobjidl.h> +#include "resource.h" +#include "callbacks.h" +#include "plugin.h" +#include "utility.h" +#include "xtray.h" +#include "sdTray.h" +#include "sdAlerts.h" +#include "plugin.h" + +/*****************************************************/ +/**** Don't want to pollute the namespace do we? *****/ +/*****************************************************/ +std::list<xchat_hook *> g_vHooks; + +/*****************************************************/ +/************ Global Identifiers *********************/ +/*****************************************************/ +WNDPROC g_hOldProc; +xchat_plugin *ph; + +/*****************************************************/ +/***************** Resources *************************/ +/*****************************************************/ +HWND g_hXchatWnd; +HWND g_hHotkeyWnd; +HWND g_hPrefDlg; +HMENU g_hTrayMenu; +HICON g_hIcons[11]; +HANDLE g_hInstance; +/*****************************************************/ +/***************** Preferences ***********************/ +/*****************************************************/ +unsigned int g_dwPrefs; +TCHAR g_szAway[512]; +int g_iTime; + + +BOOL WINAPI DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpVoid) +{ + if((fdwReason == DLL_PROCESS_ATTACH) || (fdwReason == DLL_THREAD_ATTACH)) + { + g_hInstance = hModule; + } + + return TRUE; +} + +int xchat_plugin_init(xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg) +{ + ph = plugin_handle; + + *plugin_name = "X-Tray"; + *plugin_desc = "Minimize XChat to the Windows system tray"; + *plugin_version = "1.2.4"; + + /***************************************************************************************************************************/ + /************************* Load our preferances from xTray.ini *************************************************************/ + /***************************************************************************************************************************/ + LoadPrefs(); + + /***************************************************************************************************************************/ + /************************* Finds the xChat window and saves it for later use ***********************************************/ + /***************************************************************************************************************************/ + g_hXchatWnd = (HWND)xchat_get_info(ph, "win_ptr"); + + if(g_hXchatWnd == NULL) + { + EnumThreadWindows(GetCurrentThreadId(), EnumWindowsProc, 0); + } + + g_hOldProc = (WNDPROC)GetWindowLongPtr(g_hXchatWnd, GWLP_WNDPROC); + SetWindowLongPtr(g_hXchatWnd, GWLP_WNDPROC, (LONG_PTR)WindowProc); + + /***************************************************************************************************************************/ + /************************* Grab the xChat Icon, Load our menu, create the window to receive the hotkey messages ***********/ + /************************* and register the windows message so we know if explorer crashes ***********/ + /***************************************************************************************************************************/ + g_hTrayMenu = GetSubMenu(LoadMenu((HINSTANCE)g_hInstance, MAKEINTRESOURCE(IDR_TRAY_MENU)), 0); + g_hHotkeyWnd = CreateDialog((HINSTANCE)g_hInstance, MAKEINTRESOURCE(IDD_ALERT), NULL, (DLGPROC)HotKeyProc); + g_hPrefDlg = CreateDialog((HINSTANCE)g_hInstance, MAKEINTRESOURCE(IDD_PREF), g_hXchatWnd, (DLGPROC)PrefProc); + + g_hIcons[0] = (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_XCHAT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + g_hIcons[1] = (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_CHANMSG), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + g_hIcons[2] = (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_HIGHLIGHT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + g_hIcons[5] = (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_BANNED), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + g_hIcons[6] = (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_KICKED), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + g_hIcons[8] = (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_PMSG), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + g_hIcons[10]= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_SNOTICE), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + g_hIcons[11]= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_DISCONNECTED), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + + /***************************************************************************************************************************/ + /************************* Add our icon to the tray ************************************************************************/ + /***************************************************************************************************************************/ + char szVersion[64]; + _snprintf(szVersion, 64, "XChat-WDK [%s]", xchat_get_info(ph, "version")); + AddIcon(g_hXchatWnd, 1, g_hIcons[0], szVersion, (NIF_ICON | NIF_MESSAGE | NIF_TIP), WM_TRAYMSG); + + /***************************************************************************************************************************/ + /***************************************************************************************************************************/ + /***************************************************************************************************************************/ + if(g_dwPrefs & (1<<PREF_DNSIT)) + { + DWORD dwStyle; + dwStyle = GetWindowLong(g_hXchatWnd, GWL_STYLE); + dwStyle |= (1<<WS_CHILD); + SetWindowLongPtr(g_hXchatWnd, GWL_STYLE, (LONG_PTR)dwStyle); + SetWindowLongPtr(g_hXchatWnd, GWL_HWNDPARENT, (LONG_PTR)g_hHotkeyWnd); + } + + /***************************************************************************************************************************/ + /************************* Set our hooks and save them for later so we can unhook them *************************************/ + /***************************************************************************************************************************/ + g_vHooks.push_back(xchat_hook_print(ph, "Channel Msg Hilight", XCHAT_PRI_NORM, event_cb, (void *)CHAN_HILIGHT)); + g_vHooks.push_back(xchat_hook_print(ph, "Channel Message", XCHAT_PRI_NORM, event_cb, (void *)CHAN_MESSAGE)); + g_vHooks.push_back(xchat_hook_print(ph, "Topic Change", XCHAT_PRI_NORM, event_cb, (void *)CHAN_TOPIC_CHANGE)); + g_vHooks.push_back(xchat_hook_print(ph, "Channel Action Hilight", XCHAT_PRI_NORM, event_cb, (void *)CHAN_HILIGHT)); + g_vHooks.push_back(xchat_hook_print(ph, "Channel INVITE", XCHAT_PRI_NORM, event_cb, (void *)CHAN_INVITE)); + g_vHooks.push_back(xchat_hook_print(ph, "You Kicked", XCHAT_PRI_NORM, event_cb, (void *)CHAN_KICKED)); + g_vHooks.push_back(xchat_hook_print(ph, "Banned", XCHAT_PRI_NORM, event_cb, (void *)CHAN_BANNED)); + g_vHooks.push_back(xchat_hook_print(ph, "CTCP Generic", XCHAT_PRI_NORM, event_cb, (void *)CTCP_GENERIC)); + g_vHooks.push_back(xchat_hook_print(ph, "Private Message", XCHAT_PRI_NORM, event_cb, (void *)PMSG_RECEIVE)); + g_vHooks.push_back(xchat_hook_print(ph, "Private Message to Dialog", XCHAT_PRI_NORM, event_cb, (void *)PMSG_RECEIVE)); + g_vHooks.push_back(xchat_hook_print(ph, "Disconnected", XCHAT_PRI_NORM, event_cb, (void *)SERV_DISCONNECT)); + g_vHooks.push_back(xchat_hook_print(ph, "Killed", XCHAT_PRI_NORM, event_cb, (void *)SERV_KILLED)); + g_vHooks.push_back(xchat_hook_print(ph, "Notice", XCHAT_PRI_NORM, event_cb, (void *)SERV_NOTICE)); + g_vHooks.push_back(xchat_hook_command(ph, "tray_alert", XCHAT_PRI_NORM, command_cb, "Create an Alert", NULL)); + + return 1; +} + +int xchat_plugin_deinit(xchat_plugin *plugin_handle) +{ + /******************************************/ + /****** Remove the Icon from the tray *****/ + /******************************************/ + StopBlink(g_hXchatWnd, 1, g_hIcons[0]); + RemoveIcon(g_hXchatWnd, 1); + + /*******************************************/ + /*******************************************/ + /*******************************************/ + if(g_dwPrefs & (1<<PREF_DNSIT)) + { + DWORD dwStyle; + dwStyle = GetWindowLong(g_hXchatWnd, GWL_STYLE); + dwStyle &= ~(1<<WS_CHILD); + SetWindowLongPtr(g_hXchatWnd, GWL_STYLE, (LONG_PTR)dwStyle); + SetWindowLongPtr(g_hXchatWnd, GWL_HWNDPARENT, NULL); + } + + /******************************************/ + /****** Unload our resources **************/ + /******************************************/ + DestroyMenu(g_hTrayMenu); + + for(int i = 0; i <= 11; i++) + { + DestroyIcon(g_hIcons[i]); + } + + /******************************************/ + /****** Remove our window hook ************/ + /******************************************/ + SetWindowLongPtr(g_hXchatWnd, GWLP_WNDPROC, (LONG_PTR)g_hOldProc); + + /******************************************/ + /****** Remove our hotkey, and destroy ****/ + /****** the window that receives its ****/ + /****** messages ****/ + /******************************************/ + UnregisterHotKey(g_hHotkeyWnd, 1); + DestroyWindow(g_hHotkeyWnd); + DestroyWindow(g_hPrefDlg); + + /******************************************/ + /************* Clean up Isle 7 ************/ + /******************************************/ + if(sdAlertNum()) + { + sdCloseAlerts(); + } + /******************************************/ + /****** remove our xchat_hook_*s **********/ + /******************************************/ + while(!g_vHooks.empty()) + { + if(g_vHooks.back() != NULL) + { + xchat_unhook(ph, g_vHooks.back()); + } + g_vHooks.pop_back(); + } + + return 1; +} diff --git a/plugins/xtray/xtray.h b/plugins/xtray/xtray.h new file mode 100644 index 00000000..56323cf2 --- /dev/null +++ b/plugins/xtray/xtray.h @@ -0,0 +1,77 @@ +/* X-Tray + * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com> + * + * X-Tray is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * X-Tray is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with X-Tray; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _XTRAY_H +#define _XTRAY_H + +/******************** Globals *************************/ +extern HWND g_hXchatWnd; +extern HWND g_hHotkeyWnd; +extern HWND g_hPrefDlg; +extern HMENU g_hTrayMenu; +extern HICON g_hIcons[11]; +extern HANDLE g_hInstance; +extern unsigned int g_dwPrefs; +extern TCHAR g_szAway[512]; +extern int g_iTime; +extern WNDPROC g_hOldProc; +extern struct _xchat_plugin *ph; +/******************************************************/ + +/******************** Messages ************************/ +#define WM_TRAYMSG WM_APP +/******************************************************/ + +/********************* Events *************************/ +#define CHAN_HILIGHT 1 +#define CHAN_INVITE 2 +#define CHAN_TOPIC_CHANGE 3 +#define CHAN_BANNED 4 +#define CHAN_KICKED 5 + +#define CTCP_GENERIC 6 +#define PMSG_RECEIVE 7 + +#define SERV_KILLED 8 +#define SERV_NOTICE 9 +#define SERV_DISCONNECT 10 + +/* new events */ +#define CHAN_MESSAGE 21 + +#define PREF_AOM 11 // away on minimize +#define PREF_TOT 12 // Tray on Taskbar +#define PREF_AMAE 13 // alert me about events +#define PREF_OSBWM 14 // Only Show Balloon When Minimized +#define PREF_UWIOB 15 // Use Window Instead of Balloon +#define PREF_KAOI 16 // Keep alerts open indefinately +#define PREF_MIOC 17 // Minimize instead of close +#define PREF_BLINK 18 // blink icon +#define PREF_CICO 19 // change icon - not implemented +#define PREF_DNSIT 20 // Do not show in taskbar +/******************************************************/ +#endif + +#ifdef _WIN64 +/* use replacement with the same value, and use SetWindowLongPtr instead + of SetWindowLong. more info: + + http://msdn.microsoft.com/en-us/library/ms633591.aspx + http://msdn.microsoft.com/en-us/library/ms644898.aspx */ +#define GWL_HWNDPARENT GWLP_HWNDPARENT +#endif |