commit feca086612ce1b6c22118dae2812cdc3b9a70253 Author: Brian Cline Date: Sun Jan 25 18:26:44 2015 -0600 Initial commit of code released on 2002-07-15 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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 to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), 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 Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. 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. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/CS/COPYING b/CS/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/CS/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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 to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), 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 Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. 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. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/HTTP/X_registration_form.txt b/HTTP/X_registration_form.txt new file mode 100644 index 0000000..d48b80e --- /dev/null +++ b/HTTP/X_registration_form.txt @@ -0,0 +1,74 @@ +################################################################### +# Undernet Channel Service # +# Registration Form # +################################################################### +# Instructions: # +# o Read the Channel Service Committee Guidelines # +# This document can be obtained from: # +# ftp://ftp.undernet.org/pub/irc/docs/X/CSC-guidelines # +# /msg helpbot get CSC-guidelines # +# o Fill out this registration form completely # +# If you need help, ask in #cservice. # +# o Email completed form to cservice@undernet.org # +# Please be sure to include this form in the # +# BODY of your email, NOT as an attachment. # +# o If you do not receive acknowledgement of receipt of # +# this form within 2 weeks, please email it again, # +# stating that it is a second attempt. # +# o If your channel is not registered within 4 weeks, # +# you may email cservice@undernet.org to find out why # +################################################################### + +------------------------------------------------------------------- +NOTE: Channel registration is not meant as a means to start a new + channel. It is meant for previously established channels + to have an opportunity to have some stability. If you are + first starting a new channel, then just start it, give it + some time to make sure you have a decent userbase, and then + consider registration. Thanks. +------------------------------------------------------------------- + +A) Your Real Name : + +B) The usual nick you use : + +C) Your E-mail address : + +D) The user@host that you use on irc : + {the address in your /whois on IRC} + {please try to include asterisks (*) wherever necessary} + +E) Channel Name : + +F) Purpose of channel : + {brief description} + +G) Supporter's list : + This is a list of people who support you as channel + manager of this channel and who will frequent the channel. + You may want to CC them a copy of your application. + - Please do NOT include yourself as a supporter. + - Please do NOT use 2 (or more) different email addresses + of a user as being 2 (or more) different supporters. + Each entry in this list must be a different user. + + --------------------------------------------------------------- + Nickname | E-mail address + --------------------------------------------------------------- + + 1: + 2: + 3: + 4: + 5: + 6: + 7: + 8: + 9: +10: + _______________________________________________________________ + + PLEASE NOTE -- You must have at least 10 supporters to register + a channel. You also may only register 1 channel. + _______________________________________________________________ + diff --git a/HTTP/b_arrow.gif b/HTTP/b_arrow.gif new file mode 100644 index 0000000..4a28444 Binary files /dev/null and b/HTTP/b_arrow.gif differ diff --git a/HTTP/chanopfaq.html b/HTTP/chanopfaq.html new file mode 100644 index 0000000..92668b3 --- /dev/null +++ b/HTTP/chanopfaq.html @@ -0,0 +1,276 @@ + + +Undernet Channel Service: Channel Operators FAQ + + +
+

+


+

Undernet Channel Service Committee

+

Channel Operator's FAQ

+
+
+ +
+Introduction: This FAQ has been put together by the Undernet Channel Service Committee for any and all users who have Channel Operator status on a Registered Channel on the Undernet.
+
+
+1) What is the Undernet Channel Service Committee?
+The Undernet Channel Service Committee is a sub committee of the Undernet User Committee (User-Com). The CSC (Channel Service Committee) is in charge of administrating the Channel Service and assisting users with its use.

+ +2) Who are X and W?
+X and W are the two Channel Service (CService) bots. They reside on Undernet's registered channels. Each registered channel has either X or W, but not both. They are exactly the same in the functions they can perform. The bots + hold separate user lists for each channel they reside on. These are lists of users for each channel who have access to certain functions on the bots depending on the level and settings of the user.

+ +3) What is a Channel Operator?
+A Channel Operator (ChanOp) is a user who has been given the privilege of helping the Channel Manager run the channel. ChanOps are expected to abide by all of the Channel Manager's rules, as well as CService's rules.

+ +4) What are the responsibilities of a ChanOp?
+A ChanOp is responsible for helping to maintain the atmosphere that the Channel Manager has set for his/her channel. This means ensuring that all users abide by the set channel rules and warning/removing users who do not abide by +them.

+ +5) Who is the Channel Manager?
+The Channel Manager is the person who registered the channel. There is generally only one Channel Manager, unless a special arrangement has been made with CService to have more than one. The Channel Manager makes the decisions on + how the channel is to be run. This is the person to go to first if you have a problem on your channel.

+

+ To find out who the Channel Manager is:
+ /msg x chaninfo #channel
+ or
+ /msg w chaninfo #channel
+ Depending on which bot resides on that particular channel.
+

+

+*** All examples that follow will refer to X, but can be used with W as well.

+ +6) Can a user be a ChanOp even if s/he is not on the user list?
+Yes. A user can gain ops on a channel if they are given operator status from a current operator. This does not mean that just because someone makes you an op, you automatically have access to X/W. All it means is that you can pe +rform any operator commands that you can normally do on a non-registered channel.

+

+Keep in mind that it is not a good idea to give ops to just anyone on the channel, though, since as an operator they have the ability to kick and ban anyone off the channel including X/W. Most forms of abuse of X/W are from users who do not know what X/ +W are nor know and understand the CService rules. If you are going to give someone ops make sure that they will not be abusive and they will not try to kick/ban X/W off the channel. Also, some Channel Managers have their own rules about giving out ops +to users who are not on X/W's user list, so make sure you follow the Channel Manager's rules as well.

+ +7) How do I know who is on the user list?
+You can find out if someone is on the user list for a channel by:
+

+/msg x access #channel nickname

+ +If the person is on the list for that channel, you will get a notice which looks like this:

+

+
+-X- USER: teal (*!*erf103@*.psu.edu) ACCESS: ?450
+-X- CHANNEL: #Help -- AUTOOP: YES -- PROTECT: YES
+-X- LAST SEEN: 10 days, 19:42:16 ago

+ +Line 1: nickname, user@host mask and access level
+Line 2: channel name, autoop setting, protect setting
+Line 3: how long ago user was last seen on the channel

+

+ +8) How do I get added to a channel's user list?
+Only ChanOps with ACCESS level 400 or higher can add users to the channel's user list. Who gets added is usually determined by the Channel Manager. Some channels may have a recommendation/voting process to add new ChanOps. Best +bet is to ask someone who is a ChanOp on that channel.

+ +9) What is this ACCESS level thing?
+A user's level determines what commands the user has access to on X or W. Users will have access to the commands for their level, plus all commands for any levels below them. For example, a level 75 user will have access to ban a +nd unban, plus the level 50 and level 0 commands.

+ +To find out what commands you have access to on a particular channel,

+

+/msg x showcommands #channelname

+

+Here are the commands for the all the different levels:
+
    +
      +
    • Level 500: set +
    • Level 450: addchan join part remchan +
    • Level 400: adduser clearmode modinfo remuser status +
    • Level 100: deop invite op suspend unsuspend +
    • Level 75: ban unban +
    • Level 50: kick topic +
    • Level 0: access banlist chaninfo deauth help lbanlist map motd newpass pass showcommands showignore verify

      +

    +
+Some Notes:
+ +
    +
      +
    • 500........... Channel Manager.

      + +

    • 450 & 400..... Trusted Administrators. These are ChanOps that the Channel Manager has allowed to help in administrative duties on the channel.

      + +

    • 100........... These ChanOps can command X to perform all regular ChanOp commands, including some special X/W commands.

      + +

    • 75 & 50....... These ChanOps can command X to perform most regular ChanOp commands (see above list) as well as some special ones.

      + +

    • 0............. All users who are not on the bot's user list for that channel. Also, any ChanOp who has a password set, but has not yet msg'd the bot with his/her password will be seen as a level 0 user.

      +

    +
+
+NOTE: For "regular" ChanOp commands (ie. kick, ban, unban, op, deop) these levels just allow for the ChanOp to command the bot to do them. Regardless of the ChanOp's level, these commands can still be performed manually by the ChanOp.

+

+
+	For example:
+		A level 100 ChanOp can op another user either by:
+			/msg x op #channel nickname
+				or
+			/mode #channel +o nickname
+
+		A level 50 or level 75 ChanOp can op another user by:
+			/mode #channel +o nickname
+		BUT cannot /msg x op   as the level 100 can.
+
+

+10) What does the ? next to a user's ACCESS level mean?
+The ? just means that the bot is not sure if the user is on-line. This could mean that either the user is not signed on, or has not given their password to identify themselves yet.

+ +11) What is AUTOOP?
+When AUTOOP is set to ON, you will be automatically opped by X upon entering the channel. If you have a password set though, then AUTOOP will only work if you /msg X with your password BEFORE you enter the channel.

+

+If AUTOOP is set to OFF, you will need to /msg x op #channel yournick for X to op you. Again, if you have a password set, you will need to /msg x with your password before you ask it to op you.

+

+12) What is PROTECT?
+When PROTECT is set to ON, you will be protected by X from other ops banning or deopping you. What this means is that if someone tries to ban or deop you, they will be deopped (even if they are protected also) and X will automatic +ally unban or reop you.

+ +13) Why would I use a password and how do I set one?
+A password gives more protection against someone faking your user@host and obtaining ops. If you have a password set, X/W will only recognize you if you have the correct user@host AND give the correct password.

+ + To set your password for the first time:
+

    +
      +
    • /msg x@channels.undernet.org newpass #channel yourpassword +
    • /msg w@channels2.undernet.org newpass #channel yourpassword +
    +
+

+ To change your password:
+

    +
      +
    • Identify yourself first: +
    • /msg x@channels.undernet.org pass #channel currentpassword +
    • /msg w@channels2.undernet.org pass #channel currentpassword +
    +
+

+ Then change it:
+

    +
      +
    • /msg x@channels.undernet.org newpass #channel newpassword +
    • /msg w@channels2.undernet.org newpass #channel newpassword +
    +
+

+ NOTES:
+

    +
      +
    • Once you have sent your password to X once, it will remember who you are until you signoff. Also, if you get caught on the opposite side of a netsplit from X, it will consider you as having signed off and it will forget who you are until you /msg y +our password again. + +
    • x@channels.undernet.org and w@channels2.undernet.org are only needed when sending a newpass or a pass command. This was done to ensure that as long as you use the proper command, you will always be sure it is the real X or W when sending your passw +ord. There were too many problems with users taking the nick X or W when one was split, and being able to obtain passwords that way. + +
    • If you IRC from a site with a lot of users, eg, a university or a large Internet Service Provider, it is wise to have a password to guard against other people imitating you and causing problems on your channel and with X/W and CService. +
    +
+

+14) What happens if I can't remember my password?
+Your password will have to be reset by any 400 or higher level ChanOp on your channel. Speak to one of them. You can find out who these are by:

+

+ /msg x access #channel -min 400
+ or
+ /msg x chaninfo #channel (tells you who the channel manager is)

+ +If you are the Channel Manager, then you will have to get a CService Admin to reset it for you. Ask in #cservice or email cservice@undernet.org +

+

+15) What is a Hack Script and why can't it be used?
+Hack scripts were written by EFnet users to prevent people from "hacking" ops on channels during netsplits. Since the Undernet uses new code for its servers which prevents users from getting ops during a netsplit, these scripts ar +e NOT necessary at all here.

+

+The reason it can't be used with X or W on a channel is because X and W technically "hack" ops when they join a channel. If an op is running one of these scripts, it will detect this hack and then deop X or W.

+

+ +16) What is a protect script and how can it cause problems?
+Protect scripts, such as the mIRC Friends List, work similarly to X/W's PROTECT function. CService asks that you please do NOT use these scripts on registered channels. If you have someone on your protect list, and for some reaso +n they get banned/deopped/kicked by X/W, then your script will try to ban/deop/kick (depending upon the script) X/W. This is considered abuse of the Channel Service.

+ +17) What exactly does CService consider abuse?
+Any time X or W is kicked, banned and/or deopped, this is considered abuse of the Channel Service. The CService bots are not to be played with. So-called "testing" of the bots is not allowed. Abusing the Channel Service could re +sult in you losing your ops or even being banned from the channel. The channel could also be placed in NoOp mode or even purged if necessary to prevent further abuse.

+ +18) What is NoOp mode?
+NoOp mode means that no one except X will be able to have ops on the channel and all kicks/bans must be done through X. Here is where the access level really determines what commands a user can perform.

+ +19) Where can I get more information about X/W and CService?
+Online, you can '/msg x help' for help with commands. You can also obtain help from someone in #cservice or any of the CService Admins who happen to be online. If you can't find someone online to help, you can email cservice@unde +rnet.org and someone will respond via email. Also, all CService documents can be obtained from ftp://ftp.undernet.org/pub/irc/docs/cservice/

+ +20) Who are the Channel Service Administrators?
+The Channel Service Administrators are users who have administrative access to the Channel Service bots. The CService Admins are volunteers who are committed to making sure the Channel Service is used as it was created to and that + the Channel Service is not abused. CService Admins represent the Undernet Channel Service, as well as the Undernet as a whole.

+ +Below is a list of Administrators as of the time this FAQ was written. If a user comes into your channel claiming to be a CService Administrator or a CService Helper, you may ask them to authenticate themselves to the bot, and the +n you can use:

+

+ /msg x,w verify nickname

+

+If the user is a true Admin or Helper, you will get a notice from the bot that looks similar to:

+

+-X- Teal!~friedman@moscow.cse.psu.edu is a trusted CSERVICE admin

+ +If the user is not verifiable by either of the bots, then assume the user is not an Admin or Helper unless a verifiable person can vouch for them.

+


+

Current Cservice Administrators

+
+** Creator of the Undernet Channel Service

+ +SeKs - seks@alias.undernet.org

+ +** Channel Service Coordinator

+ +Super - super@alias.undernet.org

+ +** Channel Service Coders

+ +Kev - kev@alias.undernet.org
+WildThang - wildthang@alias.undernet.org

+ +** Channel Service is housed by:

+FootPrint - footprint@alias.undernet.org (X)
+WildThang - wildthang@alias.undernet.org(W)

+ +** Senior Administrators

+Chaos - chaos@alias.undernet.org
+Cowboy - cowboy@alias.undernet.org
+Footprint - footprint@alias.undernet.org
+Jini - jini@alias.undernet.org
+Meredith - meredith@alias.undernet.org
+Morrissey - jradford@npl.com
+Striker - striker@alias.undernet.org
+Teal - teal@alias.undernet.org

+** Administrators

+AnElf - anelf@alias.undernet.org
+BitBT - bitbt@alias.undernet.org
+Crip - crip@alias.undernet.org
+Jase - jase@alias.undernet.org
+MatthewA - matthewa@alias.undernet.org
+Signe - signe@alias.undernet.org

+ +


+ +Closing Note: If there is anything in this document that needs to be fixed or anything that you feel should be added, please send suggestions to teal@alias.undernet.org
+
+Thanks to the various CService Admins and Helpers for their suggestions. +
+
+Undernet Channel Service Committee
+Channel Operator's FAQ
+Teal!friedman@cse.psu.edu
+Version 1.2
+3/22/96

+

+

+


+Back to main page + diff --git a/HTTP/cmfaq.html b/HTTP/cmfaq.html new file mode 100644 index 0000000..c0f5bef --- /dev/null +++ b/HTTP/cmfaq.html @@ -0,0 +1,264 @@ + +Channel Managers' FAQ + + + +

Channel Managers FAQ

+ +
+ +IMPORTANT: The channel service bot users an Undernet service called +Uworld to gain ops on channels. To some scripts/bots (such as Phoenix), +this is considered a nethack. Please ensure that no one uses nethack +protection or hack protection scripts. These scripts deop X/W and are +considered abuse of the Channel service. It is not possible to get ops +off of a netsplit on Undernet. DO NOT DO ANY "TESTING" WITH X/W. +If you have questions send mail or drop by #cservice and the Channel +Service Committee will answer your questions for you. +

+ +


+ +Introduction: This FAQ is to answer general questions that channel +managers may have in regards to the Undernet Channel Service (UCS). +If you don'tknow what the UCS is you should get the Undernet Channel +Service FAQ fromftp.undernet.org in /pub/irc/docs/cservice. In all +examples, we will assume thatthe channel name is #foo, the nick is +foobar, the user@host is foo@test.com.For ease of documentation, X +will be used in all examples, but there are 2 channel service bots, X and W. +

+

+
I received my confirmation letter from the Channel Service +Committee (CSC), what does this mean?
+
What are my responsibilities as the channel manager?
+
How does X know that I am the right person.
+
So I have access to the the channel, what can I do?
+
What do you mean "hacked" user@host?
+
What happens if I have a password set.
+
I have my access, what now?
+
What are channel defaults?
+
X is on my channel, how do I configure it?
+
What is Massdeop, NickFlood, FloodPro?
+
What is NoOp and AlwaysOp mode?
+
How to I add other users to X's oplist?
+
What are the different levels?
+
How can I see my userlist?
+
How can I give someone AUTOOP?
+
How can I get a second 500 level user?
+
X used to respond to me, but now it is not, what happend?
+
I can't be on-line 24 hours a day, how will I know if someone is abusing X on my channel?
+
So is that it?
+
+

+


+

+ +

1 - I received my confirmation letter from the Channel Service Committee (CSC), what does this +mean?

+The confirmation letter means you have been added as the channel manager +of the channel that you applied for. If you are anxious and/or having mail +problems you can check if your channel has been added by doing a +/msg x,w chaninfo #channel. This will return a response from both channel +service bots to say wether your channel has been registered or not. Your +channel will only be registered on one of the two bots. +

+


+

+

2 - What are my responsibilities as the channel manager?

+As the channel manager, you are responsible for all activities of your +channel including its users and bots. It is recommended that you do not +run other bots on the channel besides X since there is no need for it. X +will always be there and maintains an oplist. You are also +responsible to ensure that none of your channel operators (including bots) +are not running hack protection scripts (such as phoenix). You are also to +ensure that none of your ops deop/kick/ban X. This is considered abuse and +will be dealt with severly and can result in the removal of X from the +channel. "Testing", such as seeing what will happen if X is deop'd, +is considered abuse. +

+


+ +

3 - How does X know that I am the right person.

+The Channel Service Committee has added the IRC address that you specified +in your application form to the UCS bot X. To check the user@host that +has been added you can type /msg X access #channel nick. For example: +/msg X access #foo foobar. If your user@host is not correct contact the +CSC by sending mail to cservice@undernet.org or drop by #cservice +and ask. +

+


+ +

4 - So I have access to the the channel, what can I do?

+To find out what commands you have access to do a /msg X showcommands #channel. +It is also a good idea to have a password, just in case someone is using +a hacked username and is able to replicate your user@host name. +

+


+ +

5 - What do you mean "hacked" user@host?

+Most users with PPP/SLIP access from your site or sites that do not run +identd can have hacked user@host. This means, the user can select the +userid of their choice at any time they wish. In general it is a good idea +to have a password. To setyour password type /msg X newpass password. +For example to make Foobar's password into FooPass1 it would be +/msg X newpass FooPass1. +

+


+ +

6 - What happens if I have a password set.

+If you have a password set, X will not recognize you until you send X +your password (even if you have AutoOp set on. You can identify yourself to +X using /msg X pass #channel password. For example: /msg X pass #foo FooPass1X +will return a confirmation message to say that your identification iscorrect. +If you have lost or forgotten your password, contact the CSC and askthem to +reset it for you. Once you have identified yourself once, you should not have +to do it until you log off of IRC. In some instances of netsplits and the +rare occurance that X needs to be restarted, you will need to resend your +password. +

+


+ +

7 - I have my access, what now?

+First thing you will want to do is move X onto your channel by sending X +a join message /msg X join #channel. For example: /msg X join #foobar. +To have X leave your channel do a /msg X part #channel. This will not remove +you from the channel service, it will just move X off of the channel. You +can bring X back at any time by sending the join message. +Now you will want to add your channel to X by /msg X addchan #channel. +For example: /msg X addchan #foobar. This will add #foobar to the list of +channels. This will add your channel to the channel database for X which +must be done before anything else.Also this will set up all of the channel's +defaults. +

+


+ +

8 - What are channel defaults?

+The channel defaults are X modes such as flood protection level, AlwaysOp, +NoOp, etc... To see what the X settings are for your channel type +/msg X status #channel. +

+


+ +

9 - X is on my channel, how do I configure it?

+When X is on the channel you can now configure X for the channel. The +variables the can be set are: MassDeop, NickFlood, FloodPro, NoOp, and AlwaysOp. +

+


+ +

10 - What is Massdeop, NickFlood, FloodPro?

+MassDeop is the maximum number of deops one user can do in a 15 second period. +This is an integer value and is set by /msg X set #channel MassDeop #. +For example: /msg X #foo MassDeop 5. NickFlood is the maximum number of +nick changes one user can do in a 15 second period. +This is an integer value and is set by /msg X set #channel NickFlood #. +For example /msg set #foo NickFlood 5. FloodPro is the limit of TOPIC, MODE, +and KICKS that one can send to a channel in a 15 secondperiod. This does +not cover public floods since X is deaf to all public messages to the channel. +This is an integer value set by /msg X set #channel FloodPro #. For example: +/msg X #foo Floodpro 20. Any user surpassing the set levels will be kicked +or deop'd by X. +

+


+ +

11 - What is NoOp and AlwaysOp mode?

+NoOp is a special mode where X is the only channel operator. This is an +on/off value that can be set by /msg X set #channel NoOp on/off. AlwaysOp +is a mode that ensures that X will always be an operator. This canbe set +with a /msg X set #channel AlwaysOp on/off. The default for NoOp is Off and +AlwaysOp is On. If a user with access >= 450 deops X, AlwaysOp is turned off +automatically. If a user with access >= 450 kicks X, AlwaysOp is turned off +AND a remchan is issued, so X won't rejoin. NoOp mode can only be reset by the +channel manager. +

+


+ +

12 - How to I add other users to X's oplist?

+To add a user to X's oplist you must be at least a 400 level operator on +the channel. If you have the correct access, you can addsomeone by +/msg X adduser #channel nick *!*user@host level password.The pasword and +user@host fields are optional and you may only add someone to a lower level +than you are. For example, if I am foobar with level 500 (channel manager) +and I want to add foo2 who's irc address is foo2@my.own.server with a password +of foopass I would /msg X adduser #foo foo2 *!*foo2@*.own.server 400 foopass +By placing an extra * in the host name creates a larger host mask that will +cover differnet server names that the user may have. However a *!*@* would +be a really bad entry since that covers all users. Be very careful with your +use of the * on the userlist.If there are entries that pose a threat to +X it is considered abuse and will be removed and can result in the complete +removal of X from the channel. If the user is on Undernet at the time that +you are adding them, X will automatically add the wildcards to the user@host +if a /msg X adduser #foo nick level format is used. +

+


+ +

13 - What are the different levels?

+When adding someone you can give any level you wish as long as it is less +than your own and it is a positive integer value. However, a user must +have a certain level to gain certain access. +Level 500 - Channel Manager
+>=450 - Trusted Admins (can remove X from the channel)
+>=400 - List administrator, may add users to the userlist
+>=100 - Channel Operator +

+


+ +

14 - How can I see my userlist?

+The user list for the channel can be received by/msg X access #channel * +the asterix will show all users that have access on the specified channel. +If you want to check a specific users access type /msg X access #channel nick. +

+


+ +

15 - How can I give someone AUTOOP?

+You can give someone autoops on the channel by adding them to the user list +at any level (that is less than yours) and using the modinfo command. +/msg X modinfo #channelname AUTOOP nick ON +This should get the channel service bot to respond and show you the person's +entry in the database reflecting the change. This also applies to PROTECT. +

+


+ +

16 - How can I get a second 500 level user?

+In general, there should only be one 500 level user. In some extreme cases +the CSC will allow a second channel manager. If there was more than one 500 +level user there can be disputes with the 500 level users which will lead +to problems since all 500 level users have the same access. It is best to +choose one person to be the channel manager and have that person add the +others at level 499. The only command that the level 500 person has is the +set command which is rarely used. +

+


+ +

17 - X used to respond to me, but now it is not, what happend?

+One of three things may be occuring. You may have had your access +suspended. Your access can be suspended for deop'ing X, attempting to op +someone that is not allowed to be op'd (banned or suspended user), +banning/kicking X, etc... To see if you have been suspended type +/msg x access #channel mynick Your user@host may also be different. Just +/msg x access #channel mynick to check if your access is correct. Thirdly, +you may need to send X your password if you have one set. If you still +cannot get X to respond, contact the Channel Service Committee. +

+


+ +

18 - I can't be on-line 24 hours a day, how will I know if someone is abusing X on my +channel?

+If there is abuse of X and a CSC representative is available, they will join +the channel and warn the users and answer any questions they might have. If +the abuse problem is severe (repeated deop's of X), then the channel will +be placed in NoOp mode and the channel topic will be changed to reflect this. +Only the channel manager can reset this mode. If you find the channel you +manage in NoOp mode, you can assume that there was abuse. This is also a +warning for the channel manager to ensure that their users will not abuse X +in the future. +

+


+ +

19 - So is that it?

+No. These are the basics. There are a lot of things in here but there is +still a lot to learn. Managing a channel is not an easy task. Managing +a popular channel is even harder. If you are unsure, please ask. +

+


+
Back to main page + diff --git a/HTTP/faq.html b/HTTP/faq.html new file mode 100644 index 0000000..8cf5776 --- /dev/null +++ b/HTTP/faq.html @@ -0,0 +1,400 @@ + +Undernet Channel Service: FAQ + + +

Channel Service Frequently Asked Questions

+
+ +

Introduction:

+This file answers some of the most frequently asked questions +regarding the Undernet Channel Service and the X and W bots. If your +question is not answered here, check the sources found in Section 5. If +there is a question that you feel should be in here, send it to +Signe@alias.undernet.org.

+


+ +

Section 1: General UCS/CSC questions

+ +

Section 2: General X/W Questions

+ +

Section 3: Registration Information

+ +

Section 4: Complaints and Channel Problems

+ +

Section 5: Getting More Help

+ +

Section 6: FAQ Credits

+

+ +

SECTION 1: General UCS/CSC Questions

+ +

Question 1.1: What is the UCS/CSC?

+The Undernet Channel Service (UCS), aka the Channel Service +Committee (CSC), is the Undernet committee responsible for the registration +of channels and for handling problems with those channels. It is comprised +of unpaid volunteers who want to help out.

+ +

Question 1.2: Who owns the UCS/CSC?

+The CSC is not owned by any one person. It is an organization +chartered by the Undernet administrators, and run by the CSC administrators +(see 1.7). Currently David Low, aka Super, oversees the CSC.

+ +

Question 1.3: Where is the CSC's office? What is the CSC's phone number?

+The CSC does not have a physical office or phone number. Some +helpers and admins can be found in channel #cservice on Undernet. All +correspondances should be emailed to cservice@undernet.org

+ +

Question 1.4: Who pays for the CSC? How does the CSC make a profit?

+The CSC relies solely on the donation of time, disk space, and +services by Undernet administrators. The CSC helpers and admins are not +paid for their time. The disk space and computer time to run X/W are +donated by the respective system administrators. The CSC does not charge +for channel registrations, and therefore does not turn a profit.

+ +

Question 1.5: How can I become a CSC helper/admin?

+Generally, CSC helpers are people who hang around on #cservice and +help out answering questions. Trusted helpers are those who have been +around for a while, and are trusted by the admins. CSC admins are chosen by +the current administrators, usually from the trusted helpers. If you want +to help out, just join #cservice and start answering questions.

+ +

Question 1.6: How can I tell if someone really is a CSC helper/admin?

+Trusted helpers and admins can be verified through X/W with one of +the following commands: + /msg X verify nickname + /msg W verify nickname +Sometimes helpers may not be verifiable by this method. You should then ask +#cservice if they are truly a helper. If you have the slightest doubt about +someone's claim to be a helper or admin, do not hesitate to check it out. If +you find that someone is impersonating a CSC admin, please report it to +#cservice.

+ +

Question 1.7: Who are the admins?

+Currently, the list of CSC admins is as follows: Super, Seks, cowboy, +meredith, Morrissey, Chaos, Teal, jini, Jase, Signe, and AnElf

+ +


+

SECTION 2: General X/W Questions

+ +

Question 2.1: What are X and W? What do X and W do?

+X and W are the CSC bots, written by Seks. One of these is assigned +to each registered channel. For each channel, these bots maintain a +userlist, which specifies who has what access and who should be opped, and a +banlist, which specifies who to ban from joining the channel (or from +getting ops), and for how long. They are designed to keep a channel open 24 +hours a day, and prevent channel takeovers.

+ +

Question 2.2: How does this differ from any other bot?

+X and W are actually each servers, not just bots. They are allowed +to work this way because they are run by the Undernet administration. This +allows them to do several special functions, such as regaining ops if ops +are lost. Also, each bot is on a large number of channels. By having one +bot for many channels, this reduces the load on the Undernet network that +would be caused by having one separate bot on each channel.

+ +

Question 2.3: How do X and W differ from each other?

+There is no difference between X and W as far as the commands and +services availible is concerned. The only differences are that X and W each +run on separate computer systems and networks, and each one handles a +different list of channels. The bots are assigned to registered channels at +random.

+ +

Question 2.4: Why are X/W slow sometimes? Why do X/W disappear sometimes?

+Just like any other bot or user on Undernet, X and W are subject to +lag and netsplits caused by bad connections between Undernet servers. This +can cause X and W to slow down drastically (sometimes up to 5 minutes lag), +and even disappear. If this happens, please be patient. Be assured that +Undernet and CSC admins are working to get them back to normal as quickly as +possible in the event of a problem.

+ +

Question 2.5: Why doesn't the CSC put X/W on a better system?

+X and W each require a lot of disk space and computer resources. +And on top of this, they need to be run on a machine that is an Undernet +server. Currently, the system administrators of irc.ucdavis.edu +(davis.ca.us.undernet.org) and irc.wildstar.net (okc.ok.us.undernet.org) +are donating the neccessary resources. While it is possible to move X and +W, it is not feasible, as there is not another system to move one of them to +right now, and moving them involves a lot of time and work.

+ +


+

SECTION 3: Registration Information

+ +

Question 3.1: Why would I want to register my channel?

+Registration not only provides you with the ability to keep your +channel open 24 hours a day, it also gives the channel stability. In the +case of a channel takeover, the manager always has ultimate control to +regain the channel. Also, it provides you with a way to have users +auto-op'd, and a more permanent banlist.

+ +

Question 3.2: What channels can get X/W onto it?

+Almost any Undernet channel can be registered. The only types of +channels that are currently excluded are warez-type channels, and channels +dealing with child pornography, although the CSC admins do reserve the right +to reject any channel registration for any reason that they deem valid. Do +not try to change the name of one of these types of channels, or try and +conceal the channel activity, as CSC has many ways of finding out the true +uses of a channel.

+ +

Question 3.3: How do I get X/W on to a channel?

+To get X/W onto your channel, the channel must be registered. In +order to do this, you must first have some consensus on the channel as to +who will be the channel manager. Then you must have 10 supporters. +Supporters are people who frequent your channel (not neccessarily ops), and +want you to register it. Once you have these two things, you need to fill +out the registration form, which you can get on WWW or on IRC by doing: +"/msg Helpbot get XForm" Once you have filled out the application, email it +to cservice@undernet.org + +

Question 3.4: Why does the application require supporters?

+Supporters are required because the CSC only registers established, +well used channels. By requiring supporters, CSC can know that there are at +least 10 people who use this channel. It also prevents users with malicious +intents from taking over a channel by registering it out from under the true +users of the channel.

+ +

Question 3.5: Can I have more than one manager?

+The CSC frowns greatly on multiple channel managers. This is +because in the case of a dispute between channel managers, there is no way +for CSC to mediate. Multiple managers are only allowed in extreme +circumstances, and to have more than one manager you must petition +cservice@undernet.org with the reasons.

+ +

Question 3.6: What is the registration process?

+After your registration form is received by the CSC, it is grouped +together with all the applications that come in withing the same 1 or 2 week +span as it. These are compiled into a pre-registration list which is then +posted to the cservice mailing list, and the alt.irc.undernet newsgroup. +This is the posting period, and it lasts for 1 week. During this time CSC +watches for any objections to the registration. If there are some, they are +evaluated by CSC, and if deemed valid, the registration is rejected. If +there are no objections, your channel goes into a list of channels waited to +be added to X/W. At this point you are emailed saying that your +registration has been accepted, and you are also sent a copy of the +manager's FAQ. Within 1 to 1 1/2 weeks after you receive your acceptance +letter, you channel will be added to X/W, and you may begin configuring +whichever one you are assigned.

+ +

Question 3.7: Why does registration take so long?

+Every week, there are many registrations to be processed. Some +weeks there are over 250 applications. Each of these applications must be +checked for completeness, checked to see if it is already registered, and +then compiled into the pre-registration list. Then the posting period must +pass, objections must be evaluated, and a final registration list compiled. +All of this work is done by one CSC admin, who is a volunteer who has other +things to do, such as work or school. After this final list is compiled, it +must be reviewed by the admins, and then they must make time to add all the +channels, which is a time consuming task. This is why the registration +process takes so long.

+ +

Question 3.8: How can I check to see if my channel has been added?

+You can check to see if your channel has been added to X or W by +typing the following commands to check both bots:
    +
  • /msg X chaninfo #yourchannel +
  • /msg W chaninfo #yourchannel

+ +

Question 3.9: It's been more than a month since I sent in my application, and I haven't heard anything from CSC, what should I do?

+If you do not hear anything from CSC, one of several things may have +happened:
    +
  • 1) Your application may never have arrived, or may have been lost +
  • 2) There could be some backups on registrations causing them to take longer than a month +
  • 3) Your channel could have been rejected and you missed the email telling you this.
+So if a month has passed, and you have not heard anything, your best bet is +to resend your application, and put a note at the top stating that the +application was submitted over a month ago, and you have not heard anything +back from CSC, so could someone kindly tell you what the status of your +application is.

+ +

Question 3.10: What if I have problems (such as a takeover) before my channel is added to X/W?

+Because your channel is not technically a registered channel until +it is actually added to X or W, there is nothing that CSC or #cservice can +do to help you with channel problems at this point. You need to talk to an +IRCOp, which you can find on #wasteland, and ask them if they will help you +out.

+ +

Question 3.11: My channel is added, what do I do now?

+Congratulations, you are now a channel manager. The channel +manager's FAQ, which you will have received by email before now, will tell +you how to set up the channel and userlist. Please read the manager's FAQ +thoroughly.

+ +

Question 3.12: Can I register more than one channel?

+Each user is allowed to register one channel. They may, in addition +to this channel, register a help channel that provides assistance to users +for things such as: Software products, Internet services, Internet Service +Providers. If you are unsure if you channel falls under this category, +email cservice@undernet.org and ask. ("Each user" is defined as a person, +not as an email address. If you have multiple email addresses, you may not +register multiple channels. One channel, and optionally one help channel, +per person) + +

Question 3.13: What if I want to switch channel names?

+Since the registration is for the channel, there is no provision for +changing channel names. If you wish to do this, you must fill out a new +application for the new channel and submit it, following the normal +registration process. At the top of your application, write a note saying +that your are the channel manager of #youroldchannel and would like to have +it purged from the registered channels list in order to register a different +channel.

+ +


+

SECTION 4: Complaints and Channel Problems

+ +

Question 4.1: How can I complain about X/W being on a channel?

+If you think you have a valid reason why X/W should not be on a +registered channel (see 4.2), such as the manager is never +around, or it is a warez or child pornography channel, you can email your +complaint to cservice@undernet.org. +If there is a lot of support for your complaint, please include the email +addresses and nicks of those who support you in your letter (do NOT have +everyone send a separate letter). The CSC admins will evaluate your +complaint, and if it is valid, action will be taken.

+ +

Question 4.2: I don't like the content of a channel with X/W on it, what can I do?

+Because CSC does not consider content during the registration +process, excepting warez and child porn channels, there is nothing you can +do about this. The CSC specifically disclaims responsibility for the +content of a channel, and the way the manager chooses to run the channel, as +it would be an overwhelming task for CSC to police every registered +channel.

+ +

Question 4.3: I was kicked/banned from a channel with X/W on it for no reason, who can I complain to?

+As stated in 4.2 above, the CSC has no reponsibility for, nor say +over how a manager, and those he gives operator status to, choose to run the +channel. A channel operator can kick and/or ban someone for any reason they +choose, or no reason at all. Therefore there is noone taht you can complain +to about this except the people who run that specific channel (the +manager).

+ +

Question 4.4: I tried to deop/kick X/W, but I got this message that says I can't do that. Why?

+Because X and W are Undernet services that exist to provide +stability to registered channels, the Undernet and CSC admins have chosen to +modify the Undernet servers to make it so that X and W cannot be kicked or +deopped. By doing this, the stability of registered channels is greatly +increased, and the load on the Undernet IRC network is decreased. This +modification is in effect on some, but not all, Undernet servers at this +point in time.

+ +

Question 4.5: I deopped/kicked X/W, why did people get on my case about doing that?

+As stated in 4.4 above, X and W exist to provide channel stability. +When they are deopped or kicked, their ability to maintain the channel is +disrupted, in addition to the fact that this places an extra load on the +Undernet network. For this reason, these actions are responded to by CSC +admins and/or helpers so that it will not happen again. If X/W is +repeatedly deopped and kicked on a channel, that channel can be removed from +the registered channels list, and X/W removed from the channel.

+ +

Question 4.6: Admins/Helpers say that I deopped/kicked X/W, but I didn't!

+If a CSC admin or helper comes onto a channel and says that you +kicked or deopped X/W, they are going to be right 99% of the time. It is +possible that you are running scripts or remotes that have deopped or kicked +X/W without your knowledge. If this is the case, explain to the admin or +helper that you did not deop/kick X/W consciously, and they will probably be +able to help you fix your script or remote so that it does not happen +again.

+ +

Question 4.7: A CSC helper/admin was very rude to me, what can I do?

+If you think an admin or helper was unnecessarily rude or abusive +towards you, please make sure you have a log of the incident. Email this +log, and a note explaining the situation, to cservice@undernet.org. The +admins will read and evaluate the situation, and respond accordingly.

+ +


+

SECTION 5: Getting More Help

+ +

Question 5.1: How can I get help for X/W on IRC?

+The CSC maintains a help channel on Undernet called #cservice. +There are helpers and/or admins on this channel almost all the time. +However, please make sure you have checked this FAQ, and the Op FAQ before +asking a question there. If there is noone there to answer your question, +you can email it to cservice@undernet.org.

+ +

Question 5.2: How can I get a copy of the manager's FAQ?

+The manager's FAQ is availible several ways:
    +
  • 1) On IRC: The Manager's FAQ is availible via DCC from Helpbot. Just +type: "/msg Helpbot get Xfaq.manager" +
  • 2) On WWW: The Manager's FAQ is availible here +
  • 3) By FTP: The Manager's FAQ is availible on the Undernet FTP server at + +ftp.undernet.org, or its mirror at + +ftp2.undernet.org.
+ +

Question 5.3: How can I get a copy of the Op FAQ?

+The Op FAQ is availible several ways:
    +
  • 1) On IRC: The Op FAQ is availible via DCC from Helpbot. Just type: +"/msg Helpbot get Xfaq.op" +
  • 2) On WWW: The Op FAQ is availible here +
  • 3) By FTP: The Op FAQ is availible on the Undernet FTP server at + +ftp.undernet.org, or its mirror at + +ftp2.undernet.org.
+ +

Question 5.4: Where are the CSC WWW pages?

+CSC maintains 2 WWW pages, one for X, and one for W. On these +pages, besides getting information about CSC and X/W, you can access channel +userlists, banlists, chaninfo, and perform a whois search on Undernet. +These pages are located at: + +

Question 5.5: What if I have other questions?

+If none of these methods work, and you still have questions, feel +free to email them to cservice@undernet.org

+ +


+

SECTION 6: FAQ Credits

+ +This FAQ was composed by Todd Palino (Signe). Some of the questions were +gathered from the original Xfaq.general.

+ +All comments, quips, quotes, and additions should be sent to +Signe@alias.undernet.org + +


+Back to main page \ No newline at end of file diff --git a/HTTP/guidelines.html b/HTTP/guidelines.html new file mode 100644 index 0000000..7234843 --- /dev/null +++ b/HTTP/guidelines.html @@ -0,0 +1,228 @@ + +Undernet Channel Service: Guidelines + + + +

The Undernet Channel Service Guidelines

+
  
+                                                       Revised: May 12, 1995
+
+

+ +

History & Ethos of The Channel Service

+ + Thanks to a lot of work by Seks and the rest of the Undernet IRCops, + Undernet now has a channel service. This service will allow users to run a + channel without running a bot. This service replaces the need for a bot on + a channel.

+ + This channel service gives the opportunity to users to manage a channel. + This is *not* ownership because the service will only be placed on the + channel if that there is a general demand for. It cannot be used in + channel wars/op wars or in an attempt to end "take over" a channel. +

+ The Channel Service works the same way that a bot works. It can control + all channel modes (including ops). One advantage that the service has is + if ops are lost either due to someone messing up and deop'ing everyone (or + a flooder/hacker doing it intentionally) then the bot can use Uworld + (special Undernet service) and regain ops. +

+ The Channel Service has many different modes. AlwaysOp will ensure that + the bot always has ops. If ops are ever lost or the bot is unable to join + the channel then the bot will use Uworld to gain access. NoOp mode will + make it so the Channel Service is the only Op on the channel. All kicks, + bans, topic, etc have to be made through the bot. Mode changes still need + to be done manually. The bot also has flood protection against nick, kick, + topic and mode changes to ensure that channel flooders are not a problem. +

+ The Channel Service retains a userlist for every channel that it is + registered on. The manager of the channel (person who registered the + channel) controls the list for that particular channel. +

+ +


+ +

Committee Guidelines

+

Structure of committee, and general aims

+
+ +
(i) The Channel Service committee is a sub committee of User-com (Undernet + user committee).
+
(ii) The CSC (Channel Service Committee) are in charge of administrating + the channel service
+
(iii) The CSC Will (a) NOT enter into discussions on how a channel is run + (b) mediate upon discussions of channel managers.
+
(iv) The CSC will only register 1 channel per USER (this means user, not + account or e-mail address). This rule may be relaxed at the + discretion of the committee for special channels which provide a + service, such as help channels.
+
+

+

Committee Procedure

+
+

Standard Registration:

+
+ +
(i) Applications are review once per week by the CSC to ensure the + proper information has been included. A response letter is sent + to the applicant acknowledging the application when it is +reviewed.
+ +
(ii) The committee will send a weekly posting to alt.irc.undernet of + registration requests, for public viewing.
+ +
(iii) Provided there is no objections the channel service will be moved into + place on a trial basis, of 14 days. After which it will be + permanent, subject to the standard review procedures. The CSC will + post an FAQ to the manager.
+ +
(iv) The CSC will add the channel to the listing of channels that are + covered by the Channel service (ftp site ca.undernet.org in + pub/undernet) and changes to the document will be posted to cservice + on a regular basis.
+
+

Objections

+
+
(i) Users have 14 days in which to make an objection to the Channel + Service being placed on a channel
+ +
(ii) All objections will be considered by the committee. The CSC chall + invoke the following procedures:
+
(a) remove the bot from the channel while discussions take +place
+
(b) attempt mediation between the objectors and the registered +owner.
+
(i) by trying to put them into contact with each +other
+
(ii) by helping if requested to with discussions.
+
+
(c) if mediation fails, the BOT will NOT be placed on the Channel.
+
- a new application may be made in 2 months, but will not be + considered before then.
+
- the committee will suggest that a channel under a different + name be registered.
+
+
(iii) if an objection is received after that time; the CSC will consider + it if:
+
(a) it is supported by a reasonable number of users (min. 10 - more + for larger channels)
+
(b) has reasonable grounds. + A valid objection will be dealt with in the same way as for (ii) + above; but with the presumption that if the objector cannot + substantiate the claim sufficiently, then the bot will +>tay.
+ +
(iv) The decision of the CSC in all these matters is Final.
+ + +

+

+

+

Registering a channel

+
+ +
(i) Make sure that you have read these guidelines carefully, and are + willing to use the channel service (X) in conjunction with the + rules of use.
+
(ii) Fill out the form below (copy available by anonymous ftp to: + ca.undernet.org:/pub/undernet/CS
+
(iii) Post this to cservice@undernet.org
+
+ ###########################################################################
+ ## E-MAIL COMPLETED FORM TO cservice@undernet.org                        ##
+ ###########################################################################
+ 
+ 1) Your Name : 
+ 
+ 2) The usual nick you use :
+ 
+ 3) Your E-mail address :
+ 
+ 4) The user@host that you use on irc :
+    {if different from your e-mail address}
+ 
+ 5) Channel Name:
+ 
+ 6) Purpose of channel:
+    {brief description}
+    
+ 7) Supporter's list:
+ 
+    -------------------------------------------------------------------------
+    Nickname                     | E-mail address                  
+    -------------------------------------------------------------------------
+  1)
+  2)
+  3)
+  4)
+  5)
+  6)
+  7)
+  8)
+  9)
+ 10)
+ 
+ Please note, to register your channel, you need 10 supporters
+ 
+ ###########################################################################
+
+
+

+

Rules:

+
+
(i) All e-mail addresses that are used on IRC and at least one mail + address that the applicant can be reached at should be included. If a + hacked user@host is used on IRC, a valid mail address is necessary.
+ +
(ii) At least 10 supporters are needed for the request to be processed. + The supporters need to be included on the application with nick and + e-mail addresses.
+ +
(iii) Any abuse of the channel service by the channel manager will result + in the immediate removal of the service. Any abuse of other users will + result in their refusal of the service to that user. The above includes + anyone "testing". If testing is required, there is a test network of + Undernet servers that can be used. If a CSC administrator finds + that the Channel Service is being abused in any way, they may remove + the channel service from the channel immediately and relay any + necessary information to other CSC members and contact the manager + of the channel immediately with the reason for the removal. The + removal will be open to immediate review by the CSC to ensure that + the service was abused and to decide if the Channel Service should + be returned the channel or not.
+ +
(iv) Please ensure that channel operators and/or bots on the registered + channel are not running netsplit hack protection because they will + get into an opwar with X. This is considered abuse and can result in + the removal of the channel service. X will always win in an +opwar.
+ +
(v) The registered channel manager must appear on the channel once every 3 + weeks. If the CSC is notified of a prolonged absence a the channel + - managing may be transferred for the intermittant period. Any abuse + of the Channel Service done by the temporary channel manager will be + both the responsibility of the channel manager and the temporary + manager.
+ +
(vi) The Channel Service will be removed from any channel that has low + traffic. Channel not being used or only has less than 5 regular + users (open to discretion).
+
+ +

+

Disclaimer

+ + The Channel Service will not be responsible for any activity that occurs + on the channel. Anything that occurs on the channel are the + resposibilities of the people involved and has nothing to do with the + Channel Service, its administrators and the Undernet as a whole, including + the Operators that run it. The guidelines may change without notice.

+ + - Original CSC Guidelines
+ - Amended by Super
+ - This Draft #Ox.1
+ - html by striker
+


+ +Back to main page + diff --git a/HTTP/hline.gif b/HTTP/hline.gif new file mode 100644 index 0000000..0b8950f Binary files /dev/null and b/HTTP/hline.gif differ diff --git a/HTTP/index.html.dist b/HTTP/index.html.dist new file mode 100644 index 0000000..234863f --- /dev/null +++ b/HTTP/index.html.dist @@ -0,0 +1,105 @@ + +Undernet Channel Service + + + +

The Undernet Channel Service Page

+

+Welcome! This page provides Undernet users of the Channel +Service bot with a familiar, easy to use WWW interface to its +databases. It is still in construction, and more services will be +added to it as time goes by, but you may find it useful +already.

+
+To access X's database, use http://irc.direct.ca:7357/
+To access W's database, use http://www.wildstar.net:7357/
+
+

General information

+
+
* +The Channel Service Committee Guidelines +
+
* +The Channel Service FAQ +
+
* +The Channel Managers' FAQ +
+
* +The Channel Operators FAQ +
* +Channel Service Application Form +
+
* +Send Email to the Channel Service Mailing List +
+
+
+

User list management

+Manage or consult your channel's user list from the comfort of your +favorite WWW-browser. This feature will allow you to view the complete +list of users on the channel you specify. Just enter the channel name +into the blank and click on "Go baby!"

+

+Enter the channel name: + +
+
+

Ban list management

+Same as the above, but this time for the ban list. Just enter the channel +name into the blank and click on the "Go baby!"

+

+Enter the channel name: + +
+
+

Channel information

+Obtain the information X/W has stored in its databases with regards to +the channel you specify. This is an interesting way to find out +whether your channel has been registered. :) Again, just enter the +channel name in the blank field and click on "Go Baby!".

+

+Enter the channel name: + +
+
+

/WHOIS on the web!

+Find out if your friends (or enemies) are currently signed on to +Undernet IRC. This works just like the IRC /WHOIS command. Just +supply a nick and click on "Go Baby!"

+

+Please enter a nick: + +
+
+

Online HELP files!

+You can access the channel service HELP files from this page. All you +have to do is enter a command and then click on "Go Baby!"

+

+Please enter a command: + +
+
+

Undernet Resources

+Undernet offers several services via the World Wide Web. These few +sites offer a good jumping off point to several of them.

+

+
*The Official +Undernet Page
+
*Aaron Gifford's Undernet +Page
+
*The Undernet +User Committee Home Page
+
*Links to other pages
+
+
+ +This page is brought to you by the administrators of the Undernet Channel Service +Committee. + diff --git a/HTTP/links.html b/HTTP/links.html new file mode 100644 index 0000000..8c1449c --- /dev/null +++ b/HTTP/links.html @@ -0,0 +1,40 @@ + +Undernet Channel Service: Links + + + +

Links to other pages

+ +If you would like to add links on this page, please contact +seks@alias.undernet.org +

+Not responsible for content! +


+Alpine's Page
+Amy's Homepage on the WWW!
+BlackWorld HomePage
+Brent Foster's Home Page
+Elise's Home Page
+Erin's page of Junk
+#ircnewbies Channel Web Page
+Kevin Mitchell's Home Page
+Land Of Ozz
+#MacUnderground Home page
+#Newbies Channel Web Page
+#ReadyRoom Home Page
+Super's Home Page!!!!
+#Teen Channel Web Page
+Terrabyte's Homepage
+Why AOL Sucks
+WildThang's Personal Home Page
+(Untitled)
+#13-17BestBet Homepage
+#13-17Regz Homepage
+

+ +Yahoo - Computer and Internet:Internet:Chatting:IRC:Undernet
+ +InfoSeek Guide Search: IRC UNDERNET
+


+Back to main page + diff --git a/HTTP/reddrop.gif b/HTTP/reddrop.gif new file mode 100644 index 0000000..e493108 Binary files /dev/null and b/HTTP/reddrop.gif differ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8c77001 --- /dev/null +++ b/Makefile @@ -0,0 +1,97 @@ +# Undernet Channel Service (X) +# Copyright (C) 1995-2002 Robin Thellend +# +# 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 +# +# The author can be contact by email at +# +# Please note that this software is unsupported and mostly +# obsolete. It was replaced by GNUworld/CMaster. See +# http://gnuworld.sourceforge.net/ for more information. +# + +CC = gcc +RM = /bin/rm + +CFLAGS = -Wall -g -O0 +#CFLAGS = -O6 + +#DEFINES = -DDEBUG +#DEFINES = -DBACKUP +#DEFINES = -DDEBUG_MALLOC -DHISTORY +#DEFINES= -DHISTORY +DEFINES= + +# necessary for Solaris +#LIBS = -lsocket -lnsl + +OBJECTS = bans.o buffer.o channels.o chat.o conf.o connect.o dbio.o debug.o \ + defchan.o events.o floodpro.o help.o http.o ignore.o kicks.o \ + match.o modes.o nick.o opcom.o ops.o patch.o privmsg.o \ + replies.o servers.o shitlist.o socketio.o special.o userlist.o \ + users.o version.o + +SOURCES = bans.c buffer.c channels.c chat.c conf.c connect.c dbio.c debug.c \ + defchan.c events.c floodpro.c help.c http.c ignore.c kicks.c \ + match.c modes.c nick.c opcom.c ops.c patch.c privmsg.c \ + replies.c servers.c shitlist.c socketio.c special.c userlist.c \ + users.c version.c + +MAKE = make -f Sources.mak 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'DEFINES=${DEFINES}'\ + 'LIBS=${LIBS}' 'SOURCES=${SOURCES}' 'OBJECTS=${OBJECTS}'\ + 'RM=${RM}' + +all: cs fixdb showdb show_old_managers + @echo 'All Done! :)' + +cs: dummy + @echo "Making cs..." + @if [ -f cs ] ; then \ + mv -f cs cs.old; \ + sleep 1; \ + fi + @cd Sources; ${MAKE}; cd ..; + +list: dummy + @echo "Making list..." + @cd Sources; ${MAKE} list; cd ..; + +listall: dummy + @echo "Making listall" + @cd Sources; ${MAKE} listall; cd ..; + +fixdb: dummy + @echo "Making fixdb" + @cd Sources; ${MAKE} fixdb; cd ..; + +showdb: dummy + @echo "Making showdb" + @cd Sources; ${MAKE} showdb; cd ..; + +show_old_managers: dummy + @echo "Making show_old_managers" + @cd Sources; ${MAKE} show_old_managers; cd ..; + +clean: dummy + @cd Sources; ${MAKE} clean; cd ..; + $(RM) -f core cs list listall cs.log *.bak + +depend: dummy + @cd Sources; ${MAKE} depend; cd ..; + +love: + -@echo "With you?? dream on! :P" + +dummy: diff --git a/README b/README new file mode 100644 index 0000000..02dab6e --- /dev/null +++ b/README @@ -0,0 +1,50 @@ +Undernet Channel Service (X) +Copyright (C) 1995-2002 Robin Thellend + +This is the original Channel Service software that was used +on Undernet from 1995 to 2001. + +For copying and licensing information, please see COPYING in +this directory. + +This software is mostly obsolete now. It has been replaced +by GNUworld/CMaster, which can be found at: + http://gnuworld.sourceforge.net/ + +This software is unsupported, which means I have no intention +of ever releasing a new version. It is provided mainly for +educational and historical purposes. + +I used this code on many different platforms, including +Solaris (sparc and x86), Linux, Freebsd, and OSF/1. As far as +I know, it should still compile and run fine on any of them with +a few minor adjustments. + + +BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + +To compile: + $ cp config.h.dist config.h + $ vi config.h # set everything correctly + $ cp cs.conf.dist cs.conf + $ vi cs.conf # set everything correctly + $ make + +To run: + $ ./cs -f cs.conf + +You can reach me at for questions or comments, +but I reserve the right to completely ignore you if I feel like it. + +Enjoy! +/Robin + diff --git a/Sources/Makefile b/Sources/Makefile new file mode 100644 index 0000000..83492be --- /dev/null +++ b/Sources/Makefile @@ -0,0 +1,27 @@ +# Undernet Channel Service (X) +# Copyright (C) 1995-2002 Robin Thellend +# +# 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 +# +# The author can be contact by email at +# +# Please note that this software is unsupported and mostly +# obsolete. It was replaced by GNUworld/CMaster. See +# http://gnuworld.sourceforge.net/ for more information. +# + + +all: + @cd ..; make; cd Sources; diff --git a/Sources/Sources.mak b/Sources/Sources.mak new file mode 100644 index 0000000..119ac51 --- /dev/null +++ b/Sources/Sources.mak @@ -0,0 +1,72 @@ +# Undernet Channel Service (X) +# Copyright (C) 1995-2002 Robin Thellend +# +# 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 +# +# The author can be contact by email at +# +# Please note that this software is unsupported and mostly +# obsolete. It was replaced by GNUworld/CMaster. See +# http://gnuworld.sourceforge.net/ for more information. + + +all: ../cs + +.c.o: + ${CC} ${CFLAGS} ${DEFINES} -c $< + +../cs: ver ${OBJECTS} cksum.o cksum + ${CC} ${CFLAGS} ${DEFINES} ${LIBS} -o ../cs main.c cksum.o ${OBJECTS} -DBINCKSUM1=0 -DBINCKSUM2=0 + ${CC} ${CFLAGS} ${DEFINES} ${LIBS} -o ../cs main.c cksum.o ${OBJECTS} `./cksum ../cs` + +ver: + @chmod +x version.SH + @./version.SH + +cksum: cksum.c + ${CC} ${CFLAGS} -o cksum cksum.c -DMAIN + +list: ../list + +../list: list.c + ${CC} -o ../list list.c + +listall: ../listall + +../listall: listall.c + ${CC} -o ../listall listall.c + +fixdb: match.o + ${CC} fixdb.c match.o -DMAIN -o ../fixdb + +showdb: match.o + ${CC} -Wall showdb.c match.o -DMAIN -o ../showdb + +show_old_managers: match.o + ${CC} -Wall -o ../show_old_managers show_old_managers.c match.o -DMAIN + +clean: + $(RM) -f *.o *.bak + +depend: + -gcc -MM ${CFLAGS} ${SOURCES} > make.dep + +backup: ${SOURCES} list.c listall.c + -cd ..; backups/backup + +love: + -@echo "With you?? dream on! :P" + +include make.dep diff --git a/Sources/bans.c b/Sources/bans.c new file mode 100644 index 0000000..94858bf --- /dev/null +++ b/Sources/bans.c @@ -0,0 +1,427 @@ +/* @(#)$Id: bans.c,v 1.12 1999/04/04 17:00:03 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +void ban(char *source, char *chan, char *nicklist) +{ + char buffer[300]; + char OneNick[NICK_LENGTH]; + char channel[CHANNELNAME_LENGTH]; + register auser *user; + register aluser *luser; + register achannel *ch; + register int i = 0; + + if (*nicklist == '#') + { + GetWord(0, nicklist, channel); + nicklist = ToWord(1, nicklist); + } + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: ban [nick2|addr2] [...]"); + return; + } + +#ifdef DEBUG + printf("BAN REQUEST FOR %s\nON CHANNEL %s\nBY %s (%d)\n", + nicklist, channel, source, Access(channel, source)); +#endif + + if (*source && Access(channel, source) < BAN_LEVEL) + { + notice(source, "Your Access on this channel is too low"); + return; + } + + ch = ToChannel(channel); + + /* I'm not on this channel.. so screw it! */ + if (ch == NULL || !ch->on) + { + notice(source, "I'm NOT on that channel!"); + return; + } + + if (!ch->AmChanOp) + { + notice(source, "I'm not channel operator!"); + return; + } + + if (!*nicklist) + { + notice(source, "SYNTAX: ban [nick2|addr2] [...]"); + return; + } + + GetWord(0, nicklist, OneNick); + + while (*OneNick) + { + luser = ToLuser(OneNick); + if (luser) + sprintf(buffer, "%s!%s@%s", luser->nick, + luser->username, luser->site); + if (luser) + { + sprintf(buffer, "I BAN %s!%s@%s ON %s", luser->nick, + luser->username, luser->site, channel); + log(buffer); + + user = ToUser(channel, OneNick); + if (user && user->chanop) + { + changemode(channel, "-o", user->N->nick, 0); + } + + MakeBanMask(luser, buffer); + changemode(channel, "+b", buffer, 0); + } + GetWord(++i, nicklist, OneNick); + } + flushmode(channel); +} + +void mban(char *source, char *ch, char *args) +{ + char buffer[200]; + char channel[80]; + register int found = 0; + register achannel *chan; + register auser *user; + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: mban "); + return; + } + + if ((chan = ToChannel(channel)) == NULL || !chan->on) + { + if (*source) + notice(source, "I'm NOT on that channel!"); + return; + } + + if (!chan->AmChanOp) + { + if (*source) + notice(source, "I am NOT channel operator!"); + return; + } + + if (*source && Access(channel, source) < MASS_BAN_LEVEL) + { + notice(source, "Your Access on this channel is too low!"); + return; + } + + if (!*args) + { + notice(source, "SYNTAX: mban "); + return; + } + + user = chan->users; + + while (user) + { + sprintf(buffer, "%s!%s@%s", + user->N->nick, user->N->username, user->N->site); + if (match(buffer, args)) + { + sprintf(buffer, "I BAN %s!%s@%s on %s (%s)", user->N->nick, + user->N->username, user->N->site, channel, args); + log(buffer); + + if (user->chanop) + { + changemode(channel, "-o", user->N->nick, 0); + user->chanop = 0; + } + + /*MakeBanMask(user->N,buffer); */ + if (!found) + changemode(channel, "+b", args, 0); + found = 1; + } + user = user->next; + } + if (found) + flushmode(channel); + else if (*source) + { + notice(source, "No match."); + } +} + +void unban(char *source, char *ch, char *list) +{ + register aban *bans; + register aluser *luser; + register achannel *chan; + char channel[CHANNELNAME_LENGTH]; + char buffer[512]; + char one[200]; + register int found; + register int i, exact; + + if (*list == '#') + { + GetWord(0, list, channel); + list = ToWord(1, list); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + chan = ToChannel(channel); + if (chan == NULL || !chan->on) + { + notice(source, "I am NOT on that channel!"); + return; + } + + if (!chan->AmChanOp) + { + notice(source, "I am not channel operator!"); + return; + } + + if (*source && Access(channel, source) < BAN_LEVEL) + { + notice(source, "You're Access on this channel is too low"); + return; + } + + if (!*list) + { + notice(source, "SYNTAX: unban [#channel] [] [...]"); + return; + } + + i = 0; + GetWord(0, list, one); + while (*one) + { + found = 0; + luser = ToLuser(one); + if (luser != NULL) + { + sprintf(one, "%s!%s@%s", luser->nick, luser->username, + luser->site); + exact = 0; + } + else + { + exact = 1; + } + bans = chan->bans; + while (bans != NULL) + { + if ((!exact && match(one, bans->pattern)) || + (exact && !strcasecmp(one, bans->pattern))) + { + sprintf(buffer, "I UNBAN %s ON %s", + bans->pattern, chan->name); + log(buffer); + changemode(channel, "-b", bans->pattern, 0); + RemBan(channel, bans->pattern); + bans = chan->bans; + found = 1; + if (exact) + break; + } + else + bans = bans->next; + } + if (*source && !found) + { + sprintf(buffer, "%s is not in %s's banlist!", + one, channel); + notice(source, buffer); + } + GetWord(++i, list, one); + } + flushmode(channel); +} + + +void showbanlist(char *source, char *ch, char *args) +{ + char buffer[200]; + char channel[80]; + register achannel *chan; + register aban *curr; + + if (*args == '#') + { + GetWord(0, args, channel); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: banlist "); + return; + } + + /* user must be on a channel to see the ban list + */ + if (ToUser(channel, source) == NULL) + { + sprintf(buffer, "%s: You are not on that channel", channel); + notice(source, buffer); + return; + } + + chan = ToChannel(channel); + curr = chan->bans; + if (curr == NULL) + { + sprintf(buffer, "%s: ban list is empty.", channel); + notice(source, buffer); + return; + } + + while (curr != NULL) + { + notice(source, curr->pattern); + curr = curr->next; + } + + sprintf(buffer, "%s: End of ban list", channel); + notice(source, buffer); +} + +void MakeBanMask(aluser * luser, char *output) +{ + register int isip = 1; + register int i, j; + int a1, a2, a3, a4; + char hostmask[200]; + register char *ptr; + + if (luser == NULL) + { + /* Don't do anything */ + return; + } + + /* check if hostname is a numeric IP address + */ + for (i = 0; luser->site[i] != '\0' && isip; i++) + { + if (!isdigit(luser->site[i]) && luser->site[i] != '.') + isip = 0; + } + + if (isip) + { + sscanf(luser->site, "%d.%d.%d.%d", &a1, &a2, &a3, &a4); + + if (a1 <= 127) + { /* class A */ + /*sprintf(hostmask,"%d.*",a1); *shrugs* */ + sprintf(hostmask, "%d.%d.*", a1, a2); + } + else if (a1 <= 191) + { /* class B */ + sprintf(hostmask, "%d.%d.*", a1, a2); + } + else + { /* class C */ + sprintf(hostmask, "%d.%d.%d.*", a1, a2, a3); + } + } + else + { /* not numeric address */ + ptr = luser->site + strlen(luser->site); + i = 0; + + if (!strcasecmp(luser->site + strlen(luser->site) - 3, ".AU") || + !strncasecmp(luser->site + strlen(luser->site) - 7, ".NET.", 4) || + !strncasecmp(luser->site + strlen(luser->site) - 7, ".COM.", 4) || + !strncasecmp(luser->site + strlen(luser->site) - 7, ".EDU.", 4) || + !strncasecmp(luser->site + strlen(luser->site) - 6, ".AC.", 3)) + j = 3; + else + j = 2; + + while (i != j && ptr != luser->site) + { + if (*ptr == '.') + i++; + ptr--; + } + if (i == j) + ptr += 2; + + if (ptr == luser->site) + strcpy(hostmask, ptr); + else + sprintf(hostmask, "*.%s", ptr); + } + + if (!strncasecmp(luser->username, "^wld", 4)) + { + /* special case for telnet users */ + sprintf(output, "*!^wld*@%s", hostmask); + } + else + { + ptr = luser->username; + while (strlen(ptr) == 10 || *ptr == '~') + ptr++; + + sprintf(output, "*!*%s@%s", ptr, hostmask); + } +} diff --git a/Sources/buffer.c b/Sources/buffer.c new file mode 100644 index 0000000..0a49366 --- /dev/null +++ b/Sources/buffer.c @@ -0,0 +1,288 @@ +/* @(#)$Id: buffer.c,v 1.3 1996/11/13 00:40:34 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +/* These routines were first developed for the telnet3d project. + * Special thanks to Danny Mitchell (wildthang@irc) for his help + */ + +#include "h.h" + +static struct buffer_block *avail=NULL; +/*static unsigned long MEM_buffers=0;*/ +static unsigned long NB_avail_buffer_blocks=0; +static unsigned long NB_alloc_buffer_blocks=0; + + +/* get_buffer_block() by SeKs + * returns a ptr to an empty buffer_block or NULL if malloc() + * returns an error. + */ +struct buffer_block *get_buffer_block(void) +{ + register struct buffer_block *block; + + /* I would like to move this to the GetMemory + ** and linklist functions as soon as we get them + ** finished. Mainly for use in keeping track + ** of overall memory usage, and such. + ** just a reminder. --DVM + */ + + if(avail==NULL){ + block=(struct buffer_block *)malloc(sizeof(struct buffer_block)); + block->next=NULL; + }else{ + block=avail; + avail=avail->next; + NB_avail_buffer_blocks--; + } + + block->offset_read=0; + block->offset_write=0; + block->next=NULL; + + NB_alloc_buffer_blocks++; + + return block; +} + +/* return_buffer_block() by SeKs + * returns the given "block" to the "system". Blocks are not + * free()'d. They are kept in order to be re-allocated by + * get_buffer_block(). + */ +void return_buffer_block(struct buffer_block *block) +{ + block->next=avail; + avail=block; + NB_avail_buffer_blocks++; + NB_alloc_buffer_blocks--; +} + +/* copy_from_buffer() by SeKs + * copies characters from the buffer starting at the buffer_block + * '*block' into 'string' until a char in 'stop' is encountered or + * 'max' bytes are read. + * Blocks that are completely copied are returned to the system with + * return_buffer_block(). + * Returns the number of characters that were copied. + */ +int +copy_from_buffer(struct buffer_block **block,char *string,char stop,int max) +{ + register struct buffer_block *tmp; + register int count=0; + + if(block==NULL || *block==NULL || string==NULL) + return -1; + + while(countoffset_read == (*block)->offset_write){ + tmp=*block; + *block=(*block)->next; + return_buffer_block(tmp); + break; + } + count++; + + *string=(*block)->buf[(*block)->offset_read++]; + + if((*block)->offset_read == BUFFER_BLOCK_SIZE){ + tmp=*block; + *block=(*block)->next; + return_buffer_block(tmp); + } + + string++; + if(stop!='\0' && stop==*(string-1)) + break; + } + *string='\0'; + + return count; +} + + +/* look_in_buffer() by SeKs + * Same as copy_from_buffer() except that the buffer remains unchanged + * when the function returns. + * ** Added offset counter otherwise offset_read IS changed when returned -DVM + */ +int +look_in_buffer(struct buffer_block **block,char *string,char stop,int max) +{ + register int count=0; + register int offset=0; /* added DVM */ + + if(block==NULL || *block==NULL || string==NULL) + return -1; + + if((*block)->offset_read == (*block)->offset_write){ + return_buffer_block(*block); + *block=NULL; + } + + while(countoffset_read+offset == (*block)->offset_write) + break; + + count++; + *string=(*block)->buf[(*block)->offset_read+offset]; + offset++; + if((*block)->offset_read+offset == BUFFER_BLOCK_SIZE){ + block=&(*block)->next; + offset=0; + } + string++; + if(stop!='\0' && stop==*(string-1)) + break; + } + *string='\0'; + + return count; +} + + +/* copy_to_buffer() by SeKs + * adds a string to the specified buffer. + * New buffer_blocks are requested when necessary. + * Returns the number of characters in the buffer after the + * new string is added. + * arguments are: + * ( struct buffer_block **block, char *format, args... ) + */ +long copy_to_buffer(struct buffer_block **block, char *string,int length) +{ + register long count=0; + + if(block==NULL || length<=0) + return -1; + + if(*block==NULL) + *block=get_buffer_block(); + + while((*block)->next!=NULL){ + count+=(BUFFER_BLOCK_SIZE)-(*block)->offset_read; + block=&(*block)->next; + } + count+=(*block)->offset_write-(*block)->offset_read; + + while(length--){ + count++; + (*block)->buf[(*block)->offset_write++]=*(string++); + if((*block)->offset_write == BUFFER_BLOCK_SIZE){ + (*block)->offset_write=-1; + (*block)->next=get_buffer_block(); + block=&(*block)->next; + if(*block==NULL){ + break; + } + } + } + + return count; +} + +/* zap_buffer() by SeKs + * clears the buffer starting at the buffer_block '*block' + * return -1 if block is NULL + * 0 otherwise + */ +int zap_buffer(struct buffer_block **block) +{ + struct buffer_block *tmp; + + if(block==NULL) + return -1; + + while((tmp=*block)!=NULL){ + *block=(*block)->next; + return_buffer_block(tmp); + } + + return 0; +} + +/* find_char_in_buffer() by SeKs + * returns 1 if any character of string 'findit' is present within the first + * 'max' characters of the buffer. + * returns 0 otherwise. + */ +int find_char_in_buffer(struct buffer_block **block, char findit,int max) +{ + register int offset; + register int count=0; + + if( (block == NULL) || (*block == NULL)) + return 0; /* DVM */ + + offset=(*block)->offset_read; +loop: + if(offset == (*block)->offset_write) + return 0; + if(findit == (*block)->buf[offset]) + return 1; + if(++count > max) + return 0; + if(++offset == BUFFER_BLOCK_SIZE){ + block=&(*block)->next; + if(*block == NULL) + return 0; + offset=0; + } + goto loop; +} + +/* skip_char_in_buffer() by SeKs + * flushes the first 'n' characters in buffer starting at + * buffer_block '*block' + */ +int skip_char_in_buffer(struct buffer_block **block, int n) +{ + register struct buffer_block *tmp; + register int count=0; + + while(countoffset_read == (*block)->offset_write){ + tmp=*block; + *block=(*block)->next; + return_buffer_block(tmp); + break; + } + count++; + (*block)->offset_read++; + if((*block)->offset_read == BUFFER_BLOCK_SIZE){ + tmp=*block; + *block=(*block)->next; + return_buffer_block(tmp); + if(*block==NULL) + break; + } + } + + return count; +} + diff --git a/Sources/change_byte_order.c b/Sources/change_byte_order.c new file mode 100644 index 0000000..722a083 --- /dev/null +++ b/Sources/change_byte_order.c @@ -0,0 +1,185 @@ +/* @(#)$Id: change_byte_order.c,v 1.3 1996/11/13 00:40:34 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ +#include +#include +#include +#include +#include +#include "defines.h" +#include "struct.h" +#include "version.h" +#include "../config.h" + +typedef struct DiskUser { + char realname[80]; + char match[80]; + int Access; + char passwd[20]; + char channel[80]; + unsigned long flags; + char reserved[20]; + time_t suspend; + time_t lastseen; +} DiskUser; + +typedef struct ShitDisk { + time_t time; + time_t expiration; + char match[80]; + char from[80]; + char reason[200]; + char channel[50]; + int level; +} ShitDisk; + + +void main(void) +{ + FILE *in; + FILE *out; + DiskUser olduser; + DiskUser user; + adefchan oldchan; + adefchan chan; + ShitDisk oldshit,shit; + time_t now; + char swap, *ptr; + + + if(chdir(HOMEDIR)<0){ + perror(HOMEDIR); + exit(1); + } + + now=time(NULL); + + out=fopen("userlist.dat.new","w"); + if(out==NULL){ + perror("userlist.dat.new"); + exit(1); + } + + in=fopen(USERFILE,"r"); + if(in==NULL){ + perror(USERFILE); + return; + } + while(fread(&user,sizeof(DiskUser),1,in)>0){ + ptr=(char *)&user.Access; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&user.flags; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&user.suspend; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&user.lastseen; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + fwrite(&user,sizeof(DiskUser),1,out); + } + + fclose(in); + fclose(out); + out=fopen("channellist.dat.new","w"); + if(out==NULL){ + perror("channellist.dat.new"); + exit(1); + } + + in=fopen(DEFAULT_CHANNELS_FILE,"r"); + if(in==NULL){ + perror(DEFAULT_CHANNELS_FILE); + exit(1); + } + + while(fread(&chan,sizeof(adefchan),1,in)>0){ + ptr=(char *)&chan.MassDeopPro; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&chan.NickFloodPro; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&chan.MsgFloodPro; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&chan.TS; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&chan.flags; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&chan.uflags; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + fwrite(&chan,sizeof(adefchan),1,out); + } + + fclose(in); + fclose(out); + + out=fopen("shitlist.dat.new","w"); + if(out==NULL){ + perror("shitlist.dat.new"); + exit(1); + } + + in=fopen(SHITLIST_FILE,"r"); + if(in==NULL){ + perror(SHITLIST_FILE); + exit(1); + } + + while(fread(&shit,sizeof(ShitDisk),1,in)>0){ + ptr=(char *)&shit.time; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&shit.expiration; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + ptr=(char *)&shit.level; + swap=ptr[0]; ptr[0]=ptr[3]; ptr[3]=swap; + swap=ptr[1]; ptr[1]=ptr[2]; ptr[2]=swap; + + fwrite(&shit,sizeof(ShitDisk),1,out); + } + + fclose(in); + fclose(out); +} diff --git a/Sources/channels.c b/Sources/channels.c new file mode 100644 index 0000000..d5e2d89 --- /dev/null +++ b/Sources/channels.c @@ -0,0 +1,1833 @@ +/* @(#)$Id: channels.c,v 1.29 2000/02/26 15:59:30 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +int cl_hash(char *channel) +{ + register int i, j; + + for (i = j = 0; i < strlen(channel); i++) + j += (unsigned char)toupper(channel[i]); + return (j % 1000); +} + +void NewChannel(char *channelname, time_t TS, int on) +{ + register achannel *chan; + register adefchan *defs; + char buffer[200]; + + if (!channelname || !*channelname) + { + log("ERROR: NewChannel(): empty channel string!!!"); + log(channelname); + } + + /* find defaults (if any) */ + for (defs = DefChanList; defs && strcasecmp(defs->name, channelname); + defs = defs->next); + + chan = (achannel *) MALLOC(sizeof(achannel)); + + chan->name = (char *)MALLOC(strlen(channelname) + 1); + strcpy(chan->name, channelname); + chan->AmChanOp = on; + chan->on = on; + chan->lastact = now; + chan->lasttopic = now; + + chan->lang = L_DEFAULT; + + if (defs) + { + chan->MassDeopPro = defs->MassDeopPro; + chan->NickFloodPro = defs->NickFloodPro; + chan->MsgFloodPro = defs->MsgFloodPro; + chan->flags = defs->flags; + chan->uflags = defs->uflags; + chan->TS = defs->TS; + strcpy(chan->mode, defs->mode); + } + else + { + /* channel default settings */ + chan->MassDeopPro = MAX_DEOP_RATE; + chan->NickFloodPro = MAX_NICKCHANGE_RATE; + chan->MsgFloodPro = MAX_PUBLIC_MSG_RATE; + chan->flags = CFL_ALWAYSOP; + chan->uflags = 0; + chan->TS = TS; + chan->mode[0] = '\0'; + } + strcpy(chan->lastjoin, ""); + chan->bans = NULL; + chan->users = NULL; + chan->modebuff = NULL; + chan->next = ChannelList[cl_hash(channelname)]; + ChannelList[cl_hash(channelname)] = chan; + if (on) + { + changemode(chan->name, "+o", mynick, 1); + if (*chan->mode != '\0') + { + strcpy(buffer, "-"); + strcat(buffer, chan->mode); + bounce(chan->name, buffer, chan->TS); + } + flushmode(chan->name); + } +} + +void DelChannel(char *channelname) +{ + register achannel *chan; + register achannel *prec = NULL; + register auser *user; + register modequeue *mode; + register aban *ban; + + chan = ChannelList[cl_hash(channelname)]; + + while (chan) + { + if (!strcasecmp(chan->name, channelname)) + { + while ((user = chan->users) != NULL) + { + chan->users = user->next; + FreeUser(user); + } + if (prec) + { + prec->next = chan->next; + while ((mode = chan->modebuff) != NULL) + { + chan->modebuff = mode->next; + TTLALLOCMEM -= sizeof(modequeue); + free(mode); + } + while ((ban = chan->bans) != NULL) + { + chan->bans = ban->next; + TTLALLOCMEM -= sizeof(aban); + free(ban); + } + TTLALLOCMEM -= strlen(chan->name) + 1; + free(chan->name); + TTLALLOCMEM -= sizeof(achannel); + free(chan); + chan = prec->next; + } + else + { + ChannelList[cl_hash(channelname)] = chan->next; + while ((mode = chan->modebuff) != NULL) + { + chan->modebuff = mode->next; + TTLALLOCMEM -= sizeof(modequeue); + free(mode); + } + while ((ban = chan->bans) != NULL) + { + chan->bans = ban->next; + TTLALLOCMEM -= sizeof(aban); + free(ban); + } + TTLALLOCMEM -= strlen(chan->name) + 1; + free(chan->name); + TTLALLOCMEM -= sizeof(achannel); + free(chan); + chan = ChannelList[cl_hash(channelname)]; + } + break; + } + else + { + prec = chan; + chan = chan->next; + } + } +} + +void FreeUser(auser * user) +{ + register adeop *nodedeop; + register amsg *nodemsg; + while ((nodedeop = user->deophist) != NULL) + { + user->deophist = nodedeop->next; + TTLALLOCMEM -= sizeof(adeop); + free(nodedeop); + } + + while ((nodemsg = user->msghist) != NULL) + { + user->msghist = nodemsg->next; + TTLALLOCMEM -= sizeof(amsg); + free(nodemsg); + } + TTLALLOCMEM -= sizeof(auser); + free(user); + /* phew! */ +} + + +achannel *ToChannel(char *channel) +{ + register achannel *curr = ChannelList[cl_hash(channel)]; + + while (curr && strcasecmp(curr->name, channel) != 0) + { + curr = curr->next; + } + return curr; +} + +auser *ToUser(char *channel, char *nick) +{ + register auser *curr; + register achannel *chan; + + chan = ToChannel(channel); + if (!chan) + { + curr = NULL; +#ifdef DEBUG + printf("ToUser(): channel not found!\n"); +#endif + } + else + curr = chan->users; +#ifdef DEBUG + printf("Looking for %s...\n", nick); +#endif + + while (curr && strcasecmp(nick, curr->N->nick)) + { +#ifdef DEBUG + printf("ToUser(): is on -> %s!%s@%s\n", + curr->N->nick, curr->N->username, curr->N->site); +#endif + curr = curr->next; + } +#ifdef DEBUG + if (!curr) + printf("ToUser(): user not found!\n"); +#endif + return (curr); +} + + +void GetOps(char *channel) +{ + char buffer[200]; + register aluser *user; + +#ifdef FAKE_UWORLD + if (Uworld_status == 1) + { + sprintf(buffer, ":%s MODE %s +o %s\n", + UFAKE_SERVER, channel, mynick); + sendtoserv(buffer); + log("REOP by fake Uworld"); + sprintf(buffer, "+o %s", mynick); + ModeChange(UFAKE_SERVER, channel, buffer); + return; + } +#endif + + if ((user = ToLuser(UWORLD)) != NULL && !match(user->site, UWORLD_HOST)) + user = NULL; + +#ifdef UWORLD2 + if (user == NULL) + { + if ((user = ToLuser(UWORLD2)) != NULL && !match(user->site, UWORLD2_HOST)) + user = NULL; + } +#endif + + if (user != NULL) + { + sprintf(buffer, ":%s PRIVMSG %s :" UWORLD_COMMAND "\n", + mynick, user->nick, channel); + sendtoserv(buffer); + sprintf(buffer, "I ASK %s FOR REOP ON %s", user->nick, channel); + log(buffer); + } +#ifdef DEBUG + else + { + printf("GetOps(): %s isn't online...\n", UWORLD); + } +#endif + /* If Uworld is not present, queue the request + * and try again later.. + * If he's present, send the request and check later on + * if it worked. + */ + AddEvent(EVENT_GETOPS, now + GETOPS_FREQ, channel); +} + +int GuessChannel(char *nick, char *output) +{ + register aluser *luser; + register avalchan *vchan; + register achannelnode *nchan; + register int found = 0; + char tmp[80]; + + luser = ToLuser(nick); + if (luser == NULL) + { + return 0; + } + + vchan = luser->valchan; + + if (vchan && !strcmp(vchan->name, "*")) + vchan = vchan->next; + + if (vchan && !vchan->next) + { + strcpy(output, vchan->name); + return 1; + } + + nchan = luser->channel; + while (nchan != NULL) + { + if (nchan->N->on) + { + found++; + strcpy(tmp, nchan->N->name); + } + nchan = nchan->next; + } + + if (found == 1) + { + strcpy(output, tmp); + return 1; + } + + return 0; +} + +int IsOpless(char *channel) +{ + register achannel *chan; + register auser *user; + + chan = ToChannel(channel); + if (chan == NULL) + return 0; + + user = chan->users; + while (user != NULL && !user->chanop) + user = user->next; + + if (user != NULL || chan->AmChanOp) + return 0; + else + return 1; +} + +void onopless(char *channel) +{ + register achannel *chan; + + if ((chan = ToChannel(channel)) == NULL || !chan->on) + { + /* don't do anything if not on channel + */ + return; + } + + GetOps(channel); +} + +void oninvite(char *source, char *channel) +{ + char buffer[1024]; +#ifdef DEBUG + printf("Received INVITE from %s to %s\n", source, channel); +#endif + sprintf(buffer, "I'M INVITED ON %s BY %s", channel, source); + log(buffer); + + if (strlen(channel) > 150) + { + notice(source, "yeah.. I know that game!"); + return; + } + + if (Access(channel, source) >= LEVEL_JOIN) + { + join(source, channel, ""); + } +} + +int IsReg(char *channel) +{ + struct stat st; + register struct RegUser *reg; + + if (stat(make_dbfname(channel), &st) < 0) + { + for (reg = UserList[ul_hash(channel)]; reg != NULL; reg = reg->next) + if (!strcasecmp(reg->channel, channel)) + break; + if (reg == NULL) + return 0; + } + + return 1; +} + + +void join(char *source, char *chan, char *arg) +{ + char buffer[1024]; + char channel[80]; + register achannel *ch; + register auser *user; + register char *ptr; + + if (*arg == '#') + { + GetWord(0, arg, channel); + } + else + { + GetWord(0, chan, channel); + } + + if (strchr(channel, ',') != NULL) + { + if (*source) + notice(source, "Invalid channel name!"); + return; + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: join "); + return; + } + + for (ptr = channel; *ptr; ptr++) + { + *ptr = tolowertmp(*ptr); + } + + if (*source && Access(channel, source) < LEVEL_JOIN) + { + ReplyNotAccess(source, channel); + return; + } + + if (*source && !IsReg(channel)) + { + notice(source, "That channel is not registered"); + return; + } + + /* The server's messages are unreliable for *long* channel names + so I decided that the bot will simply NOT join any channel + which have names longer than 45 characters... no big deal! */ + + if (strlen(channel) <= 45) + { + ch = ToChannel(channel); + if (ch != NULL) + { + for (user = ch->users; user != NULL; user = user->next) + { + if (!strcasecmp(user->N->username, DEFAULT_USERNAME) && + !strcasecmp(user->N->site, DEFAULT_HOSTNAME)) + { + if (*source) + { + sprintf(buffer, "%s is already on that channel", user->N->nick); + notice(source, buffer); + } + return; + } + } + } + sprintf(buffer, "I JOIN %s", channel); + log(buffer); + sprintf(buffer, ":%s JOIN %s\n", mynick, channel); + sendtoserv(buffer); + if (ch == NULL) + { + NewChannel(channel, now, 1); + } + else + { + ch->on = 1; + ch->lastact = now; + if (IsOpless(channel) || ((ch->flags & CFL_ALWAYSOP) && + !ch->AmChanOp)) + AddEvent(EVENT_GETOPS, + now + GETOPS_ONJOIN_DELAY, channel); + } + } +#ifdef DEBUG + else + printf("ARGH! *VERY* long channel name.. won't join :/\n"); +#endif +} + +void joindefault(void) +{ + register adefchan *chan; + register achannel *ch; + + chan = DefChanList; + while (chan) + { + ch = ToChannel(chan->name); + /* join the channel if not already on */ + if (ch == NULL || ch->on == 0) + join("", chan->name, ""); + chan = chan->next; + } +} + +void part(char *source, char *chan, char *arg) +{ + char buffer[512]; + char channel[80]; + register achannel *ch; + + if (*arg == '#') + { + GetWord(0, arg, channel); + } + else + { + GetWord(0, chan, channel); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: part "); + return; + } + + ch = ToChannel(channel); + if (ch == NULL) + { + notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); + return; + } + if (*source && Access(channel, source) < LEVEL_PART) + { + ReplyNotAccess(source, channel); + return; + } + + ch->on = 0; + ch->AmChanOp = 0; + if (ch->users == NULL) + DelChannel(channel); + + sprintf(buffer, "I LEAVE %s", channel); + log(buffer); + + sprintf(buffer, ":%s PART %s\n", mynick, channel); + sendtoserv(buffer); +} + +void invite(char *source, char *ch, char *args) +{ + char buffer[512]; + char channel[80]; + char target[80]; + register achannel *chan; + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + GetWord(0, ch, channel); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: invite [channel]"); + return; + } + + if ((chan = ToChannel(channel)) == NULL || !chan->on) + { + notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); + return; + } + + if (chan->flags & CFL_OPONLY) + { + notice(source, replies[RPL_OPONLY][chan->lang]); + return; + } + + if (Access(channel, source) < INVITE_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + + if (IsSet(channel, 'i', NULL) && !chan->AmChanOp) + { + notice(source, replies[RPL_NOTCHANOP][chan->lang]); + return; + } + + GetWord(0, args, target); + + if (*target != '\0' && strcasecmp(target, source) && (source[0] != '+')) + { + notice(source, "You are only allowed to invite yourself"); + return; + } + + if(*target == '\0') + strcpy(target, source); + + if (ToUser(channel, target) != NULL) + { + notice(source, replies[RPL_ALREADYONCHANNEL][chan->lang]); + return; + } + + sprintf(buffer, ":%s INVITE %s %s\n", mynick, target, channel); + sendtoserv(buffer); + + /* No need to confirm the invitation since it was sent to + * the user already! + */ + if (strcasecmp(target, source)) + { + sprintf(buffer, replies[RPL_IINVITED][chan->lang], target, channel); + notice(source, buffer); + sprintf(buffer, replies[RPL_YOUAREINVITED][chan->lang], source, channel); + notice(target, buffer); + } +} + +void onjoin(char *source, char *channel) +{ + char buffer[512]; + char mask[200], reason[200]; + char *ptr; + register achannel *chan; + register achannelnode *c; + register aluser *user; + register auser *usr, *tmp; + register RegUser *reg; + +#ifdef DEBUG + printf("onjoin( %s, %s)\n", source, channel); +#endif + + user = ToLuser(source); + if (user == NULL) + { + /* a server would send a KILL, but I think + * it'll be ok to ignore it + */ + sprintf(buffer, "ERROR onjoin(): Unknown USER %s!", source); + log(buffer); + return; + } + + if (channel[0] == ':') + channel++; + + while (channel) + { + ptr = strchr(channel, ','); + if (ptr != NULL) + *(ptr++) = '\0'; + + /* join 0 */ + if (!strcmp(channel, "0")) + { + while ((c = user->channel) != NULL) + { + onpart(source, c->N->name); + } + channel = ptr; + continue; + } +#ifdef DEBUG + printf("JOIN: %s!%s@%s on channel %s\n", + user->nick, user->username, user->site, channel); +#endif + + if (!*channel) + { + log("ERROR: onjoin(): JOIN to null channel!"); + log(source); + log(channel); + channel = ptr; + continue; + } + + chan = ToChannel(channel); + if (!chan) + { +#ifdef DEBUG + printf("onjoin(): New channel\n"); +#endif + NewChannel(channel, now + TSoffset, 0); + chan = ToChannel(channel); + } + + chan->lastact = now; + + c = (achannelnode *) MALLOC(sizeof(achannelnode)); + c->N = chan; + c->nickhist = NULL; + c->next = user->channel; + user->channel = c; + + strcpy(chan->lastjoin, source); + + usr = (auser *) MALLOC(sizeof(auser)); + + usr->chanop = 0; + usr->deophist = NULL; + usr->lastact = now; + usr->msghist = NULL; + usr->N = user; + usr->next = chan->users; + chan->users = usr; + + if (chan->on) + { + for (tmp = chan->users; tmp != NULL; tmp = tmp->next) + { + if (!strcasecmp(tmp->N->username, DEFAULT_USERNAME) + && !strcasecmp(tmp->N->site, DEFAULT_HOSTNAME) + && tmp->N->time <= logTS) + { + sprintf(buffer, "PAL's already on %s (%ld <= %ld)", + chan->name, tmp->N->time, logTS); + log(buffer); + part("", chan->name, ""); + } + } + } + + + try_find(channel, user); + reg = IsValid(user, channel); + + sprintf(buffer, "%s!%s@%s", user->nick, user->username, user->site); + + if (chan->on && chan->AmChanOp && + IsShit(channel, buffer, mask, reason) >= AUTO_KICK_SHIT_LEVEL) + { + log("Detected banned user (AUTO-KICK LEVEL)"); + notice(source, "*** Sorry. You are on my banlist ***"); + mban("", channel, mask); + sprintf(buffer, "%s %s [%s]", mask, mask, reason); + kick("", channel, buffer); + } + else if (chan->on && chan->AmChanOp + && reg && (reg->flags & UFL_AUTOOP) + && reg->suspend < now + && *reg->passwd != '\0' + && !(chan->flags & CFL_NOOP) + && IsShit(channel, buffer, NULL, NULL) < NO_OP_SHIT_LEVEL + ) + { + op("", channel, source); + } + + if (chan->on && chan->AmChanOp && (chan->flags & CFL_AUTOTOPIC) && + chan->lasttopic + AUTOTOPIC_FREQ < now) + { + adefchan *def = DefChanList; + while (def != NULL && strcasecmp(def->name, chan->name)) + def = def->next; + if (def != NULL && (def->url || def->topic)) + { + chan->lasttopic = now; + sprintf(buffer, "%s (%s)", (def->topic) ? def->topic : "", + (def->url) ? def->url : ""); + topic("", chan->name, buffer); + } + } + channel = ptr; + } +} + +void onpart(char *nick, char *channel) +{ + char buffer[200]; + register auser *user; + register aluser *luser; + register auser *prec = NULL; + register achannel *chan; + register achannelnode **ch, *c; + register anickchange *nickhist; + +#ifdef DEBUG + printf("PART: %s from %s\n", nick, channel); +#endif + + luser = ToLuser(nick); + if (luser == NULL) + { + sprintf(buffer, "ERROR: onpart(): Unknown USER %s!", nick); + log(buffer); +#ifdef HISTORY + History(NULL); +#endif + + return; + } + chan = ToChannel(channel); + + if (chan == NULL) + { + user = NULL; + log("ERROR: onpart(): null channel!? /*core dumped*/"); + log(nick); + log(channel); + /*dumpcore(""); */ + return; + } + else + { + chan->lastact = now; + user = chan->users; + } + + while (user) + { + if (!strcasecmp(user->N->nick, nick)) + { + /* remove the structure from mem */ + + if (prec) + { + prec->next = user->next; + FreeUser(user); + user = prec->next; + } + else + { + chan->users = user->next; + FreeUser(user); + user = chan->users; + } + break; + } + else + { + prec = user; + user = user->next; + } + } + + ch = &luser->channel; + while (*ch && strcasecmp(channel, (*ch)->N->name)) + ch = &(*ch)->next; + c = *ch; + if (c == NULL) + { +#ifdef DEBUG + printf("WARNING: onpart(): channel %s not found!\n", channel); +#endif + } + else + { + *ch = c->next; + + while ((nickhist = c->nickhist) != NULL) + { + c->nickhist = nickhist->next; + TTLALLOCMEM -= sizeof(anickchange); + free(nickhist); + } + TTLALLOCMEM -= sizeof(achannelnode); + free(c); + } + + if (chan != NULL && chan->users == NULL && !chan->on) + { + DelChannel(channel); + } + if (IsOpless(channel)) + onopless(channel); +} + +void onkick(char *source, char *channel, char *body) +{ + char nick[NICK_LENGTH]; + char buffer[1024]; + register achannel *chan; + register auser *user; + register int count; + + GetWord(0, body, nick); + if (!strcasecmp(mynick, nick)) + { + user = ToUser(channel, source); + if (user == NULL) + { + sprintf(buffer, "I'M KICKED OFF %s by %s", + channel, source); + } + else + { + sprintf(buffer, "I'M KICKED OFF %s BY %s!%s@%s (%d) %s", + channel, user->N->nick, user->N->username, user->N->site, + Access(channel, source), ToWord(1, body)); + } + log(buffer); + broadcast(buffer, 0); + chan = ToChannel(channel); + if ((chan->flags & CFL_ALWAYSOP) && Access(channel, source) >= ALWAYSOP_OVERRIDE_LEVEL) + { + chan->flags &= ~CFL_ALWAYSOP; + sprintf(buffer, "AlwaysOp is turned off on %s", channel); + log(buffer); + RemChan(source, channel, channel); + notice(source, replies[RPL_ALWAYSOPWASACTIVE][chan->lang]); + } + if (chan->flags & CFL_ALWAYSOP) + { + /* In AlwaysOp mode, if someone KICKs the bot, he/she + * gets deops/suspended/shitlisted for predetermined + * time and levels + */ + if (user != NULL) + { + count = IsShit(channel, source, NULL, NULL); + notice(source, replies[RPL_ALWAYSOP][chan->lang]); + switch (count) + { + case 0: + case 1: + case 2: + case 3: + case 4: + log("First warning"); + notice(source, replies[RPL_KICK1ST][chan->lang]); + changemode(channel, "-o", source, 0); + flushmode(channel); + user->chanop = 0; + break; + + case 5: + case 6: + case 7: + case 8: + case 9: + log("Second warning"); + notice(source, replies[RPL_KICK2ND][chan->lang]); + kick("", channel, source); + break; + + default: + changemode(channel, "-o", source, 0); + flushmode(channel); + user->chanop = 0; + sprintf(buffer, "%s!%s@%s %d", + user->N->nick, user->N->username, + user->N->site, + DEOPME_SUSPEND_TIME); + suspend("", channel, buffer); + sprintf(buffer, "Suspended %s!%s@%s on %s for repeatedly kicking me", + user->N->nick, user->N->username, user->N->site, channel); + SpecLog(buffer); + broadcast(buffer, 0); + } + sprintf(buffer, "%s %d %d *** KICK WHILE ALWAYSOP ACTIVE ***", + source, DEOP_SHITLIST_TIME, + (count < 10) ? count + 5 : + DEOP_SHITLIST_LEVEL); + AddToShitList("", channel, buffer, 0); + } + part("", channel, ""); + join("", channel, ""); + GetOps(channel); + } + else + { + part("", channel, ""); + } + } + CheckFlood(source, channel, 80); +} + +void QuitAll(void) +{ + register int j; + + if (ServerList != NULL) + onsquit("", ServerList->name, NULL); + + for (j = 0; j < 1000; j++) + { + while (ChannelList[j] != NULL) + { + DelChannel(ChannelList[j]->name); + } + } +} + +void CheckIdleChannels(void) +{ + register achannel *chan, *tmp; + register int i; + char buffer[200]; + + for (i = 0; i < 1000; i++) + { + chan = ChannelList[i]; + while (chan != NULL) + { + tmp = chan->next; + if (chan->on && chan->lastact + MAX_IDLE_TIME <= now) + { + sprintf(buffer, "Channel %s has exceeded the idle time limit of %.2f hours", chan->name, (float)MAX_IDLE_TIME / 3600.0); + SpecLog(buffer); + part("", chan->name, ""); + RemChan("", chan->name, ""); + } + chan = tmp; + } + } +} + + +void topic(char *source, char *chan, char *args) +{ + char buffer[1024]; + char channel[80]; + register achannel *ch; + strcpy(channel, chan); + + if (*source) + { + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: topic "); + return; + } + + if (Access(channel, source) < TOPIC_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + if (!*args) + { + notice(source, "SYNTAX: topic [channel] "); + return; + } + } + + ch = ToChannel(channel); + if (ch == NULL) + { + notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); + return; + } + + if (ch->flags & CFL_OPONLY) + { + notice(source, replies[RPL_OPONLY][ch->lang]); + return; + } + + ch->lastact = now; + sprintf(buffer, "I CHANGED TOPIC on %s to %s", channel, args); + log(buffer); + + sprintf(buffer, ":%s TOPIC %s :%s\n", mynick, channel, args); + sendtoserv(buffer); +} + +void ontopic(char *source, char *target, char *body) +{ + CheckFlood(source, target, strlen(body) + 60); +} + +void onnotice(char *source, char *target, char *body) +{ + if (*target == '#') + CheckFlood(source, target, strlen(body) + 10); + else + CheckPrivateFlood(source, strlen(body) + 10, "NOTICE-"); +} + +void SetChanFlag(char *source, char *ch, char *args) +{ + char buffer[200]; + char channel[80]; + char variable[80]; + char svalue[80]; + register int value, acc, i, found; + register achannel *chan; + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + acc = Access(channel, source); + + GetWord(0, args, variable); + GetWord(1, args, svalue); + + if (!strcmp(channel, "*") || !*variable) + { + notice(source, "SYNTAX: set [#channel] "); + return; + } + + chan = ToChannel(channel); + if (chan == NULL) + { + notice(source, replies[RPL_CHANNOTEXIST][L_DEFAULT]); + return; + } + + value = atoi(svalue); + + if (!strncasecmp(variable, "FLOODPRO", strlen(variable))) + { + if (acc < CH_FLOOD_LIMIT_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + if (value != 0 && (value < 3 || value > 20)) + { + notice(source, replies[RPL_BADFLOODLIMIT][chan->lang]); + return; + } + + chan->MsgFloodPro = value; + sprintf(buffer, replies[RPL_SETFLOODLIMIT][chan->lang], value); + notice(source, buffer); + + sprintf(buffer, "%s SET FLOODPRO ON %s TO %d", + source, channel, value); + log(buffer); + + } + else if (!strncasecmp(variable, "NICKFLOODPRO", strlen(variable))) + { + if (acc < CH_NICK_FLOOD_LIMIT_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + if (value != 0 && (value < 3 || value > 10)) + { + notice(source, replies[RPL_BADNICKFLOODLIMIT][chan->lang]); + return; + } + + chan->NickFloodPro = value; + sprintf(buffer, replies[RPL_SETNICKFLOODLIMIT][chan->lang], value); + notice(source, buffer); + + sprintf(buffer, "%s SET NICKFLOODPRO ON %s TO %d", + source, channel, value); + log(buffer); + + } + else if (!strncasecmp(variable, "MASSDEOPPRO", strlen(variable))) + { + if (acc < CH_MASSDEOP_LIMIT_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + if (value != 0 && (value < 3 || value > 10)) + { + notice(source, replies[RPL_BADMASSDEOPLIMIT][chan->lang]); + return; + } + + chan->MassDeopPro = value; + sprintf(buffer, replies[RPL_SETMASSDEOPLIMIT][chan->lang], value); + notice(source, buffer); + + sprintf(buffer, "%s SET MASSDEOPPRO ON %s TO %d", + source, channel, value); + log(buffer); + + + } + else if (!strncasecmp(variable, "NOOP", strlen(variable))) + { + if (acc < CH_NOOP_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) + { + chan->flags |= CFL_NOOP; + notice(source, replies[RPL_NOOPON][chan->lang]); + massdeop(channel); + sprintf(buffer, "%s SET NOOP ON %s ON", source, channel); + log(buffer); + } + else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) + { + chan->flags &= ~CFL_NOOP; + notice(source, replies[RPL_NOOPOFF][chan->lang]); + sprintf(buffer, "%s SET NOOP ON %s OFF", source, channel); + log(buffer); + } + else + notice(source, replies[RPL_BADNOOP][chan->lang]); + + } + else if (!strncasecmp(variable, "ALWAYSOP", strlen(variable))) + { + if (acc < CH_ALWAYSOP_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) + { + chan->flags |= CFL_ALWAYSOP; + notice(source, replies[RPL_ALWAYSOPON][chan->lang]); + sprintf(buffer, "%s SET ALWAYSOP ON %s ON", + source, channel); + log(buffer); + /* looks like ppl would like X to op himself when + * ALWAYSOP is truned on... fine ;) + */ + if (!chan->AmChanOp) + { + GetOps(chan->name); + } + } + else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) + { + chan->flags &= ~CFL_ALWAYSOP; + notice(source, replies[RPL_ALWAYSOPOFF][chan->lang]); + sprintf(buffer, "%s SET ALWAYSOP ON %s OFF", + source, channel); + log(buffer); + } + else + notice(source, replies[RPL_BADALWAYSOP][chan->lang]); + } + else if (!strncasecmp(variable, "OPONLY", strlen(variable))) + { + if (acc < CH_OPONLY_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) + { + chan->flags |= CFL_OPONLY; + notice(source, replies[RPL_OPONLYON][chan->lang]); + sprintf(buffer, "%s SET OPONLY ON %s ON", + source, channel); + log(buffer); + } + else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) + { + chan->flags &= ~CFL_OPONLY; + notice(source, replies[RPL_OPONLYOFF][chan->lang]); + sprintf(buffer, "%s SET OPONLY ON %s OFF", + source, channel); + log(buffer); + } + else + notice(source, replies[RPL_BADOPONLY][chan->lang]); + } + else if (!strncasecmp(variable, "STRICTOP", strlen(variable))) + { + if (acc < CH_STRICTOP_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) + { + chan->flags |= CFL_STRICTOP; + notice(source, replies[RPL_STRICTOPON][chan->lang]); + sprintf(buffer, "%s SET STRICTOP ON %s ON", + source, channel); + log(buffer); + } + else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) + { + chan->flags &= ~CFL_STRICTOP; + notice(source, replies[RPL_STRICTOPOFF][chan->lang]); + sprintf(buffer, "%s SET STRICTOP ON %s OFF", + source, channel); + log(buffer); + } + else + notice(source, replies[RPL_BADSTRICTOP][chan->lang]); + } + else if (!strncasecmp(variable, "USERFLAGS", strlen(variable))) + { + if (acc < CH_USERFLAGS_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + if (value < 0 || value > 3) + { + notice(source, replies[RPL_BADUSERFLAGS][chan->lang]); + return; + } + chan->uflags = (unsigned long)value; + sprintf(buffer, replies[RPL_SETUSERFLAGS][chan->lang], value); + notice(source, buffer); + sprintf(buffer, "%s SET USERFLAGS TO %d on %s", + source, value, channel); + log(buffer); + } + else if (!strncasecmp(variable, "LANGUAGE", strlen(variable))) + { + if (acc < CH_LANG_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + found = 0; + for (i = 0; i < NO_LANG; i++) + { + if (!strcasecmp(svalue, Lang[i].abbr) || + !strcasecmp(svalue, Lang[i].name)) + { + chan->lang = i; + found = 1; + break; + } + } + if (!found) + { + strcpy(buffer, replies[RPL_KNOWNLANG][chan->lang]); + for (i = 0; i < NO_LANG; i++) + { + strcat(buffer, " "); + strcat(buffer, Lang[i].abbr); + strcat(buffer, " ("); + strcat(buffer, Lang[i].name); + strcat(buffer, ")"); + } + notice(source, buffer); + } + else + { + sprintf(buffer, replies[RPL_SETLANG][chan->lang], + Lang[chan->lang].abbr, Lang[chan->lang].name); + notice(source, buffer); + } + } + else if (!strncasecmp(variable, "TOPIC", strlen(variable)) || + !strncasecmp(variable, "DESCRIPTION", strlen(variable))) + { + register adefchan *def; + if (acc < CH_TOPIC_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + def = DefChanList; + while (def && strcasecmp(def->name, channel)) + def = def->next; + if (!def) + { + notice(source, "You must use 'addchan' first."); + return; + } + strncpy(def->topic, ToWord(1, args), 79); + def->topic[79] = '\0'; + notice(source, "New description set"); + } + else if (!strncasecmp(variable, "URL", strlen(variable))) + { + register adefchan *def; + register char *ptr; + if (acc < CH_URL_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + def = DefChanList; + while (def && strcasecmp(def->name, channel)) + def = def->next; + if (!def) + { + notice(source, "You must use 'addchan' first."); + return; + } + for (ptr = svalue; *ptr; ptr++) + { + if (*(unsigned char *)ptr >= 0x80 || *ptr < 0x20 || + strchr("<>;\"&\\", *ptr)) + { + notice(source, "Invalid URL"); + return; + } + } + strncpy(def->url, svalue, 79); + def->url[79] = '\0'; + notice(source, "New URL set"); + } + else if (!strncasecmp(variable, "AUTOTOPIC", strlen(variable))) + { + if (acc < CH_AUTOTOPIC_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) + { + chan->flags |= CFL_AUTOTOPIC; + notice(source, replies[RPL_AUTOTOPICON][chan->lang]); + sprintf(buffer, "%s SET AUTOTOPIC ON %s ON", + source, channel); + log(buffer); + } + else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) + { + chan->flags &= ~CFL_AUTOTOPIC; + notice(source, replies[RPL_AUTOTOPICOFF][chan->lang]); + sprintf(buffer, "%s SET AUTOTOPIC ON %s OFF", + source, channel); + log(buffer); + } + else + notice(source, replies[RPL_BADAUTOTOPIC][chan->lang]); + } + +} + +void showstatus(char *source, char *ch, char *args) +{ + char buffer[512]; + char channel[80]; + char global[] = "*"; + register achannel *chan; + register auser *user; + register aluser *luser; + register achannelnode *lchan; + register int i, j, k, isoper = 0; + register time_t t; + register int days, hours, mins, secs; + register RegUser *reg; + int srcaccess; + + if (*args == '#' || *args == '*') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + luser = ToLuser(source); + if (luser) + isoper = (luser->mode & LFL_ISOPER) ? 1 : 0; + + if (!strcmp(channel, "*") && !IsValid(luser, channel) && !isoper) + { + notice(source, "SYNTAX: status "); + return; + } + + if ((srcaccess = Access(channel, source)) < STATUS_ACCESS && + Access(global, source) < XADMIN_LEVEL && !isoper) + { + ReplyNotAccess(source, channel); + return; + } + + if (!strcmp(channel, "*")) + { + /* count the number of channels */ + for (i = j = k = 0; j < 1000; j++) + { + chan = ChannelList[j]; + while (chan) + { + if (chan->on) + i++; + k++; + chan = chan->next; + } + } + + sprintf(buffer, "I'm on %d channel%c (out of %d)", i, (i > 1) ? 's' : ' ', k); + notice(source, buffer); + + for (i = j = k = 0; j < 1000; j++) + { + luser = Lusers[j]; + while (luser) + { + lchan = luser->channel; + while (lchan) + { + if (lchan->N->on) + { + i++; + break; + } + lchan = lchan->next; + } + k++; + luser = luser->next; + } + } + sprintf(buffer, "I'm seeing %d users (out of %d)", i, k + 1 /* add self */ ); + notice(source, buffer); + + sprintf(buffer, "Total read bytes: %lu Total sent bytes: %lu", + TTLREADBYTES, TTLSENTBYTES); + notice(source, buffer); + sprintf(buffer, "Total sent bytes in http: %lu", + HTTPTTLSENTBYTES); + notice(source, buffer); + sprintf(buffer, "Total allocated memory: %lu", TTLALLOCMEM); + notice(source, buffer); + + t = now - TSonline; + days = (int)t / 86400; + t %= 86400; + hours = (int)t / 3600; + t %= 3600; + mins = (int)t / 60; + t %= 60; + secs = (int)t; + + if (days > 0) + sprintf(buffer, "Service Up %d day%s %d:%s%d:%s%d", + days, (days > 1) ? "s" : "", hours, + (mins <= 9) ? "0" : "", mins, + (secs <= 9) ? "0" : "", secs); + else + sprintf(buffer, "Service Up %d:%s%d:%s%d", + hours, + (mins <= 9) ? "0" : "", mins, + (secs <= 9) ? "0" : "", secs); + notice(source, buffer); + } + else + { + chan = ToChannel(channel); + if (!chan || !chan->on) + { + notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); + return; + } + + /* count the number of users */ + i = j = 0; + user = chan->users; + while (user) + { + if (user->chanop) + j++; + i++; + user = user->next; + } + if (chan->AmChanOp) + j++; + + if (chan->lang != L_GERMAN) + { + sprintf(buffer, replies[RPL_STATUS1][chan->lang], + channel, i + 1, (i > 0) ? "s" : "", j, (j > 1) ? "s" : ""); + } + else + { + sprintf(buffer, replies[RPL_STATUS1][chan->lang], + channel, i + 1, j); + } + notice(source, buffer); + + if (srcaccess >= STATUS_ACCESS_MODE || isoper) + { + sprintf(buffer, replies[RPL_STATUS2][chan->lang], chan->mode); + notice(source, buffer); + } + + sprintf(buffer, "MassDeopPro: %3d NickFloodPro: %3d FloodPro: %3d", + chan->MassDeopPro, + chan->NickFloodPro, + chan->MsgFloodPro); + notice(source, buffer); + + if (chan->lang != L_GERMAN) + { + sprintf(buffer, "NoOp: %3s AlwaysOp: %3s OpOnly: %3s StrictOp: %3s AutoTopic: %3s", + (chan->flags & CFL_NOOP) ? "ON" : "OFF", + (chan->flags & CFL_ALWAYSOP) ? "ON" : "OFF", + (chan->flags & CFL_OPONLY) ? "ON" : "OFF", + (chan->flags & CFL_STRICTOP) ? "ON" : "OFF", + (chan->flags & CFL_AUTOTOPIC) ? "ON" : "OFF"); + } + else + { + sprintf(buffer, "NoOp: %3s AlwaysOp: %3s OpOnly: %3s StrictOp: %3s AutoTopic: %3s", + (chan->flags & CFL_NOOP) ? "EIN" : "AUS", + (chan->flags & CFL_ALWAYSOP) ? "EIN" : "AUS", + (chan->flags & CFL_OPONLY) ? "EIN" : "AUS", + (chan->flags & CFL_STRICTOP) ? "EIN" : "AUS", + (chan->flags & CFL_AUTOTOPIC) ? "EIN" : "AUS"); + } + notice(source, buffer); + + if (chan->uflags) + { + sprintf(buffer, replies[RPL_STATUS3][chan->lang], + (chan->uflags & UFL_AUTOOP) ? " AUTOOP" : ""); + notice(source, buffer); + } + + sprintf(buffer, replies[RPL_STATUS4][chan->lang], Lang[chan->lang].name); + notice(source, buffer); + + i = (now - chan->lastact); + if (i != 0) + { + sprintf(buffer, replies[RPL_STATUS5][chan->lang], + i, (i > 1) ? "s" : ""); + notice(source, buffer); + } + + strcpy(buffer, "Auth:"); + for (j = 0; j < 1000; j++) + { + luser = Lusers[j]; + while (luser) + { + if ((reg = IsValid(luser, chan->name)) != NULL) + { + sprintf(buffer + strlen(buffer), " %s(%s%d)", luser->nick, + *reg->channel == '*' ? "*" : "", reg->access); + } + + if (strlen(buffer) > 400) + { + notice(source, buffer); + strcpy(buffer, "Auth:"); + } + + luser = luser->next; + } + } + + if (strlen(buffer) > 5) + notice(source, buffer); + } +} + +void SendBurst(void) +{ + register achannel *chan; + register adefchan *defs; + char buffer[512], buffer2[200]; + register char *ptr; + + sprintf(buffer, ":%s JOIN ", mynick); + + /* find defaults (if any) */ + for (defs = DefChanList; defs != NULL; defs = defs->next) + { + + chan = (achannel *) MALLOC(sizeof(achannel)); + + for (ptr = defs->name; *ptr; ptr++) + { + *ptr = tolowertmp(*ptr); + } + + chan->name = (char *)MALLOC(strlen(defs->name) + 1); + strcpy(chan->name, defs->name); + chan->AmChanOp = 1; + chan->on = 1; + chan->lastact = now; + chan->lasttopic = now; + chan->lang = 0; + chan->MassDeopPro = defs->MassDeopPro; + chan->NickFloodPro = defs->NickFloodPro; + chan->MsgFloodPro = defs->MsgFloodPro; + chan->flags = defs->flags; + chan->uflags = defs->uflags; + chan->TS = defs->TS; + strcpy(chan->mode, defs->mode); + + strcpy(chan->lastjoin, ""); + chan->bans = NULL; + chan->users = NULL; + chan->modebuff = NULL; + chan->next = ChannelList[cl_hash(chan->name)]; + ChannelList[cl_hash(chan->name)] = chan; + + if (*ToWord(2, buffer)) + strcat(buffer, ","); + strcat(buffer, chan->name); + + if (defs->next == NULL || strlen(buffer) > 400) + { + strcat(buffer, "\n"); + sendtoserv(buffer); + sprintf(buffer, ":%s JOIN ", mynick); + } + + changemode(chan->name, "+o", mynick, 1); + if (*chan->mode != '\0') + { + strcpy(buffer2, "-"); + strcat(buffer2, chan->mode); + bounce(chan->name, buffer2, chan->TS); + } + } + + for (defs = DefChanList; defs != NULL; defs = defs->next) + flushmode(defs->name); +} + +void showusers(char *chan) +{ + auser *user; + aluser *u; + achannel *channel; + int index = 0; + +#ifdef DEBUG + printf("ACK\n"); +#endif + + for (index = 0; index < 1000; index++) + { + channel = ChannelList[index]; + + while (channel) + { + if (match(channel->name, chan)) + { + user = channel->users; + + while (user) + { + u = user->N; + printf("%s: %s!%s@%s %d\n", + channel->name, u->nick, u->username, + u->site, user->chanop); + user = user->next; + } + printf("MODE FOR %s is %s\n", + channel->name, channel->mode); + } + channel = channel->next; + } + } +} + +void showchannels(void) +{ + achannel *channel; + aban *b; + modequeue *mode; + int index; + +#ifdef DEBUG + printf("ACK\n"); +#endif + + for (index = 0; index < 1000; index++) + { + channel = ChannelList[index]; + + while (channel != NULL) + { + printf("%s TS: %ld on: %d amchanop: %d\n", + channel->name, + channel->TS, channel->on, channel->AmChanOp); + b = channel->bans; + printf("%s - banlist\n", channel->name); + while (b != NULL) + { + printf("\t%s\n", b->pattern); + b = b->next; + } + printf("%s - modebuff\n", channel->name); + mode = channel->modebuff; + while (mode != NULL) + { + printf("\t%d %s %s\n", mode->AsServer, mode->flag, mode->arg); + mode = mode->next; + } + channel = channel->next; + } + } +} diff --git a/Sources/chat.c b/Sources/chat.c new file mode 100644 index 0000000..6960126 --- /dev/null +++ b/Sources/chat.c @@ -0,0 +1,266 @@ +/* @(#)$Id: chat.c,v 1.10 2000/09/09 15:38:13 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +#ifdef DOHTTP + +struct chat_user +{ + char user[10]; + char host[80]; + aluser *luser; +}; + + +void chat_sendtoall(char *from, char *msg) +{ + register http_socket *scan = HttpList; + while (scan != NULL) + { + if (scan->status == HTTP_CHAT && ((struct chat_user *)scan->hook)->luser) + { + if (from) + sendto_http(scan, "<%s> %s\n", from, msg); + else + sendto_http(scan, "%s\n", msg); + } + scan = scan->next; + } +} + +static void login_ok(struct http_socket *hsock, RegUser * reg) +{ + char buffer[512], nick[15]; + struct chat_user *cu = (struct chat_user *)hsock->hook; + register http_socket *scan; + int count = 0; + + sprintf(buffer, "1 %ld %s %s %s", now, cu->user + 1, cu->host, VirtualServer.name); + + strcpy(nick, cu->user); + + while (ToLuser(nick) != NULL) + sprintf(nick, "+%d%s", ++count, cu->user + 1); + + nick[9] = '\0'; + onnick(VirtualServer.name, nick, buffer); + + cu->luser = ToLuser(nick); + + cu->luser->valchan = (avalchan *) MALLOC(sizeof(avalchan)); + cu->luser->valchan->name = (char *)MALLOC(strlen(reg->channel) + 1); + strcpy(cu->luser->valchan->name, reg->channel); + cu->luser->valchan->reg = reg; + reg->inuse++; + reg->lastseen = now; + reg->modified = 1; + cu->luser->valchan->next = NULL; + + sendto_http(hsock, "Welcome to %s's chat line\n", mynick); + + count = 0; + sprintf(buffer, "*** Currently on: "); + + for (scan = HttpList; scan != NULL; scan = scan->next) + { + if (scan->status != HTTP_CHAT || ((struct chat_user *)scan->hook)->luser == NULL) + continue; + if (strlen(buffer) > 70) + { + sendto_http(hsock, "%s\n", buffer); + sprintf(buffer, "*** "); + } + strcat(buffer, ((struct chat_user *)scan->hook)->luser->nick + 1); + strcat(buffer, " "); + } + sendto_http(hsock, "%s\n", buffer); + + sprintf(buffer, "*** JOIN: %s@%s", cu->luser->nick + 1, cu->host); + chat_sendtoall(NULL, buffer); +} + + +static void + chat_login_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + extern RegUser *load_dbuser(off_t, dbuser *); + register RegUser *reg; + struct http_socket *hsock = (struct http_socket *)hook1; + struct chat_user *cu; + char userhost[200]; + + if (dbu != NULL) + { + cu = (struct chat_user *)hsock->hook; + reg = load_dbuser(off, dbu); + + sprintf(userhost, "%s!%s@%s", cu->user, cu->user + 1, cu->host); + + if (reg != NULL && *reg->match == '+' && match(userhost, reg->match)) + { +#ifdef DEBUG + printf("login_ok: %s %s\n", userhost, reg->match); +#endif + login_ok(hsock, reg); + } + else + { + sendto_http(hsock, "Authentication failed!\n"); + hsock->status = HTTP_ENDING; + } + } + else + { + if (count == 0) + { + sendto_http(hsock, "Authentication failed!\n"); + hsock->status = HTTP_ENDING; + hsock->dbio = 0; + } + } +} + + +void chat_login(struct http_socket *hsock, char *user, char *password) +{ + char userhost[200], channel[] = "*", buffer[200]; + struct chat_user *cu; + register RegUser *ruser; + + cu = (struct chat_user *)malloc(sizeof(struct chat_user)); + sprintf(buffer, "+%s", user); + strncpy(cu->user, buffer, 9); + cu->user[9] = '\0'; + strcpy(cu->host, inet_ntoa(hsock->peer.sin_addr)); + cu->luser = NULL; + hsock->hook = (void *)cu; + + sprintf(userhost, "%s!%s@%s", cu->user, cu->user + 1, cu->host); + + ruser = UserList[ul_hash(channel)]; + while (ruser != NULL) + { + if (!strcasecmp(ruser->channel, channel) && + *ruser->match == '+' && match(userhost, ruser->match) && + !strcmp(ruser->passwd, password)) + break; + ruser = ruser->next; + } + + if (ruser == NULL) + { /* ok.. not in memory.. send db query */ + db_fetch(channel, DBGETUHPASS, userhost, password, 0, + hsock, NULL, chat_login_callback); + hsock->dbio = 1; + } + else + { +#ifdef DEBUG + printf("login_ok: %s %s\n", userhost, ruser->match); +#endif + login_ok(hsock, ruser); + } +} + + +void chat_notice(char *user, char *msg) +{ + register http_socket *scan = HttpList; + register struct chat_user *cu; + +#ifdef DEBUG + printf("chat: ->%s %s\n", user, msg); +#endif + + while (scan != NULL) + { + cu = (struct chat_user *)scan->hook; + if (scan->status == HTTP_CHAT && cu->luser && + !strcasecmp(cu->luser->nick, user)) + { + sendto_http(scan, "-%s- %s\n", mynick, msg); + break; + } + scan = scan->next; + } +} + + +void parse_chat(struct http_socket *hsock, char *line) +{ + char buffer[200], global[] = "*", *ptr; + + if (hsock == NULL || hsock->hook == NULL || + ((struct chat_user *)hsock->hook)->luser == NULL) + return; + + if ((ptr = strpbrk(line, "\r\n")) != NULL) + *ptr = '\0'; + +#ifdef DEBUG + printf("chat: <%s> %s\n", ((struct chat_user *)hsock->hook)->luser->nick + 1, line); +#endif + + if ((*line == '/') || (*line == '.')) + { + sprintf(buffer, "%s@%s", mynick, SERVERNAME); + parse_command(((struct chat_user *)hsock->hook)->luser->nick, + buffer, global, line + 1); + } + else + chat_sendtoall(((struct chat_user *)hsock->hook)->luser->nick + 1, line); +} + + +void chat_close(http_socket * hsock, char *comment) +{ + char buffer[512]; + struct chat_user *cu = (struct chat_user *)hsock->hook; + + if (cu->luser) + { + sprintf(buffer, "*** LEAVE: %s@%s", cu->luser->nick + 1, cu->host); + chat_sendtoall(NULL, buffer); + onquit(cu->luser->nick); + } +} + + +void DccMe(char *source, char *arg) +{ + char global[] = "*", buffer[512]; + if(Access(global, source) >= 600) + { + unsigned long addr = inet_addr(BINDADDR); + addr = ntohl(addr); + sprintf(buffer, ":%s PRIVMSG %s :\001DCC CHAT chat %u %u\001\n", + mynick, source, addr, HTTP_PORT); + sendtoserv(buffer); + } +} +#endif diff --git a/Sources/cksum.c b/Sources/cksum.c new file mode 100644 index 0000000..ebb161b --- /dev/null +++ b/Sources/cksum.c @@ -0,0 +1,100 @@ +/* $Id: cksum.c,v 1.1 1997/06/30 03:48:05 cvs Exp $ + */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void cksum(char *file, unsigned int *sum1, unsigned int *sum2) +{ + int fd=-1, size; + unsigned char buffer[1024]; + + if(strchr(file,'/') != NULL) + { + fd = open(file,O_RDONLY); + } + else /* check path */ + { + char *tok,*path = getenv("PATH"); + if(path == NULL) + return; + for(tok=strtok(path,":"); tok!=NULL; tok=strtok(NULL,":"))/* mangles PATH*/ + { + strncpy(buffer,tok,1023); + strncat(buffer,"/",1023); + strncat(buffer,file,1023); + buffer[1023] = '\0'; + fd = open(buffer,O_RDONLY); + if(fd >= 0) + break; + } + } + + if(fd<0) + { + return; + } + + *sum1 = *sum2 = 0; + + while((size=read(fd,buffer,1023))>0) + { + while(size--) + { + *sum1 += buffer[size]; + *sum2 += (size&1)?-buffer[size]:buffer[size]; + } + } + + close(fd); +} + + +#ifdef MAIN +int main(int argc, char **argv) +{ + unsigned int sum,pro; + + if(argc != 2) + { + fprintf(stderr,"usage: %s file\n",argv[0]); + exit(1); + } + + cksum(argv[1],&sum,&pro); + printf("-DBINCKSUM1=0x%x -DBINCKSUM2=0x%x\n",sum,pro); + exit(0); +} +#endif + diff --git a/Sources/conf.c b/Sources/conf.c new file mode 100644 index 0000000..9dcd851 --- /dev/null +++ b/Sources/conf.c @@ -0,0 +1,241 @@ +/* @(#)$Id: conf.c,v 1.5 1998/01/22 09:36:11 chaos Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +void read_conf(char *conf) +{ + FILE *fp; + char buffer[1024], *ptr; + + fp = fopen(conf, "r"); + if (fp == NULL) + { + perror(conf); + exit(1); + } + + while (fgets(buffer, 1024, fp) != NULL) + { + if (*buffer == '#' || *buffer == '\0') + continue; + if ((ptr = strchr(buffer, '\n')) != NULL) + *ptr = '\0'; + + if (!strncasecmp(buffer, "NICKNAME ", 9)) + { + strncpy(mynick, buffer + 9, NICK_LENGTH); + mynick[NICK_LENGTH - 1] = '\0'; + } + else if (!strncasecmp(buffer, "USERNAME ", 9)) + { + strncpy(myuser, buffer + 9, USERNAME_LENGTH); + myuser[USERNAME_LENGTH - 1] = '\0'; + } + else if (!strncasecmp(buffer, "HOSTNAME ", 9)) + { + strncpy(mysite, buffer + 9, SITE_LENGTH); + mysite[SITE_LENGTH - 1] = '\0'; + } + else if (!strncasecmp(buffer, "REALNAME ", 9)) + { + strncpy(myrealname, buffer + 9, REALNAME_LENGTH); + myrealname[REALNAME_LENGTH - 1] = '\0'; + } + else if (!strncasecmp(buffer, "UPLINK ", 7)) + { + strncpy(server, buffer + 7, SERVER_NAME_LENGTH); + server[SERVER_NAME_LENGTH - 1] = '\0'; + } + else if (!strncasecmp(buffer, "PORT ", 5)) + { + DEFAULT_PORTNUM = atoi(buffer + 5); + } + else if (!strncasecmp(buffer, "UMODE ", 6)) + { + strncpy(UMODE, buffer + 6, 10); + UMODE[9] = '\0'; + } + else if (!strncasecmp(buffer, "SERVERNAME ", 11)) + { + strncpy(SERVERNAME, buffer + 11, 80); + SERVERNAME[79] = '\0'; + } + else if (!strncasecmp(buffer, "SERVERINFO ", 11)) + { + strncpy(SERVERINFO, buffer + 11, 80); + SERVERINFO[79] = '\0'; + } + else if (!strncasecmp(buffer, "PASSWORD ", 9)) + { + strncpy(PASSWORD, buffer + 9, 80); + PASSWORD[79] = '\0'; + } + else if (!strncasecmp(buffer, "HOMEDIR ", 8)) + { + strncpy(HOMEDIR, buffer + 8, 256); + HOMEDIR[255] = '\0'; + } + else if (!strncasecmp(buffer, "UMASK ", 6)) + { + sscanf(buffer + 6, "%d", &UMASK); + } + else if (!strncasecmp(buffer, "EXEC ", 5)) + { + strncpy(EXEC_FILE, buffer + 5, 256); + EXEC_FILE[255] = '\0'; + } + else if (!strncasecmp(buffer, "MOTD ", 5)) + { + strncpy(MOTD_FILE, buffer + 5, 256); + MOTD_FILE[255] = '\0'; + } + else if (!strncasecmp(buffer, "LOG ", 4)) + { + strncpy(LOGFILE, buffer + 4, 256); + LOGFILE[255] = '\0'; + } + else if (!strncasecmp(buffer, "LOGBAK ", 7)) + { + strncpy(LOGFILEBAK, buffer + 7, 256); + LOGFILEBAK[255] = '\0'; + } + else if (!strncasecmp(buffer, "PID ", 4)) + { + strncpy(PIDFILE, buffer + 4, 256); + PIDFILE[255] = '\0'; + } + else if (!strncasecmp(buffer, "HELPDIR ", 8)) + { + strncpy(HELP_DIR, buffer + 8, 256); + HELP_DIR[255] = '\0'; + } + else if (!strncasecmp(buffer, "MASTER_NICK ", 12)) + { + strncpy(MASTER_REALNAME, buffer + 12, 80); + MASTER_REALNAME[79] = '\0'; + } + else if (!strncasecmp(buffer, "MASTER_MASK ", 12)) + { + strncpy(MASTER_MATCH, buffer + 12, 80); + MASTER_MATCH[79] = '\0'; + } + else if (!strncasecmp(buffer, "MASTER_PASSWD ", 14)) + { + strncpy(MASTER_PASSWD, buffer + 14, 20); + MASTER_PASSWD[19] = '\0'; + } + else if (!strncasecmp(buffer, "BROADCAST ", 10)) + { + strncpy(BROADCAST_CHANNEL, buffer + 10, 80); + BROADCAST_CHANNEL[79] = '\0'; + } + else if (!strncasecmp(buffer, "VERIFYID ", 9)) + { + strncpy(VERIFY_ID, buffer + 9, 256); + VERIFY_ID[255] = '\0'; + } + else if (!strncasecmp(buffer, "UWORLD_NICK ", 12)) + { + strncpy(UWORLD, buffer + 12, 10); + UWORLD[9] = '\0'; + } + else if (!strncasecmp(buffer, "UWORLD_HOST ", 12)) + { + strncpy(UWORLD_HOST, buffer + 12, 80); + UWORLD_HOST[79] = '\0'; + } + else if (!strncasecmp(buffer, "UWORLD_SERVER ", 14)) + { + strncpy(UWORLD_SERVER, buffer + 14, 80); + UWORLD_SERVER[79] = '\0'; + } + else if (!strncasecmp(buffer, "UWORLD2_NICK ", 13)) + { + strncpy(UWORLD2_NICK, buffer + 13, 10); + UWORLD2_NICK[9] = '\0'; + } + else if (!strncasecmp(buffer, "UWORLD2_HOST ", 13)) + { + strncpy(UWORLD2_HOST, buffer + 13, 80); + UWORLD2_HOST[79] = '\0'; + } + else if (!strncasecmp(buffer, "UWORLD2_SERVER ", 15)) + { + strncpy(UWORLD2_SERVER, buffer + 15, 80); + UWORLD2_SERVER[79] = '\0'; + } + else if (!strncasecmp(buffer, "CALMDOWNTOPIC ", 14)) + { + strncpy(CALMDOWNTOPIC, buffer + 14, 512); + CALMDOWNTOPIC[511] = '\0'; + } + else if (!strncasecmp(buffer, "NSERV_NICK ", 11)) + { +#ifdef NICKSERV + strncpy(NSERV_NICK, buffer + 11, 10); + NSERV_NICK[9] = '\0'; +#endif + } + else if (!strncasecmp(buffer, "NSERV_USER ", 11)) + { +#ifdef NICKSERV + strncpy(NSERV_USER, buffer + 11, 10); + NSERV_USER[9] = '\0'; +#endif + } + else if (!strncasecmp(buffer, "NSERV_HOST ", 11)) + { +#ifdef NICKSERV + strncpy(NSERV_HOST, buffer + 11, 80); + NSERV_HOST[79] = '\0'; +#endif + } + else if (!strncasecmp(buffer, "NSERV_INFO ", 11)) + { +#ifdef NICKSERV + strncpy(NSERV_INFO, buffer + 11, 200); + NSERV_INFO[199] = '\0'; +#endif + } + else if (!strncasecmp(buffer, "NSERV_STAT ", 11)) + { +#ifdef NICKSERV + if (!strncmp(buffer + 11, "on", 2)) + NServ_status = 1; + else if (!strncmp(buffer + 11, "off", 3)) + NServ_status = 0; + else + fprintf(stderr, "NSERV_STAT: Unknown value. Must be ON or OFF\n"); +#endif + } + else + { + fprintf(stderr, "%s: Unknown keyword \"%s\"\n", conf, buffer); + } + } + fclose(fp); +} diff --git a/Sources/connect.c b/Sources/connect.c new file mode 100644 index 0000000..7edf496 --- /dev/null +++ b/Sources/connect.c @@ -0,0 +1,696 @@ +/* @(#)$Id: connect.c,v 1.12 1998/01/25 18:35:42 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" +#ifndef FD_ZERO +#define FD_ZERO(set) (((set)->fds_bits[0]) = 0) +#define FD_SET(s1, set) (((set)->fds_bits[0]) |= 1 << (s1)) +#define FD_ISSET(s1, set) (((set)->fds_bits[0]) & (1 << (s1))) +#define FD_SETSIZE 30 +#endif + +int read_from_server(int); +int write_to_server(irc_socket *); + +int connection(char *serv) +{ + char buffer[200]; + int portnum; + char *ptr; + struct sockaddr_in socketname; +#ifdef BINDADDR + struct sockaddr_in myname; +#endif + struct hostent *remote_host; + + if ((ptr = strchr(serv, ':')) != NULL) + { + *(ptr++) = 0; + sscanf(ptr, "%d", &portnum); +#ifdef DEBUG + printf("Server: %s\nPort: %d\n", serv, portnum); +#endif + } + else + { + portnum = DEFAULT_PORTNUM; + } + + sprintf(buffer, "CONNECTING TO %s ON PORT %d", serv, portnum); + log(buffer); + + if (Irc.outbuf) + zap_buffer(&Irc.outbuf); + if (Irc.inbuf) + zap_buffer(&Irc.inbuf); + read_from_server(1); /* reset input buffer */ + + now = time(NULL); + + /* open an inet socket */ + if ((Irc.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { +#ifdef DEBUG + fprintf(stderr, "ERROR: Can't assign fd for socket, darn!\n"); +#endif + log("ERROR ASSIGNING FD FOR SOCKET"); + exit(1); + } + +#ifdef BINDADDR + memset(&myname, 0, sizeof(myname)); + myname.sin_family = AF_INET; + myname.sin_port = 0; + myname.sin_addr.s_addr = inet_addr(BINDADDR); + if (bind(Irc.fd, (struct sockaddr *)&myname, sizeof(myname)) < 0) + { +#ifdef DEBUG + fprintf(stderr, "ERROR: Can't bind local address %s\n", BINDADDR); +#endif + log("Can't bind local address"); + log(BINDADDR); + exit(1); + } +#endif + + /* make it non-blocking */ + fcntl(Irc.fd, F_SETFL, O_NONBLOCK); + + /* lookup host */ + socketname.sin_family = AF_INET; + if ((remote_host = gethostbyname(serv)) == NULL) + { +#ifdef DEBUG + fprintf(stderr, "ERROR: Host %s is unknown, wtf?\n", serv); +#endif + log("ERROR: BULLSHIT HOST!"); + exit(1); + } + memcpy((void *)&socketname.sin_addr, (void *)remote_host->h_addr, remote_host->h_length); + socketname.sin_port = htons(portnum); + + /* connect socket */ + if (connect(Irc.fd, (struct sockaddr *)&socketname, sizeof(socketname)) < 0 + && errno != EINPROGRESS) + { + close(Irc.fd); + Irc.fd = -1; +#ifdef DEBUG + printf("ERROR: connect() %d: %s\n", errno, strerror(errno)); +#endif + log("ERROR: COULDN'T CONNECT"); + return (1); + } + TSconnect = Irc.TS = now = time(NULL); + errno = 0; + return 0; +} + +int wait_msg(void) +{ + fd_set readfds, writefds; + struct timeval timeout; + static int pingflag = 0; + int maxfd = -1; + int to; +#ifdef DOHTTP + void http_log(char *fmt,...); + register http_socket *hsock, *hsocktmp; + register http_file_pipe *fpipe, *fpipetmp; +#endif +#ifdef UPGRADE + register misc_socket *msock, *msocktmp; +#endif + register dbquery **dq, *dqtmp; + register dbsync **ds, *dstmp; + + /* initialize the fd_sets + */ + FD_ZERO(&readfds); + FD_ZERO(&writefds); + + /* set timeout + */ + if (EventList != NULL) + { + to = EventList->time - now; + if (to < PING_FREQ) + timeout.tv_sec = (to > 0) ? to : 0; + else + timeout.tv_sec = PING_FREQ; + } + else + { + timeout.tv_sec = PING_FREQ; + } + timeout.tv_usec = 0; + + /* Check the DBQuery list before the server fd because + * end_db_read() might writing something in the server's + * buffer. + */ + dq = &DBQuery; + while (*dq) + { + if ((*dq)->fd < 0) + { + dqtmp = *dq; + *dq = (*dq)->next; + end_db_read(dqtmp); + free(dqtmp); + } + else + { + if ((*dq)->fd > maxfd) + maxfd = (*dq)->fd; + FD_SET((*dq)->fd, &readfds); + dq = &(*dq)->next; + } + } + + ds = &DBSync; + while (*ds) + { + if ((*ds)->fd < 0) + { + dstmp = *ds; + *ds = (*ds)->next; + end_db_sync(dstmp); + free(dstmp); + } + else + { + if ((*ds)->fd > maxfd) + maxfd = (*ds)->fd; + if ((*ds)->status == SYNC_PENDWRITE) + FD_SET((*ds)->fd, &writefds); + else + FD_SET((*ds)->fd, &readfds); + ds = &(*ds)->next; + } + } + + + /* check if the uplink's socket is ready for reading.. + */ + FD_SET(Irc.fd, &readfds); + + /* check if the uplink's socket is ready for writing only if + * we have something to write + */ + if (Irc.outbuf != NULL) + FD_SET(Irc.fd, &writefds); + + if (Irc.fd > maxfd) + maxfd = Irc.fd; + +#ifdef DOHTTP + fpipe = FilePipes; + while (fpipe != NULL) + { + if (fpipe->fd > maxfd) + maxfd = fpipe->fd; + + FD_SET(fpipe->fd, &readfds); + fpipe = fpipe->next; + } + + hsock = HttpList; + while (hsock != NULL) + { + if (hsock->fd < 0 || hsock->status == HTTP_ERROR) + { + hsock = hsock->next; /* am I an idiot or what? -Kev */ + continue; /* you should see the logs from below! -Kev */ + } + if (hsock->fd > maxfd) + maxfd = hsock->fd; + if (hsock->status != HTTP_LISTEN && + hsock->status != HTTP_CHAT && + hsock->since + 2 * HTTP_TIMEOUT < now) + { + http_log("ERROR: absolute timeout for fd %d (%d)", + hsock->fd, hsock->status); + close(hsock->fd); + hsock->fd = -1; + hsock->status = HTTP_ERROR; + } + if (hsock->status != HTTP_LISTEN && + hsock->status != HTTP_CHAT && + hsock->TS + HTTP_TIMEOUT < now) + { + close(hsock->fd); + hsock->fd = -1; + hsock->status = HTTP_ERROR; + } + if (hsock->status == HTTP_ENDING && + hsock->outbuf == NULL) + { + close(hsock->fd); + hsock->fd = -1; + hsock->status = HTTP_ERROR; + } + if (hsock->status != HTTP_ERROR) + { + if (hsock->status != HTTP_ENDING && + hsock->status != HTTP_PIPE) + FD_SET(hsock->fd, &readfds); + if (hsock->outbuf != NULL) + FD_SET(hsock->fd, &writefds); + } + hsock = hsock->next; + } +#endif + +#ifdef UPGRADE + msock = MiscList; + while (msock != NULL) + { + if (msock->fd > maxfd) + maxfd = msock->fd; + if (msock->TS + MISC_TIMEOUT < now) + { + close(msock->fd); + msock->fd = -1; + msock->status = MISC_ERROR; + notice(msock->link, "connection timeout!"); + } + if (msock->status != MISC_ERROR) + { + FD_SET(msock->fd, &readfds); + if (msock->outbuf != NULL) + FD_SET(msock->fd, &writefds); + } + msock = msock->next; + } +#endif + + /* Wait till the socket is ready for reading + * and/or writing and/or a timeout + */ + if (select(maxfd + 1, &readfds, &writefds, NULL, &timeout) < 0) + { + log("ERROR: select()"); + log((char *)sys_errlist[errno]); + return (-1); + } + + now = time(NULL); + + /* The uplink's socket is ready for reading... */ + if (FD_ISSET(Irc.fd, &readfds)) + { + if (read_from_server(0) < 0) + { + log("ERROR: in read_from_server()"); + return (-1); + } + pingflag = 0; + Irc.TS = now; + } + + /* The uplink's socket is ready for writing... */ + if (FD_ISSET(Irc.fd, &writefds)) + { + if (write_to_server(&Irc) < 0) + { + log("ERROR: in write_to_server()"); + return (-1); + } + } + +#ifdef DOHTTP + fpipe = FilePipes; + while (fpipe != NULL) + { + fpipetmp = fpipe; + fpipe = fpipe->next; + if (FD_ISSET(fpipetmp->fd, &readfds)) + { + readfrom_file(fpipetmp); + } + } + + hsock = HttpList; + while (hsock != NULL) + { + while (hsock != NULL && hsock->status == HTTP_ERROR) + { + hsocktmp = hsock; + hsock = hsock->next; + remove_httpsock(hsocktmp); + } + if (hsock == NULL) + break; + + if (hsock->fd >= 0 && FD_ISSET(hsock->fd, &readfds)) + { + if (hsock->status == HTTP_LISTEN) + { + http_accept(hsock->fd); + } + else + { + readfrom_http(hsock); + hsock->TS = now; + } + } + if (hsock->fd >= 0 && FD_ISSET(hsock->fd, &writefds)) + { + if (flush_http_buffer(hsock) != -1) + hsock->TS = now; + if (hsock->status == HTTP_ENDING && hsock->outbuf == NULL) + { + close(hsock->fd); + hsock->fd = -1; + hsock->status = HTTP_ERROR; + } + } + hsock = hsock->next; + } +#endif + +#ifdef UPGRADE + msocktmp = NULL; + msock = MiscList; + while (msock != NULL) + { + while (msock != NULL && msock->status == MISC_ERROR) + { + if (msocktmp == NULL) + { + MiscList = msock->next; + free(msock); + msock = MiscList; + } + else + { + msocktmp->next = msock->next; + free(msock); + msock = msocktmp->next; + } + } + if (msock == NULL) + break; + + if (msock->fd >= 0 && FD_ISSET(msock->fd, &readfds)) + { + readfrom_misc(msock); + msock->TS = now; + } + if (msock->fd >= 0 && FD_ISSET(msock->fd, &writefds)) + { + if (flush_misc_buffer(msock) != -1) + msock->TS = now; + } + msocktmp = msock; + msock = msock->next; + } +#endif + + dqtmp = DBQuery; + while (dqtmp) + { + if (FD_ISSET(dqtmp->fd, &readfds)) + read_db(dqtmp); + dqtmp = dqtmp->next; + } + + dstmp = DBSync; + while (dstmp) + { + if (FD_ISSET(dstmp->fd, &readfds) || FD_ISSET(dstmp->fd, &writefds)) + db_sync_ready(dstmp); + dstmp = dstmp->next; + } + + if (EventList != NULL && now >= EventList->time) + CheckEvent(); + + /* send a PING to the server if nothing is received within + * PING_FREQ seconds... if yet nothing arrives within 3 * PING_FREQ + * seconds it's a ping timeout and the connection should be closed + */ + if ((now - Irc.TS) >= (3 * PING_FREQ + 1)) + { + log("Errr PING TIMEOUT"); +#ifdef DEBUG + printf("Ping timeout..\n"); +#endif + sendtoserv("ERROR :Connection timeout\n"); + return (-1); + } + else if (pingflag == 0 && (now - Irc.TS) >= (PING_FREQ - 1)) + { + sendtoserv("PING :"); + sendtoserv(SERVERNAME); + sendtoserv("\n"); + pingflag = 1; + } + + if (DB_Save_Status != -1) + do_cold_sync_slice(); + + return 0; +} + +void sendtoserv(char *msg) +{ +#ifdef DEBUG + printf("#OUT#%s", msg); +#endif + CurrentSendQ = copy_to_buffer(&Irc.outbuf, msg, strlen(msg)); + + if (CurrentSendQ > MAX_SENDQ) + { + log("ERROR: Reached MAX_SENDQ!!!"); + zap_buffer(&Irc.outbuf); + close(Irc.fd); + exit(-1); + } +} + +void dumpbuff(void) +{ + if (Irc.fd < 0) + return; + + /* remove the O_NONBLOCK flag */ + fcntl(Irc.fd, F_SETFL, 0); + + write_to_server(&Irc); + + if (Irc.fd >= 0) + /* reset the O_NONBLOCK flag */ + fcntl(Irc.fd, F_SETFL, O_NONBLOCK); +} + +int read_from_server(int reset) +{ + static char inbuff[1025] = ""; + static char source[SERVER_NAME_LENGTH] = ""; + static char function[10] = ""; + static char target[513] = ""; + static char body[513] = ""; + + static int in_pos = 0; + static int in_offset = 0; + static int length = 0; + char *inchar; + int end; +#ifdef HISTORY + char buffer[600]; +#endif + + if (reset) + { + *inbuff = *source = *function = *target = *body = '\0'; + in_pos = in_offset = length = 0; + return 0; + } +#ifdef DEBUG + printf("#IN#"); +#endif + end = 1; + while (end > 0) + { + errno = 0; + if ((length = read(Irc.fd, inbuff, 1024)) <= 0) + { + if (errno == EWOULDBLOCK || errno == EAGAIN || length == 0) + { + end = 0; + } + else + { + end = -1; + in_pos = in_offset = 0; + *source = *function = *target = *body = '\0'; +#ifdef DEBUG + printf("Read error.. not EWOULDBLOCK!\n"); +#endif + } + return (end); + } + TTLREADBYTES += length; + + inchar = inbuff; + while (length--) + { +#ifdef DEBUG + putchar(*inchar); +#endif + if (*inchar != '\n' && *inchar != '\r') + { + if (*inchar == ' ' && in_pos < 3) + { + switch (in_pos) + { + case 0: + source[in_offset] = '\0'; + break; + + case 1: + function[in_offset] = '\0'; + break; + + case 2: + target[in_offset] = '\0'; + break; + + default: + exit(1); + } + in_pos++; + in_offset = 0; + } + else + { + switch (in_pos) + { + case 0: + if (in_offset == 0 && *inchar != ':') + { + source[0] = '\0'; + in_pos++; + function[in_offset++] = *inchar; + } + else + source[in_offset++] = *inchar; + break; + + case 1: + function[in_offset++] = *inchar; + break; + + case 2: + target[in_offset++] = *inchar; + break; + + case 3: + body[in_offset++] = *inchar; + break; + + default: /*shouldn't happen */ + exit(1); + } + } + } + if (*inchar == '\n') + { + if (in_pos >= 3) + body[in_offset] = '\0'; + else + { + body[0] = '\0'; + switch (in_pos) + { + case 2: + target[in_offset] = '\0'; + break; + + case 1: + function[in_offset] = '\0'; + break; + + case 0: + source[in_offset] = '\0'; + + default: + break; + } + } + + /* parse the received line */ +#ifdef HISTORY + sprintf(buffer, "%s %s %s %s", source, function, target, body); + History(buffer); +#endif + proc(source, function, target, body); + in_pos = in_offset = end = 0; + *source = *function = *target = *body = '\0'; + } + inchar++; + } /* while */ + } /*while */ + + return 1; +} + + +int write_to_server(irc_socket * isock) +{ + char buf[1024]; + int length; + int count; + + if (isock == NULL || isock->outbuf == NULL) + return -1; + + while ((count = look_in_buffer(&isock->outbuf, buf, '\0', 1023)) > 0) + { + if ((length = write(isock->fd, buf, count)) <= 0) + { + if (errno == EWOULDBLOCK || errno == EAGAIN) + { + return 0; + } + else + { + close(isock->fd); + isock->fd = -1; + return -1; + } + } + else + { + TTLSENTBYTES += length; + CurrentSendQ -= length; + skip_char_in_buffer(&isock->outbuf, length); + } + } + return 0; +} diff --git a/Sources/dbio.c b/Sources/dbio.c new file mode 100644 index 0000000..3632f58 --- /dev/null +++ b/Sources/dbio.c @@ -0,0 +1,755 @@ +/* @(#)$Id: dbio.c,v 1.12 1998/01/02 18:30:08 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + + +char *make_dbfname(char *channel) +{ + static char fname[600]; + char tmp[600]; + register char *ptr; + + strcpy(tmp, channel); + for (ptr = tmp; *ptr; ptr++) + { + if (*ptr == '/') + *ptr = ' '; + else + *ptr = tolower(*ptr); + } + + sprintf(fname, "db/channels/%04X/%s", ul_hash(channel), tmp); + return fname; +} + + +/* db_query() + * This is used to *retreive* information from the database. + * The arguments are: + * channel := channel name (null terminated string) + * type := query type, either of: + * DBGETNICK (Get entry by nick) + * DBGET1STUH (Get first matching userhost) + * DBGETALLUH (Get all matching userhosts) + * DBCOUNTUH (Count the number of matching userhosts) + * ... + * info := Either a nick or a userhost depending on type + * action := value passed to the callback function + * hook1 := pointer passed to the callback function + * hook2 := pointer passed to the callback function + * callback := callback function + * + * Since the database is accessed asychronously, 'hook' should not point to + * a structure that can be free()'d by a function other than callback, + * e.g. a pointer to a luser structure. + */ +int db_fetch(char *channel, unsigned int type, char *info, char *passwd, + int action, void *hook1, void *hook2, DBCALLBACK(callback)) +{ + dbquery *new; + int fd; + + if ((fd = open(make_dbfname(channel), O_RDONLY | O_NONBLOCK)) < 0) + { + callback(&fd, (off_t) 0, action, hook1, hook2, NULL, 0); + return -1; /* caller can check errno to see want happened */ + } + + new = (dbquery *) malloc(sizeof(dbquery)); + new->fd = fd; + new->offset = (off_t) 0; + new->time = now; + new->type = type; + new->action = action; + new->count = 0; + new->callback = callback; + new->buf = NULL; + new->hook1 = hook1; + new->hook2 = hook2; + strcpy(new->info, info); + strncpy(new->channel, channel, 79); + new->channel[79] = '\0'; + if (passwd) + strcpy(new->passwd, passwd); + else + new->passwd[0] = '\0'; + new->next = DBQuery; + DBQuery = new; + + return 0; +} + +/* fix_db() + * Remove db entries that are not in the right file. + */ +static void fix_db(char *channel, off_t offset) +{ + register RegUser *reg; + register int idx; + + idx = ul_hash(channel); + /* check if already taken care of */ + reg = UserList[idx]; + while (reg != NULL && (reg->offset != offset || strcasecmp(reg->channel, channel))) + reg = reg->next; + + if (reg) /* already there.. disregard */ + return; + + reg = (RegUser *) MALLOC(sizeof(RegUser)); + memset(reg, 0, sizeof(RegUser)); + reg->realname = (char *)MALLOC(6); + strcpy(reg->realname, "!DEL!"); + reg->passwd = (char *)MALLOC(1); + *reg->passwd = '\0'; + reg->match = (char *)MALLOC(6); + strcpy(reg->match, "!DEL!"); + reg->channel = (char *)MALLOC(strlen(channel) + 1); + strcpy(reg->channel, channel); + reg->modif = (char *)MALLOC(1); + *reg->modif = '\0'; + reg->modified = 1; + reg->offset = offset; + reg->next = UserList[idx]; + UserList[idx] = reg; +} + +/* read_db() + * This should be called from the select() loop. Data is read sequentially + * and the query is processed according to 'type'. + */ +void read_db(dbquery * query) +{ + struct dbuser buffer[11]; + int size, status, end = 0; + + size = read(query->fd, buffer, 10 * sizeof(dbuser)); + if (size <= 0) + { + if (errno != EAGAIN && errno != EWOULDBLOCK) + { + close(query->fd); + query->fd = -1; + } + return; + } + + copy_to_buffer(&query->buf, (char *)buffer, size); + while (!end && look_in_buffer(&query->buf, (char *)buffer, '\0', sizeof(dbuser)) + == sizeof(dbuser)) + { + if (buffer[0].header[0] == 0xFF && buffer[0].header[1] == 0xFF && + buffer[0].footer[0] == 0xFF && buffer[0].footer[1] == 0xFF) + { + status = 1; /* block is used */ + } + else if (buffer[0].header[0] == 0x00 && buffer[0].header[1] == 0x00 && + buffer[0].footer[0] == 0x00 && buffer[0].footer[1] == 0x00) + { + status = 0; /* block is free */ + } + else + { + status = -1; /* block has been written to while reading it */ + } + + if (status == 1 && strcasecmp(query->channel, buffer[0].channel)) + { + fix_db(query->channel, query->offset); + skip_char_in_buffer(&query->buf, sizeof(dbuser)); + query->offset += sizeof(dbuser); + continue; + } + + +#ifdef DEBUG + printf("hdr: %X%X nick: %s match: %s passwd: %s channel: %s " + "modif: %s access: %d flags: %ld susp: %ld last: %ld ftr: %X%X" + "sta: %d\n", + buffer[0].header[0], buffer[0].header[1], buffer[0].nick, buffer[0].match, buffer[0].passwd, + buffer[0].channel, buffer[0].modif, buffer[0].access, buffer[0].flags, buffer[0].suspend, + buffer[0].lastseen, buffer[0].footer[0], buffer[0].footer[1], status); +#endif + + switch (query->type) + { + case DBGETNICK: + if (status == 1 && !strcasecmp(buffer[0].nick, query->info)) + { + close(query->fd); + query->fd = -1; + query->count++; + query->callback(&query->fd, query->offset, query->action, query->hook1, + query->hook2, buffer, query->count); + end = 1; + } + break; + case DBGET1STUH: + if (status == 1 && match(query->info, buffer[0].match)) + { + close(query->fd); + query->fd = -1; + query->count++; + query->callback(&query->fd, query->offset, query->action, query->hook1, + query->hook2, buffer, query->count); + end = 1; + } + break; + case DBGETALLUH: + if (status == 1 && match(query->info, buffer[0].match)) + { + query->count++; + query->callback(&query->fd, query->offset, query->action, query->hook1, + query->hook2, buffer, query->count); + } + break; + case DBGETUHPASS: + if (status == 1 && match(query->info, buffer[0].match) && + !strcmp(query->passwd, buffer[0].passwd)) + { + close(query->fd); + query->fd = -1; + query->count++; + query->callback(&query->fd, query->offset, query->action, query->hook1, + query->hook2, buffer, query->count); + end = 1; + } + break; + case DBCOUNTUH: + if (status == 1 && match(query->info, buffer[0].match)) + { + query->count++; + } + break; + case DBGET1STCMP: + if (status == 1 && (!*query->info || compare(query->info, buffer[0].match))) + { + close(query->fd); + query->fd = -1; + query->count++; + query->callback(&query->fd, query->offset, query->action, query->hook1, + query->hook2, buffer, query->count); + end = 1; + } + break; + case DBGETALLCMP: + if (status == 1 && (!*query->info || compare(query->info, buffer[0].match))) + { + query->count++; + query->callback(&query->fd, query->offset, query->action, query->hook1, + query->hook2, buffer, query->count); + } + break; + case DBCNTCMP: + if (status == 1 && (!*query->info || compare(query->info, buffer[0].match))) + { + query->count++; + } + break; + case DBGET1STFREE: + if (status == 0) + { + close(query->fd); + query->fd = -1; + query->count++; + query->callback(&query->fd, query->offset, query->action, query->hook1, + query->hook2, buffer, query->count); + end = 1; + } + break; + } + skip_char_in_buffer(&query->buf, sizeof(dbuser)); + query->offset += sizeof(dbuser); + if (query->fd < 0) + end = 1; + } +} + +void end_db_read(dbquery * query) +{ + zap_buffer(&query->buf); + query->callback(&query->fd, query->offset, query->action, query->hook1, + query->hook2, NULL, query->count); +} + + +void make_dbuser(RegUser * reg, dbuser * dbu) +{ + memset(dbu, 0, sizeof(dbuser)); + if (reg->access != 0) + { + strncpy(dbu->nick, reg->realname, 79); + dbu->nick[79] = '\0';; + strncpy(dbu->match, reg->match, 79); + dbu->match[79] = '\0'; + strncpy(dbu->channel, reg->channel, 49); + dbu->channel[49] = '\0'; + strncpy(dbu->passwd, reg->passwd, 19); + dbu->passwd[19] = '\0'; + strncpy(dbu->modif, reg->modif, 79); + dbu->modif[79] = '\0'; + dbu->access = reg->access; + dbu->flags = reg->flags; + dbu->suspend = reg->suspend; + dbu->lastseen = reg->lastseen; + dbu->header[0] = 0xFF; + dbu->header[1] = 0xFF; + dbu->footer[0] = 0xFF; + dbu->footer[1] = 0xFF; + } +} + +void sync_next_channel(void) +{ + register syncchan *tmp; + + if ((tmp = SyncChan) != NULL) + { + SyncChan = SyncChan->next; + db_sync(tmp->name); + free(tmp); + } +} + +static void set_sync(dbsync * sync) +{ + struct dbuser dbu; + + if (*sync->reg == NULL) + { + close(sync->fd); + sync->fd = -1; + return; + } + + if ((*sync->reg)->access == 0) /* delete */ + { + make_dbuser(*sync->reg, &dbu); + zap_buffer(&sync->buf); + copy_to_buffer(&sync->buf, (char *)&dbu, sizeof(dbuser)); + sync->type = SYNC_DELETE; + sync->status = SYNC_PENDWRITE; + sync->offset = (*sync->reg)->offset; + lseek(sync->fd, (*sync->reg)->offset, SEEK_SET); + } + else if ((*sync->reg)->offset != (off_t) - 1) /* update */ + { + make_dbuser(*sync->reg, &dbu); + zap_buffer(&sync->buf); + copy_to_buffer(&sync->buf, (char *)&dbu, sizeof(dbuser)); + sync->type = SYNC_UPDATE; + sync->status = SYNC_PENDWRITE; + sync->offset = (*sync->reg)->offset; + lseek(sync->fd, (*sync->reg)->offset, SEEK_SET); + } + else + /* add */ + { + sync->type = SYNC_ADD; + sync->status = SYNC_SEEKFREE; + sync->offset = (off_t) 0; + lseek(sync->fd, 0L, SEEK_SET); + } +} + + +static void sync_next(dbsync * sync, char *channel) +{ + register RegUser **reg = sync->reg; + + if (*reg == NULL) + { + close(sync->fd); + sync->fd = -1; + return; + } + + while (*reg != NULL && ((*reg)->modified == 0 || (*reg)->access == 1000 || + strcasecmp((*reg)->channel, channel))) + { + if ((*reg)->inuse == 0 && (*reg)->lastused + CACHE_TIMEOUT < now) + free_user(reg); + else + reg = &(*reg)->next; + } + + sync->time = now; + sync->reg = reg; + set_sync(sync); +} + + + +void db_sync(char *channel) +{ + register RegUser **reg, *tmp; + register char *ch; + register dbsync *sync; + struct stat st; + int fd; + +#ifdef DEBUG + printf("SYNC: %s\n", channel); +#endif + + if (DBSync != NULL && (DBSync->fd != -1 || DBSync->next != NULL)) + { + log("ERROR: simultaneous syncs??"); + return; + } + + ch = make_dbfname(channel); + + /* IF file does not exist.. remove all deletes and mark + * all other entries as new. + */ + if (stat(ch, &st) < 0) + { + /* remove all deletes */ + reg = &UserList[ul_hash(channel)]; + while (*reg) + { + (*reg)->offset = (off_t) - 1; + if ((*reg)->access == 0 && (*reg)->inuse == 0 && + !strcasecmp((*reg)->channel, channel)) + { + tmp = *reg; + *reg = (*reg)->next; + free_user(reg); + } + else + reg = &(*reg)->next; + } + fd = open(ch, O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, 0600); + } + else + { + fd = open(ch, O_RDWR | O_NONBLOCK); + } + + /* create new sync struct + */ + sync = (dbsync *) malloc(sizeof(dbsync)); + sync->fd = fd; + sync->reg = &UserList[ul_hash(channel)]; + sync->buf = NULL; + sync->next = DBSync; + DBSync = sync; + + sync_next(sync, channel); +} + + +void db_sync_ready(dbsync * sync) +{ + struct dbuser buffer[10]; + register RegUser **reg = sync->reg; + int size; + +#ifdef DEBUG + printf("SYNC_READY: status= %d\n", sync->status); +#endif + + if (sync->status == SYNC_PENDWRITE) + { + size = look_in_buffer(&sync->buf, (char *)buffer, '\0', sizeof(dbuser)); + if (size == 0) + zap_buffer(&sync->buf); + if (sync->buf == NULL) + { + if ((*reg)->access == 0 && (*reg)->inuse == 0) + free_user(reg); + else + (*reg)->modified = 0; + sync_next(sync, (*reg)->channel); + return; + } +#ifdef DEBUG + printf("PENDWRITE: %d bytes to write...", size); +#endif + size = write(sync->fd, buffer, size); +#ifdef DEBUG + printf("%d written\n", size); +#endif + if (size <= 0) + { + if (errno != EWOULDBLOCK && errno != EAGAIN) + { + close(sync->fd); + sync->fd = -1; + } + return; + } + skip_char_in_buffer(&sync->buf, size); + } + + else if (sync->status == SYNC_SEEKFREE) + { + size = read(sync->fd, buffer, 10 * sizeof(dbuser)); + if (size <= 0) + { + if (errno != EAGAIN && errno != EWOULDBLOCK) + { + make_dbuser(*sync->reg, buffer); + zap_buffer(&sync->buf); + copy_to_buffer(&sync->buf, (char *)buffer, sizeof(dbuser)); + sync->status = SYNC_PENDWRITE; + lseek(sync->fd, 0L, SEEK_END); + } + return; + } + + copy_to_buffer(&sync->buf, (char *)buffer, size); + while (look_in_buffer(&sync->buf, (char *)buffer, '\0', sizeof(dbuser)) + == sizeof(dbuser)) + { + if (buffer[0].header[0] == 0x00 && buffer[0].header[1] == 0x00 && + buffer[0].footer[0] == 0x00 && buffer[0].footer[1] == 0x00) + { + make_dbuser(*sync->reg, buffer); + zap_buffer(&sync->buf); + copy_to_buffer(&sync->buf, (char *)buffer, sizeof(dbuser)); + sync->status = SYNC_PENDWRITE; + (*sync->reg)->offset = sync->offset; + lseek(sync->fd, sync->offset, SEEK_SET); + return; + } + skip_char_in_buffer(&sync->buf, sizeof(dbuser)); + sync->offset += sizeof(dbuser); + } + } +} + +void end_db_sync(dbsync * sync) +{ +#ifdef DEBUG + printf("SYNC_END\n"); +#endif + sync_next_channel(); + return; +} + + +void cold_save_one(RegUser * reg) +{ + struct stat st; + dbuser dbu; + char *fname; + register int fd; + off_t off; + + fname = make_dbfname(reg->channel); + + if (stat(fname, &st) < 0) /* file doesn't exist -- don't save delete */ + { + if (reg->access == 0) + return; + fd = open(fname, O_RDWR | O_CREAT, 0600); + } + else + fd = open(fname, O_RDWR | O_EXCL); + + if (fd < 0) /* hmmm? */ + return; + + if (reg->offset == (off_t) - 1) /* new ==> seek for empty slot */ + { + lseek(fd, 0L, SEEK_SET); + off = (off_t) 0; + while (read(fd, &dbu, sizeof(dbuser)) == sizeof(dbuser)) + { + if (dbu.header[0] == 0x00 && dbu.header[1] == 0x00 && + dbu.footer[0] == 0x00 && dbu.footer[1] == 0x00) + break; /* found empty slot */ + off += sizeof(dbuser); + } + } + else + off = reg->offset; + + lseek(fd, off, SEEK_SET); /* go to write position */ + + if (reg->access != 0) + make_dbuser(reg, &dbu); + else + memset(&dbu, 0, sizeof(dbuser)); + + write(fd, &dbu, sizeof(dbuser)); + + if (reg->access != 0) + reg->offset = off; + else + reg->offset = (off_t) - 1; + + reg->modified = 0; + + close(fd); +} + + +void do_cold_sync_slice(void) +{ + register RegUser **reg; + + if (DB_Save_Status < 0) + return; + + reg = &UserList[DB_Save_Status]; + while (*reg != NULL) + { + if ((*reg)->modified && (*reg)->access < 1000) + cold_save_one(*reg); + if ((*reg)->inuse == 0 && (*reg)->access < 1000 && + ((*reg)->access == 0 || (*reg)->lastused + CACHE_TIMEOUT < now)) + free_user(reg); + else + reg = &(*reg)->next; + } + + if (++DB_Save_Status == 1000) + { + DB_Save_Status = -1; + if (*DB_Save_Nick) + notice(DB_Save_Nick, "Userlist sync complete!"); + } +} + + +void do_cold_sync(void) +{ + register dbsync *sync; + register syncchan *schan; + register RegUser **reg; + register int i; + char buffer[200]; + + /* SET AWAY MESSAGE */ + sprintf(buffer, ":%s AWAY :Busy saving precious user list\n", mynick); + sendtoserv(buffer); + dumpbuff(); + + /* First, cancel *all* sync requests */ + while ((sync = DBSync) != NULL) + { + DBSync = DBSync->next; + if (sync->fd >= 0) + close(sync->fd); + zap_buffer(&sync->buf); + free(sync); + } + + /* Also, clear *all* pending syncs */ + while ((schan = SyncChan) != NULL) + { + SyncChan = SyncChan->next; + free(schan); + } + + /* Now, go thru *all* the user entries in memory and save them + * to their respective files. + */ + for (i = 0; i < 1000; i++) + { + reg = &UserList[i]; + while (*reg != NULL) + { + if ((*reg)->modified && (*reg)->access < 1000) + cold_save_one(*reg); + if ((*reg)->inuse == 0 && (*reg)->access < 1000 && + ((*reg)->access == 0 || (*reg)->lastused + CACHE_TIMEOUT < now)) + free_user(reg); + else + reg = &(*reg)->next; + } + } + sprintf(buffer, ":%s AWAY\n", mynick); + sendtoserv(buffer); +} + + + + +#ifdef DEBUG +void db_test_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + char buffer[512]; + + sprintf(buffer, "off: %ld act: %d hook=%p cnt: %d", off, action, hook1, count); + notice((char *)hook1, buffer); + + if (dbu) + { + sprintf(buffer, "hdr: %X%X nick: %s match: %s passwd: %s channel: %s " + "modif: %s access: %d flags: %ld susp: %ld last: %ld ftr: %X%X", + dbu->header[0], dbu->header[1], dbu->nick, dbu->match, dbu->passwd, + dbu->channel, dbu->modif, dbu->access, dbu->flags, dbu->suspend, + dbu->lastseen, dbu->footer[0], dbu->footer[1]); + notice((char *)hook1, buffer); + } + else + { + notice((char *)hook1, "End."); + free(hook1); + } +} + +void db_test(char *source, char *chan, char *args) +{ + char channel[80], type[80], info[80], *hook; + + GetWord(0, args, channel); + GetWord(1, args, type); + GetWord(2, args, info); + hook = (char *)malloc(strlen(source) + 1); + strcpy(hook, source); + + if (!strcmp(type, "nick")) + db_fetch(channel, DBGETNICK, info, NULL, 0, hook, NULL, db_test_callback); + + else if (!strcmp(type, "alluh")) + db_fetch(channel, DBGETALLUH, info, NULL, 0, hook, NULL, db_test_callback); + + else if (!strcmp(type, "1stuh")) + db_fetch(channel, DBGET1STUH, info, NULL, 0, hook, NULL, db_test_callback); + + else if (!strcmp(type, "count")) + db_fetch(channel, DBCOUNTUH, info, NULL, 0, hook, NULL, db_test_callback); + + else if (!strcmp(type, "1stcmp")) + db_fetch(channel, DBGET1STCMP, info, NULL, 0, hook, NULL, db_test_callback); + + else if (!strcmp(type, "allcmp")) + db_fetch(channel, DBGETALLCMP, info, NULL, 0, hook, NULL, db_test_callback); + + else if (!strcmp(type, "cntcmp")) + db_fetch(channel, DBCNTCMP, info, NULL, 0, hook, NULL, db_test_callback); + + else if (!strcmp(type, "sync")) + db_sync(channel); +} +#endif diff --git a/Sources/dbio.h b/Sources/dbio.h new file mode 100644 index 0000000..b934683 --- /dev/null +++ b/Sources/dbio.h @@ -0,0 +1,43 @@ +/* @(#)$Id: dbio.h,v 1.3 1996/11/13 00:40:36 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#define DBGETNICK 0x00000001 +#define DBGET1STUH 0x00000002 +#define DBGETALLUH 0x00000004 +#define DBCOUNTUH 0x00000008 +#define DBGET1STCMP 0x00000010 +#define DBGETALLCMP 0x00000020 +#define DBCNTCMP 0x00000040 +#define DBGETUHPASS 0x00000080 +#define DBGET1STFREE 0x00000100 + +#define SYNC_UPDATE 0x00000001 +#define SYNC_DELETE 0x00000002 +#define SYNC_ADD 0x00000004 + +#define SYNC_PENDWRITE 0x00000001 +#define SYNC_SEEKFREE 0x00000002 + diff --git a/Sources/debug.c b/Sources/debug.c new file mode 100644 index 0000000..eaf0dde --- /dev/null +++ b/Sources/debug.c @@ -0,0 +1,70 @@ +/* @(#)$Id: debug.c,v 1.3 1996/11/13 00:40:36 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +#ifdef DEBUG_MALLOC + +#include +#undef malloc +#undef free + +static FILE *debug_malloc_file; + +void open_debug_malloc(void) +{ + debug_malloc_file=fopen("malloc.log","w"); +} + +void close_debug_malloc(void) +{ + fclose(debug_malloc_file); +} + +void log_malloc(char *fmt,...) +{ + va_list ap; + va_start(ap,fmt); + vfprintf(debug_malloc_file,fmt,ap); + va_end(ap); +} + +void *debug_malloc(char *file, int line, size_t size) +{ + register void *ptr; + ptr=malloc(size); + log_malloc("%s(%d):malloc(%ld)= %p\n",file,line,(long)size,ptr); + return ptr; +} + +void debug_free(char *file, int line, void *ptr) +{ + log_malloc("%s(%d):free(%p)\n",file,line,ptr); + free(ptr); +} + +#endif + diff --git a/Sources/debug.h b/Sources/debug.h new file mode 100644 index 0000000..0b002fa --- /dev/null +++ b/Sources/debug.h @@ -0,0 +1,37 @@ +/* @(#)$Id: debug.h,v 1.3 1996/11/13 00:40:37 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#ifdef DEBUG_MALLOC +void open_debug_malloc(void); +void close_debug_malloc(void); +void *debug_malloc(char *,int,size_t); +void debug_free(char *,int,void *); + +#define malloc(X) debug_malloc(__FILE__,__LINE__,X) +#define free(X) debug_free(__FILE__,__LINE__,X) + +#endif + diff --git a/Sources/defchan.c b/Sources/defchan.c new file mode 100644 index 0000000..71e41fa --- /dev/null +++ b/Sources/defchan.c @@ -0,0 +1,493 @@ +/* @(#)$Id: defchan.c,v 1.7 1999/12/19 16:33:13 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +#define FORMATNO 0x02 + +typedef struct adefchan0 { + char name[50]; + char mode[80]; + char reserved[20]; + int MassDeopPro; + int NickFloodPro; + int MsgFloodPro; + time_t TS; + unsigned long flags; + unsigned long uflags; + struct adefchan *next; +} adefchan0; + +typedef struct adefchan1 { + char name[50]; + char mode[80]; + int MassDeopPro; + int NickFloodPro; + int MsgFloodPro; + int lang; + time_t TS; + unsigned long flags; + unsigned long uflags; + struct adefchan *next; +} adefchan1; + +static int active=0; + +void SearchChan(char *source,char *ch,char *args) +{ + char buffer[200],keylist[512]; + char *tok[16]; + adefchan *list[11]; + register adefchan *curr; + register int found=0,i=0; + + if(!*args){ + notice(source,"SYNTAX: search "); + return; + } + + strcpy(keylist,args); + + tok[0]=strtok(keylist," "); + while(i<16 && (tok[++i]=strtok(NULL," "))!=NULL); + tok[i]=NULL; + + for(curr=DefChanList; curr; curr=curr->next){ + if((key_match(curr->name,tok)||key_match(curr->topic,tok)) && + !IsSet(curr->name,'s',"") && !IsSet(curr->name,'p',"")){ + list[found]=curr; + found++; + if(found>10){ + sprintf(buffer,"There are more than 10 entries matching [%s]",args); + notice(source,buffer); + sprintf(buffer,"Please restrict your search mask"); + notice(source,buffer); + return; + } + } + } + + if(!found){ + sprintf(buffer,"No matching entries for [%s]",args); + notice(source,buffer); + return; + } + + for(i=0; iname,list[i]->topic); + notice(source,buffer); + } +} + + +void AddChan(char *source,char *ch,char *args) +{ + char buffer[200]; + char channel[80]; + register adefchan *curr,**scan; + register achannel *chan; + register int found=0; + + if(*args=='#'){ + GetWord(0,args,channel); + }else{ + strcpy(channel,ch); + GuessChannel(source,channel); + } + + if(!strcmp(channel,"*")){ + notice(source,"SYNTAX: addchan "); + return; + } + + chan=ToChannel(channel); + if(chan==NULL || !chan->on){ + notice(source,replies[RPL_NOTONCHANNEL][L_DEFAULT]); + return; + } + + if(Access(channel,source)name,channel)){ + /* look if the channel is already in the + * default channels list + */ + + curr=DefChanList; + while(curr&&strcasecmp(curr->name,channel)) + curr=curr->next; + + /* The channel *IS NOT* in the list */ + if(curr==NULL){ + curr=(adefchan *)MALLOC(sizeof(adefchan)); + scan=&DefChanList; + while(*scan && strcasecmp((*scan)->name,chan->name)<0) + scan=&(*scan)->next; + curr->next=*scan; + *scan=curr; + + curr->url[0]='\0'; + curr->topic[0]='\0'; + } + + strcpy(curr->name,chan->name); + strcpy(curr->mode,chan->mode); + curr->MassDeopPro=chan->MassDeopPro; + curr->NickFloodPro=chan->NickFloodPro; + curr->MsgFloodPro=chan->MsgFloodPro; + curr->lang=chan->lang; + curr->flags=chan->flags; + curr->uflags=chan->uflags; + curr->TS=chan->TS; + + found=1; + }else + chan=chan->next; + } + sprintf(buffer,"I ADD DEFAULT CHANNEL %s",channel); + log(buffer); + + if(found){ + notice(source,replies[RPL_SETCHANDEFS][chan->lang]); +#ifdef BACKUP + notice(source,"This modification will not be permanent"); +#endif + }else{ + notice(source,replies[RPL_NOTONCHANNEL][L_DEFAULT]); + } +} + +void RemChan(char *source, char *ch, char *arg) +{ + char buffer[200]; + char channel[80]; + register adefchan *chan,*prev; + + if(*arg=='#'){ + GetWord(0,arg,channel); + }else{ + strcpy(channel,ch); + GuessChannel(source,channel); + } + + if(!strcmp(channel,"*")){ + notice(source,"SYNTAX: remchan "); + return; + } + + if(*source && Access(channel,source)name);chan=chan->next) + prev=chan; + + if(!chan){ + notice(source,replies[RPL_NOTDEF][L_DEFAULT]); + return; + } + + if(prev) + prev->next=chan->next; + else + DefChanList=chan->next; + + TTLALLOCMEM-=sizeof(adefchan); + free(chan); + + sprintf(buffer,"I REMOVE DEFAULT CHANNEL %s",channel); + log(buffer); + if(*source){ + notice(source,replies[RPL_REMDEF][L_DEFAULT]); +#ifdef BACKUP + notice(source,"This modification will not be permanent"); +#endif + } +} + +void SaveDefs(char *source) +{ + register int file; + register adefchan *curr; + adefchan buff; + filehdr hdr; + char global[]="*"; + char buffer[200]; + + if(*source&&Access(global,source)name); + + buff = *curr; + if(chan) + buff.TS = chan->TS; + else + buff.TS = curr->TS; + buff.flags = curr->flags; + + alarm(2); + if(write(file,&buff,sizeof(adefchan))<=0){ + alarm(0); + close(file); + log("ERROR: Can't save channel list"); + log((char *)sys_errlist[errno]); + alarm(2); + remove(DEFAULT_CHANNELS_FILE".new"); + alarm(0); + active=0; + sprintf(buffer,":%s AWAY\n",mynick); + sendtoserv(buffer); + return; + } + alarm(0); + curr=curr->next; + } + close(file); + alarm(20); + rename(DEFAULT_CHANNELS_FILE".new",DEFAULT_CHANNELS_FILE); + alarm(0); + if(*source) + notice(source,"Done."); + } + active=0; + sprintf(buffer,":%s AWAY\n",mynick); + sendtoserv(buffer); +} + +void LoadDefs(char *source) +{ + register adefchan *curr,**scan; + adefchan buffer; + adefchan0 bufold0; + adefchan1 bufold1; + filehdr hdr; + register int file; + char global[]="*"; + + if(*source&&Access(global,source)next; + TTLALLOCMEM-=sizeof(adefchan); + free(curr); + } + + /* find file format */ + read(file,&hdr,sizeof(hdr)); + if(hdr.magic!=0xff){ + lseek(file,0L,SEEK_SET); + hdr.no=0x00; + } + + if(hdr.no == FORMATNO){ + scan=&DefChanList; + while(read(file,&buffer,sizeof(adefchan))>0){ +#ifdef DEBUG + printf("DEFCHAN: %s %d %d %d %ld\n",buffer.name, + buffer.MassDeopPro,buffer.NickFloodPro, + buffer.MsgFloodPro,buffer.flags); + printf("TS: %lu\n",buffer.TS); +#endif + if(logTS==0||buffer.TSnext=*scan; + *scan=curr; + scan=&(*scan)->next; + } + }else if(hdr.no == 0x01){ + while(read(file,&bufold1,sizeof(adefchan1))>0){ +#ifdef DEBUG + printf("DEFCHAN: %s %d %d %d %ld\n",bufold1.name, + bufold1.MassDeopPro,bufold1.NickFloodPro, + bufold1.MsgFloodPro,bufold1.flags); + printf("TS: %lu\n",bufold1.TS); +#endif + if(logTS==0||bufold1.TSname,bufold1.name); + strcpy(curr->mode,bufold1.mode); + curr->url[0]='\0'; + curr->topic[0]='\0'; + curr->MassDeopPro=bufold1.MassDeopPro; + curr->NickFloodPro=bufold1.NickFloodPro; + curr->MsgFloodPro=bufold1.MsgFloodPro; + curr->lang=bufold1.lang; + curr->TS=bufold1.TS; + curr->flags=bufold1.flags; + curr->uflags=bufold1.uflags; + scan=&DefChanList; + while(*scan && strcasecmp((*scan)->name,curr->name)<0) + scan=&(*scan)->next; + curr->next=*scan; + *scan=curr; + } + }else{ /* old file format */ + while(read(file,&bufold0,sizeof(adefchan0))>0){ +#ifdef DEBUG + printf("DEFCHAN: %s %d %d %d %ld\n",bufold0.name, + bufold0.MassDeopPro,bufold0.NickFloodPro, + bufold0.MsgFloodPro,bufold0.flags); + printf("TS: %lu\n",bufold0.TS); +#endif + if(logTS==0||bufold0.TSname,bufold0.name); + strcpy(curr->mode,bufold0.mode); + curr->url[0]='\0'; + curr->topic[0]='\0'; + curr->MassDeopPro=bufold0.MassDeopPro; + curr->NickFloodPro=bufold0.NickFloodPro; + curr->MsgFloodPro=bufold0.MsgFloodPro; + curr->lang=L_DEFAULT; + curr->TS=bufold0.TS; + curr->flags=bufold0.flags; + curr->uflags=bufold0.uflags; + scan=&DefChanList; + while(*scan && strcasecmp((*scan)->name,curr->name)<0) + scan=&(*scan)->next; + curr->next=*scan; + *scan=curr; + } + } + + close(file); + + if(*source) + notice(source,"Defaults file loaded!"); + + active=0; +} diff --git a/Sources/defines.h b/Sources/defines.h new file mode 100644 index 0000000..4ac341b --- /dev/null +++ b/Sources/defines.h @@ -0,0 +1,141 @@ +/* @(#)$Id: defines.h,v 1.11 2000/06/04 16:54:16 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#define NICK_LENGTH 20 +#define USERNAME_LENGTH 20 +#define SITE_LENGTH 80 +#define REALNAME_LENGTH 80 +#define CHANNELNAME_LENGTH 80 +#define SERVER_NAME_LENGTH 80 +#define PASSWD_LENGTH 20 + +#define COMMAND_PREFIX "X " +#define MAX_MODE_PER_LINE 6 + +#define MAX_DEOP_RATE 3 /* deops within 15 seconds */ +#define MASSDEOP_SUSPEND_TIME 600 /* seconds */ +#define MASSDEOP_SHITLIST_TIME 1 /* hours */ +#define MASSDEOP_SHITLIST_LEVEL 20 + +#define MAX_NICKCHANGE_RATE 5 /* nick change within 15 seconds */ +#define NICK_FLOOD_SUSPEND_TIME 600 /* seconds */ + +#define MAX_PUBLIC_MSG_RATE 7 /* within 15 seconds */ +#define PUBLIC_FLOOD_SUSPEND_TIME 600 /* seconds */ +#define PUBLIC_FLOOD_SHITLIST_TIME 24 /* hour */ +#define PUBLIC_FLOOD_SHITLIST_LEVEL 75 + +#define PRIVATE_FLOOD_RATE 10 /* messages per 30 seconds */ +#define PRIVATE_FLOOD_SIZE 800 /* bytes per 30 seconds */ +#define FLOOD_FLOOD_RATE 10 /* messages per 30 seconds */ +#define FLOOD_FLOOD_SIZE 60 /* lines per 30 seconds */ +#define MAX_IGNORE_PER_SITE 3 /* ignores per site */ +#define IGNORE_TIME 3600 /* in seconds */ +#define FLOOD_FLOOD_IGNORE 300 /* in seconds */ + +#define LEVEL_DIE 900 +#define LEVEL_CORE 900 +#define RUSAGE_ACCESS 900 +#define LEVEL_UPGRADE 900 +#define LEVEL_JOIN 450 +#define LEVEL_PART 450 +#define INVITE_LEVEL 100 +#define OP_LEVEL 100 +#define TOPIC_LEVEL 50 +#define KICK_LEVEL 50 +#define MASS_KICK_LEVEL 200 +#define BAN_LEVEL 75 +#define MASS_BAN_LEVEL 200 +#define ADD_USER_LEVEL 400 +#define SHOW_ACCESS_LEVEL 0 +#define REMOVE_USER_LEVEL 400 +#define MOD_USERINFO_LEVEL 400 +#define LEVEL_SUSPEND 100 +#define ADD_TO_SHITLIST_LEVEL 75 +#define CLEAN_SHITLIST_LEVEL 200 +#define SET_DEFAULT_LEVEL 450 +#define LOAD_DEFAULT_LEVEL 999 +#define SAVE_DEFAULTS_LEVEL 600 +#define SAVE_SHITLIST_LEVEL 600 +#define LOAD_SHITLIST_LEVEL 999 +#define SAVE_USERLIST_LEVEL 600 +#define LOAD_USERLIST_LEVEL 999 +#define STATUS_ACCESS 1 +#define STATUS_ACCESS_MODE 200 +#define CH_FLOOD_LIMIT_LEVEL 500 +#define CH_NICK_FLOOD_LIMIT_LEVEL 450 +#define CH_MASSDEOP_LIMIT_LEVEL 450 +#define CH_NOOP_LEVEL 500 +#define CH_OPONLY_LEVEL 500 +#define CH_AUTOTOPIC_LEVEL 450 +#define CH_ALWAYSOP_LEVEL 450 +#define CH_STRICTOP_LEVEL 500 +#define CH_USERFLAGS_LEVEL 450 +#define CH_LANG_LEVEL 500 +#define CH_TOPIC_LEVEL 450 +#define CH_URL_LEVEL 450 +#define ACCESS_BAN_PRIORITY 450 +#define ALWAYSOP_OVERRIDE_LEVEL 450 +#define PROTECT_OVERRIDE_LEVEL 450 +#define MASSDEOP_IMMUNE_LEVEL 450 +#define CLEARMODE_LEVEL 400 +#define XADMIN_LEVEL 750 + +#define AUTO_KICK_SHIT_LEVEL 75 +#define NO_OP_SHIT_LEVEL 20 +#define SHITLIST_DEFAULT_TIME (24*3) /* hours */ +#define SUSPEND_TIME_FOR_OPPING_A_SHITLISTED_USER 600 /* seconds */ +#define SUSPEND_TIME_FOR_BANNING_A_PROTECTED_USER 600 /* seconds */ +#define DEOPME_SUSPEND_TIME 3600 /* seconds */ +#define DEOP_SHITLIST_TIME 1 /* hours */ +#define DEOP_SHITLIST_LEVEL 20 +#define MAX_BAN 50 + +#define MIN_LASTSEEN (3*24*3600) /* 3 days */ + +#define HTTP_LISTEN 1 +#define HTTP_ACTIVE 2 +#define HTTP_ENDING 3 +#define HTTP_RECV_POST 4 +#define HTTP_PIPE 5 +#define HTTP_CSRAW 6 +#define HTTP_CHAT 7 +#define HTTP_ERROR 0 + +#define MISC_GETPATCH 1 +#define MISC_PIPE_PATCH 2 +#define MISC_PIPE_MAKE 3 + +#define MISC_ERROR -1 +#define MISC_CONNECTING 1 +#define MISC_HANDSHAKE 2 +#define MISC_RECV 3 + +#define BUFFER_BLOCK_SIZE 512 + +#define CACHE_TIMEOUT 4800 /* 1.5 hours */ + +#define AUTOTOPIC_FREQ 1800 /* 30 minutes*/ diff --git a/Sources/events.c b/Sources/events.c new file mode 100644 index 0000000..acd9abf --- /dev/null +++ b/Sources/events.c @@ -0,0 +1,189 @@ +/* @(#)$Id: events.c,v 1.6 1998/01/02 18:30:09 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +void InitEvent(void) +{ + AddEvent(EVENT_SAVESHITLIST, now + SHITLIST_SAVE_FREQ + 300, ""); + AddEvent(EVENT_SAVEDEFCHANNELS, now + DEFS_SAVE_FREQ + 600, ""); + AddEvent(EVENT_SYNC, now + SYNC_FREQ + 900, ""); + AddEvent(EVENT_CHECK_IDLE, now + CHECK_IDLE_FREQ, ""); + AddEvent(EVENT_RENAME_LOGFILE, now + RENAME_LOGFILE_FREQ, ""); + AddEvent(EVENT_SYNCDB, now + CACHE_TIMEOUT, ""); +#ifdef CHANNEL_LOG + AddEvent(EVENT_LOG_CHANNEL, now + CHANNEL_LOG_FREQ, ""); +#endif +#ifdef NICKSERV + AddEvent(EVENT_SAVENICKSERV, now + NSERV_SAVE_FREQ, ""); +#endif +} + +void AddEvent(int event, time_t time, char *param) +{ + register anevent **curr = &EventList; + register anevent *new; + +#ifdef DEBUG + printf("AddEvent( %d, %ld, %s)\n", event, time, param); +#endif + + /* the events are store in ascending time order, so the new + * event is inserted before the first event with a greater + * time + */ + while (*curr && (*curr)->time < time) + curr = &(*curr)->next; + + /* create a new event structure + */ + new = (anevent *) MALLOC(sizeof(anevent)); + new->time = time; + new->event = event; + strncpy(new->param, param, 79); + new->param[79] = '\0'; + + /* link the new structure to the list + */ + new->next = *curr; + *curr = new; +} + +void CheckEvent(void) +{ + register anevent *curr; + register achannel *chan; + + while (EventList != NULL && EventList->time <= now) + { + /* remove the event from the list */ + curr = EventList; + EventList = EventList->next; + +#ifdef DEBUG + printf("Scheduled event %d\n", curr->event); +#endif + switch (curr->event) + { + case EVENT_SAVEUSERLIST: + /* replaced by SYNCDB */ + break; + + case EVENT_SAVESHITLIST: + SaveShitList("", ""); + AddEvent(EVENT_SAVESHITLIST, + now + SHITLIST_SAVE_FREQ, ""); + break; + + case EVENT_SAVEDEFCHANNELS: + SaveDefs(""); + AddEvent(EVENT_SAVEDEFCHANNELS, + now + DEFS_SAVE_FREQ, ""); + break; + + case EVENT_CLEANSHITLIST: + CleanShitList("", curr->param); + break; + + case EVENT_FLUSHMODEBUFF: + flushmode(curr->param); + break; + + case EVENT_GETOPS: + chan = ToChannel(curr->param); + if (chan != NULL && chan->on && + (IsOpless(curr->param) || + ((chan->flags & CFL_ALWAYSOP) && + !chan->AmChanOp))) + GetOps(curr->param); + break; + + case EVENT_SYNC: + sync(); + AddEvent(EVENT_SYNC, + now + SYNC_FREQ, ""); + break; + + case EVENT_CLEAN_IGNORES: + CleanIgnores(); + break; + + case EVENT_CHECK_IDLE: + CheckIdleChannels(); + AddEvent(EVENT_CHECK_IDLE, now + CHECK_IDLE_FREQ, ""); + break; + + case EVENT_RENAME_LOGFILE: + log("Closing log file"); + close(logfile); + rename(LOGFILE, LOGFILEBAK); + logfile = open(LOGFILE, O_WRONLY | O_CREAT | O_APPEND, 0600); /* "a" in case rename() fails */ + log("Opening log file"); + AddEvent(EVENT_RENAME_LOGFILE, now + RENAME_LOGFILE_FREQ, ""); + break; + + case EVENT_SYNCDB: + if (DB_Save_Status == -1) + { + DB_Save_Status = 0; + *DB_Save_Nick = '\0'; + } + /*SaveUserList("",""); */ + /* + gather_sync_channels(); + if(DBSync==NULL) + sync_next_channel(); + sync_next_channel(); + */ + AddEvent(EVENT_SYNCDB, now + CACHE_TIMEOUT, ""); + break; + +#ifdef CHANNEL_LOG + case EVENT_LOG_CHANNEL: + LogChan(); + AddEvent(EVENT_LOG_CHANNEL, now + CHANNEL_LOG_FREQ, ""); + break; +#endif +#ifdef NICKSERV + case EVENT_CHECKREGNICK: + nserv_checkregnick(curr->param); + break; + + case EVENT_SAVENICKSERV: + nserv_save(); + break; +#endif + default: +#ifdef DEBUG + printf("Err.. unknown event %d\n", curr->event); +#endif + break; + } + + TTLALLOCMEM -= sizeof(anevent); + free(curr); + } +} diff --git a/Sources/events.h b/Sources/events.h new file mode 100644 index 0000000..5f562ae --- /dev/null +++ b/Sources/events.h @@ -0,0 +1,40 @@ +/* @(#)$Id: events.h,v 1.4 1997/07/01 21:51:08 cvs Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#define EVENT_SAVEUSERLIST 1 +#define EVENT_SAVESHITLIST 2 +#define EVENT_SAVEDEFCHANNELS 3 +#define EVENT_SYNC 4 +#define EVENT_CLEANSHITLIST 5 +#define EVENT_FLUSHMODEBUFF 6 +#define EVENT_GETOPS 7 +#define EVENT_CLEAN_IGNORES 8 +#define EVENT_CHECK_IDLE 9 +#define EVENT_RENAME_LOGFILE 10 +#define EVENT_LOG_CHANNEL 11 +#define EVENT_SYNCDB 12 +#define EVENT_CHECKREGNICK 13 +#define EVENT_SAVENICKSERV 14 diff --git a/Sources/fixdb.c b/Sources/fixdb.c new file mode 100644 index 0000000..60460f5 --- /dev/null +++ b/Sources/fixdb.c @@ -0,0 +1,203 @@ +/* @(#)$Id: fixdb.c,v 1.5 1998/01/12 20:02:17 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" +#include "dirent.h" +#define SPECFILE "special.log" + +struct node +{ + dbuser dbu; + struct node *next; +}; + +unsigned long ttlread = 0L, ttlwrite = 0L; +time_t now; + +void SpecLog(char *text) +{ + int fd; + char date[80], buffer[1024]; + strcpy(date, ctime(&now)); + *strchr(date, '\n') = '\0'; + + if ((fd = open(SPECFILE, O_WRONLY | O_CREAT | O_APPEND, 0600)) >= 0) + { + sprintf(buffer, "%s: %s\n", date, text); + write(fd, buffer, strlen(buffer)); + close(fd); + } +} + + +void fix_user_file(char *file, char *channel) +{ + char tmpfile[256], buffer[200]; + struct node *List = NULL, *tmp; + dbuser dbu; + int fd; + + fd = open(file, O_RDONLY); + if (fd < 0) + { + fprintf(stderr, "Can't open %s [%s]\n", file, sys_errlist[errno]); + return; + } + + while (read(fd, &dbu, sizeof(dbuser)) == sizeof(dbuser)) + { + ttlread += sizeof(dbuser); + + if (dbu.header[0] != 0xFF || dbu.header[1] != 0xFF || + dbu.footer[0] != 0xFF || dbu.footer[1] != 0xFF) + { + continue; + } + if (strcasecmp(channel, dbu.channel)) + continue; + + if (!strcmp(dbu.match, "!DEL!")) + continue; + + if (dbu.lastseen + USERLIST_EXP_TIME <= now) + { + sprintf(buffer, "Exp: %s [%s] (%d) on %s", + dbu.nick, dbu.match, dbu.access, dbu.channel); + SpecLog(buffer); + continue; + } + + tmp = (struct node *)malloc(sizeof(struct node)); + memcpy(&tmp->dbu, &dbu, sizeof(dbuser)); + tmp->next = List; + List = tmp; + } + close(fd); + + sprintf(tmpfile, "%s.new", file); + + fd = open(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) + { + fprintf(stderr, "Can't open %s\n", tmpfile); + /* don't return.. need to free the list! */ + } + + while ((tmp = List) != NULL) + { + write(fd, &tmp->dbu, sizeof(dbuser)); + ttlwrite += sizeof(dbuser); + List = List->next; + free(tmp); + } + close(fd); + + if (fd >= 0) + rename(tmpfile, file); +} + +void fix_user_db(void) +{ + DIR *dp; + struct dirent *ent; + char dir[256], file[256], channel[80], *ptr; + int count; + + for (count = 0; count < 1000; count++) + { + sprintf(dir, "db/channels/%04X", count); + dp = opendir(dir); + if (dp == NULL) + { + fprintf(stderr, "Can't read %s [%s]\n", dir, sys_errlist[errno]); + continue; + } + while ((ent = readdir(dp)) != NULL) + { + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + continue; + strcpy(channel, ent->d_name); + for (ptr = channel; *ptr; ptr++) + if (*ptr == ' ') + *ptr = '/'; + sprintf(file, "db/channels/%04X/%s", count, ent->d_name); + + /* If no comma in channel name, proceed with clean up */ + if (strchr(channel, ',') == NULL) + fix_user_file(file, channel); + } + closedir(dp); + } +} + +int main(void) +{ + int pid = 0; + FILE *fp; + + if (chdir(HOMEDIR) < 0) + { + perror(HOMEDIR); + exit(1); + } + + if ((fp = fopen(PIDFILE, "r")) != NULL) + { + fscanf(fp, "%d", &pid); + fclose(fp); + if (!kill((pid_t) pid, 0)) + { + fprintf(stderr, "Detected cs is running [pid %d]. Abort.\n", pid); + exit(1); + } + } + + if (rename("cs", "cs.fixdb") < 0) + { + perror("rename"); + exit(1); + } + + if (symlink("/bin/true", "cs") < 0) + { + perror("symlink"); + exit(1); + } + + time(&now); + + fix_user_db(); + + if (unlink("cs") < 0) + perror("unlink"); + + if (rename("cs.fixdb", "cs") < 0) + perror("rename"); + + printf("ttlread= %ld ttlwrite= %ld\n", ttlread, ttlwrite); + + return 0; +} diff --git a/Sources/flags.h b/Sources/flags.h new file mode 100644 index 0000000..01d37a2 --- /dev/null +++ b/Sources/flags.h @@ -0,0 +1,36 @@ +/* @(#)$Id: flags.h,v 1.4 1996/11/13 00:40:39 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#define UFL_AUTOOP 1 +/*#define UFL_PROTECT 2*/ + +#define CFL_NOOP 1 +#define CFL_ALWAYSOP 2 +#define CFL_OPONLY 4 +#define CFL_STRICTOP 8 +#define CFL_AUTOTOPIC 16 + +#define LFL_ISOPER 1 diff --git a/Sources/floodpro.c b/Sources/floodpro.c new file mode 100644 index 0000000..4fd3dfa --- /dev/null +++ b/Sources/floodpro.c @@ -0,0 +1,135 @@ +/* @(#)$Id: floodpro.c,v 1.4 1999/04/04 17:00:06 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +int CheckFlood(char *source, char *channel, int length) +{ + char buffer[200]; + register achannel *chan; + register auser *user; + register amsg *msg, *prev; + register int count = 0; + + chan = ToChannel(channel); + user = ToUser(channel, source); + + if (!chan || !chan->on || !user) + return 0; + + /* BEGINNING OF FLOOD PROTECTION ROUTINE */ + /* 1st clean msghist older than 15 seconds */ + prev = NULL; + msg = user->msghist; + while (msg) + { + if (msg->time < (now - 15)) + { + if (prev) + { + prev->next = msg->next; + TTLALLOCMEM -= sizeof(amsg); + free(msg); + msg = prev->next; + } + else + { + user->msghist = msg->next; + TTLALLOCMEM -= sizeof(amsg); + free(msg); + msg = user->msghist; + } + } + else + { + prev = msg; + msg = msg->next; + } + } + /* now add the current msg to the history */ + msg = (amsg *) MALLOC(sizeof(amsg)); + msg->time = now; + msg->length = length; + msg->next = user->msghist; + user->msghist = msg; + + /* now count the number of entry in the history.. + if it's greater than the max allowed... bite! */ + + count = 0; + for (msg = user->msghist; msg; msg = msg->next, count++); + + if (chan->MsgFloodPro != 0 && count == chan->MsgFloodPro) + { + notice(source, "### FLOOD PROTECTION ACTIVATED ###"); + sprintf(buffer, "%s!%s@%s %d", user->N->nick, + user->N->username, user->N->site, PUBLIC_FLOOD_SUSPEND_TIME); + suspend("", channel, buffer); + + count = IsShit(channel, source, NULL, NULL); +#ifdef DEBUG + printf("Argh! %s has a shit level %d\n", source, count); +#endif + sprintf(buffer, "FLOODPRO ACTIVATED BY %s ON %s", source, channel); + log(buffer); + + switch (count) + { + case 0: + case 1: + case 2: + case 3: + case 4: + log("First warning"); + sprintf(buffer, "%s That was not very smart!", source); + break; + + case 5: + case 6: + case 7: + case 8: + case 9: + log("Second warning"); + sprintf(buffer, "%s You're pushing your luck too far!", source); + break; + + default: + sprintf(buffer, "%s That was one time too many", source); + } + + kick("", channel, buffer); + + sprintf(buffer, "%s %d %d *** FLOOD ***", + user->N->nick, + PUBLIC_FLOOD_SHITLIST_TIME, + (count < 10) ? count + 5 : + PUBLIC_FLOOD_SHITLIST_LEVEL); + AddToShitList("", channel, buffer, 0); + + return 1; + } + return 0; +} diff --git a/Sources/globalvar.h b/Sources/globalvar.h new file mode 100644 index 0000000..d9ead4f --- /dev/null +++ b/Sources/globalvar.h @@ -0,0 +1,105 @@ +/* @(#)$Id: globalvar.h,v 1.12 2000/10/24 15:15:53 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#if !defined(__FreeBSD__) && !defined(__linux__) + +extern int errno; +extern char *sys_errlist[]; +#endif +extern char mynick[NICK_LENGTH]; +extern char myuser[USERNAME_LENGTH]; +extern char mysite[SITE_LENGTH]; +extern char myrealname[REALNAME_LENGTH]; +extern char server[SERVER_NAME_LENGTH]; +extern int logfile; +extern RegUser *UserList[1000]; +extern ShitUser *ShitList[1000]; +extern aluser *Lusers[1000]; +extern achannel *ChannelList[1000]; +extern adefchan *DefChanList; +extern anevent *EventList; +extern aserver *ServerList; +extern aserver VirtualServer; +extern dbquery *DBQuery; +extern dbsync *DBSync; +extern syncchan *SyncChan; +#ifdef DOHTTP +extern http_socket *HttpList; +extern http_file_pipe *FilePipes; +#endif +extern misc_socket *MiscList; +extern irc_socket Irc; +extern char *TmpPtr; +extern time_t now; +extern time_t logTS; +extern time_t TSoffset; +extern time_t TSonline; +extern time_t TSconnect; +extern unsigned long long TTLREADBYTES; +extern unsigned long long TTLSENTBYTES; +extern unsigned long TTLALLOCMEM; +extern unsigned long long HTTPTTLSENTBYTES; +extern alang Lang[NO_LANG]; +extern char *replies[][NO_LANG]; +#ifdef FAKE_UWORLD +extern int Uworld_status; +extern time_t UworldTS,UworldServTS; +#endif +#ifdef NICKSERV +extern int NServ_status; +#endif +extern unsigned long MEM_buffers; +extern unsigned long NB_avail_buffer_blocks; +extern unsigned long NB_alloc_buffer_blocks; +extern long CurrentSendQ; + +extern int DB_Save_Status; +extern char DB_Save_Nick[NICK_LENGTH]; + +#define MALLOC(X) ((TmpPtr=(char *)malloc(X))? \ + TmpPtr : (char *)quit("ERROR: malloc() failed", 1));\ + TTLALLOCMEM+=X + +#define close(X) if((X)>=0) close(X) +#define ABS(X) ((X>0)?(X):(-(X))) + +/* I use '}' and ']' instead of 'z' and 'Z' + * in order to respect RFC-1459 (section 2.2) + */ +#undef toupper +#undef tolower +#if 0 +#define toupper(X) ( ((X)>='a'&&(X)<='~') ? ((X)&223) : (X) ) +#define tolower(X) ( ((X)>='A'&&(X)<='^') ? ((X)|32) : (X) ) +#endif +#define toupper(X) ( ((X)>='a'&&(X)<='~') || ((unsigned char)(X)>=0xe0&&(unsigned char)(X)<=0xff&&(unsigned char)(X)!=0xf7)? ((X)&223) : (X) ) +#define tolower(X) ( ((X)>='A'&&(X)<='^') || ((unsigned char)(X)>=0xc0&&(unsigned char)(X)<=0xdf&&(unsigned char)(X)!=0xd7)? ((X)|32) : (X) ) + +#define touppertmp(X) ( ((X)>='a'&&(X)<='~') || ((unsigned char)(X)>=0xe0&&(unsigned char)(X)<=0xff&&(unsigned char)(X)!=0xf7)? ((X)&223) : (X) ) +#define tolowertmp(X) ( ((X)>='A'&&(X)<='^') || ((unsigned char)(X)>=0xc0&&(unsigned char)(X)<=0xdf&&(unsigned char)(X)!=0xd7)? ((X)|32) : (X) ) + +#define strcasecmp mycasecmp +#define strcmp mycasecmp diff --git a/Sources/h.h b/Sources/h.h new file mode 100644 index 0000000..830ef73 --- /dev/null +++ b/Sources/h.h @@ -0,0 +1,56 @@ +/* @(#)$Id: h.h,v 1.3 1996/11/13 00:40:40 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../config.h" +#include "debug.h" +#include "defines.h" +#include "struct.h" +#include "lang.h" +#include "replies.h" +#include "prototypes.h" +#include "globalvar.h" +#include "events.h" +#include "flags.h" +#include "dbio.h" +#include "version.h" diff --git a/Sources/help.c b/Sources/help.c new file mode 100644 index 0000000..6e7222e --- /dev/null +++ b/Sources/help.c @@ -0,0 +1,761 @@ +/* @(#)$Id: help.c,v 1.22 2000/10/02 00:55:13 lgm Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +static struct item +{ + char *name; + int Access; + char *file; +} +commands[] = +{ + { + "showcommands", 0, "SHOWCOMMANDS" + } + , + { + "status", STATUS_ACCESS, "STATUS" + } + , + { + "join", LEVEL_JOIN, "JOIN" + } + , + { + "invite", INVITE_LEVEL, "INVITE" + } + , + { + "part", LEVEL_PART, "JOIN" + } + , + { + "topic", TOPIC_LEVEL, "TOPIC" + } + , + { + "kick", KICK_LEVEL, "KICK" + } + , + { + "ban", BAN_LEVEL, "BAN" + } + , + { + "unban", BAN_LEVEL, "BAN" + } + , + { + "banlist", 0, "BAN" + } + , + { + "lbanlist", 0, "BAN" + } + , + { + "adduser", ADD_USER_LEVEL, "ADDUSER" + } + , + { + "access", SHOW_ACCESS_LEVEL, "ACCESS" + } + , + { + "verify", 0, "VERIFY" + } + , + { + "remuser", REMOVE_USER_LEVEL, "ADDUSER" + } + , + { + "modinfo", MOD_USERINFO_LEVEL, "ADDUSER" + } + , + { + "purge", XADMIN_LEVEL, "XADMIN" + } + , + { + "isreg", 0, "ISREG" + } + , + { + "set", CH_FLOOD_LIMIT_LEVEL, "SET" + } + , + { + "suspend", LEVEL_SUSPEND, "SUSPEND" + } + , + { + "unsuspend", LEVEL_SUSPEND, "SUSPEND" + } + , + { + "saveuserlist", SAVE_USERLIST_LEVEL, "SAVEUSERLIST" + } + , + { + "addchan", SET_DEFAULT_LEVEL, "DEFCHAN" + } + , + { + "remchan", SET_DEFAULT_LEVEL, "DEFCHAN" + } + , + { + "savedefs", SAVE_DEFAULTS_LEVEL, "DEFCHAN" + } + , + { + "loaddefs", LOAD_DEFAULT_LEVEL, "LOADDEFS" + } + , + { + "savebanlist", SAVE_SHITLIST_LEVEL, "SAVEBANLIST" + } + , + { + "loadbanlist", LOAD_SHITLIST_LEVEL, "LOADBANLIST" + } + , + { + "pass", 0, "PASSWORD" + } + , + { + "login", 0, "PASSWORD" + } + , + { + "newpass", 0, "PASSWORD" + } + , + { + "deauth", 0, "PASSWORD" + } + , + { + "die", LEVEL_DIE, "DIE" + } + , + { + "restart", LEVEL_DIE, "RESTART" + } + , + { + "core", LEVEL_CORE, "CORE" + } + , + { + "rusage", RUSAGE_ACCESS, "RUSAGE" + } + , +#ifdef UPGRADE + { + "upgrade", LEVEL_UPGRADE, "UPGRADE" + } + , +#endif + { + "op", OP_LEVEL, "OP" + } + , + { + "deop", OP_LEVEL, "OP" + } + , + { + "clearmode", CLEARMODE_LEVEL, "CLEARMODE" + } + , + { + "map", 0, "MAP" + } + , + { + "help", 0, "HELP" + } + , + { + "motd", 0, "MOTD" + } + , + { + "showignore", 0, "SHOWIGNORE" + } + , + { + "remignore", XADMIN_LEVEL, "REMIGNORE" + } + , + { + "chaninfo", 0, "CHANINFO" + } + , + { + NULL, -1, NULL + } +}; +static int N = 0; + +static void sort(void) +{ + struct item tmp; + register int i, j, k; + + /* sort the command list using a simple bubble sort algo. + * 1st sort the commands by decreasing access + */ + for (i = 0; i < N - 1; i++) + { + for (j = N - 1; j > i; j--) + { + if (commands[j - 1].Access < commands[j].Access) + { + tmp = commands[j - 1]; + commands[j - 1] = commands[j]; + commands[j] = tmp; + } + } + } + + /* Then, sort the commands by alphabetical order + */ + i = k = 0; + while (k < N - 1) + { + while (commands[k].Access == commands[i].Access) + k++; + + while (i < k - 1) + { + for (j = k - 1; j > i; j--) + { + if (strcmp(commands[j - 1].name, commands[j].name) > 0) + { + tmp = commands[j - 1]; + commands[j - 1] = commands[j]; + commands[j] = tmp; + } + } + i++; + } + + i = k; + } +} + +static void listinit(void) +{ + static int sorted = 0; + + /* count the number of commands + */ + if (N == 0) + { + for (N = 0; commands[N].name != NULL; N++); + N--; + } + + /* sort the list if not already done + */ + if (!sorted) + { + sort(); + sorted = 1; + } +} + +void showcommands(char *source, char *chan, char *args) +{ + char buffer[500]; + char channel[80]; + register aluser *luser; + register int useraccess; + register int i, j; + + if (*args == '#' || *args == '*') + GetWord(0, args, channel); + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + luser = ToLuser(source); + if (!luser) + return; + + if (!strcmp(channel, "*") && !IsValid(luser, channel)) + { + notice(source, "SYNTAX: showcommands "); + return; + } + + useraccess = LAccess(channel, luser); + + listinit(); + + /* Now show the sorted command list to the user. + */ + i = useraccess; + sprintf(buffer, "Level%5d:", i); + + for (j = 0; j < N + 1; j++) + { + if (commands[j].Access < i) + { + if (strlen(buffer) > 13) + notice(source, buffer); + i = commands[j].Access; + sprintf(buffer, "Level%5d:", i); + } + + if (commands[j].Access <= useraccess) + { + strcat(buffer, " "); + strcat(buffer, commands[j].name); + } + } + + notice(source, buffer); +} + +void showhelp(char *source, char *chan, char *args) +{ + struct buffer_block *dyn = NULL; + char buffer[512], word[80], *ptr; + int i, l, index = 0, found = 0, file, linecount = 0; + + if (CurrentSendQ > HIGHSENDQTHRESHOLD) + { + notice(source, "Cannot process your request at this time. Try again later."); + return; + } + + GetWord(0, args, word); + if (!*word) + strcpy(word, "help"); + + listinit(); + + /* find the command index */ + for (i = 0; i <= N; i++) + { + if (!strcasecmp(word, commands[i].name)) + { + found = 1; + index = i; + break; + } + else if (!strncasecmp(word, commands[i].name, strlen(word))) + { + found++; + index = i; + } + } + + if (found > 1) + { + sprintf(buffer, "%s is ambiguous", word); + notice(source, buffer); + return; + } + else if (found == 0) + { + if (!strcasecmp(word, "INFO")) + { + sprintf(buffer, "%s/INFO", HELP_DIR); + } + else if (!strcasecmp(word, "FORM")) + { + sprintf(buffer, "%s/FORM", HELP_DIR); + } + else + { + sprintf(buffer, "No help on %s. Please use " + "showcommands to get a list of commands " + "available to you", word); + notice(source, buffer); + return; + } + } + else + { + sprintf(buffer, "%s/%s", HELP_DIR, commands[index].file); + } + + alarm(2); + file = open(buffer, O_RDONLY); + alarm(0); + if (file < 0) + { + if (found) + sprintf(buffer, "The help file for command %s " + "is not available", commands[index].name); + else + sprintf(buffer, "This help file is not available"); + + notice(source, buffer); + return; + } + + if (found) + { + sprintf(buffer, + " HELP on %-20s Minimum access: %4d ", + commands[index].name, commands[index].Access); + notice(source, buffer); + } + + alarm(3); + while ((l = read(file, buffer, 511)) > 0) + { + copy_to_buffer(&dyn, buffer, l); + } + alarm(0); + close(file); + + while (dyn != NULL) + { + copy_from_buffer(&dyn, buffer, '\n', 199); + if ((ptr = strchr(buffer, '\n')) != NULL) + *ptr = '\0'; + else + continue; + if (*buffer == '\0') + strcpy(buffer, " "); + string_swap(buffer, 512, "$NICK", mynick); + string_swap(buffer, 512, "$SERVER", SERVERNAME); + notice(source, buffer); + linecount++; + } + + if (linecount > 0) + CheckFloodFlood(source, linecount); +} + +void showmotd(char *source) +{ + struct buffer_block *dyn = NULL; + char buffer[512]; + int fd, l; + + alarm(3); + fd = open(MOTD_FILE, O_RDONLY); + if (fd < 0) + { + notice(source, "MOTD is empty"); + return; + } + + if (CurrentSendQ > HIGHSENDQTHRESHOLD) + { + notice(source, "Cannot process your request at this time. Try again later."); + return; + } + + while ((l = read(fd, buffer, 511)) > 0) + { + copy_to_buffer(&dyn, buffer, l); + } + close(fd); + alarm(0); + + while (dyn != NULL) + { + char *ptr; + copy_from_buffer(&dyn, buffer, '\n', 199); + if ((ptr = strchr(buffer, '\n')) != NULL) + *ptr = '\0'; + else + continue; + if (*buffer == '\0') + strcpy(buffer, " "); + notice(source, buffer); + } +} + + +static void + chaninfo_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + char buffer[512]; + register adefchan *def; + time_t t; + + if (count == 1 && dbu != NULL) + { + sprintf(buffer, "%s is registered by:", (char *)hook2); + notice((char *)hook1, buffer); + } + + if (dbu == NULL) + { + if (count == 0) + { + notice((char *)hook1, "That channel is not registered"); + } + else + { + def = DefChanList; + while (def && strcasecmp(def->name, (char *)hook2)) + def = def->next; + + if (def) + { + if (*def->topic) + { + sprintf(buffer, "Desc: %s", def->topic); + notice((char *)hook1, buffer); + } + if (*def->url) + { + sprintf(buffer, "URL: %s", def->url); + notice((char *)hook1, buffer); + } + } + } + free(hook1); + free(hook2); + } + else if (dbu->access >= 500) + { + t = now - dbu->lastseen; + + sprintf(buffer, "%s (%s) last seen: %s ago", + dbu->nick, dbu->match, + time_remaining(t)); + notice((char *)hook1, buffer); + } +} + +void ShowChanInfo(char *source, char *chan, char *args) +{ + char channel[80], *hook1, *hook2; + + if (*args == '#') + GetWord(0, args, channel); + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: chaninfo "); + return; + } + + hook1 = (char *)malloc(strlen(source) + 1); + strcpy(hook1, source); + hook2 = (char *)malloc(strlen(channel) + 1); + strcpy(hook2, channel); + + db_fetch(channel, DBGETALLCMP, "", NULL, 0, hook1, hook2, chaninfo_callback); +} + + +void isreg(char *source, char *chan, char *args) +{ + char channel[80], buffer[512]; + struct stat st; + + if (*args == '#') + GetWord(0, args, channel); + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: isreg "); + return; + } + + if (stat(make_dbfname(channel), &st) < 0) + sprintf(buffer, "%s is not registered.",channel); + else + sprintf(buffer, "%s is registered.",channel); + notice(source, buffer); +} + + +#ifdef DOHTTP +void http_show_help(http_socket * hsock, char *command) +{ + char buffer[512], buffer2[200]; + struct buffer_block *dyn = NULL; + register char *ptr, *ptr2; + register int i, index = 0, found = 0; + int file, l; + + listinit(); + + /* find the command index */ + for (i = 0; i <= N; i++) + { + if (!strcasecmp(command, commands[i].name)) + { + found = 1; + index = i; + break; + } + else if (!strncasecmp(command, commands[i].name, strlen(command))) + { + found++; + index = i; + } + } + + buffer[0] = '\0'; + + sendto_http(hsock, HTTP_HEADER, command); + sendto_http(hsock, HTTP_BODY); + + sendto_http(hsock, "

HELP ON %s

\n", (*command) ? command : "COMMANDS"); + sendto_http(hsock, "
\n");
+
+  if (found > 1)
+  {
+    if (*command)
+      sendto_http(hsock, "%s is ambiguous\n", command);
+  }
+  else if (found == 0)
+  {
+    if (!strcasecmp(command, "INFO"))
+    {
+      sprintf(buffer, "%s/INFO", HELP_DIR);
+    }
+    else if (!strcasecmp(command, "FORM"))
+    {
+      sprintf(buffer, "%s/FORM", HELP_DIR);
+    }
+    else
+    {
+      sendto_http(hsock, "No help on %s.\n", command);
+    }
+  }
+  else
+  {
+    sprintf(buffer, "%s/%s", HELP_DIR, commands[index].file);
+  }
+
+  if (buffer[0] != '\0')
+  {
+    alarm(2);
+    file = open(buffer, O_RDONLY);
+    if (file < 0)
+    {
+      alarm(0);
+      if (found)
+	sendto_http(hsock, "The help file for command %s "
+	  "is not available\n", commands[index].name);
+      else
+	sendto_http(hsock, "This help file is not available\n");
+    }
+    else
+    {
+      alarm(2);
+      while ((l = read(file, buffer, 511)) > 0)
+      {
+	copy_to_buffer(&dyn, buffer, l);
+      }
+      alarm(0);
+      close(file);
+
+      while (dyn != NULL)
+      {
+	copy_from_buffer(&dyn, buffer, '\n', 199);
+	if ((ptr = strchr(buffer, '\n')) == NULL)
+	  continue;
+	if ((ptr = strstr(buffer, "$NICK")) != NULL)
+	{
+	  *ptr = '\0';
+	  sprintf(buffer2, "%s%s%s", buffer, mynick, ptr + 5);
+	  strcpy(buffer, buffer2);
+	}
+
+	/* Some nasty char quoting required.. */
+	ptr = buffer;
+	ptr2 = buffer2;
+	do
+	{
+	  if (*ptr == '<')
+	  {
+	    ptr2[0] = '&';
+	    ptr2[1] = 'l';
+	    ptr2[2] = 't';
+	    ptr2[3] = ';';
+	    ptr2 += 4;
+	  }
+	  else if (*ptr == '>')
+	  {
+	    ptr2[0] = '&';
+	    ptr2[1] = 'g';
+	    ptr2[2] = 't';
+	    ptr2[3] = ';';
+	    ptr2 += 4;
+	  }
+	  else
+	  {
+	    ptr2[0] = ptr[0];
+	    ptr2++;
+	  }
+	}
+	while (*(ptr++) != '\0');
+	sendto_http(hsock, "%s", buffer2);
+      }
+    }
+    sendto_http(hsock, "
\n"); + } + else + { /* show list of commands */ + sendto_http(hsock, "\n

List of commands:

\n"); + sendto_http(hsock, "\n"); + for (i = 0; i < N + 1; i++) + { + if (commands[i].Access <= 500) + sendto_http(hsock, "%s\n", + commands[i].name, commands[i].name); + } + sendto_http(hsock, "

\n"); + } + + sendto_http(hsock, "


%s\n", HTTP_FOOTER); + sendto_http(hsock, "\n"); + hsock->status = HTTP_ENDING; +} +#endif diff --git a/Sources/http.c b/Sources/http.c new file mode 100644 index 0000000..8ba8263 --- /dev/null +++ b/Sources/http.c @@ -0,0 +1,1427 @@ +/* @(#)$Id: http.c,v 1.31 2000/10/26 03:00:35 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +#ifdef DOHTTP +#include + +void cold_save_one(RegUser * reg); + +struct http_deny +{ + struct in_addr addr; + struct http_deny *next; +} +*HttpDeny = NULL; + +#ifdef DEBUG +static void show_list(void) +{ + register http_socket *tmp; + register http_file_pipe *fpipe; + + printf("http fd list: "); + for (tmp = HttpList; tmp != NULL; tmp = tmp->next) + { + printf("%d ", tmp->fd); + switch (tmp->status) + { + case HTTP_ERROR: + printf("(ERROR) "); + break; + case HTTP_LISTEN: + printf("(LISTEN) "); + break; + case HTTP_ACTIVE: + printf("(ACTIVE) "); + break; + case HTTP_ENDING: + printf("(ENDING) "); + break; + case HTTP_RECV_POST: + printf("(POST) "); + break; + case HTTP_PIPE: + printf("(PIPE) "); + break; + default: + printf("(----) "); + break; + } + } + printf("\nFiles: "); + + for (fpipe = FilePipes; fpipe != NULL; fpipe = fpipe->next) + { + printf("%d (FILE->%d) ", fpipe->fd, fpipe->hsock->fd); + } + printf("\n"); +} +#endif + +void http_log(char *fmt,...) +{ + char buffer[1024], date[80]; + va_list ap; + int fd; + + strcpy(date, ctime(&now)); + *strchr(date, '\n') = '\0'; + + va_start(ap, fmt); + alarm(2); + if ((fd = open(HTTP_LOG, O_WRONLY | O_CREAT | O_APPEND, 0600)) >= 0) + { + alarm(0); + sprintf(buffer, "%s: ", date); + alarm(2); + write(fd, buffer, strlen(buffer)); + alarm(0); + vsprintf(buffer, fmt, ap); + alarm(2); + write(fd, buffer, strlen(buffer)); + write(fd, "\n", 1); + alarm(0); + close(fd); + } + alarm(0); + va_end(ap); +} + + +void quote_html(char *in, char *out) +{ + do + { + if (*in == '<') + { + out[0] = '&'; + out[1] = 'l'; + out[2] = 't'; + out[3] = ';'; + out += 4; + } + else if (*in == '>') + { + out[0] = '&'; + out[1] = 'g'; + out[2] = 't'; + out[3] = ';'; + out += 4; + } + else if (*in == '&') + { + out[0] = '&'; + out[1] = 'a'; + out[2] = 'm'; + out[3] = 'p'; + out[4] = ';'; + out += 5; + } + else + { + out[0] = in[0]; + out++; + } + } + while (*(in++) != '\0'); +} + +static http_socket *new_struct(void) +{ + register http_socket *tmp; + + tmp = (http_socket *) MALLOC(sizeof(http_socket)); +#ifdef DEBUG + printf("New http_socket struct at %p\n", tmp); +#endif + tmp->next = NULL; + tmp->inbuf = NULL; + tmp->outbuf = NULL; + tmp->hook = NULL; + tmp->fd = -1; + tmp->status = -1; + tmp->dbio = 0; + tmp->TS = now; + tmp->since = now; + + return tmp; +} + +static void add_struct(http_socket * new) +{ + new->next = HttpList; + HttpList = new; +#ifdef DEBUG + show_list(); +#endif +} + +void remove_httpsock(http_socket * old) +{ + extern void chat_quit(struct http_socket *hsock); + register http_socket *tmp = HttpList; + + if (old->dbio) + return; /* can't free yet.. there are other pointers + * the that structure */ + + if (old->inbuf) + zap_buffer(&old->inbuf); + if (old->outbuf) + zap_buffer(&old->outbuf); + + if (old->hook) + free(old->hook); + + if (tmp == old) + { + HttpList = HttpList->next; + free(old); + } + else + { + while (tmp->next != old) + { + tmp = tmp->next; + if (tmp == NULL) + { + http_log("ERROR: remove_struct() tmp->next==NULL"); + return; + } + } + tmp->next = old->next; + free(old); + } +#ifdef DEBUG + show_list(); +#endif +} + +void open_http(void) +{ + register http_socket *new; + struct sockaddr_in myaddr; + int opt = 1; + + new = new_struct(); + new->fd = socket(AF_INET, SOCK_STREAM, 0); + if (new->fd < 0) + { + http_log("ERROR: open_http() socket() failed!"); + http_log("%d: %s", errno, sys_errlist[errno]); + free(new); + return; + } + +#ifdef SO_REUSEADDR + if (setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)) < 0) + { + http_log("ERROR: open_http() setsockopt() failed!"); + http_log("%d: %s", errno, sys_errlist[errno]); + close(new->fd); + free(new); + return; + } +#endif + if (fcntl(new->fd, F_SETFL, O_NONBLOCK) < 0) + { + http_log("ERROR: open_http() fcntl() failed!"); + http_log("%d: %s", errno, sys_errlist[errno]); + close(new->fd); + free(new); + return; + } + + memset(&myaddr, 0, sizeof(myaddr)); + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(HTTP_PORT); +#ifdef BINDADDR + myaddr.sin_addr.s_addr = inet_addr(BINDADDR); +#else + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); +#endif + if (bind(new->fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) + { + http_log("ERROR: open_http() bind() failed!"); + http_log("%d: %s", errno, sys_errlist[errno]); + close(new->fd); + free(new); + /*return; */ + /* Can't bind to local port.. exit! */ + exit(0); + } + + if (listen(new->fd, 10) < 0) + { + http_log("ERROR: open_http() listen() failed!"); + http_log("%d: %s", errno, sys_errlist[errno]); + close(new->fd); + free(new); + return; + } + + new->status = HTTP_LISTEN; + add_struct(new); +} + +void read_http_conf(char *source) +{ + register struct http_deny *tmp; + char buffer[80], ip[80], global[] = "*"; + FILE *fp; + + if (*source && Access(global, source) < MASTER_ACCESS) + { + ReplyNotAccess(source, global); + return; + } + + while ((tmp = HttpDeny) != NULL) + { + HttpDeny = HttpDeny->next; + free(tmp); + } + + if ((fp = fopen(HTTP_DENY, "r")) != NULL) + { + while (fgets(buffer, 79, fp) != NULL) + { + if (*buffer == '#' || *buffer == '\n' || *buffer == '\0') + continue; + sscanf(buffer, "%s\n", ip); + tmp = (struct http_deny *)MALLOC(sizeof(struct http_deny)); + tmp->addr.s_addr = inet_addr(ip); + tmp->next = HttpDeny; + HttpDeny = tmp; + } + fclose(fp); + if (*source) + notice(source, "done."); + } + else + { + if (*source) + notice(source, "Can't open file: " HTTP_DENY); + } +} + +static int check_http_deny(struct in_addr *addr) +{ + char tmp[5]; + register struct http_deny *scan = HttpDeny; + + tmp[4] = '\0'; + while (scan != NULL) + { + /* Not sure which one is faster... */ + /* tmp[0]=((char *)&(scan->addr.s_addr))[0]; */ + /* tmp[1]=((char *)&(scan->addr.s_addr))[1]; */ + /* tmp[2]=((char *)&(scan->addr.s_addr))[2]; */ + /* tmp[3]=((char *)&(scan->addr.s_addr))[3]; */ + memcpy((void *)tmp, (void *)&(scan->addr.s_addr), 4); + if (!memcmp((void *)tmp, (void *)&(addr->s_addr), strlen(tmp))) + return 1; + scan = scan->next; + } + return 0; +} + +void http_accept(int sock) +{ + register http_socket *new; + int size; + struct in_addr addr; + + new = new_struct(); + + size = sizeof(new->peer); + new->fd = accept(sock, (struct sockaddr *)&new->peer, &size); + if (size != sizeof(new->peer)) + { + http_log("WARNING: uh huh.. size changed in accept()!" + " %d != %d", size, (int)sizeof(new->peer)); + } + if (new->fd < 0) + { + http_log("ERROR: http_accept() accept() failed!"); + http_log("%d: %s", errno, sys_errlist[errno]); + free(new); + return; + } + + if (fcntl(new->fd, F_SETFL, O_NONBLOCK) < 0) + { + http_log("ERROR: open_accept() fcntl() failed!"); + http_log("%d: %s", errno, sys_errlist[errno]); + close(new->fd); + free(new); + return; + } + + new->status = HTTP_ACTIVE; + add_struct(new); + + addr.s_addr = new->peer.sin_addr.s_addr; + if (check_http_deny(&new->peer.sin_addr)) + { + http_log("Connection refused (%s)", inet_ntoa(addr)); + sendto_http(new, HTTP_HEADER, "You're banned!"); + sendto_http(new, HTTP_BODY); + sendto_http(new, "

Due to abuse from users of your site " + "(%s), connections are no longer accepted.

\n", inet_ntoa(addr)); + sendto_http(new, "
%s\n\n", HTTP_FOOTER); + new->status = HTTP_ENDING; + return; + } + + http_log("[%d] HTTP CONNECTION (%s)", new->fd, inet_ntoa(addr)); + + if (new->fd >= MAX_CONNECTIONS) + { + new->status = HTTP_ENDING; + sendto_http(new, HTTP_HEADER "\n", "Too many connections!"); + http_log("ERROR: reached MAX_CONNECTIONS!!"); + } +} + + +static void + http_userlist_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + time_t t; + int days, hours, mins, secs; + + if (dbu == NULL) + { + if (count == 0) + sendto_http((http_socket *) hook1, + "Userlist is empty on %s!

\n", mynick); + sendto_http((http_socket *) hook1, "


%s\n", HTTP_FOOTER); + sendto_http((http_socket *) hook1, "\n"); + ((http_socket *) hook1)->status = HTTP_ENDING; + ((http_socket *) hook1)->dbio = 0; + free(hook2); + } + else + { + sendto_http((http_socket *) hook1, + "USER: %s (%s) ACCESS: %d
\n", + dbu->nick, dbu->match, dbu->access); + sendto_http((http_socket *) hook1, + "CHANNEL: %s -- AUTOOP: %s
\n", + dbu->channel, + (dbu->flags & UFL_AUTOOP) ? "ON" : "OFF"); + if (dbu->suspend > now) + { + sendto_http((http_socket *) hook1, + "SUSPEND EXP: %s
\n", + time_remaining(dbu->suspend - now)); + } + t = now - dbu->lastseen; + days = (int)t / 86400; + t %= 86400; + hours = (int)t / 3600; + t %= 3600; + mins = (int)t / 60; + t %= 60; + secs = (int)t; + + if (days > 0) + sendto_http((http_socket *) hook1, + "LAST SEEN: %d days, %02d:%02d:%02d ago
\n", + days, hours, mins, secs); + else + sendto_http((http_socket *) hook1, + "LAST SEEN: %02d:%02d:%02d ago
\n", + hours, mins, secs); + if (dbu->modif[0] == '\0') + sendto_http((http_socket *) hook1, + "LAST MODIF: unknown

\n"); + else + sendto_http((http_socket *) hook1, + "LAST MODIF: %s

\n", dbu->modif); + } +} + +static void http_show_userlist(http_socket * hsock, char *channel, char *protocol) +{ + char date[80]; + struct tm *timeptr; + int *hook; + + timeptr = gmtime(&now); + sprintf(date, "%sUTC", asctime(timeptr)); + *strchr(date, '\n') = ' '; + + sendto_http(hsock, "HTTP/1.0 200 Document follows%c", 10); + sendto_http(hsock, "Date: %s%c", date, 10); + sendto_http(hsock, "Server: CS/1.0%c", 10); + sendto_http(hsock, "Content-type: text/html%c%c", 10, 10); + + sendto_http(hsock, HTTP_HEADER, "User list"); + sendto_http(hsock, HTTP_BODY); + sendto_http(hsock, "\n

User list for channel %s

\n", channel); + sendto_http(hsock, "%s

\n", date); + + if (!strcmp(channel, "*")) + { + sendto_http(hsock, "Userlist is empty on %s!

\n", mynick); + sendto_http(hsock, "


%s\n", HTTP_FOOTER); + sendto_http(hsock, "\n"); + hsock->status = HTTP_ENDING; + hsock->dbio = 0; + } + else + { + if (!strcmp(channel, "secret_admin_list")) + { + strcpy(channel, "*"); /* Enable us to see the * userlist via the web */ + } + hook = (int *)malloc(sizeof(int)); + *hook = 0; + + db_fetch(channel, DBGETALLCMP, "", NULL, 0, hsock, hook, + http_userlist_callback); + hsock->dbio = 1; + } +} + + +static void http_show_banlist(http_socket * hsock, char *channel, char *protocol) +{ + char date[80]; + register ShitUser *curr; + struct tm *timeptr; + int found = 0; + + timeptr = gmtime(&now); + sprintf(date, "%sUTC", asctime(timeptr)); + *strchr(date, '\n') = ' '; + + sendto_http(hsock, "HTTP/1.0 200 Document follows%c", 10); + sendto_http(hsock, "Date: %s%c", date, 10); + sendto_http(hsock, "Server: CS/1.0%c", 10); + sendto_http(hsock, "Content-type: text/html%c%c", 10, 10); + + sendto_http(hsock, HTTP_HEADER, "Ban list"); + sendto_http(hsock, HTTP_BODY); + sendto_http(hsock, "

Ban list for channel %s

\n", channel); + sendto_http(hsock, "%s

\n", date); + + sendto_http(hsock, HTTP_BAN_DISCLAIMER); + curr = ShitList[sl_hash(channel)]; + while (curr) + { + if (!strcasecmp(channel, curr->channel)) + { + found++; + sendto_http(hsock, "%s %s Level: %d
\n", + curr->channel, curr->match, curr->level); + sendto_http(hsock, "ADDED BY: %s (%s)
\n", curr->from, + (*curr->reason) ? curr->reason : "No reason given"); + + timeptr = gmtime(&curr->time); + sprintf(date, "%sUCT", asctime(timeptr)); + *strchr(date, '\n') = ' '; + sendto_http(hsock, "SINCE: %s
\n", date); + + sendto_http(hsock, "EXP: %s

\n", + time_remaining(curr->expiration - now)); + } + curr = curr->next; + } + + if (!found) + { + sendto_http(hsock, "Ban list is empty!

\n"); + } + + sendto_http(hsock, "


%s\n", HTTP_FOOTER); + sendto_http(hsock, "\n"); + hsock->status = HTTP_ENDING; +} + + +static void http_show_list(http_socket * hsock, char *keylist) +{ + char date[80], top[512], *tok[16]; + register adefchan *def; + int found = 0, i = 0; + struct tm *timeptr; + + timeptr = gmtime(&now); + sprintf(date, "%sUTC", asctime(timeptr)); + *strchr(date, '\n') = ' '; + + sendto_http(hsock, "HTTP/1.0 200 Document follows\n\n"); + + sendto_http(hsock, HTTP_HEADER, "Channel list"); + sendto_http(hsock, HTTP_BODY); + if (*keylist) + { + sendto_http(hsock, "

Channel search result for [%s]

\n", keylist); + } + else + { + sendto_http(hsock, "

Channel search result: Whole list

\n"); + } + sendto_http(hsock, "%s

\n", date); + + tok[0] = strtok(keylist, " "); + while (i < 15 && (tok[++i] = strtok(NULL, " ")) != NULL); + tok[i] = NULL; + + def = DefChanList; + while (def) + { + if ((!*keylist || key_match(def->name, tok) || + key_match(def->topic, tok)) && + !IsSet(def->name, 's', "") && !IsSet(def->name, 'p', "")) + { + found = 1; + quote_html(def->topic, top); + if (*def->url) + sendto_http(hsock, "%s %s
\n", + def->url, def->name, top); + else + sendto_http(hsock, "%s %s
\n", def->name, top); + } + def = def->next; + } + + if (!found) + { + sendto_http(hsock, "No match!

\n"); + } + + sendto_http(hsock, "


%s\n", HTTP_FOOTER); + hsock->status = HTTP_ENDING; +} + + +static void + http_chaninfo_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + register adefchan *def; + time_t t; + + if (count == 1 && dbu != NULL) + { + sendto_http((http_socket *) hook1, + "%s is registered by:

\n", (char *)hook2); + } + + if (dbu == NULL) + { + if (count == 0) + { + sendto_http((http_socket *) hook1, + "Channel %s is not registered", + (char *)hook2); + } + else + { + def = DefChanList; + while (def && strcasecmp((char *)hook2, def->name)) + def = def->next; + + if (def) + { + char top[512]; + quote_html(def->topic, top); + sendto_http((http_socket *) hook1, "Desc: %s
\n", top); + sendto_http((http_socket *) hook1, "URL: %s
\n", + def->url, def->url); + } + } + sendto_http((http_socket *) hook1, "


%s\n", HTTP_FOOTER); + ((http_socket *) hook1)->status = HTTP_ENDING; + ((http_socket *) hook1)->dbio = 0; + free(hook2); + } + else if (dbu->access >= 500) + { + t = now - dbu->lastseen; + + sendto_http((http_socket *) hook1, "%s (%s) last seen: %s ago
\n", + dbu->nick, dbu->match, + time_remaining(t)); + } +} + +static void http_show_chaninfo(http_socket * hsock, char *channel) +{ + char date[80], *hook; + struct tm *timeptr; + + timeptr = gmtime(&now); + sprintf(date, "%sUCT", asctime(timeptr)); + *strchr(date, '\n') = ' '; + + sendto_http(hsock, HTTP_HEADER, "Channel information"); + sendto_http(hsock, HTTP_BODY); + sendto_http(hsock, "

Channel information

\n"); + sendto_http(hsock, "%s

", date); + + hook = (char *)malloc(strlen(channel) + 1); + strcpy(hook, channel); + db_fetch(channel, DBGETALLCMP, "", NULL, 0, hsock, hook, + http_chaninfo_callback); + hsock->dbio = 1; +} + + +static void http_show_whois(http_socket * hsock, char *nick) +{ + register aluser *user; + register achannelnode *chan; + register auser *usr; + + char date[80]; + struct tm *timeptr; + + timeptr = gmtime(&now); + sprintf(date, "%sUTC", asctime(timeptr)); + *strchr(date, '\n') = ' '; + +#ifdef DEBUG + printf("HTTP WHOIS: \"%s\"\n", nick); +#endif + sendto_http(hsock, HTTP_HEADER, "WHOIS"); + sendto_http(hsock, HTTP_BODY); + sendto_http(hsock, "

WHOIS Information

\n"); + sendto_http(hsock, "%s

\n", date); + + user = ToLuser(nick); + + if (user == NULL) + { + sendto_http(hsock, "*** %s: No such nick

\n", nick); + } + else + { + sendto_http(hsock, "*** %s is (%s@%s)
\n", + user->nick, user->username, user->site); + chan = user->channel; + if (chan != NULL) + { + sendto_http(hsock, "*** on channels: "); + while (chan != NULL) + { + if (!IsSet(chan->N->name, 's', "") && + !IsSet(chan->N->name, 'p', "")) + { + usr = ToUser(chan->N->name, nick); + if (usr->chanop) + sendto_http(hsock, "@%s ", chan->N->name); + else + sendto_http(hsock, "%s ", chan->N->name); + } + chan = chan->next; + } + sendto_http(hsock, "
\n"); + } + sendto_http(hsock, "*** on irc via server %s
\n", user->server->name); + + if (user->mode & LFL_ISOPER) + { + sendto_http(hsock, "*** %s is an IRC Operator
\n", user->nick); + } + } + + sendto_http(hsock, "


%s\n", HTTP_FOOTER); + hsock->status = HTTP_ENDING; +} + + +static int get_file_pipe(http_socket * hsock, int fd) +{ + register http_file_pipe *new; + + new = (http_file_pipe *) malloc(sizeof(http_file_pipe)); + if (new == NULL) + return -1; + + new->fd = fd; + new->hsock = hsock; + new->next = FilePipes; + FilePipes = new; + + new->hsock->status = HTTP_PIPE; +#ifdef DEBUG + show_list(); +#endif + return 0; +} + +void destroy_file_pipe(http_file_pipe * old) +{ + register http_file_pipe **tmp = &FilePipes; + + while (*tmp != NULL && *tmp != old) + { + tmp = &(*tmp)->next; + } + + if (*tmp != NULL) + { + *tmp = old->next; + free(old); + } +#ifdef DEBUG + show_list(); +#endif +} + +void readfrom_file(http_file_pipe * fpipe) +{ + char buffer[2048]; + int length; + + if (fpipe->hsock->status == HTTP_ERROR) + { + close(fpipe->fd); + fpipe->fd = -1; + destroy_file_pipe(fpipe); + return; + } + + if ((length = read(fpipe->fd, buffer, 2047)) > 0) + { + copy_to_buffer(&fpipe->hsock->outbuf, buffer, length); + } + else if (length == 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) + { + fpipe->hsock->status = HTTP_ENDING; + close(fpipe->fd); + fpipe->fd = -1; + destroy_file_pipe(fpipe); + } + return; +} + + +static void http_send_file(http_socket * hsock, char *fname, char *protocol) +{ + char file[256], date[80]; + struct stat sbuf; + struct tm *timeptr; + register char *ptr; + int fd, cnt; + int tmpfd; + +#ifdef DEBUG + printf("fname= \"%s\"\n", fname); +#endif + cnt = 0; + for (ptr = fname; *ptr; ptr++) + { + if (*ptr == '.') + cnt++; + if ((!isalnum(*ptr) && !strchr("./_-", *ptr)) || cnt > 1) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + } + + sprintf(file, "HTTP/%s", fname); + if ((fd = open(file, O_RDONLY)) < 0 || fstat(fd, &sbuf) < 0 || + fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + { + hsock->status = HTTP_ERROR; + if (fd >= 0) + close(fd); + if (hsock->fd >= 0) + { + close(hsock->fd); + hsock->fd = -1; + } + return; + } + + sprintf(file, "HTTP/%s.#", fname); + if ((tmpfd = open(file, O_RDWR | O_CREAT, 0600)) >= 0) + { + char buf[80] = ""; + cnt = 0; + if (read(tmpfd, buf, 79) > 0) + { + sscanf(buf, "%d", &cnt); + lseek(tmpfd, 0L, SEEK_SET); + } + sprintf(buf, "%d\n", ++cnt); + write(tmpfd, buf, strlen(buf)); + close(tmpfd); + } + + sendto_http(hsock, "HTTP/1.0 200 Document follows%c", 10); + timeptr = gmtime(&now); + sprintf(date, "%sUTC", asctime(timeptr)); + *strchr(date, '\n') = ' '; + sendto_http(hsock, "Date: %s%c", date, 10); + sendto_http(hsock, "Server: CS/1.0%c", 10); + sendto_http(hsock, "Mime-version: 1.0%c", 10); + + if (strstr(fname, ".gif")) + { + sendto_http(hsock, "Content-type: image/gif%c", 10); + } + else if (strstr(fname, ".jpg")) + { + sendto_http(hsock, "Content-type: image/jpeg%c", 10); + } + else if (strstr(fname, ".html")) + { + sendto_http(hsock, "Content-type: text/html%c", 10); + } + else if (strstr(fname, ".txt")) + { + sendto_http(hsock, "Content-type: text/plain%c", 10); + } + else + { + sendto_http(hsock, "Content-type: */*%c", 10); + } + + timeptr = gmtime(&sbuf.st_mtime); + sprintf(date, "%sUTC", asctime(timeptr)); + *strchr(date, '\n') = ' '; + sendto_http(hsock, "Last-modified: %s%c", date, 10); + sendto_http(hsock, "Content-length: %ld\n\n", sbuf.st_size); + + if (get_file_pipe(hsock, fd) < 0) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + } +} + + +static void send_http_error(http_socket * hsock) +{ + sendto_http(hsock, HTTP_HEADER, "ERROR"); + sendto_http(hsock, HTTP_BODY); + sendto_http(hsock, "

Error in request

\n"); + sendto_http(hsock, "


%s\n", HTTP_FOOTER); +} + +static void parse_get(http_socket * hsock, char *path, char *protocol) +{ + extern void http_show_help(http_socket *, char *); + char channel[80]; + register char *ptr; + +#ifdef DEBUG + printf("GET: %s\n", path); +#endif + if (*path != '/') + { + send_http_error(hsock); + hsock->status = HTTP_ENDING; + return; + } + + if ((ptr = strchr(path + 1, '/')) == NULL) + { + ptr = path + strlen(path); + } + else + { + *(ptr++) = '\0'; + } + sprintf(channel, "#%s", ptr); + + if (!strcasecmp(path + 1, "USERLIST")) + { + http_show_userlist(hsock, channel, protocol); + } + else if (!strcasecmp(path + 1, "BANLIST")) + { + http_show_banlist(hsock, channel, protocol); + } + else if (!strcasecmp(path + 1, "CHANINFO")) + { + http_show_chaninfo(hsock, channel); + } + else if (!strcasecmp(path + 1, "LIST")) + { + http_show_list(hsock, channel); + } + else if (!strcasecmp(path + 1, "WHOIS")) + { + http_show_whois(hsock, ptr); + } + else if (!strcasecmp(path + 1, "FILES")) + { + http_send_file(hsock, ptr, protocol); + } + else if (!strcasecmp(path + 1, "HELP")) + { + http_show_help(hsock, ptr); + } + else + { +#ifdef HTTP_REDIRECT + sendto_http(hsock, "HTTP/1.0 301 Document was moved\n"); + sendto_http(hsock, "Location: " HTTP_REDIRECT "\n\n"); + sendto_http(hsock, "Document has moved\n"); + sendto_http(hsock, "

Document was moved to " + "" + HTTP_REDIRECT "

\n"); + hsock->status = HTTP_ENDING; +#else + http_send_file(hsock, "index.html", protocol); +#endif + } +} + +static int auth_raw(u_long addr) +{ + FILE *fp; + char buffer[80], *ptr; + if ((fp = fopen("raw.auth", "r")) == NULL) + return 0; + + while (fgets(buffer, 79, fp) != NULL) + { + if ((ptr = strpbrk(buffer, "\r\n")) != NULL) + *ptr = '\0'; + if (inet_addr(buffer) == addr) + { + fclose(fp); + return 1; + } + } + fclose(fp); + return 0; +} + +static void proc_raw(http_socket * hsock, char *line) +{ + register http_raw *raw = (http_raw *) hsock->hook; + register char *ptr; + unsigned long key = 0; + + if ((ptr = strpbrk(line, "\r\n")) != NULL) + *ptr = '\0'; + + if (raw == NULL) + { + if (!auth_raw(hsock->peer.sin_addr.s_addr)) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + hsock->hook = (void *)MALLOC(sizeof(http_raw)); + ((http_raw *) hsock->hook)->key = + (((unsigned long)hsock->hook % 0xFFFF) + + (((HTTPTTLSENTBYTES) & 0xFFFF) << 16)) ^ now; + sendto_http(hsock, "PING %lu\n", ((http_raw *) hsock->hook)->key); + return; + } + + if (raw->key != 0) + { + if (strncasecmp(line, "PONG ", 5)) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + + sscanf(line + 5, "%lu", &key); + if (key != raw->key) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + raw->key = 0; + } + else + { + char target[80], cmd[80]; + GetWord(0, line, cmd); + GetWord(1, line, target); + if (!strcasecmp(cmd, "ISREG")) + { + struct stat st; + if (stat(make_dbfname(target), &st) < 0) + sendto_http(hsock, "NO\n"); + else + sendto_http(hsock, "YES\n"); + } + else if (!strcasecmp(cmd, "REG")) + { + char buf[256]; + struct stat st; + RegUser *reg; + int bad = 0; + if (stat(make_dbfname(target), &st) >= 0) + bad = 1; + if (!bad) + { + reg = UserList[ul_hash(target)]; + while (reg != NULL && (strcasecmp(reg->channel, target) || reg->access == 0)) + reg = reg->next; + if (reg != NULL) + bad = 1; + } + if (bad) + { + sendto_http(hsock, "ERROR Userlist not empty\n"); + } + else + { + char tmp[80]; + reg = (RegUser *) MALLOC(sizeof(RegUser)); + memset(reg, 0, sizeof(RegUser)); + GetWord(2, line, tmp); + reg->realname = (char *)MALLOC(strlen(tmp) + 1); + strcpy(reg->realname, tmp); + GetWord(3, line, tmp); + reg->match = (char *)MALLOC(strlen(tmp) + 1); + strcpy(reg->match, tmp); + GetWord(4, line, tmp); + reg->modif = (char *)MALLOC(strlen(tmp) + 1); + strcpy(reg->modif, tmp); + reg->channel = (char *)MALLOC(strlen(target) + 1); + strcpy(reg->channel, target); + GetWord(6, line, tmp); + if (tmp && tmp[0] != '\0') + { + reg->passwd = (char *)MALLOC(strlen(tmp) + 1); + strcpy(reg->passwd, tmp); + } + else + { + reg->passwd = (char *)MALLOC(1); + reg->passwd[0] = '\0'; + } + reg->access = 500; + reg->suspend = 0; + reg->lastseen = now; + reg->flags = 0; + reg->offset = (off_t) - 1; + reg->modified = 1; + reg->next = UserList[ul_hash(target)]; + UserList[ul_hash(target)] = reg; + cold_save_one(reg); + + sendto_http(hsock, "DONE\n"); + sprintf(buf, "%s registered %s to %s", reg->modif, + reg->channel, reg->match); + broadcast(buf, 0); + } + } + hsock->status = HTTP_ENDING; + } +} + +static void parse_post(http_socket * hsock, char *line) +{ + extern void http_show_help(http_socket *, char *); + char buffer[512], tmp[10], *channel = NULL, *nick = NULL, *arg = NULL; + register char *ptr1, *ptr2; + int value; + register http_post *post; + + post = (http_post *) hsock->hook; + + if (post->count++ > 30) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + +#ifdef check_referer + if (!strncasecmp(line, "Referer: ", 9) && check_referer(line + 9)) + { + sendto_http(hsock, "HTTP/1.0 302 Check there\n" + "Location: %s\n\n", HTTP_BAD_REFERER); + hsock->status = HTTP_ENDING; + return; + } +#endif + + while ((ptr1 = strpbrk(line, "\r\n")) != NULL) + *ptr1 = '\0'; + + if (!strcasecmp(line, "Content-Type: application/x-www-form-urlencoded")) + { + post->ready = 1; + return; + } + + if (*line == '\0') + { + post->ready = 2; + return; + } + + if (post->ready != 2) + { + return; + } + +#ifdef DEBUG + printf("line= \"%s\"\n", line); +#endif + + for (ptr1 = line, ptr2 = buffer; *ptr1 && (ptr2 - buffer) < 511; ptr1++) + { + if (ptr1[0] == '%' && ptr1[1] && ptr1[2]) + { + tmp[0] = ptr1[1]; + tmp[1] = ptr1[2]; + tmp[2] = '\0'; + sscanf(tmp, "%x", &value); + *(ptr2++) = value; + ptr1 += 2; + } + else if (ptr1[0] == '&') + { + *(ptr2++) = ' '; + } + else + { + *(ptr2++) = *ptr1; + } + } + *ptr2 = '\0'; + +#ifdef DEBUG + printf("LINE= \"%s\"\n", buffer); +#endif + http_log("LINE: %s", buffer); + + if (*post->path != '/') + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + if ((ptr1 = strchr(post->path + 1, '/')) != NULL) + { + *ptr1 = '\0'; + } + + ptr1 = buffer; + if ((channel = strstr(ptr1, "CHANNEL=")) != NULL) + { + channel += 8; + if ((ptr1 = strchr(channel, ' ')) != NULL) + { + *(ptr1++) = '\0'; + } + } + if (ptr1 && (nick = strstr(ptr1, "NICK=")) != NULL) + { + nick += 5; + if ((ptr1 = strchr(nick, ' ')) != NULL) + { + *(ptr1++) = '\0'; + } + } + if (ptr1 && (arg = strstr(ptr1, "ARG=")) != NULL) + { + arg += 4; + if ((ptr1 = strchr(arg, ' ')) != NULL) + { + *(ptr1++) = '\0'; + } + } + + if (!strcasecmp(post->path + 1, "USERLIST")) + { + if (channel == NULL) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + http_show_userlist(hsock, channel, post->protocol); + } + else if (!strcasecmp(post->path + 1, "BANLIST")) + { + if (channel == NULL) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + http_show_banlist(hsock, channel, post->protocol); + } + else if (!strcasecmp(post->path + 1, "CHANINFO")) + { + if (channel == NULL) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + http_show_chaninfo(hsock, channel); + } + else if (!strcasecmp(post->path + 1, "LIST")) + { + if (channel == NULL) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + http_show_list(hsock, channel); + } + else if (!strcasecmp(post->path + 1, "WHOIS")) + { + if (nick == NULL) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + http_show_whois(hsock, nick); + } + else if (!strcasecmp(post->path + 1, "HELP")) + { + if (arg == NULL) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } + http_show_help(hsock, arg); + } + else + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + return; + } +} + + +void parse_http(http_socket * hsock, char *buf) +{ + extern void parse_chat(struct http_socket *, char *); + extern void chat_login(struct http_socket *, char *, char *); + char method[80], path[80], protocol[80], *ptr; + +#ifdef DEBUG + printf("#IN# %s\n", buf); +#endif + if (hsock->status == HTTP_RECV_POST) + { + parse_post(hsock, buf); + return; + } + if (hsock->status == HTTP_CSRAW) + { + proc_raw(hsock, buf); + return; + } + if (hsock->status == HTTP_CHAT) + { + parse_chat(hsock, buf); + return; + } + + if ((ptr = strpbrk(buf, "\r\n")) != NULL) + *ptr = '\0'; + + GetWord(0, buf, method); + GetWord(1, buf, path); + GetWord(2, buf, protocol); + if (*protocol == '\0') + strcpy(protocol, "HTTP/1.0"); + + http_log("[%d] %s %s %s", hsock->fd, method, path, protocol); + + if (!strcasecmp(method, "GET")) + { + parse_get(hsock, path, protocol); + } + else if (!strcasecmp(method, "POST")) + { + hsock->status = HTTP_RECV_POST; + hsock->hook = (void *)MALLOC(sizeof(http_post)); + strcpy(((http_post *) hsock->hook)->path, path); + strcpy(((http_post *) hsock->hook)->protocol, protocol); + ((http_post *) hsock->hook)->count = 0; + ((http_post *) hsock->hook)->ready = 0; + } + else if (!strcasecmp(method, "CSRAW")) + { + hsock->status = HTTP_CSRAW; + proc_raw(hsock, buf + 6); + } + else if (!strcasecmp(method, "CHAT")) + { + if ((ptr = strchr(path, '/')) == NULL) + { + hsock->status = HTTP_ERROR; + close(hsock->fd); + hsock->fd = -1; + } + else + { + *(ptr++) = '\0'; + hsock->status = HTTP_CHAT; + chat_login(hsock, path, ptr); + } + } +/* + else{ + hsock->status=HTTP_ERROR; + close(hsock->fd); + hsock->fd=-1; + } + */ +} + +#endif diff --git a/Sources/ignore.c b/Sources/ignore.c new file mode 100644 index 0000000..3b7d21c --- /dev/null +++ b/Sources/ignore.c @@ -0,0 +1,572 @@ +/* @(#)$Id: ignore.c,v 1.19 2000/10/24 16:04:24 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +typedef struct aprivmsg +{ + char user[200]; + time_t time; + int length; + struct aprivmsg *next; +} +aprivmsg; + +typedef struct aignore +{ + char mask[200]; + time_t time; + struct aignore *next; +} +aignore; + + +static aprivmsg *MessageList = NULL; +static aprivmsg *FloodList = NULL; +static aprivmsg *AddUserFloodList = NULL; +static aignore *IgnoreList = NULL; + +void add_silence(char *, char *); +void rem_silence(char *); + +int CheckPrivateFlood(char *source, int length, char *type) +{ + char buffer[200]; + char userhost[200]; + char global[] = "*"; + register aluser *user; + register aprivmsg *msg, *prev; + register int count, size; + + if ((user = ToLuser(source)) == NULL) + { + sprintf(buffer, "ERROR! CheckPrivateFlood(): %s not found", source); + log(buffer); + return 1; + } + + /* Don't check flood from admins */ + if (IsValid(user, global) && Access(global, source) >= 1) + return 0; + + if (!strcasecmp(user->username, DEFAULT_USERNAME) && + !strcasecmp(user->site, DEFAULT_HOSTNAME)) + { + return 0; + } + + /* clean messages older than 30 seconds */ + prev = NULL; + msg = MessageList; + while (msg != NULL) + { + if (msg->time < (now - 30)) + { + if (prev) + { + prev->next = msg->next; + TTLALLOCMEM -= sizeof(aprivmsg); + free(msg); + msg = prev->next; + } + else + { + MessageList = msg->next; + TTLALLOCMEM -= sizeof(aprivmsg); + free(msg); + msg = MessageList; + } + } + else + { + prev = msg; + msg = msg->next; + } + } + + /* now add the current message in the list */ + sprintf(userhost, "%s@%s", user->username, user->site); + msg = (aprivmsg *) MALLOC(sizeof(aprivmsg)); + strcpy(msg->user, userhost); + msg->time = now; + msg->length = length; + msg->next = MessageList; + MessageList = msg; + + /* count how many messages were received from that user + * and also how many bytes + */ + count = size = 0; + for (msg = MessageList; msg != NULL; msg = msg->next) + { + if (compare(userhost, msg->user)) + { + count++; + size += msg->length; + } + } + + if (count >= PRIVATE_FLOOD_RATE || size >= PRIVATE_FLOOD_SIZE) + { +#ifdef DEBUG + printf("FLOODED by %s!%s\n", user->nick, userhost); +#endif + if (!IsIgnored(source)) + { + sprintf(buffer, "%sFLOOD from %s!%s", type, user->nick, userhost); + log(buffer); + + sprintf(buffer, "%sFLOOD from %s!%s (%s)", type, + user->nick, userhost, user->server->name); + broadcast(buffer, 1); + } + MakeBanMask(user, buffer); + AddIgnore(source, buffer, IGNORE_TIME); + return 1; + } + + return 0; +} + +void AddIgnore(char *source, char *mask, int t) +{ + char buffer[200]; + char *site; + aignore *curr; + int count; + + if (IsIgnored(source)) + return; + + /* count number of ignores from the same site */ + site = strchr(mask, '@') + 1; + count = 0; + curr = IgnoreList; + while (curr) + { + if (!mycasecmp(strchr(curr->mask, '@') + 1, site)) + count++; + curr = curr->next; + } + + /* add the entry in the list */ + curr = (aignore *) MALLOC(sizeof(aignore)); + curr->time = now + t; + curr->next = IgnoreList; + IgnoreList = curr; + strcpy(curr->mask, mask); + + add_silence(source, curr->mask); + notice(source, "I don't like being flooded! " + "I will ignore you from now on."); + + /* schedule ignore removal */ + AddEvent(EVENT_CLEAN_IGNORES, curr->time, ""); + + /* If there are already too many ignores from this site + * ignore the whole site + */ + if (count >= (MAX_IGNORE_PER_SITE - 1)) + { + curr = (aignore *) MALLOC(sizeof(aignore)); + curr->time = now + 300; + curr->next = IgnoreList; + IgnoreList = curr; + +#ifdef DEBUG + printf("TOO MANY IGNORES FROM THE SAME SITE\n"); +#endif + log("Too many ignores.. ignoring the whole site"); + sprintf(curr->mask, "*!*@%s", site); + sprintf(buffer, "Ignoring the whole site! (%s)", site); + broadcast(buffer, 1); + add_silence(source, curr->mask); + AddEvent(EVENT_CLEAN_IGNORES, curr->time, ""); + } +} + +void CleanIgnores(void) +{ + char buffer[200]; + aignore *curr, *prev; + + prev = NULL; + curr = IgnoreList; + while (curr != NULL) + { + if (curr->time <= now) + { + sprintf(buffer, "Removing ignore for %s", curr->mask); + log(buffer); + rem_silence(curr->mask); + if (prev != NULL) + { + prev->next = curr->next; + TTLALLOCMEM -= sizeof(aignore); + free(curr); + curr = prev->next; + } + else + { + IgnoreList = curr->next; + TTLALLOCMEM -= sizeof(aignore); + free(curr); + curr = IgnoreList; + } + } + else + { + prev = curr; + curr = curr->next; + } + } +} + +int IsIgnored(char *nick) +{ + char userhost[200]; + register aignore *curr; + register aluser *user; + register int found = 0; + + if ((user = ToLuser(nick)) == NULL) + { + return 1; + } + + sprintf(userhost, "%s!%s@%s", user->nick, user->username, user->site); + + curr = IgnoreList; + while (curr != NULL && !found) + { + if (compare(userhost, curr->mask)) + { + add_silence(nick, curr->mask); + found++; + } + curr = curr->next; + } + + return (found); +} + +void ShowIgnoreList(char *source, char *channel, char *args) +{ + char buffer[200]; + aignore *curr = IgnoreList; + time_t m; + + if (curr == NULL) + { + notice(source, "Ignore list is empty"); + } + else + { + notice(source, "Ignore list:"); + while (curr != NULL) + { + m = (curr->time - now) / 60 + 1; + sprintf(buffer, "%s for %ld minute%s", + curr->mask, m, (m > 1) ? "s" : ""); + notice(source, buffer); + curr = curr->next; + } + } +} + +void add_silence(char *nick, char *mask) +{ + char buffer[200]; + + sprintf(buffer, ":%s SILENCE %s :%s\n", mynick, nick, mask); + sendtoserv(buffer); +#ifdef FAKE_UWORLD + if (Uworld_status == 1) + { + sprintf(buffer, ":%s SILENCE %s :%s\n", UFAKE_NICK, nick, mask); + sendtoserv(buffer); + } +#endif +} + +void rem_silence(char *mask) +{ + char buffer[200]; + + sprintf(buffer, ":%s SILENCE * -%s\n", mynick, mask); + sendtoserv(buffer); +#ifdef FAKE_UWORLD + if (Uworld_status == 1) + { + sprintf(buffer, ":%s SILENCE * -%s\n", UFAKE_NICK, mask); + sendtoserv(buffer); + } +#endif +} + + +int CheckFloodFlood(char *source, int length) +{ + char buffer[200]; + char userhost[200]; + char global[] = "*"; + register aluser *user; + register aprivmsg *msg, *prev; + register int count, size; + + if ((user = ToLuser(source)) == NULL) + { + sprintf(buffer, "ERROR! CheckFloodFlood(): %s not found", source); + log(buffer); + return 1; + } + + /* Don't check flood from admins */ + if (IsValid(user, global) && Access(global, source) >= 1) + return 0; + + if (!strcasecmp(user->username, DEFAULT_USERNAME) && + !strcasecmp(user->site, DEFAULT_HOSTNAME)) + { + return 0; + } + + /* clean messages older than 30 seconds */ + prev = NULL; + msg = FloodList; + while (msg != NULL) + { + if (msg->time < (now - 30)) + { + if (prev) + { + prev->next = msg->next; + TTLALLOCMEM -= sizeof(aprivmsg); + free(msg); + msg = prev->next; + } + else + { + FloodList = msg->next; + TTLALLOCMEM -= sizeof(aprivmsg); + free(msg); + msg = FloodList; + } + } + else + { + prev = msg; + msg = msg->next; + } + } + + /* now add the current message in the list */ + sprintf(userhost, "%s@%s", user->username, user->site); + msg = (aprivmsg *) MALLOC(sizeof(aprivmsg)); + strcpy(msg->user, userhost); + msg->time = now; + msg->length = length; + msg->next = FloodList; + FloodList = msg; + + /* count how many messages were received from that user + * and also how many bytes + */ + count = size = 0; + for (msg = FloodList; msg != NULL; msg = msg->next) + { + if (compare(userhost, msg->user)) + { + count++; + size += msg->length; + } + } + + if (count >= FLOOD_FLOOD_RATE || size >= FLOOD_FLOOD_SIZE) + { + if (!IsIgnored(source)) + { + sprintf(buffer, "OUTPUT-FLOOD from %s!%s", user->nick, userhost); + log(buffer); + + sprintf(buffer, "OUTPUT-FLOOD from %s!%s (%s)", + user->nick, userhost, user->server->name); + broadcast(buffer, 1); + } + MakeBanMask(user, buffer); + AddIgnore(source, buffer, FLOOD_FLOOD_IGNORE); + return 1; + } + return 0; +} + + +int CheckAdduserFlood(char *source, char *channel) +{ + char buffer[200]; + char userhost[200]; + char global[] = "*"; + register aluser *user; + register aprivmsg *msg, *prev; + register int count; + + if ((user = ToLuser(source)) == NULL) + { + sprintf(buffer, "ERROR! CheckAdduserFlood(): %s not found", source); + log(buffer); + return 1; + } + + /* Don't check flood from admins */ + if (IsValid(user, global) && Access(global, source) >= 1) + return 0; + + if (!strcasecmp(user->username, DEFAULT_USERNAME) && + !strcasecmp(user->site, DEFAULT_HOSTNAME)) + { + return 0; + } + + /* clean messages older than 1 hour */ + prev = NULL; + msg = AddUserFloodList; + while (msg != NULL) + { + if (msg->time < (now - 3600)) + { + if (prev) + { + prev->next = msg->next; + TTLALLOCMEM -= sizeof(aprivmsg); + free(msg); + msg = prev->next; + } + else + { + AddUserFloodList = msg->next; + TTLALLOCMEM -= sizeof(aprivmsg); + free(msg); + msg = AddUserFloodList; + } + } + else + { + prev = msg; + msg = msg->next; + } + } + + sprintf(userhost, "%s@%s", user->username, user->site); + + /* now add the current message in the list */ + msg = (aprivmsg *) MALLOC(sizeof(aprivmsg)); + strcpy(msg->user, channel); + msg->time = now; + msg->length = 0; + msg->next = AddUserFloodList; + AddUserFloodList = msg; + + /* count how many messages were received from that user + * and also how many bytes + */ + count = 0; + for (msg = AddUserFloodList; msg != NULL; msg = msg->next) + { + if (!strcmp(channel, msg->user)) + { + count++; + } + } + + if (count >= 20) + { + if (!IsIgnored(source)) + { + sprintf(buffer, "ADDUSER-FLOOD from %s!%s [%s]", user->nick, userhost, channel); + log(buffer); + + sprintf(buffer, "ADDUSER-FLOOD from %s!%s [%s] (%s)", + user->nick, userhost, channel, user->server->name); + broadcast(buffer, 1); + } + MakeBanMask(user, buffer); + AddIgnore(source, buffer, 120); + return 1; + } + return 0; +} + + +void AdminRemoveIgnore(char *source, char *ch, char *args) +{ + char mask[200], global[] = "*"; + char buffer[200]; + aignore **curr, *tmp; + int change = 0; + + if (Access(global, source) < XADMIN_LEVEL) + { + ReplyNotAccess(source, global); + return; + } + + GetWord(0, args, mask); + + if (!*mask) + { + notice(source, "SYNTAX: remignore "); + return; + } + + curr = &IgnoreList; + while (*curr != NULL) + { + if (!strcasecmp((*curr)->mask, mask) || !strcasecmp(mask, "all")) + { + change = 1; + sprintf(buffer, "removed %s", (*curr)->mask); + notice(source, buffer); + log(buffer); + rem_silence((*curr)->mask); + + tmp = *curr; + *curr = tmp->next; + + free(tmp); + TTLALLOCMEM -= sizeof(aignore); + } + else + { + curr = &(*curr)->next; + } + } + + if (change) + { + sprintf(buffer, "%s removed ignore for [%s]", source, mask); + broadcast(buffer, 1); + } +} diff --git a/Sources/kicks.c b/Sources/kicks.c new file mode 100644 index 0000000..e32f59d --- /dev/null +++ b/Sources/kicks.c @@ -0,0 +1,148 @@ +/* @(#)$Id: kicks.c,v 1.5 1997/07/18 07:55:04 cvs Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +void kick(char *source,char *chanarg,char *args) +{ + char buffer[500]; + char nick[80]; + char channel[80]; + char *comment; + int found=0; + achannel *chan; + auser *user; + + if(*args=='#'){ + GetWord(0,args,channel); + GetWord(1,args,nick); + comment=ToWord(2,args); + }else{ + GetWord(0,args,nick); + comment=ToWord(1,args); + strcpy(channel,chanarg); + GuessChannel(source,channel); + } + + if(strlen(comment)>200) + comment[200]='\0'; + + if(!strcmp(channel,"*") || !*nick){ + notice(source,"SYNTAX: kick [#channel] [reason]"); + return; + } + + chan=ToChannel(channel); + if(!chan||!chan->on){ + if(*source) + notice(source,replies[RPL_NOTONCHANNEL][L_DEFAULT]); + return; + } + + if(*source && (chan->flags&CFL_OPONLY)){ + notice(source,replies[RPL_OPONLY][chan->lang]); + return; + } + + if(!chan->AmChanOp){ + if(*source) + notice(source,replies[RPL_NOTCHANOP][chan->lang]); + return; + } + + /* check whether there are wildcards or not. + * if there are wildcards, it's a masskick and nick is a match pattern + * otherwise, it's an ordinary kick and nick is the nick to kick + */ + if(!strpbrk(nick,"*?")){ +#ifdef DEBUG + printf("KICK REQUEST (NO WILDCARDS)\nSOURCE %s\nCHANNEL %s\nTARGET %s\n", + source,channel,nick); +#endif + if(*source&&Access(channel,source)users; + while(user){ + sprintf(buffer,"%s!%s@%s",user->N->nick,user->N->username,user->N->site); + if(match(buffer,nick)&&(!*source||strcasecmp(user->N->nick,source))){ + if(*comment){ + if(*source) + sprintf(buffer,":%s KICK %s %s :(%s) %s\n",mynick,channel,user->N->nick,source,comment); + else + sprintf(buffer,":%s KICK %s %s :%s\n",mynick,channel,user->N->nick,comment); + }else{ + if(*source) + sprintf(buffer,":%s KICK %s %s :From %s\n", + mynick,channel,user->N->nick,source); + else + sprintf(buffer,":%s KICK %s %s :%s\n", + mynick,channel,user->N->nick,mynick); + } + sendtoserv(buffer); + sprintf(buffer,"I KICK %s OFF %s",user->N->nick,channel); + log(buffer); + found=1; + } + user=user->next; + } + if(*source && !found) + notice(source,replies[RPL_NOMATCH][chan->lang]); + } +} diff --git a/Sources/lang.h b/Sources/lang.h new file mode 100644 index 0000000..27fa496 --- /dev/null +++ b/Sources/lang.h @@ -0,0 +1,35 @@ +/* @(#)$Id: lang.h,v 1.5 1999/01/09 16:51:31 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#define NO_LANG 5 + +#define L_ENGLISH 0 +#define L_DUTCH 1 +#define L_FRENCH 2 +#define L_SPANISH 3 +#define L_GERMAN 4 + +#define L_DEFAULT L_ENGLISH diff --git a/Sources/list.c b/Sources/list.c new file mode 100644 index 0000000..05f58dd --- /dev/null +++ b/Sources/list.c @@ -0,0 +1,122 @@ +/* @(#)$Id: list.c,v 1.3 1996/11/13 00:40:43 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include +#include +#include +#include +#include +#include +#include "defines.h" +#include "struct.h" +#include "version.h" +#include "../config.h" + +typedef struct DiskUser { + char realname[80]; + char match[80]; + int Access; + char passwd[20]; + char channel[80]; + unsigned long flags; + char reserved[20]; + time_t suspend; + time_t lastseen; +} DiskUser; + +void main(void) +{ + FILE *in1,*in2; + FILE *out; + char *ptr; + adefchan channel; + DiskUser user; + time_t currtime; + + + if(chdir(HOMEDIR)<0){ + perror(HOMEDIR); + exit(1); + } + + out=fopen("Registered_Channels","w"); + if(out==NULL){ + fclose(in1); + perror("Registered_Channels"); + exit(1); + } + + currtime=time(NULL); + + fprintf(out, + "%s\n" + "(c) 1995,1996 by Robin Thellend \n" + "\n" + "This is the list of currently registered channels on Undernet.\n" + "Note that secret and private channels are NOT showed here.\n" + "This file is updated every hour.\n" + "\n" + "Last update: %s" + "Montreal's local time is used.\n\n", + VERSION,ctime(&currtime)); + + in1=fopen(DEFAULT_CHANNELS_FILE,"r"); + if(in1==NULL){ + fprintf(out,"There are no registered channels\n"); + return; + } + + while(fread(&channel,sizeof(adefchan),1,in1)>0){ + ptr=strchr(channel.mode,' '); + if(ptr!=NULL) + *ptr='\0'; + + /* don't show secret or private channel */ + if(strpbrk(channel.mode,"sp")) + continue; + + fprintf(out,"%s Created: %s",channel.name,ctime(&channel.TS)); + + in2=fopen(USERFILE,"r"); + if(in2==NULL){ + fprintf(out,"Can't open \"%s\"\n",USERFILE); + }else{ + while(fread(&user,sizeof(DiskUser),1,in2)>0){ + if(!strcasecmp(user.channel,channel.name)&& + user.Access>=SET_DEFAULT_LEVEL){ + fprintf(out," %s %s Last seen: %s", + user.realname,user.match, + ctime(&user.lastseen)); + } + } + fclose(in2); + } + fprintf(out,"\n"); + } + + fclose(in1); + fclose(out); +} diff --git a/Sources/listall.c b/Sources/listall.c new file mode 100644 index 0000000..61cf05e --- /dev/null +++ b/Sources/listall.c @@ -0,0 +1,79 @@ +/* @(#)$Id: listall.c,v 1.3 1996/11/13 00:40:43 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include +#include +#include +#include +#include +#include "defines.h" +#include "struct.h" +#include "version.h" +#include "../config.h" + +typedef struct DiskUser { + char realname[80]; + char match[80]; + char passwd[20]; + char channel[80]; + char modif[80]; + int Access; + unsigned long flags; + time_t suspend; + time_t lastseen; +} DiskUser; + +void main(void) +{ + FILE *in1,*in2; + FILE *out; + char *ptr; + adefchan channel; + DiskUser user; + time_t currtime; + + + if(chdir(HOMEDIR)<0){ + perror(HOMEDIR); + exit(1); + } + + out=stdout; + + currtime=time(NULL); + + in2=fopen(USERFILE,"r"); + while(fread(&user,sizeof(DiskUser),1,in2)>0){ + for(ptr=user.channel;*ptr;ptr++) + *ptr=tolower(*ptr); + fprintf(out,"[%s] %s %s (%d) Last modif: %s, Last seen: %s", + user.channel, + user.realname,user.match,user.Access, + user.modif,ctime(&user.lastseen)); + } + fclose(in2); + fclose(out); +} diff --git a/Sources/main.c b/Sources/main.c new file mode 100644 index 0000000..2551c6e --- /dev/null +++ b/Sources/main.c @@ -0,0 +1,1002 @@ +/* @(#)$Id: main.c,v 1.21 2000/04/25 00:04:27 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#define MAIN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../config.h" +#include "debug.h" +#include "defines.h" +#include "struct.h" +#include "lang.h" +#include "prototypes.h" +#include "events.h" +#include "flags.h" +#include "version.h" +#ifdef DEBUG +#include +#endif + +#ifndef SIGCLD +#define SIGCLD SIGCHLD +#endif +#if !defined(__FreeBSD__) +extern int errno; +#endif +char mynick[NICK_LENGTH] = DEFAULT_NICKNAME; +char myuser[USERNAME_LENGTH] = DEFAULT_USERNAME; +char mysite[SITE_LENGTH] = DEFAULT_HOSTNAME; +char myrealname[REALNAME_LENGTH] = DEFAULT_REALNAME; +char *TmpPtr; +int logfile; +time_t now; +time_t logTS = 0; +time_t TSoffset = 0; +time_t TSonline; +time_t TSconnect; +unsigned long long TTLREADBYTES = 0; +unsigned long long TTLSENTBYTES = 0; +unsigned long TTLALLOCMEM = 0; +unsigned long long HTTPTTLSENTBYTES = 0; +long CurrentSendQ = 0; + +char server[SERVER_NAME_LENGTH] = DEFAULT_SERVER; + +RegUser *UserList[1000]; +ShitUser *ShitList[1000]; +aluser *Lusers[1000]; +achannel *ChannelList[1000]; +adefchan *DefChanList = NULL; +anevent *EventList = NULL; +aserver *ServerList = NULL; +aserver VirtualServer; +dbquery *DBQuery = NULL; +dbsync *DBSync = NULL; +syncchan *SyncChan = NULL; +#ifdef DOHTTP +http_socket *HttpList = NULL; +http_file_pipe *FilePipes = NULL; +#endif +misc_socket *MiscList = NULL; +irc_socket Irc = +{-1, 0, NULL, NULL, NULL}; +unsigned long MEM_buffers = 0; +unsigned long NB_avail_buffer_blocks = 0; +unsigned long NB_alloc_buffer_blocks = 0; + +static int Data_files_loaded = 0; + +int DB_Save_Status = -1; +char DB_Save_Nick[NICK_LENGTH] = ""; + +const unsigned int glob_cksum1 = BINCKSUM1; +const unsigned int glob_cksum2 = 0; + +#ifdef FAKE_UWORLD +int Uworld_status = 0; +time_t UworldTS, UworldServTS; +#endif + +#ifdef NICKSERV +int NServ_status = 1; +#endif + +void rec_sigpipe(int sig) +{ + quit("ERROR: Received SIGPIPE :(", 1); +} + +void rec_sigsegv(int sig) +{ + quit("ERROR: Received SIGSEGV :(", 1); +} + +void rec_sigbus(int sig) +{ + quit("ERROR: Received SIGBUS :(", 1); +} + +void rec_sigterm(int sig) +{ + quit("Oops! I'll be right back...", 0); +} + +void rec_sigint(int sig) +{ + restart("Received SIGINT.. that probably meant " + "\"restart you stupid bot!\" ;)"); +} + +void rec_sigusr(int sig) +{ + /*fflush(logfile); */ + signal(SIGUSR1, rec_sigusr); +} + +void regist(void) +{ + char buffer[256]; + time_t t; + + t = time(NULL); + + /* First clean memory */ + /*QuitAll(); */ + + /* Then send reg stuff to server.. */ + sprintf(buffer, "PASS %s\nSERVER %s 1 %ld %ld J09 :%s\n", + PASSWORD, SERVERNAME, t, t, SERVERINFO); + sendtoserv(buffer); +} + +void signon(void) +{ + char buffer[256]; + + sprintf(buffer, ":%s KILL %s :%s (Clean up kill)\n", SERVERNAME, mynick, SERVERNAME); + sendtoserv(buffer); + /* The original left out the duplicate server name; u2.10 requires it to be there if the server is using P09 */ + sprintf(buffer, ":%s NICK %s 1 %ld %s %s %s :%s\n", SERVERNAME, mynick, logTS, myuser, mysite, SERVERNAME, myrealname); + sendtoserv(buffer); + sprintf(buffer, ":%s MODE %s %s\n", mynick, mynick, UMODE); + sendtoserv(buffer); +#ifdef BACKUP + /* see above */ + sprintf(buffer, ":%s NICK %s 1 %ld %s %s %s %s\n", SERVERNAME, MAIN_NICK, logTS - 1000, myuser, mysite, SERVERNAME, MAIN_REALNAME); + sendtoserv(buffer); + sprintf(buffer, ":%s AWAY :Temporarily down.. please use %s\n", MAIN_NICK, mynick); + sendtoserv(buffer); +#endif +#ifdef FAKE_UWORLD + if (Uworld_status == 1) + IntroduceUworld(); +#endif +#ifdef NICKSERV + if (NServ_status == 1) + IntroduceNickserv(); +#endif + /* + sprintf(buffer,":%s USER %s %s %s :%s\n",mynick,myuser,mysite,SERVERNAME,myrealname); + sendtoserv(buffer); + */ +} + +#ifdef FAKE_UWORLD +void IntroduceUworld(void) +{ + char buffer[500]; + UworldServTS = now; + UworldTS = logTS; /* force nick collision */ + sprintf(buffer, ":%s SERVER %s 2 0 %ld P09 :%s\n" + ":%s NICK %s 2 %ld %s %s %s :%s\n", + SERVERNAME, UFAKE_SERVER, UworldServTS, UFAKE_INFO, + SERVERNAME, UFAKE_NICK, UworldTS, UFAKE_NICK, UFAKE_HOST, SERVERNAME, UFAKE_INFO); + sendtoserv(buffer); +} + +void KillUworld(char *msg) +{ + char buffer[500]; + sprintf(buffer, ":%s QUIT :%s\n" + ":%s SQUIT %s %ld :%s\n", + UFAKE_NICK, msg, + UFAKE_SERVER, UFAKE_SERVER, UworldServTS, msg); + sendtoserv(buffer); +} +#endif + +#ifdef NICKSERV +void IntroduceNickserv(void) +{ + char buffer[500]; + sprintf(buffer, ":%s NICK %s 1 %ld %s %s %s :%s\n", + SERVERNAME, NSERV_NICK, logTS, NSERV_USER, NSERV_HOST, + SERVERNAME, NSERV_INFO); + sendtoserv(buffer); + sprintf(buffer, ":%s MODE %s +kd\r\n", NSERV_NICK, NSERV_NICK); + sendtoserv(buffer); + NServ_status = 1; +} + +void KillNickserv(char *msg) +{ + char buffer[500]; + sprintf(buffer, ":%s QUIT :%s\r\n", NSERV_NICK, msg); + sendtoserv(buffer); + NServ_status = 0; +} +#endif + +int reconnect(char *server) +{ +#ifdef BACKUP + quit("DISCONNECTED", 0); + /* not reached */ +#else + close(Irc.fd); + Irc.fd = -1; +#ifdef DEBUG + printf("Lost connection... sleeping 5 seconds...\n"); +#endif + log("Lost connection somehow.. trying to reconnect in 5 seconds"); + sleep(5); + QuitAll(); + if (!connection(server)) + { + regist(); + signon(); + SendBurst(); + return 0; + } + else + return 1; +#endif +} + +void try_later(char *server) +{ +#ifdef BACKUP + quit("DISCONNECTED", 0); +#else + close(Irc.fd); + QuitAll(); + do + { + Irc.fd = -1; + log("Oh well.. let's try again in one minute"); +#ifdef DEBUG + printf("Unable to keep the connection... sleeping 60 seconds...\n"); +#endif + sleep(60); + } + while (connection(server)); + regist(); + signon(); + SendBurst(); +#endif +} + + +void dumpcore(char *source) +{ + int file; + pid_t pid; + char global[] = "*"; + + if (*source && Access(global, source) < LEVEL_CORE) + { + notice(source, "Sorry. Your Access is a little too low for that!"); + return; + } + + pid = getpid(); + if (fork() >= 0) + { + kill(pid, SIGABRT); + } + + /* rewrite the pid file after the fork() + */ + alarm(2); + file = open(PIDFILE, O_WRONLY | O_CREAT | O_TRUNC, 0600); + alarm(0); + if (file >= 0) + { + char buf[32]; + sprintf(buf, "%ld\n", (long)getpid()); + alarm(2); + write(file, buf, strlen(buf)); + alarm(0); + close(file); + } + + log("Core dumped"); + + if (*source) + { + notice(source, "Core dumped"); + } +} + +#ifdef RUSAGE_SELF +void show_rusage(char *source) +{ + char buffer[512], global[] = "*"; + struct rusage usage; + + if (Access(global, source) < RUSAGE_ACCESS) + { + notice(source, "This command is not for you!"); + return; + } + + getrusage(RUSAGE_SELF, &usage); + sprintf(buffer, "utime: %ld.%06lds stime: %ld.%06lds", + (long)usage.ru_utime.tv_sec, (long)usage.ru_utime.tv_usec, + (long)usage.ru_stime.tv_sec, (long)usage.ru_stime.tv_usec); + notice(source, buffer); + sprintf(buffer, "maxrss: %ld ixrss %ld idrss: %ld isrss: %ld", + (long)usage.ru_maxrss, (long)usage.ru_ixrss, (long)usage.ru_isrss, + (long)usage.ru_isrss); + notice(source, buffer); + sprintf(buffer, "minflt: %ld majflt: %ld nswap: %ld", + (long)usage.ru_minflt, (long)usage.ru_majflt, (long)usage.ru_nswap); + notice(source, buffer); + sprintf(buffer, "inblock: %ld oublock: %ld msgsnd: %ld msgrcv: %ld", + (long)usage.ru_inblock, (long)usage.ru_oublock, (long)usage.ru_msgsnd, + (long)usage.ru_msgrcv); + notice(source, buffer); + sprintf(buffer, "nsignals: %ld nvcsw: %ld nivcsw: %ld", + (long)usage.ru_nsignals, (long)usage.ru_nvcsw, (long)usage.ru_nivcsw); + notice(source, buffer); +} +#endif + +int quit(char *msg, int flag) +{ + char buffer[200]; +#ifdef HISTORY + History(NULL); +#endif + + if (Data_files_loaded) + { + /*SaveUserList("",NULL); */ + do_cold_sync(); /* save userlist */ + SaveShitList("", NULL); + SaveDefs(""); +#ifdef NICKSERV + nserv_save(); +#endif + sync(); + } + + if (!msg || !*msg) + sprintf(buffer, ":%s QUIT :%s\n" + ":%s SQUIT %s 0 :die request\n", + mynick, mynick, SERVERNAME, SERVERNAME); + else + sprintf(buffer, ":%s QUIT :%s\n" + ":%s SQUIT %s 0 :%s\n", + mynick, msg, SERVERNAME, SERVERNAME, msg); + + if (Irc.fd >= 0) + { + sendtoserv(buffer); + dumpbuff(); + } + + sprintf(buffer, "LEAVING (%s)", msg); + log(buffer); + log("Closing log file"); + close(logfile); + +#ifdef DEBUG_MALLOC + close_debug_malloc(); +#endif + + unlink(PIDFILE); + + if (flag) + abort(); + else + exit(0); +} + +int restart(char *msg) /* added by Kev */ +{ + char buffer[200]; + int i; + + SaveUserList("", NULL); /* save necessary data... */ + SaveShitList("", NULL); + SaveDefs(""); +#ifdef NICKSERV + nserv_save(); +#endif + sync(); + + if (!msg || !*msg) /* send out QUIT/SQUIT stuff... */ + sprintf(buffer, ":%s QUIT :restarting...\n" + ":%s SQUIT %s 0 :restart request\n", + mynick, SERVERNAME, SERVERNAME); + else + sprintf(buffer, ":%s QUIT :%s\n" + ":%s SQUIT %s 0 :%s\n", + mynick, msg, SERVERNAME, SERVERNAME, msg); + + if (Irc.fd >= 0) + { /* clear buffer... */ + sendtoserv(buffer); + dumpbuff(); + } + + sprintf(buffer, "RESTARTING (%s)", msg); /* log the restart... */ + log(buffer); + switch (fork()) + { + case -1: + log("Fork error; unable to restart"); /* couldn't fork :/ */ + log("Closing log file"); /* and close the log file... */ + close(logfile); + break; + + case 0: + /* No need to write "closing log file". It's already done by parent */ + close(logfile); /* redundant, I know, but I want to know why it didn't + come back.... */ + for (i = 0; i < MAX_CONNECTIONS; i++) + close(i); /* close all fds -seks */ + sprintf(buffer, "%s/%s", HOMEDIR, EXEC_FILE); + execl(buffer, EXEC_FILE, (char *)NULL); /* and restart */ + break; + + default: + log("Closing log file"); + close(logfile); + exit(0); + } + exit(-1); +} + +void notice(char *target, char *msg) +{ +#ifdef DOHTTP + extern chat_notice(char *, char *); +#endif + char buffer[1024]; + char nick[NICK_LENGTH]; + char *ptr; + +#ifdef DOHTTP + if (*target == '+') + { + chat_notice(target, msg); + return; + } +#endif + + strncpy(nick, target, NICK_LENGTH - 1); + nick[NICK_LENGTH - 1] = '\0'; + ptr = strchr(nick, '!'); + if (ptr) + *ptr = '\0'; + + if (*nick) + { + sprintf(buffer, ":%s NOTICE %s :%s\n", mynick, nick, msg); + sendtoserv(buffer); + } +} + +void servnotice(char *target, char *msg) +{ + char buffer[1024]; + sprintf(buffer, ":%s NOTICE %s :%s\n", SERVERNAME, target, msg); + sendtoserv(buffer); +} + + +void broadcast(char *msg, int evenwallop) +{ +#ifdef DOHTTP + extern void chat_sendtoall(char *, char *); +#endif + char buffer[1024]; + achannel *chan; + + chan = ToChannel(BROADCAST_CHANNEL); + if (chan != NULL) + { + sprintf(buffer, "[%s] %s", mynick, msg); + servnotice(BROADCAST_CHANNEL, buffer); + } + else if (evenwallop) + { + sprintf(buffer, ":%s WALLOPS :%s\n", + SERVERNAME, msg); + sendtoserv(buffer); + } +#ifdef DOHTTP + sprintf(buffer, "[%s] %s", mynick, msg); + chat_sendtoall(NULL, buffer); +#endif +} + +char *ToWord(int nb, char *string) +{ + register char *ptr1 = string; + register char *ptr2; + register int i = 0; + while (i != nb) + { + if ((ptr2 = strchr(ptr1, ' ')) != NULL) + { + while (*(++ptr2) == ' '); + ptr1 = ptr2; + } + else + ptr1 = strchr(ptr1, '\0'); + i++; + } + return ptr1; +} + +void GetWord(int nb, char *string, char *output) +{ + register char *ptr1; + register char *ptr2; + register int count = 0; + + ptr1 = ToWord(nb, string); + ptr2 = output; + while (*ptr1 && *ptr1 != ' ' && count++ < 75) + *(ptr2++) = *(ptr1++); + *ptr2 = 0; +} + + +char *time_remaining(time_t t) +{ + static char s[80]; + int days, hours, mins, secs; + + days = (int)t / 86400; + t %= 86400; + hours = (int)t / 3600; + t %= 3600; + mins = (int)t / 60; + t %= 60; + secs = (int)t; + + if (days == 0) + sprintf(s, "%02d:%02d:%02d", hours, mins, secs); + else if (days == 1) + sprintf(s, "1 day, %02d:%02d:%02d", hours, mins, secs); + else + sprintf(s, "%d days, %02d:%02d:%02d", days, hours, mins, secs); + + return s; +} + +void pong(char *who) +{ + char buffer[256]; + sprintf(buffer, ":%s PONG %s\n", SERVERNAME, who); + sendtoserv(buffer); +} + +void log(char *text) +{ + static char date[80], buffer[1024]; + strcpy(date, ctime(&now)); + *strchr(date, '\n') = '\0'; + sprintf(buffer, "%s: %s\n", date, text); + alarm(3); + write(logfile, buffer, strlen(buffer)); + alarm(0); +} + +void checkpid(void) +{ + int file; + pid_t pid = 0; + char fmt[5]; + + if (sizeof(pid_t) == sizeof(long)) + strcpy(fmt, "%ld"); + else + strcpy(fmt, "%d"); + + alarm(2); + file = open(PIDFILE, O_RDONLY); + alarm(0); + if (file >= 0) + { + char buf[32]; + alarm(2); + if (read(file, buf, 31) >= 0) + { + alarm(0); + sscanf(buf, fmt, &pid); + } + else + { + alarm(0); + pid = 0; + } + close(file); + } + + if (pid == 0 || kill(pid, 0) != 0) + { + char buf[31]; + alarm(2); + file = open(PIDFILE, O_WRONLY | O_CREAT | O_TRUNC, 0600); + alarm(0); + if (file < 0) + { + perror(PIDFILE); + exit(1); + } + sprintf(buf, fmt, getpid()); + strcat(buf, "\n"); + alarm(2); + if (write(file, buf, strlen(buf)) < 0) + { + fprintf(stderr, "%s: %s\n", PIDFILE, sys_errlist[errno]); + exit(1); + } + alarm(0); + + if (close(file) < 0) + { + fprintf(stderr, "%s: %s\n", PIDFILE, sys_errlist[errno]); + exit(1); + } + } + else + { + /* the service is already running + */ + exit(0); + } +} + +void proc(char *source, char *function, char *target, char *body) +{ + if (source[0] == ':') + source++; + + if (!strcmp(function, "PING")) + { + pong(target + 1); + + } + else if (!strcmp(function, "ERROR")) + { + log(function); + log(target); + log(body); + if (reconnect(server)) + { + try_later(server); + return; + }; + + } + else if (!strcmp(function, "SQUIT")) + { + onsquit(source, target, body); + if (ServerList == NULL) + { + log("received squit from"); + log(source); + log(body); + if (reconnect(server)) + { + try_later(server); + return; + } + } + + } + else if (!strcmp(function, "SERVER")) + { + onserver(source, target, body); + + } + else if (!strcmp(function, "PRIVMSG")) + { + privmsg(source, target, body); + + } + else if (!strcmp(function, "NOTICE")) + { /* only for flood pro */ + onnotice(source, target, body); + + } + else if (!strcmp(function, "JOIN")) + { + onjoin(source, target); + + } + else if (!strcmp(function, "INVITE")) + { + oninvite(source, body + 1); + + } + else if (!strcmp(function, "PART")) + { + onpart(source, target); + + } + else if (!strcmp(function, "KILL")) + { + onkill(source, target, body); + + } + else if (!strcmp(function, "QUIT")) + { + onquit(source); + + } + else if (!strcmp(function, "KICK")) + { + onkick(source, target, body); + + } + else if (!strcmp(function, "MODE")) + { + ModeChange(source, target, body); + + } + else if (!strcmp(function, "OMODE")) + { + ModeChange(UWORLD_SERVER, target, body); + + } + else if (!strcmp(function, "NICK")) + { + onnick(source, target, body); + + } + else if (!strcmp(function, "TOPIC")) + { + ontopic(source, target, body); + + } + else if (!strcmp(function, "WHOIS")) + { + onwhois(source, body + 1); + + } + else if (!strcmp(function, "SETTIME")) + { + onsettime(source, target); + + } + else if (!strcmp(function, "VERSION")) + { + showversion(source); + } + else if (!strcmp(function, "436")) + { + if (!strcasecmp(target, mynick)) + { + NickInUse(); + } + } +} + +int main(int argc, char **argv) +{ + extern void cksum(char *, unsigned int *, unsigned int *); + extern void read_conf(char *); + int i; + unsigned int sum1, sum2; + +#if !defined(DEBUG) + int pid; +#ifdef TIOCNOTTY + int fd; +#endif +#endif +#ifdef RLIMIT_CORE + struct rlimit rlim; +#endif + char conf[256] = "./cs.conf"; + + cksum(argv[0], &sum1, &sum2); + + if (argc == 3 && !strcmp(argv[1], "-f")) + { + strncpy(conf, argv[2], 255); + conf[255] = '\0'; + } + else if (argc != 1) + { + fprintf(stderr, "usage: %s [-f config_file]\n", argv[0]); + exit(1); + } + + read_conf(conf); + + if (chdir(HOMEDIR) < 0) + { + perror(HOMEDIR); + exit(1); + } + + umask(UMASK); + + now = time(NULL); + + signal(SIGSEGV, rec_sigsegv); + signal(SIGBUS, rec_sigbus); + signal(SIGTERM, rec_sigterm); +#ifndef DEBUG + signal(SIGINT, rec_sigint); +#endif + signal(SIGCLD, SIG_IGN); + /*signal(SIGPIPE,rec_sigpipe); */ + signal(SIGPIPE, SIG_IGN); + signal(SIGUSR1, rec_sigusr); + signal(SIGALRM, SIG_IGN); + signal(SIGURG, SIG_IGN); + + /* Make sure RLIMITs are set properly */ +#ifdef RLIMIT_CORE + if (!getrlimit(RLIMIT_CORE, &rlim)) + { + rlim.rlim_cur = rlim.rlim_max; + setrlimit(RLIMIT_CORE, &rlim); + } +#endif +#ifdef RLIMIT_RSS + if (!getrlimit(RLIMIT_RSS, &rlim)) + { + rlim.rlim_cur = rlim.rlim_max; + setrlimit(RLIMIT_RSS, &rlim); + } +#elif defined(RLIMIT_VMEM) + if (!getrlimit(RLIMIT_VMEM, &rlim)) + { + rlim.rlim_cur = rlim.rlim_max; + setrlimit(RLIMIT_VMEM, &rlim); + } +#endif + +#if !defined(DEBUG) + /* if the service is not running in DEBUG mode, then + it'll go in the background */ + + switch (pid = fork()) + { + case 0: + /* this is the child part */ + /* close open streams */ + fclose(stdin); + fclose(stdout); + fclose(stderr); +#if defined(BSD) || defined(__FreeBSD__) + setpgrp(0, getpid()); +#else + setpgrp(); +#endif +#ifdef TIOCNOTTY + if ((fd = open("/dev/tty", O_RDWR)) >= 0) + { + ioctl(fd, TIOCNOTTY, NULL); + close(fd); + } +#endif + break; + case -1: + fprintf(stderr, + "\n" + "ERROR: not enough memory to fork()\n" + "exiting...\n"); + exit(1); + default: + /* fork() succeeded.. no problem */ + exit(0); + } +#endif + + /* Check if the service is already running. This MUST be + * after any possible fork() because the pid is saved to + * a file for further reference. + */ + checkpid(); + +#ifndef DEBUG + printf("%s is now running in the background [pid %ld]\n", + mynick, (long)getpid()); +#endif + + if ((logfile = open(LOGFILE, O_WRONLY | O_CREAT | O_APPEND, 0600)) < 0) + { + perror("LOGFILE"); + exit(1); + } + + log("Opening log file"); + +#ifdef DOHTTP + open_http(); + read_http_conf(""); +#endif + +#ifdef DEBUG_MALLOC + open_debug_malloc(); +#endif + + InitEvent(); + + /* init userlist & shitlist */ + for (i = 0; i < 1000; i++) + { + UserList[i] = NULL; + ShitList[i] = NULL; + } + for (i = 0; i < 1000; i++) + { + Lusers[i] = NULL; + ChannelList[i] = NULL; + } + + memset(&VirtualServer, 0, sizeof(aserver)); + VirtualServer.name = (char *)malloc(15); + strcpy(VirtualServer.name, "virtual.server"); + + LoadUserList(""); + LoadShitList(""); + LoadDefs(""); +#ifdef NICKSERV + nserv_load(); +#endif + + Data_files_loaded = 1; + + /* exit if connection failed on first attempt */ + if (connection(server)) + exit(1); + + /* OK.. connection succeeded now send signon stuff... */ + regist(); + signon(); + SendBurst(); + + TSonline = now; + + for (;;) + { + if (Irc.fd < 0 || wait_msg() < 0) + { + /* lost connection */ + try_later(server); + continue; + } + } + + return 0; +} diff --git a/Sources/make.dep b/Sources/make.dep new file mode 100644 index 0000000..e69de29 diff --git a/Sources/match.c b/Sources/match.c new file mode 100644 index 0000000..12a8a24 --- /dev/null +++ b/Sources/match.c @@ -0,0 +1,316 @@ +/* @(#)$Id: match.c,v 1.10 1999/03/06 19:15:34 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" +#include + +static int matchX(char *, char *); + +int mycasecmp(char *s1, char *s2) +{ + register unsigned char *c1 = (unsigned char *)s1, *c2 = (unsigned char *)s2; + register int d; + + while (!(d = (toupper(*c1) - toupper(*c2))) && *c1) + { + c1++; + c2++; + } + return d; +} + + +char *strcasestr(register char *s1, char *s2) +{ + register char *a, *b; + + while (*s1) + { + a = s1; + b = s2; + while (*b && *a && toupper(*a) == toupper(*b)) + { + a++; + b++; + } + if (!*b) + return s1; + s1++; + } + return NULL; +} + + +/* xmatch() returns 1 if both pat1 and pat2 can *possibly* + * match the same string. It returns 0 otherwise. + */ +int xmatch(char *pat1, char *pat2) +{ + if (!strcmp(pat1, "*") || !strcmp(pat2, "*")) + return 1; + while (*pat1 && *pat2) + { + if (*pat1 == '*' && *pat2 == '*') + return (matchX(pat1 + 1, pat2 + 1) || matchX(pat2 + 1, pat1 + 1)); + if (*pat1 == '*') + return matchX(pat1 + 1, pat2); + if (*pat2 == '*') + return matchX(pat2 + 1, pat1); + if (*pat1 == '?' || *pat2 == '?' || toupper(*pat1) == toupper(*pat2)) + { + pat1++; + pat2++; + if ((!*pat1 && !strcmp(pat2, "*")) || + (!*pat2 && !strcmp(pat1, "*"))) + return 1; + } + else + return 0; + } + if (*pat1 || *pat2) + return 0; + return 1; +} + +static int matchX(char *pat1, char *pat2) +{ + do + { + if (xmatch(pat1, pat2)) + return 1; + } + while (*pat2++); + return 0; +} + + +int match(register char *string, register char *mask) +{ + char *stack[200][2] = {{NULL, NULL}}; + register char type = 0; + register short quote, level = 0; + + while (*string) + { + quote = 0; + switch (*mask) + { + case '*': + type = '*'; + if (++level == 200) + return 0; + stack[level][0] = mask; + stack[level][1] = string; + while (*++mask == '*'); /* '*' eats any following '*' */ + break; + case '\\': + quote++; + mask++; + /* no break! */ + default: + if (toupper(*string) == toupper(*mask) || (*mask == '?' && !quote)) + { + mask++; + } + else + { + while (stack[level][0] == NULL && --level > 0); + if (level <= 0) + return 0; + mask = stack[level][0]; + string = stack[level][1]; + level--; + } + string++; + } + } + while (*mask == '*') /* Skip everything that can */ + mask++; /* match an empty string. */ + + return (*mask) ? 0 : 1; +} + + +/* compare() will return 1 if p1 and p2 can match the same + * nick!user@host. p1 and p2 are nick!user@host masks. + */ +int compare(char *p1, char *p2) +{ + char tmp1[200], tmp2[200]; + register char *s1 = tmp1, *s2 = tmp2; + register int ip1, ip2, in_uh = 0; + + do + { + ip1 = ip2 = 1; + + while (*p1 && *p1 != '!' && *p1 != '@') + { + if (ip1 && !isdigit(*p1) && *p1 != '.' && (*p1 != '*' || p1[1]) && (*p1 == '*' || s1 != tmp1)) + ip1 = 0; + *(s1++) = *(p1++); + } + if (!in_uh && *p1 == '\0') + in_uh = 1; + + while (*p2 && *p2 != '!' && *p2 != '@') + { + if (ip2 && !isdigit(*p2) && *p2 != '.' && (*p2 != '*' || p2[1]) && (*p2 == '*' || s2 != tmp2)) + ip2 = 0; + *(s2++) = *(p2++); + } + + *s2 = *s1 = '\0'; + + if (*p1 != *p2) + { + if (*p1 == '!') + { + s1 = tmp1; + if (*p1) + p1++; + while (*p1 && *p1 != '@') + { + if (ip1 && !isdigit(*p1) && *p1 != '.' && (*p1 != '*' || p1[1]) && (*p1 == '*' || s1 != tmp1)) + ip1 = 0; + *(s1++) = *(p1++); + } + if (!in_uh && *p1 == '\0') + in_uh = 1; + } + else + { + s2 = tmp2; + if (*p2) + p2++; + while (*p2 && *p2 != '@') + { + if (ip2 && !isdigit(*p2) && *p2 != '.' && (*p2 != '*' || p2[1]) && (*p1 == '*' || s2 != tmp2)) + ip2 = 0; + *(s2++) = *(p2++); + } + } + *s2 = *s1 = '\0'; + } + if ((in_uh && ip1 != ip2) || !xmatch(tmp1, tmp2)) + return 0; + + if (*p1) + p1++; + if (*p2) + p2++; + + s1 = tmp1; + s2 = tmp2; + + } + while (*p1); + + return 1; +} + + +int key_match(char *s, char *tok[]) +{ + register int k; + + for (k = 0; tok[k] != NULL; k++) + { + if (!strcasestr(s, tok[k])) + return 0; + } + + return 1; +} + +void string_swap(char *buf, size_t size, char *orig, char *new) +{ + char *ptr, *buf2; + + buf2 = (char *)alloca(sizeof(char) * size); + while ((ptr = strstr((buf), orig))) + { + *ptr = '\0'; + strncpy(buf2, buf, size - 1); + strncat(buf2, new, size - strlen(buf) - 1); + strncat(buf2, ptr + strlen(orig), size - strlen(buf) - strlen(new) - 1); + strcpy(buf, buf2); + } +} + + +/* regex_cmp() (stolen from RCSD) + * This function compares a regular expression (patern) with a string. + * Return value: 1 if there is a match + * 0 otherwise + * + * Note: if patern is NULL, the last patern that was passed to the + * function is used. + */ +#define HAVE_REGEXEC +int regex_cmp(char *patern, char *string) +{ +#if defined(HAVE_REGEXEC) + static regex_t preg; + static int called_once = 0; + register int cmpv = 0, execv; + + if (patern != NULL) + { + if (called_once) + regfree(&preg); + cmpv = regcomp(&preg, patern, REG_EXTENDED | REG_ICASE | REG_NOSUB); + } + + called_once = 1; + + if (cmpv == 0) + execv = regexec(&preg, string, 0, NULL, 0); + + return cmpv ? 0 : execv ? 0 : 1; + +#elif defined(HAVE_RE_EXEC) + register char *ptr; + + ptr = re_comp(patern); + return ptr ? 0 : re_exec(string); + +#else +#error neither re_exec() nor rexexec() :/ +#endif +} +#ifdef MATCHALONE +void main(void) +{ + char str1[80]; + char str2[80]; + puts("#1"); + gets(str1); + puts("#2"); + gets(str2); + printf("match: %d\n", match(str1, str2)); +} +#endif diff --git a/Sources/modes.c b/Sources/modes.c new file mode 100644 index 0000000..03f6734 --- /dev/null +++ b/Sources/modes.c @@ -0,0 +1,970 @@ +/* @(#)$Id: modes.c,v 1.10 1999/04/04 17:00:11 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +static void AddFlag(char *, char, char *); +static void RemFlag(char *, char); + +void setchanmode(char *line) +{ + register char *mode; + register achannel *chan; + + if ((mode = strchr(line, ' ')) != NULL) + *(mode++) = 0; + chan = ToChannel(line); + if (!chan) + return; + strcpy(chan->mode, mode + 1); /* why +1 ???? coz I don't want the + */ +} + +void AddFlag(char *string, char flag, char *arg) +{ + char newmode[15]; + char newarg[200]; + + if (strchr(string, flag)) + RemFlag(string, flag); + + GetWord(0, string, newmode); + *(newmode + strlen(newmode) + 1) = 0; + *(newmode + strlen(newmode)) = flag; + strcpy(newarg, ToWord(1, string)); + if (arg) + { + strcat(newarg, arg); + strcat(newarg, " "); + } + + sprintf(string, "%s %s", newmode, newarg); +} + +void RemFlag(char *string, char flag) +{ + char newmode[15]; + char newarg[200]; + register char *ptr; + register char *curr = newmode; + register int count = 0; + + GetWord(0, string, newmode); + strcpy(newarg, ToWord(1, string)); + + while (*curr) + { + ptr = strchr("lk", *curr); + if (*curr == flag) + { + strcpy(curr, curr + 1); + if (ptr) + strcpy(ToWord(count, newarg), ToWord(count + 1, newarg)); + } + else + { + if (ptr) + count++; + curr++; + } + } + sprintf(string, "%s %s", newmode, newarg); +} + +int IsSet(char *channel, char flag, char *param) +{ + register achannel *chan; + register char *setmode; + char setflags[20]; + char setparam[80]; + register int out; + register int i, j; + + chan = ToChannel(channel); + if (chan == NULL) + return 0; + + setmode = chan->mode; + GetWord(0, setmode, setflags); + + j = 0; + for (i = 0; setflags[i] != '\0' && setflags[i] != flag; i++) + { + if (setflags[i] == 'l' || setflags[i] == 'k') + j++; + } + + if (setflags[i] != '\0') + { + if (flag == 'l' || flag == 'k') + { + GetWord(j + 1, setmode, setparam); + if (!strcmp(setparam, param)) + out = 1; + else + out = 0; + } + else + { + out = 1; + } + } + else + { + out = 0; + } +#ifdef DEBUG + printf("IsSet(): +%c %s on %s (%d)\n", flag, param, channel, out); +#endif + return (out); +} + +void bounce(char *channel, char *change, time_t TS) +{ + char buffer[200]; + char arg[200]; + register char sign = '+'; + register auser *user; + register achannel *chan; + register int pos = 1; + register int i; + + chan = ToChannel(channel); + + for (i = 0; change[i] != '\0' && change[i] != ' '; i++) + { + if (change[i] == '+') + sign = '+'; + else if (change[i] == '-') + sign = '-'; + else if (change[i] == 'o') + { + GetWord(pos++, change, arg); + user = ToUser(channel, arg); + if (user == NULL) + continue; + if (sign == '+') + { + if (!user->chanop) + { + changemode(channel, "-o", arg, 1); + user->chanop = 0; + } + } + else + { + if (user->chanop) + { + /* + changemode(channel,"+o",arg,1); + user->chanop=1; + */ + /* don't bounce -o */ + user->chanop = 0; + } + } + } + else if (change[i] == 'v') + { + GetWord(pos++, change, arg); + if (sign == '+') + changemode(channel, "-v", arg, 1); + else + changemode(channel, "+v", arg, 1); + } + else if (change[i] == 'k') + { + GetWord(pos++, change, arg); + if (sign == '+') + { + if (!IsSet(channel, 'k', arg)) + changemode(channel, "-k", arg, 1); + } + else + { + if (IsSet(channel, 'k', arg)) + changemode(channel, "+k", arg, 1); + } + } + else if (change[i] == 'l') + { + pos++; + if (sign == '+' && !IsSet(channel, 'l', arg)) + changemode(channel, "-l", "", 1); + + } + else if ((IsSet(channel, change[i], "") && sign == '-') || + (!IsSet(channel, change[i], "") && sign == '+')) + { + sprintf(buffer, "%c%c", + (sign == '+') ? '-' : '+', + change[i]); + changemode(channel, buffer, "", 1); + } + } + AddEvent(EVENT_FLUSHMODEBUFF, now + MODE_DELAY, channel); +} + + +void ModeChange(char *source, char *channel, char *change) +{ + register char sign = '+'; + char arg[200]; + register char *ptr; + register achannel *chan; + register aluser *u; + register int count = 1; + int desync = 0; + +#ifdef DEBUG + printf("ModeChange(%s, %s, %s)\n", source, channel, change); +#endif + chan = ToChannel(channel); + /* if chan == NULL at this point.. we're dealing with a + * user mode change + */ + if (chan != NULL) + chan->lastact = now; + + u = ToLuser(source); + if (chan == NULL && u == NULL) + { + return; /* probably a lost MODE */ + } + if (u == NULL) + { + /* This is a mode change from a server.. if it is not + * a +b, then the last argument is a TS + */ + for (ptr = change; *ptr != 'b' && *ptr != ' '; ptr++); + if (*ptr != 'b' && strcasecmp(UWORLD_SERVER, source) +#ifdef UWORLD2 + && strcasecmp(UWORLD2_SERVER, source) +#endif +#ifdef FAKE_UWORLD + && strcasecmp(UFAKE_SERVER, source) +#endif + ) + { + ptr = change + strlen(change); + while (*ptr != ' ') + ptr--; + *(ptr++) = '\0'; + if (atol(ptr) > chan->TS && atol(ptr) != 0 && chan->on) + { + log(source); + log(channel); + log(change); + log(ptr); + bounce(channel, change, chan->TS); + return; + } + if (atol(ptr) != 0) + chan->TS = atol(ptr); + } + } + + while (*change && *change != ' ') + { + if (*change == '+') + { + sign = '+'; + } + else if (*change == '-') + { + sign = '-'; + } + else + { + if (sign == '+') + { + if (chan != NULL) + { + ptr = strchr("blkov", *change); + if (ptr) + { + GetWord(count, change, arg); + if (strchr("lk", *change) && *arg) + AddFlag(chan->mode, *change, arg); + count++; + } + else + { + if (strchr("imntps", *change)) + AddFlag(chan->mode, *change, NULL); + } + } + else + { + /* user mode change (+) */ + if (*change == 'o') + { + u->mode |= LFL_ISOPER; +#ifdef DEBUG + printf("%s is now IRCOP\n", source); +#endif + } + } + } + else + { + if (chan != NULL) + { + ptr = strchr("bkov", *change); + if (strchr("ilkmntps", *change)) + RemFlag(chan->mode, *change); + if (ptr) + { + GetWord(count, change, arg); + count++; + } + } + else + { + /* user mode change (-) */ + if (*change == 'o') + { + u->mode &= ~LFL_ISOPER; +#ifdef DEBUG + printf("%s is no longer IRCOP\n", source); +#endif + } + } + } + +/** other tests should go here **/ + + if (chan != NULL) + { + if (*change == 'o') + { + if (sign == '+') + onop(source, channel, arg); + else + ondeop(source, channel, arg, &desync); + } + else if (*change == 'b') + { + if (sign == '+') + onban(source, channel, arg); + else + onunban(source, channel, arg); + } + else if (*change == 'l') + { + if (sign == '+' && atoi(arg) < 2) + { + if (chan->on && chan->AmChanOp) + { + changemode(channel, "-l", "", 0); + RemFlag(chan->mode, *change); + } + } + } + } + } + change++; + if (*change == ' ') + { + change = ToWord(count, change); + count = 1; + } + } + if (chan != NULL) + { + if (desync) + { + part("", channel, ""); + join("", channel, ""); + } + CheckFlood(source, channel, 80); + flushmode(channel); + } +} + +void onop(char *source, char *channel, char *target) +{ + register auser *user; + register aluser *luser; + register achannel *chan; + char buffer[200]; + + chan = ToChannel(channel); + luser = ToLuser(source); + + user = ToUser(channel, target); + + if (!strcasecmp(mynick, target)) + { + if (!chan) + { + log("ERROR: onop() channel not found!"); + return; + } + + chan->AmChanOp = 1; + } + else + { +#ifdef DEBUG + printf("OP for %s on %s\n", target, channel); +#endif + if (!user) + { + sprintf(buffer, "ERROR: onop() user not found (%s)", + target); + log(buffer); + return; + } + + user->chanop = 1; + + sprintf(buffer, "%s!%s@%s", user->N->nick, user->N->username, user->N->site); + + if (luser && chan->on && (chan->flags & CFL_NOOP)) + { + sprintf(buffer, "NoOp MODE! deopping %s and %s", + target, source); + log(buffer); + notice(target, replies[RPL_NOOP][chan->lang]); + notice(source, replies[RPL_NOOP][chan->lang]); + changemode(channel, "-o", target, 0); + changemode(channel, "-o", source, 0); + user->chanop = 0; + user = ToUser(channel, source); + if (user != NULL) + { + user->chanop = 0; + } + + } + else if (luser && chan->on && (chan->flags & CFL_STRICTOP) && + Access(channel, target) < OP_LEVEL) + { + sprintf(buffer, "StrictOp MODE! deopping %s and %s", + target, source); + log(buffer); + notice(target, "Only authenticated users may be op in StrictOp mode"); + notice(source, "Only authenticated users may be op in StrictOp mode"); + changemode(channel, "-o", target, 0); + user->chanop = 0; + if (Access(channel, source) < OP_LEVEL) + { + changemode(channel, "-o", source, 0); + user = ToUser(channel, source); + if (user != NULL) + { + user->chanop = 0; + } + } + + } + else if (luser && chan->on && IsShit(channel, buffer, NULL, NULL) >= NO_OP_SHIT_LEVEL) + { + if (Access(channel, source) < ACCESS_BAN_PRIORITY) + { + sprintf(buffer, "%s is shitlisted (NO-OP LEVEL)!" + "Deopping %s and %s", target, target, source); + log(buffer); + notice(target, replies[RPL_CANTBEOP][chan->lang]); + notice(source, replies[RPL_CANTBEOPPED][chan->lang]); + changemode(channel, "-o", target, 0); + changemode(channel, "-o", source, 0); + user->chanop = 0; + user = ToUser(channel, source); + if (user != NULL) + user->chanop = 0; + + sprintf(buffer, "%s %d", source, SUSPEND_TIME_FOR_OPPING_A_SHITLISTED_USER); + suspend("", channel, buffer); + } + else + { + unban(source, channel, target); + } + } + } + +/** further tests should be put here **/ +#ifdef NICKSERV + nserv_onop(channel, user); +#endif +} + +void ondeop(char *source, char *channel, char *target, int *desync) +{ + char buffer[200]; + register auser *user1, *user2; + register achannel *chan; + register adeop *curr, *prec; + register int i; + + chan = ToChannel(channel); + if (!chan) + { + log("ERROR: ondeop() channel not found!"); + return; + } + + user1 = ToUser(channel, source); + user2 = ToUser(channel, target); + + if (chan->on && user1 == NULL) + { /* desync! */ + if (user2 != NULL) + { + user2->chanop = 0; + } + sprintf(buffer, "DESYNC detected! (%s deopped %s on %s)", + source, target, channel); + log(buffer); + +/* part("",channel,""); + join("",channel,""); now doing this in ChangeMode */ + + *desync = 1; + + return; + } + + if (!strcasecmp(mynick, target)) + { + if ((chan->flags & CFL_ALWAYSOP) && + Access(channel, source) >= ALWAYSOP_OVERRIDE_LEVEL) + { + chan->flags &= ~CFL_ALWAYSOP; + sprintf(buffer, "AlwaysOp is turned off on %s (deopped by %s!%s@%s)", + channel, user1->N->nick, user1->N->username, user1->N->site); + log(buffer); + notice(source, replies[RPL_ALWAYSOPWASACTIVE][chan->lang]); + } + if (chan->flags & CFL_ALWAYSOP) + { + if (user1 != NULL) + { + sprintf(buffer, "DEOPPED by %s!%s@%s (%d) while AlwaysOp active on %s", + user1->N->nick, user1->N->username, user1->N->site, + Access(channel, source), channel); + log(buffer); + broadcast(buffer, 0); + i = IsShit(channel, source, NULL, NULL); + notice(source, replies[RPL_ALWAYSOP][chan->lang]); + switch (i) + { + case 0: + case 1: + case 2: + case 3: + case 4: + log("First warning"); + notice(source, replies[RPL_DEOPPED1ST][chan->lang]); + changemode(channel, "-o", source, 0); + flushmode(channel); + user1->chanop = 0; + break; + + case 5: + case 6: + case 7: + case 8: + case 9: + log("Second warning"); + notice(source, replies[RPL_DEOPPED2ND][chan->lang]); + kick("", channel, source); + break; + + default: + notice(source, "I warned you!"); + changemode(channel, "-o", source, 0); + flushmode(channel); + user1->chanop = 0; + sprintf(buffer, "%s!%s@%s %d", + user1->N->nick, user1->N->username, + user1->N->site, + DEOPME_SUSPEND_TIME); + suspend("", channel, buffer); + sprintf(buffer, "Suspended %s!%s@%s on %s for repeatedly deopping me", + user1->N->nick, user1->N->username, user1->N->site, channel); + SpecLog(buffer); + broadcast(buffer, 0); + } + sprintf(buffer, "%s %d %d *** DEOP WHILE ALWAYSOP ACTIVE ***", + source, DEOP_SHITLIST_TIME, + (i < 10) ? i + 5 : + DEOP_SHITLIST_LEVEL); + AddToShitList("", channel, buffer, 0); + chan->AmChanOp = 0; /* to remove if I reop myself */ + GetOps(channel); + } + } + else + { + chan->AmChanOp = 0; + if (IsOpless(channel)) + onopless(channel); + } + } + + /* massdeop protection does NOT apply to the bot itself! + if(!strcasecmp(source,mynick)) return; obsolete */ + + /* No protection against server deop :/ + Hey! I'm not gonna /squit it just for doing a deop!! ;) */ + if (!user1) + return; + + if (user2) + user2->chanop = 0; + + chan = ToChannel(channel); + if (!chan) + { + log("ERROR: ondeop() channel not found!"); + return; + } + + /* If not on channel.. do NOT check for massdeop + */ + if (!chan->on) + return; + + curr = user1->deophist; + prec = NULL; + + /* ok.. let's free the *old* deops from history */ + while (curr) + { + if (curr->time < (now - 15) || !strcasecmp(curr->nick, target)) + { + if (prec) + { + prec->next = curr->next; + TTLALLOCMEM -= sizeof(adeop); + free(curr); + curr = prec->next; + } + else + { + user1->deophist = curr->next; + TTLALLOCMEM -= sizeof(adeop); + free(curr); + curr = user1->deophist; + } + } + else + { + prec = curr; + curr = curr->next; + } + } + + /* now store the deop in the user's deop history */ + curr = (adeop *) MALLOC(sizeof(adeop)); + strcpy(curr->nick, target); + curr->time = now; + curr->next = user1->deophist; + user1->deophist = curr; + + /* now we count the number of deop in the user's history + if it's equal to the max number of deops per 15 seconds + interval.. activate the massdeop protection */ + for (curr = user1->deophist, i = 0; curr; curr = curr->next, i++); + + if (i == chan->MassDeopPro && chan->MassDeopPro != 0 && chan->on) + { + sprintf(buffer, "MASSDEOP from %s on %s", source, channel); + log(buffer); + notice(source, "### MASSDEOP PROTECTION ACTIVATED ###"); + if (Access(channel, source) >= MASSDEOP_IMMUNE_LEVEL) + { + notice(source, "You are lucky your access is so high :P"); + } + else + { + sprintf(buffer, "%s %d", source, MASSDEOP_SUSPEND_TIME); + suspend("", channel, buffer); + sprintf(buffer, "%s %d %d *** MASSDEOP ***", source, + MASSDEOP_SHITLIST_TIME, + MASSDEOP_SHITLIST_LEVEL); + AddToShitList("", channel, buffer, 0); + sprintf(buffer, "%s ### MASSDEOP PROTECTION ###", source); + kick("", channel, buffer); + } + } +} + +void onban(char *nick, char *channel, char *pattern) +{ +#ifdef DEBUG + printf("Wah! BAN FROM: %s\nON CHANNEL %s\nTARGET: %s\n", + nick, channel, pattern); +#endif + AddBan(channel, pattern); +} + +void onunban(char *source, char *channel, char *pattern) +{ + /*register achannel *chan; */ + + RemBan(channel, pattern); + + /* mode -b no longer removes the ban from X's banlist + ** it has to be removed with the 'unban' command. + chan=ToChannel(channel); + if(chan!=NULL && chan->on) + RemShitList(source,channel,pattern,1); + * */ +} + +void AddBan(char *channel, char *pattern) +{ + register achannel *chan; + register aban *theban; + char buffer[200]; + + chan = ToChannel(channel); + if (chan == NULL) + { + sprintf(buffer, "ERROR: AddBan(): can't find %s", channel); + log(buffer); + return; + } + + /* check if ban isn't already there */ + for (theban = chan->bans; theban != NULL; theban = theban->next) + { + if (!strncasecmp(theban->pattern, pattern, 79)) + { + return; + } + } + + theban = (aban *) MALLOC(sizeof(aban)); + strncpy(theban->pattern, pattern, 79); + theban->pattern[79] = '\0'; + theban->next = chan->bans; + chan->bans = theban; +} + + +void RemBan(char *channel, char *pattern) +{ + register achannel *chan; + register aban **b, *theban = NULL; + + chan = ToChannel(channel); + b = &chan->bans; + while (*b != NULL) + { + if (!strncasecmp((*b)->pattern, pattern, 79)) + { + theban = *b; + *b = theban->next; + TTLALLOCMEM -= sizeof(aban); + free(theban); + } + else + { + b = &(*b)->next; + } + } +#ifdef DEBUG + if (theban == NULL) + { + printf("WARNING: RemBan(): pattern NOT found!!\n"); + } +#endif +} + + +void changemode(char *channel, char *flag, char *arg, int AsServer) +{ + register achannel *chan; + register modequeue *mode, *curr; + +#ifdef DEBUG + printf("Queueing mode change for channel %s %s %s %d\n", channel, flag, arg, AsServer); +#endif + + chan = ToChannel(channel); + if (!AsServer && (!chan || !chan->on)) + return; /* not on the channel.. ignore */ + + /* first, cancel previous contradicting mode changes.. + ex.. mode #test +o-o+o-o+o .. the bot won't do that.. */ + + mode = chan->modebuff; + while (mode) + { + if (!strcmp(arg, mode->arg) && flag[1] == mode->flag[1] && + ((flag[0] == '+' && mode->flag[0] == '-') || + (flag[0] == '-' && mode->flag[0] == '+'))) + { + if (mode->prev) + mode->prev->next = mode->next; + else + chan->modebuff = mode->next; + + if (mode->next) + mode->next->prev = mode->prev; + + curr = mode; + TTLALLOCMEM -= sizeof(modequeue); + free(curr); + } + else if (!strcmp(arg, mode->arg) && flag[1] == mode->flag[1] && + flag[0] == mode->flag[0]) + return; + mode = mode->next; + } + + curr = (modequeue *) MALLOC(sizeof(modequeue)); + strcpy(curr->arg, arg); + strcpy(curr->flag, flag); + curr->AsServer = AsServer; + curr->next = NULL; + + for (mode = chan->modebuff; mode && mode->next; mode = mode->next); + + if (mode) + { + curr->prev = mode; + mode->next = curr; + } + else + { + chan->modebuff = curr; + curr->prev = NULL; + } +} + +void flushmode(char *channel) +{ + char buffer[500]; + register achannel *chan; + register modequeue *mode, *tmp; + char flags[20] = ""; + char args[500] = ""; + register char lastsign; + register int AsServer; + register int count = 0; + +#ifdef DEBUG + printf("Flushing mode change buffer.. for channel %s\n", channel); +#endif + + /* gotta pass thru the list twice: + * the first time, check for Server mode changes + * the second time, check for user mode changes + */ + + chan = ToChannel(channel); + + if (chan == NULL) + return; + +#ifdef FAKE_UWORLD +#define ASSERVERMAX 2 +#else +#define ASSERVERMAX 1 +#endif + for (AsServer = ASSERVERMAX; AsServer >= 0; AsServer--) + { +#undef ASSERVERMAX + lastsign = '\0'; + mode = chan->modebuff; + while (mode != NULL) + { + if (!strcmp(mode->flag, "-b")) + { + RemBan(channel, mode->arg); + } + else if (!strcmp(mode->flag, "+b")) + { + AddBan(channel, mode->arg); + } + if (AsServer == mode->AsServer) + { + if (mode->arg[0] != '\0') + { + count++; + strcat(args, " "); + strcat(args, mode->arg); + } + if (lastsign != mode->flag[0]) + { + strcat(flags, mode->flag); + lastsign = mode->flag[0]; + } + else + { + strcat(flags, mode->flag + 1); + } + if (mode->prev) + mode->prev->next = mode->next; + else + chan->modebuff = mode->next; + if (mode->next) + mode->next->prev = mode->prev; + tmp = mode; + mode = mode->next; + TTLALLOCMEM -= sizeof(modequeue); + free(tmp); + } + else + { + mode = mode->next; + } + + if (count == MAX_MODE_PER_LINE || !mode) + { + if (AsServer == 0 && chan->AmChanOp && *flags != '\0') + { + sprintf(buffer, ":%s MODE %s %s%s\n", + mynick, channel, flags, args); + sendtoserv(buffer); + } + else if (AsServer == 1 && *flags != '\0') + { + sprintf(buffer, ":%s MODE %s %s%s %ld\n", + SERVERNAME, channel, + flags, args, chan->TS); + sendtoserv(buffer); + } +#ifdef FAKE_UWORLD + else if (AsServer == 2 && Uworld_status == 1 && *flags != '\0') + { + sprintf(buffer, ":%s MODE %s %s%s\n", + UFAKE_SERVER, channel, + flags, args); + sendtoserv(buffer); + } +#endif + count = *args = *flags = 0; + lastsign = '+'; + } + } + } +} diff --git a/Sources/nick.c b/Sources/nick.c new file mode 100644 index 0000000..b092cb0 --- /dev/null +++ b/Sources/nick.c @@ -0,0 +1,81 @@ +/* @(#)$Id: nick.c,v 1.3 1996/11/13 00:40:44 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +void NickInUse(void) +{ + char buffer[200]; + + sprintf(buffer,":%s SQUIT %s 0 :Unexpected nick collision\n", + SERVERNAME,SERVERNAME); + sendtoserv(buffer); + dumpbuff(); + close(Irc.fd); + Irc.fd=-1; + QuitAll(); + if(reconnect(server)){ + try_later(server); + } +#if 0 + char *ptr; + achannel *chan; + int index=0; + + do{ + if(!strcmp(mynick,DEFAULT_NICKNAME)){ + strcat(mynick,"1"); + }else{ + ptr = (mynick+strlen(mynick)-1); + (*ptr)++; + if(*ptr>'z') *ptr='0'; + } + }while(ToLuser(mynick)!=NULL); + + sprintf(buffer, + "ERROR: ARGH! Nick already in use! Changing to %s",mynick); + log(buffer); + + for(index=0;index<1000;index++){ + chan=ChannelList[index]; + while(chan!=NULL){ + chan->on=chan->AmChanOp=0; + chan=chan->next; + } + } + /*logTS=time(NULL);*/ + signon(); + joindefault(); +#endif +} + +void ChNick(char *newnick) +{ + char buffer[80]; + sprintf(buffer,":%s NICK %s :%ld\n",mynick,newnick,now); + sendtoserv(buffer); + strcpy(mynick,newnick); +} diff --git a/Sources/opcom.c b/Sources/opcom.c new file mode 100644 index 0000000..6a90190 --- /dev/null +++ b/Sources/opcom.c @@ -0,0 +1,763 @@ +/* @(#)$Id: opcom.c,v 1.19 2000/10/24 16:07:33 lgm Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +void CalmDown(char *source, char *chan, char *args) +{ + register aluser *user; + register achannel *ch; + char buffer[200], channel[80], global[] = "*"; + + if ((user = ToLuser(source)) == NULL) + { + log("ERROR: CalmDown() can't locate user!"); + return; + } + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + if (!(user->mode & LFL_ISOPER) && Access(global, source) < XADMIN_LEVEL) + { + notice(source, "This command is reserved for IRC Operators"); + return; + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: calmdown [channel]"); + return; + } + + ch = ToChannel(channel); + + if (ch == NULL || !ch->on) + { + notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); + return; + } + + sprintf(buffer, ":%s WALLOPS :%s!%s@%s is asking me to calm down on %s\n", + SERVERNAME, user->nick, user->username, user->site, ch->name); + sendtoserv(buffer); + + sprintf(buffer, "%s!%s@%s is asking me to calm down on %s\n", + user->nick, user->username, user->site, ch->name); + broadcast(buffer, 0); + + sprintf(buffer, "CALMDOWN requested by %s!%s@%s on %s", + user->nick, user->username, user->site, ch->name); + SpecLog(buffer); + + /* + part("",channel,""); + RemChan("",channel,""); + */ + ch->flags |= CFL_NOOP; + massdeop(channel); +#ifdef CALMDOWNTOPIC + topic("", channel, CALMDOWNTOPIC); +#endif +} + + +void OperJoin(char *source, char *chan, char *args) +{ + register aluser *user; + register achannel *ch; + char buffer[200], channel[80]; + + if ((user = ToLuser(source)) == NULL) + { + log("ERROR: OperJoin() can't locate user!"); + return; + } + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + if (!(user->mode & LFL_ISOPER)) + { + notice(source, "This command is reserved for IRC Operators"); + return; + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: operjoin "); + return; + } + + if (!IsReg(channel)) + { + notice(source, "That channel is not registered"); + return; + } + + ch = ToChannel(channel); + + if (ch != NULL && ch->on) + { + notice(source, "I am already on that channel"); + return; + } + + sprintf(buffer, ":%s WALLOPS :%s!%s@%s is asking me to join channel %s\n", + SERVERNAME, user->nick, user->username, user->site, channel); + sendtoserv(buffer); + + sprintf(buffer, "%s!%s@%s is asking me join channel %s\n", + user->nick, user->username, user->site, channel); + broadcast(buffer, 0); + + sprintf(buffer, "OPERJOIN requested by %s!%s@%s on %s", + user->nick, user->username, user->site, channel); + SpecLog(buffer); + + join("", channel, ""); +} + + +void OperPart(char *source, char *chan, char *args) +{ + register aluser *user; + register achannel *ch; + char buffer[200], channel[80]; + + if ((user = ToLuser(source)) == NULL) + { + log("ERROR: OperPart() can't locate user!"); + return; + } + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + if (!(user->mode & LFL_ISOPER)) + { + notice(source, "This command is reserved for IRC Operators"); + return; + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: operpart [channel]"); + return; + } + + ch = ToChannel(channel); + + if (ch == NULL || !ch->on) + { + notice(source, "I am not on that channel"); + return; + } + + sprintf(buffer, ":%s WALLOPS :%s!%s@%s is asking me to leave channel %s\n", + SERVERNAME, user->nick, user->username, user->site, channel); + sendtoserv(buffer); + + sprintf(buffer, "%s!%s@%s is asking me to leave channel %s\n", + user->nick, user->username, user->site, channel); + broadcast(buffer, 0); + + sprintf(buffer, "OPERPART requested by %s!%s@%s on %s", + user->nick, user->username, user->site, channel); + SpecLog(buffer); + + part("", channel, ""); +} + + +void ClearMode(char *source, char *chan, char *args) +{ + register aluser *user; + register achannel *ch; + register char *curr; + register int i; + char buffer[200], channel[80], arg[80]; + + if ((user = ToLuser(source)) == NULL) + { + log("ERROR: ClearMode() can't locate user!"); + return; + } + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: clearmode [channel]"); + return; + } + + if (Access(channel, source) < CLEARMODE_LEVEL) + { + if (user->mode & LFL_ISOPER) + { + sprintf(buffer, ":%s WALLOPS :%s is using clearmode on %s\n", + SERVERNAME, source, channel); + sendtoserv(buffer); + } + else + { + ReplyNotAccess(source, channel); + return; + } + } + + if ((ch = ToChannel(channel)) == NULL) + { + notice(source, "No such channel!"); + return; + } + if (!ch->on || !ch->AmChanOp) + { + notice(source, replies[RPL_NOTCHANOP][ch->lang]); + return; + } + + sprintf(buffer, "CLEARMODE on %s requested by %s!%s@%s", + channel, user->nick, user->username, user->site); + log(buffer); + + curr = ch->mode; + i = 1; + + while (*curr && *curr != ' ') + { + if (strchr("kl", *curr)) + { + GetWord(i++, ch->mode, arg); + if (*curr == 'k') + { + changemode(channel, "-k", arg, 0); + } + else + { + changemode(channel, "-l", "", 0); + } + } + else + { + sprintf(buffer, "-%c", *curr); + changemode(channel, buffer, "", 0); + } + + curr++; + } + + ch->mode[0] = '\0'; + flushmode(channel); +} + + +void verify(char *source, char *arg) +{ + aluser *luser; + char buffer[200], nick[80], global[] = "*", *oper; + int acc; + + GetWord(0, arg, nick); + if (!*nick) + { + notice(source, "SYNTAX: verify "); + return; + } + + luser = ToLuser(nick); + if (luser == NULL) + { + sprintf(buffer, "No such nick: %s", nick); + notice(source, buffer); + return; + } + + if (luser->mode & LFL_ISOPER) + { + oper = " and an IRC operator"; + } + else + { + oper = ""; + } + + acc = Access(global, nick); + if (acc == 1000) + { + sprintf(buffer, "%s!%s@%s is my daddy%s", + luser->nick, luser->username, luser->site, oper); + } + else if (acc > 900) + { + sprintf(buffer, "%s!%s@%s is an Official %s coder%s", + luser->nick, luser->username, luser->site, VERIFY_ID, oper); + } + else if (acc == 900) + { + sprintf(buffer, "%s!%s@%s is my grandma%s", + luser->nick, luser->username, luser->site, oper); + } + else if (acc == 800) + { + sprintf(buffer, "%s!%s@%s is a Co-ordinator of %s%s", + luser->nick, luser->username, luser->site, VERIFY_ID, oper); + } + else if (acc > 500) + { + sprintf(buffer, "%s!%s@%s is an Official %s admin%s", + luser->nick, luser->username, luser->site, VERIFY_ID, oper); + } + else if (acc > 0) + { + sprintf(buffer, "%s!%s@%s is an Official %s helper%s", + luser->nick, luser->username, luser->site, VERIFY_ID, oper); + } + else if (acc < 0) + { + sprintf(buffer, "%s!%s@%s is a well-known TROUBLEMAKER%s", + luser->nick, luser->username, luser->site, oper); + } + else if (luser->mode & LFL_ISOPER) + { + sprintf(buffer, "%s!%s@%s is an IRC operator", + luser->nick, luser->username, luser->site); + } + else + { + sprintf(buffer, "%s!%s@%s is NOT an authenticated %s representative", + luser->nick, luser->username, luser->site, VERIFY_ID); + } + notice(source, buffer); +} + +#ifdef FAKE_UWORLD +void Uworld_switch(char *source, char *ch, char *args) +{ + char buffer[200]; + aluser *user, *user2; + + user = ToLuser(source); + if (!user || !(user->mode & LFL_ISOPER)) + { + notice(source, "This command is reserved to IRC Operators"); + return; + } + + if (!strcasecmp(args, "ON")) + { + if (Uworld_status == 1) + { + sprintf(buffer, "%s is already active", UFAKE_NICK); + notice(source, buffer); + } + else + { + if ((user2 = ToLuser(UFAKE_NICK)) != NULL && + !strcmp(user2->site, DEFAULT_HOSTNAME)) + { + sprintf(buffer, "%s already present!", UFAKE_NICK); + notice(source, buffer); + return; + } + if (user2 != NULL) + { + onquit(UFAKE_NICK); + } + if (FindServer(&ServerList, UFAKE_SERVER) != NULL) + { + sprintf(buffer, "%s already present!", UFAKE_SERVER); + notice(source, buffer); + return; + } + sprintf(buffer, ":%s WALLOPS :%s activated %s\n", + SERVERNAME, source, UFAKE_NICK); + sendtoserv(buffer); + Uworld_status = 1; + IntroduceUworld(); + sprintf(buffer, "%s activated by %s!%s@%s", + UFAKE_NICK, user->nick, user->username, user->site); + log(buffer); + } + } + else if (!strcasecmp(args, "OFF")) + { + if (Uworld_status == 0) + { + sprintf(buffer, "%s is not active", UFAKE_NICK); + notice(source, buffer); + } + else + { + sprintf(buffer, ":%s WALLOPS :%s deactivated %s\n", + SERVERNAME, source, UFAKE_NICK); + sendtoserv(buffer); + Uworld_status = 0; + sprintf(buffer, "Deactivated by %s!%s@%s", + user->nick, user->username, user->site); + KillUworld(buffer); + sprintf(buffer, "%s deactivated by %s!%s@%s", + UFAKE_NICK, user->nick, user->username, user->site); + log(buffer); + } + } + else + { + notice(source, "SYNTAX: uworld [ON|OFF]"); + } +} + +void parse_uworld_command(char *source, char *args) +{ + char command[80]; + GetWord(0, args, command); + args = ToWord(1, args); + + if (!strcasecmp(command, "OPCOM")) + Uworld_opcom(source, args); + else if (!strcasecmp(command, "CLEARCHAN")) + ClearChan(source, args); + else if (!strcasecmp(command, "REOP")) + Uworld_reop(source, args); +} + +void Uworld_opcom(char *source, char *args) +{ + char buffer[512]; + char command[80]; + char channel[80]; + aluser *user; + + user = ToLuser(source); + if (!user || !(user->mode & LFL_ISOPER)) + { + notice(source, "This command is reserved to IRC Operators"); + return; + } + + sprintf(buffer, "%s!%s@%s", user->nick, user->username, user->site); + if (IsOperSuspended(buffer)) + { + notice(source, "Sorry, Your Uworld access is suspended"); + return; + } + + GetWord(0, args, command); + GetWord(1, args, channel); + args = ToWord(2, args); + + if (!strcasecmp(command, "MODE")) + { + if (*channel != '#') + { + sprintf(buffer, ":%s NOTICE %s :bad channel name\n", + UFAKE_NICK, source); + sendtoserv(buffer); + return; + } + sprintf(buffer, ":%s WALLOPS :%s is using %s to: MODE %s %s\n", + UFAKE_SERVER, source, UFAKE_NICK, channel, args); + sendtoserv(buffer); + sprintf(buffer, ":%s MODE %s %s\n", UFAKE_SERVER, channel, args); + sendtoserv(buffer); + sprintf(buffer, "OPCOM MODE %s %s (%s!%s@%s)", + channel, args, user->nick, user->username, user->site); + log(buffer); + ModeChange(UFAKE_SERVER, channel, args); + } + else + { + sprintf(buffer, ":%s NOTICE %s :(yet) unsupported command (%s)\n", + UFAKE_NICK, source, command); + sendtoserv(buffer); + } +} + + +void ClearChan(char *source, char *args) +{ + register aluser *user; + register auser *chanuser; + register achannel *ch; + register char *curr; + register aban *oneban; + register int i; + char buffer[200], channel[80], arg[80]; + + if ((user = ToLuser(source)) == NULL) + { + log("ERROR: ClearMode() can't locate user!"); + return; + } + + GetWord(0, args, channel); + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: clearmode [channel]"); + return; + } + + if (!user->mode & LFL_ISOPER) + { + sprintf(buffer, ":%s NOTICE %s :This command is reserved to IRC Operators\n", + UFAKE_NICK, source); + sendtoserv(buffer); + return; + } + + sprintf(buffer, "%s!%s@%s", user->nick, user->username, user->site); + if (IsOperSuspended(buffer)) + { + notice(source, "Sorry, Your Uworld access is suspended"); + return; + } + + if ((ch = ToChannel(channel)) == NULL) + { + sprintf(buffer, ":%s NOTICE %s :That channel does not exist\n", + UFAKE_NICK, source); + sendtoserv(buffer); + return; + } + + sprintf(buffer, ":%s WALLOPS :%s is using %s to: CLEARCHAN %s\n", + UFAKE_SERVER, source, UFAKE_NICK, channel); + sendtoserv(buffer); + + sprintf(buffer, "CLEARCHAN on %s requested by %s!%s@%s", + channel, user->nick, user->username, user->site); + log(buffer); + + chanuser = ch->users; + while (chanuser != NULL) + { + if (chanuser->chanop) + { + changemode(channel, "-o", chanuser->N->nick, 2); + chanuser->chanop = 0; + } + chanuser = chanuser->next; + } + + curr = ch->mode; + i = 1; + while (*curr && *curr != ' ') + { + if (strchr("kl", *curr)) + { + GetWord(i++, ch->mode, arg); + if (*curr == 'k') + { + changemode(channel, "-k", arg, 2); + } + else + { + changemode(channel, "-l", "", 2); + } + } + else + { + sprintf(buffer, "-%c", *curr); + changemode(channel, buffer, "", 2); + } + + curr++; + } + + ch->mode[0] = '\0'; + + for (oneban = ch->bans; oneban != NULL; oneban = oneban->next) + { + changemode(channel, "-b", oneban->pattern, 2); + } + flushmode(channel); +} + +void Uworld_reop(char *source, char *channel) +{ + register aluser *user; + char buffer[200]; + + user = ToLuser(source); + if (user != NULL && !strcasecmp(user->username, DEFAULT_USERNAME) && + !strcasecmp(user->site, DEFAULT_HOSTNAME)) + { + sprintf(buffer, "%s called for REOP on %s", source, channel); + log(buffer); + changemode(channel, "+o", source, 2); + flushmode(channel); + } +} + + +void OperSuspend(char *source, char *args) +{ + FILE *in, *out; + char Mask[200], strtimeout[80], global[] = "*", buffer[120], tmp[80], + *mask = Mask, *ptr; + time_t timeout; + int add = 1, count = 0; + + if (Access(global, source) < 900) + { + notice(source, "You don't have access to that command"); + return; + } + + GetWord(0, args, mask); + GetWord(1, args, strtimeout); + + if (!*mask) + { + notice(source, "SYNTAX: opersuspend [+/-] [timeout]"); + return; + } + + if (*mask == '+') + { + add = 1; + mask++; + } + else if (*mask == '-') + { + add = 0; + mask++; + } + + if (add) + { + out = fopen("opersuspend.dat", "a"); + if (!out) + { + notice(source, "Can't open file opersuspend.dat :("); + return; + } + + timeout = atol(strtimeout); + if (timeout <= 0) + timeout = 1999999999; + else + timeout += now; + + fprintf(out, "%s %ld\n", mask, timeout); + fclose(out); + notice(source, "1 entry added"); + } + else + { + in = fopen("opersuspend.dat", "r"); + if (!in) + { + notice(source, "Can't open file opersuspend.dat :("); + return; + } + out = fopen("opersuspend.dat.new", "w"); + if (!in) + { + notice(source, "Can't open file opersuspend.dat.new :("); + return; + } + + while (fgets(buffer, 120, in) != NULL) + { + if ((ptr = strchr(buffer, '\n')) != NULL) + *ptr = '\0'; + GetWord(0, buffer, tmp); + if (strcasecmp(tmp, mask) && atol(ToWord(1, buffer)) > now) + fprintf(out, "%s\n", buffer); + else + count++; + } + fclose(in); + fclose(out); + rename("opersuspend.dat.new", "opersuspend.dat"); + + sprintf(buffer, "Removed %d entry(ies)", count); + notice(source, buffer); + } +} + + +int IsOperSuspended(char *userhost) +{ + FILE *fp; + char buffer[120], mask[200], *ptr; + + if ((fp = fopen("opersuspend.dat", "r")) == NULL) + return 0; + + while (fgets(buffer, 120, fp) != NULL) + { + if ((ptr = strchr(buffer, '\n')) != NULL) + *ptr = '\0'; + GetWord(0, buffer, mask); + + if (atol(ToWord(1, buffer)) > now && match(userhost, mask)) + { + fclose(fp); + return 1; + } + } + fclose(fp); + return 0; +} + +#endif diff --git a/Sources/ops.c b/Sources/ops.c new file mode 100644 index 0000000..f27c078 --- /dev/null +++ b/Sources/ops.c @@ -0,0 +1,266 @@ +/* @(#)$Id: ops.c,v 1.6 1999/04/04 17:00:13 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +void op(char *source, char *chan, char *nicklist) +{ + char channel[80]; + char nick[80]; + char buffer[200]; + register auser *user; + register achannel *ch; + register int i; + + /* if the 1st arg is a channel name.. use it instead of 'chan' */ + if (*nicklist == '#') + { + GetWord(0, nicklist, channel); + nicklist = ToWord(1, nicklist); + } + else + { + strncpy(channel, chan, 79); + channel[79] = '\0'; + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: op [nick2] [nick3] [...]"); + return; + } + + /* Bad channel.. geez what am I supposed to do with it?? */ + if ((ch = ToChannel(channel)) == NULL || !ch->on) + { + notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); + return; + } + + if (!ch->AmChanOp) + { + notice(source, replies[RPL_NOTCHANOP][ch->lang]); + return; + } + + if (*source && (ch->flags & CFL_OPONLY) && + *nicklist && strcasecmp(nicklist, source)) + { + notice(source, replies[RPL_OPSELFONLY][ch->lang]); + return; + } + + if (*source && (ch->flags & CFL_NOOP)) + { + notice(source, replies[RPL_NOOP][ch->lang]); + return; + } + +#ifdef DEBUG + printf("OP requested....\nCHANNEL: %s\nNICKS: %s\n", channel, nicklist); +#endif + if (*source && Access(channel, source) < OP_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + if (!*nicklist) + { + strcpy(nick, source); + } + else + { + GetWord(0, nicklist, nick); + } + + i = 0; + while (*nick) + { + user = ToUser(channel, nick); +#ifdef DEBUG + if (user) + { + printf("USER FOUND!\n"); + printf("nick: %s\n", user->N->nick); + printf("Chanop: %s\n", (user->chanop) ? "YES" : "NO"); + } + else + { + printf("USER %s NOT FOUND ON CHANNEL %s\n", nick, channel); + } +#endif + /* the user might be shitlisted.. */ + + if (user) + { + sprintf(buffer, "%s!%s@%s", user->N->nick, user->N->username, user->N->site); + if (ch->flags & CFL_STRICTOP && Access(channel, user->N->nick) < OP_LEVEL) + { + if (*source) + { + notice(source, "StrictOp is active and user is not authenticated"); + } + } + else if (IsShit(channel, buffer, NULL, NULL) < NO_OP_SHIT_LEVEL) + { + if (user && !user->chanop) + { + user->chanop = 1; + changemode(channel, "+o", nick, 0); + if (*source && strcasecmp(source, nick)) + { + sprintf(buffer, replies[RPL_YOUREOPPEDBY][ch->lang], source); + notice(nick, buffer); + } + } + } + else + { + sprintf(buffer, "%s: %s", nick, replies[RPL_CANTBEOPPED][ch->lang]); + notice(source, buffer); + } + } + else + { + sprintf(buffer, replies[RPL_USERNOTONCHANNEL][ch->lang], nick, channel); + notice(source, buffer); + } + + GetWord(++i, nicklist, nick); + } + AddEvent(EVENT_FLUSHMODEBUFF, now + MODE_DELAY, channel); +} + +void deop(char *source, char *ch, char *nicklist) +{ + char channel[CHANNELNAME_LENGTH]; + char nick[80]; + char buffer[200]; + register auser *user; + register achannel *chan; + register int i; + + /* if the 1st arg is a channel name.. use it instead of 'channel' */ + if (*nicklist == '#') + { + GetWord(0, nicklist, channel); + nicklist = ToWord(1, nicklist); + } + else + { + strncpy(channel, ch, CHANNELNAME_LENGTH); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: deop [nick2] [nick3] [...]"); + return; + } + +#ifdef DEBUG + printf("DEOP requested....\nCHANNEL: %s\nNICKS: %s\n", channel, nicklist); +#endif + + if ((chan = ToChannel(channel)) == NULL || !chan->on) + { + notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); + return; + } + + if (*source && (chan->flags & CFL_OPONLY)) + { + notice(source, replies[RPL_OPONLY][chan->lang]); + return; + } + + + if (!chan->AmChanOp) + { + notice(source, replies[RPL_NOTCHANOP][chan->lang]); + return; + } + + if (*source && Access(channel, source) < OP_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + if (!*nicklist) + { + notice(source, "SYNTAX: deop [channel] [nick2] [nick3] [...]"); + return; + } + + i = 0; + GetWord(i, nicklist, nick); + while (*nick) + { + user = ToUser(channel, nick); + if (user) + { + sprintf(buffer, "%s!%s@%s", + user->N->nick, user->N->username, user->N->site); + if (user && user->chanop) + { + user->chanop = 0; + changemode(channel, "-o", nick, 0); + if (*source && strcasecmp(source, nick)) + { + sprintf(buffer, replies[RPL_YOUREDEOPPEDBY][chan->lang], source); + notice(nick, buffer); + } + } + } + GetWord(++i, nicklist, nick); + } + AddEvent(EVENT_FLUSHMODEBUFF, now + MODE_DELAY, channel); +} + +void massdeop(char *channel) +{ + achannel *chan; + auser *user; + + chan = ToChannel(channel); + if (chan == NULL || !chan->on || !chan->AmChanOp) + return; + + user = chan->users; + while (user != NULL) + { + if (user->chanop) + { + changemode(channel, "-o", user->N->nick, 0); + user->chanop = 0; + } + user = user->next; + } + flushmode(channel); +} diff --git a/Sources/patch.c b/Sources/patch.c new file mode 100644 index 0000000..2350610 --- /dev/null +++ b/Sources/patch.c @@ -0,0 +1,351 @@ +/* @(#)$Id: patch.c,v 1.3 1996/11/13 00:40:46 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" +#include + +#ifdef UPGRADE + +static void misc_closed_conn(misc_socket *); + +void upgrade(char *source, char *args) +{ + char global[]="*"; + + if(Access(global,source)type=MISC_GETPATCH; + msock->status=MISC_CONNECTING; + msock->TS=now; + strcpy(msock->link,source); + msock->inbuf=NULL; + msock->outbuf=NULL; + + if((msock->fd=socket(AF_INET,SOCK_STREAM,0))<0){ + free(msock); + sprintf(buffer,"Can't assigned fd for socket: %s",sys_errlist[errno]); + notice(source,buffer); + return; + } + + fcntl(msock->fd,F_SETFL,O_NONBLOCK); + + socketname.sin_family=AF_INET; + if((remote_host=gethostbyname(pserver))==NULL){ + sprintf(buffer,"gethostbyname() failed for %s: %s",pserver,sys_errlist[errno]); + notice(source,buffer); + close(msock->fd); + free(msock); + return; + } + + memcpy((void *)&socketname.sin_addr,(void *)remote_host->h_addr,remote_host->h_length); + socketname.sin_port = htons(port); + + if(connect(msock->fd,(struct sockaddr *)&socketname,sizeof(socketname))<0 + && errno != EINPROGRESS){ + close(msock->fd); + sprintf(buffer,"Can't connect() to %s: %s",pserver,sys_errlist[errno]); + notice(source,buffer); + free(msock); + return; + } + + msock->next=MiscList; + MiscList=msock; + + send_misc_handshake(msock); +} + + +int readfrom_misc(misc_socket *msock) +{ + void parse_misc(misc_socket *,char *); + char buf[1024]; + int length; + if((length=read(msock->fd,buf,1023))<=0){ + if(errno==EWOULDBLOCK || errno==EAGAIN){ + return 0; + }else{ + misc_closed_conn(msock); + close(msock->fd); + msock->fd=-1; + msock->status=MISC_ERROR; + return -1; + } + } + buf[length]='\0'; + + copy_to_buffer(&msock->inbuf,buf,length); + + if(find_char_in_buffer(&msock->inbuf,'\n',1023)){ + while(find_char_in_buffer(&msock->inbuf,'\n',1023)){ + copy_from_buffer(&msock->inbuf,buf,'\n',1023); + parse_misc(msock,buf); + } + } + + return 1; +} + + +int flush_misc_buffer(misc_socket *msock) +{ + char buf[1024]; + int length; + int count; + + if(msock->status==MISC_CONNECTING){ + msock->status=MISC_HANDSHAKE; + notice(msock->link,"Connected."); + } + + if(msock==NULL || msock->outbuf==NULL) + return -1; + + while((count = look_in_buffer(&msock->outbuf,buf,'\0',1023))>0){ + if((length=write(msock->fd,buf,count))<=0){ + if((errno==EWOULDBLOCK || errno==EAGAIN) && length!=0){ + return 0; + }else{ + misc_closed_conn(msock); + close(msock->fd); + msock->fd=-1; + msock->status=MISC_ERROR; + return -1; + } + }else{ + skip_char_in_buffer(&msock->outbuf,length); + } + } + + return 0; +} + + +long sendto_misc(misc_socket *msock, char *format, ...) +{ + va_list args; + char string[1024]; + + va_start(args,format); + vsprintf(string,format,args); +#ifdef DEBUG + vprintf(format,args); +#endif + va_end(args); + + return copy_to_buffer(&msock->outbuf,string,strlen(string)); +} + + +void send_misc_handshake(misc_socket *msock) +{ + struct stat stlast; + char tag[80], buffer[200]; + FILE *fp; + + if(msock->type==MISC_GETPATCH){ + if(stat("lastupgrade",&stlast)<0){ + sprintf(buffer,"lastupgrade: %s", + sys_errlist[errno]); + notice(msock->link,buffer); + close(msock->fd); + msock->status=MISC_ERROR; + } + fp=fopen("lastupgrade","r"); + if(fp==NULL){ + close(msock->fd); + msock->fd=-1; + msock->status=MISC_ERROR; + sprintf(buffer,"lastupgrade: %s",sys_errlist[errno]); + notice(msock->link,buffer); + return; + } + fgets(tag,80,fp); + fclose(fp); + + sendto_misc(msock,"%s\n%s\n",GETPATCHPASS,tag); + } +} + + +static void misc_closed_conn(misc_socket *msock) +{ + int pipefd[2],i; + char *ptr; + + if(msock->type==MISC_GETPATCH){ + if(msock->status==MISC_CONNECTING) + notice(msock->link,"Connection refused."); + else if(msock->status==MISC_HANDSHAKE) + notice(msock->link,"Handshake failed."); + else + notice(msock->link,"Connection closed."); + }else if(msock->type==MISC_PIPE_PATCH){ + notice(msock->link,"patch process exited."); + + pipe(pipefd); + switch(fork()){ + case 0: + dup2(pipefd[1],1); + dup2(pipefd[1],2); + close(0); + for(i=3;ilink,"fork() failed!"); + /* socket already closed.. */ + break; + default: + notice(msock->link,"Spawning make.."); + close(pipefd[1]); + ptr=msock->link; + msock=(misc_socket *)MALLOC(sizeof(misc_socket)); + msock->fd=pipefd[0]; + msock->type=MISC_PIPE_MAKE; + msock->status=MISC_RECV; + msock->TS=now; + strcpy(msock->link,ptr); + msock->inbuf=NULL; + msock->outbuf=NULL; + msock->next=MiscList; + MiscList=msock; + break; + } + }else if(msock->type==MISC_PIPE_MAKE){ + notice(msock->link,"make process exited."); + }else{ + notice(msock->link,"Connection closed."); + } +} + +void parse_misc(misc_socket *msock, char *line) +{ + FILE *fp; + int fdpipe[2],i; + char *ptr; + + if(msock->status==MISC_CONNECTING){ + msock->status=MISC_HANDSHAKE; + notice(msock->link,"Connected!"); + } + + while((ptr=strpbrk(line,"\r\n"))!=NULL) + *ptr='\0'; + + if(!*line) + return; + + if(msock->type==MISC_GETPATCH){ + if(msock->status==MISC_HANDSHAKE){ + if(strcmp(RECPATCHPASS,line)){ + close(msock->fd); + msock->fd=-1; + msock->status=MISC_ERROR; + notice(msock->link,"Bad password!"); + return; + } + msock->status=MISC_RECV; + }else if(msock->status==MISC_RECV){ + fp=fopen("lastupgrade","w"); + if(fp!=NULL){ + fprintf(fp,"%s\n",line); + fclose(fp); + } + + /* spawn patch */ + pipe(fdpipe); + switch(fork()){ + case 0: + fcntl(msock->fd,F_SETFL,0); + dup2(msock->fd,0); + dup2(fdpipe[1],1); + dup2(fdpipe[1],2); + for(i=3;ilink,"fork() failed"); + close(msock->fd); + msock->fd=-1; + msock->status=MISC_ERROR; + break; + default: + notice(msock->link,"Spawning patch script.."); + close(msock->fd); + while(msock->inbuf!=NULL){ + char buf[512]; + int l; + l=copy_from_buffer(&msock->inbuf,buf,'\0',511); + write(fdpipe[1],buf,l); + } + close(fdpipe[1]); + msock->fd=fdpipe[0]; + msock->type=MISC_PIPE_PATCH; + zap_buffer(&msock->outbuf); + break; + } + } + }else if(msock->type==MISC_PIPE_PATCH || msock->type==MISC_PIPE_MAKE){ + notice(msock->link,line); + } +} +#endif /* UPGRADE */ diff --git a/Sources/privmsg.c b/Sources/privmsg.c new file mode 100644 index 0000000..08b2e92 --- /dev/null +++ b/Sources/privmsg.c @@ -0,0 +1,405 @@ +/* @(#)$Id: privmsg.c,v 1.22 2000/10/24 16:04:24 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +void privmsg(char *source, char *target, char *body) +{ + register auser *user; + register achannel *chan; + register char *ptr; + char global[] = "*"; + +#ifdef DEBUG + printf("PRIVMSG from %s to %s\n", source, target); +#endif + + if ((*target == '#' || *target == '$') && strchr(target, '*')) + { +#ifdef DEBUG + printf("Received WALL... ignoring.. \n"); +#endif + return; + } + + /* CTCP */ + if (body[1] == '\001' && (ptr = strchr(body + 2, '\001')) != NULL) + { + if (*target == '#' || *target == '&') + { + if (CheckFlood(source, target, strlen(ToWord(1, body + 1)))) + return; + } + + *ptr = '\0'; + if (!IsIgnored(source) && + !CheckPrivateFlood(source, strlen(body), "CTCP-")) + parse_ctcp(source, target, body + 2); + } + + /* PRIVMSG TO A CHANNEL */ + else if (*target == '#' || *target == '&') + { + /* PRIVMSG #blah@channels.undernet.org ?? */ + if (!(chan = ToChannel(target))) + return; + chan->lastact = now; + user = ToUser(target, source); + if (!user) + return; /* not on channel.. happens if not +n */ + user->lastact = now; + + if (CheckFlood(source, target, strlen(ToWord(1, body + 1)))) + return; + + if (!strncmp(body + 1, COMMAND_PREFIX, strlen(COMMAND_PREFIX))) + parse_command(source, target, target, body + strlen(COMMAND_PREFIX) + 1); + + /* PRIVATE PRIVMSG */ + } + else + { + if (!IsIgnored(source) && !CheckPrivateFlood(source, strlen(body), "MSG-")) + { +#ifdef FAKE_UWORLD + if (!strcasecmp(target, UFAKE_NICK)) + { + parse_uworld_command(source, body + 1); + } + else +#endif + parse_command(source, target, global, body + 1); + } + } +} + +void parse_command(char *source, char *target, char *channel, char *commandline) +{ + char buffer[1024]; + char command[80]; + char global[] = "*"; + register aluser *user; + + GetWord(0, commandline, command); + +#ifdef DEBUG + printf("PARSING COMMAND: %s\nCOMMAND: %s\nARGS: %s\nSOURCE: %s\n", + commandline, command, ToWord(1, commandline), source); +#endif + + user = ToLuser(source); + + /* all commands must come from a user */ + if (user == NULL) + return; + + if (strcasecmp(command, "pass") && strcasecmp(command, "login") && + strcasecmp(command, "newpass")) + { + sprintf(buffer, "COMMAND FROM %s!%s@%s on %s: %s", + user->nick, user->username, user->site, + channel, commandline); + log(buffer); + } + else + { + sprintf(buffer, "COMMAND FROM %s!%s@%s on %s: %s XXXXXXX", + user->nick, user->username, user->site, + channel, command); + log(buffer); + } + + if (!strcmp(command, "showcommands")) + showcommands(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "pass") || !strcmp(command, "login")) + validate(source, target, ToWord(1, commandline)); + + else if (!strcmp(command, "deauth")) + DeAuth(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "die") && Access(global, source) >= LEVEL_DIE) + quit(ToWord(1, commandline), 0); + + else if (!strcmp(command, "restart") && Access(global, source) >= LEVEL_DIE) + restart(ToWord(1, commandline)); /* added by Kev; restarts */ + + else if (!strcmp(command, "search")) + SearchChan(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "join")) + join(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "part")) + part(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "op")) + op(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "deop")) + deop(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "banlist")) + showbanlist(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "kick")) + kick(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "invite")) + invite(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "topic")) + topic(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "adduser")) + AddUser(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "remuser")) + RemoveUser(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "modinfo")) + ModUserInfo(source, target, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "newpass")) + ChPass(source, target, ToWord(1, commandline)); + + else if (!strcmp(command, "set")) + SetChanFlag(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "access")) + showaccess(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "suspend")) + suspend(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "unsuspend")) + unsuspend(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "saveuserlist")) + SaveUserList(source, channel); + + else if (!strcmp(command, "lbanlist")) + ShowShitList(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "ban")) + AddToShitList(source, channel, ToWord(1, commandline), 0); + + else if (!strcmp(command, "unban")) + RemShitList(source, channel, ToWord(1, commandline), 0); + + else if (!strcmp(command, "cleanbanlist")) + CleanShitList(source, ToWord(1, commandline)); + + else if (!strcmp(command, "addchan")) + AddChan(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "remchan")) + RemChan(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "savedefs")) + SaveDefs(source); + + else if (!strcmp(command, "loaddefs")) + LoadDefs(source); + + else if (!strcmp(command, "saveshitlist")) + SaveShitList(source, channel); + + else if (!strcmp(command, "loadshitlist")) + LoadShitList(source); + + else if (!strcmp(command, "status")) + showstatus(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "map")) + showmap(source); + + else if (!strcmp(command, "help")) + showhelp(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "chaninfo")) + ShowChanInfo(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "motd")) + showmotd(source); + + else if (!strcmp(command, "isreg")) + isreg(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "core")) + dumpcore(source); + +#ifdef RUSAGE_SELF + else if (!strcmp(command, "rusage")) + show_rusage(source); +#endif + + else if (!strcmp(command, "showignore")) + ShowIgnoreList(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "remignore")) + AdminRemoveIgnore(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "calmdown")) + CalmDown(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "operjoin")) + OperJoin(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "operpart")) + OperPart(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "clearmode")) + ClearMode(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "purge")) + purge(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "verify")) + verify(source, ToWord(1, commandline)); + +#ifdef UPGRADE + else if (!strcmp(command, "upgrade")) + upgrade(source, ToWord(1, commandline)); +#endif + + else if (!strcmp(command, "random")) + RandomChannel(source); + + else if (!strcmp(command, "say")) + Say(source, ToWord(1, commandline)); + + else if (!strcmp(command, "servnotice")) + ServNotice(source, ToWord(1, commandline)); + + else if (!strcmp(command, "fuck")) + notice(source, "This command is obsolete"); + +#ifdef DEBUG + else if (!strcmp(command, "db")) + db_test(source, channel, ToWord(1, commandline)); +#endif + +#ifdef DOHTTP + else if (!strcmp(command, "rehash")) + read_http_conf(source); +#endif +#ifdef FAKE_UWORLD + else if (!strcmp(command, "uworld")) + Uworld_switch(source, channel, ToWord(1, commandline)); + + else if (!strcmp(command, "opersuspend")) + OperSuspend(source, ToWord(1, commandline)); +#endif + +#ifdef DEBUG + else if (!strcmp(command, "showusers")) + showusers(ToWord(1, commandline)); + + else if (!strcmp(command, "showchannels")) + showchannels(); +#endif + +#ifdef NICKSERV + else if (!strcmp(command, "nickserv")) + nserv_nickserv(source, ToWord(1, commandline)); + + else if (!strcmp(command, "addnick")) + nserv_addnick(source, ToWord(1, commandline)); + + else if (!strcmp(command, "remnick")) + nserv_remnick(source, ToWord(1, commandline)); + + else if (!strcmp(command, "addmask")) + nserv_addmask(source, ToWord(1, commandline)); + + else if (!strcmp(command, "remmask")) + nserv_remmask(source, ToWord(1, commandline)); + + else if (!strcmp(command, "nickinfo")) + nserv_nickinfo(source, ToWord(1, commandline)); + + else if (!strcmp(command, "identify")) + nserv_identify(source, ToWord(1, commandline)); + + else if (!strcmp(command, "ghost")) + nserv_ghost(source, ToWord(1, commandline)); + + else if (!strcmp(command, "nicknewpass")) + nserv_nicknewpass(source, ToWord(1, commandline)); + + else if (!strcmp(command, "nicknewemail")) + nserv_nicknewemail(source, ToWord(1, commandline)); +#endif +#ifdef DOHTTP + else if (!strcmp(command, "dccme")) + DccMe(source, ToWord(1, commandline)); +#endif +} + +void parse_ctcp(char *source, char *target, char *body) +{ + char func[80]; + char buffer[1024]; + char tmp[80]; + + GetWord(0, body, func); + body = ToWord(1, body); + + if (strcmp(func, "ACTION")) + { + sprintf(buffer, "CTCP %s from %s [%s]", func, source, body); + log(buffer); + } + + if (match(func, "PING")) + { + sprintf(buffer, "\001PING %s\001", body); + notice(source, buffer); + } + else if (match(func, "TIME")) + { + strcpy(tmp, ctime(&now)); + *strchr(tmp, '\n') = '\0'; + sprintf(buffer, "\001TIME %s\001", tmp); + notice(source, buffer); + } + else if (match(func, "ITIME")) + { + sprintf(buffer, "\001ITIME @%03ld\001", + 1000 * ((now + 3600) % 86400) / 86400); + notice(source, buffer); + } + else if (match(func, "VERSION")) + { + sprintf(buffer, "\001VERSION %s\001", VERSION); + notice(source, buffer); + } + else if (match(func, "GENDER")) + { + notice(source, "\001GENDER I'm a male bot! Are you a pretty young bottesse?\001"); + } +} diff --git a/Sources/prototypes.h b/Sources/prototypes.h new file mode 100644 index 0000000..1e3f3f4 --- /dev/null +++ b/Sources/prototypes.h @@ -0,0 +1,271 @@ +/* @(#)$Id: prototypes.h,v 1.20 2000/10/24 15:15:53 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +void log(char *); +void SpecLog(char *); +void LogChan(void); +int connection(char *); +void try_later(char *); +void sendtoserv(char *); +int wait_msg(void); +void dumpbuff(void); +void rec_sigsegv(int); +void rec_sigbus(int); +void rec_sigterm(int); +void rec_sigint(int); +void dumpcore(char *); +void show_rusage(char *); +void regist(void); +void signon(void); +void onserver(char *,char *,char *); +void onsettime(char *,char *); +void onsquit(char *,char *,char *); +aserver *ToServer(char *); +aserver **FindServer(aserver **, char *); +char *ToWord(int,char *); +void GetWord(int,char *,char *); +char *time_remaining(time_t); +void proc(char *,char *, char *, char *); +void pong(char *); +void showversion(char *); +int reconnect(char *server); +int xmatch(char *, char *); +int compare(char *, char *); +int match(char *, char *); +int regex_cmp(char *patern, char *string); +int mycasecmp(char *,char *); +int key_match(char *,char *[]); +void string_swap(char *, size_t, char *, char *); +int quit(char *, int); +int restart(char *); /* added for restart function -Kev */ +void showcommands(char *,char *,char *); +void showhelp(char *,char *,char *); +void showmotd(char *); +void ShowChanInfo(char *,char *,char *); +void isreg(char *,char *,char *); +void LoadUserList(char *); +void SaveUserList(char *,char *); +void DelChannel(char *); +void FreeUser(auser *); +void NewChannel(char *,time_t,int); +void QuitAll(void); +void privmsg(char *,char *,char *); +void parse_command(char *,char *,char *,char *); +int GuessChannel(char *, char *); +void try_find(char *,aluser *); +int LAccess(char *,aluser *); +int Access(char *,char *); +void verify(char *, char *); +RegUser *IsValid(aluser *,char *); +int IsShit(char *,char *,char *, char *); +void AddUser(char *,char *,char *); +void showaccess(char *,char *,char *); +void RemoveUser(char *,char *,char *); +void ModUserInfo(char *,char *,char *,char *); +void purge(char *,char *,char *); +void ChPass(char *,char *,char *); +void SetChanFlag(char *,char *,char *); +void free_user(RegUser **); +void validate(char *,char *,char *); +void DeAuth(char *, char *, char *); +void join(char *,char *,char *); +void joindefault(void); +void SendBurst(void); +void invite(char *,char *,char *); +void part(char *,char *,char *); +void oninvite(char *,char *); +void onjoin(char *,char *); +void onpart(char *,char *); +void onkick(char *,char *,char *); +void onop(char *,char *,char *); +void ondeop(char *,char *,char *,int *); +void GetOps(char *); +int IsOpless(char *); +void onopless(char *); +void onnick(char *,char *,char *); +void onban(char *,char *,char *); +void onunban(char *,char *,char *); +void showbanlist(char *,char *,char *); +void AddBan(char *,char *); +void RemBan(char *,char *); +void onwhois(char *,char *); +void UserQuit(char *); +achannel *ToChannel(char *); +auser *ToUser(char *,char *); +aluser *ToLuser(char *); +void onquit(char *); +void onkill(char *,char *,char *); +void onwho(char *); +void showusers(char *); +void showchannels(void); +void setchanmode(char *); +void ModeChange(char *,char *,char *); +void changemode(char *,char *,char *,int); +void flushmode(char *); +void bounce(char *,char *,time_t); +int IsSet(char *,char,char *); +void op(char *,char *,char *); +void deop(char *,char *,char *); +void massdeop(char *); +void MakeBanMask(aluser *, char *); +void ban(char *,char *,char *); +void mban(char *,char *,char *); +void unban(char *,char *,char *); +void kick(char *,char *,char *); +void topic(char *,char *,char *); +void notice(char *,char *); +void servnotice(char *,char *); +void broadcast(char *,int); +void NickInUse(void); +void ChNick(char *); +void AddToShitList(char *, char *, char *,int); +void RemShitList(char *,char *,char *,int); +void CleanShitList(char *,char *); +void suspend(char *, char *, char *); +void unsuspend(char *, char *, char *); +void ShowShitList(char *,char *,char *); +void LoadDefs(char *); +void SearchChan(char *,char *,char *); +void AddChan(char *,char *,char *); +void SaveDefs(char *); +void RemChan(char *, char *, char *); +int CheckFlood(char *,char *,int); +int CheckAdduserFlood(char *, char *); +void ontopic(char *,char *,char *); +void onnotice(char *,char *,char *); +void LoadShitList(char *); +void SaveShitList(char *,char *); +void parse_ctcp(char *,char *,char *); +void showstatus(char *,char *,char *); +void showmap(char *); +void showserv(char *,aserver *, int *); +void InitEvent(void); +void AddEvent(int, time_t, char *); +void CheckEvent(void); +void CleanIgnores(void); +void AddIgnore(char *,char *,int); +int CheckPrivateFlood(char *,int,char *); +int CheckFloodFlood(char *,int); +int IsIgnored(char *); +void ShowIgnoreList(char *,char *,char *); +void AdminRemoveIgnore(char *, char *, char *); +void CalmDown(char *,char *,char *); +void OperJoin(char *,char *,char *); +void OperPart(char *,char *,char *); +void ClearMode(char *, char *, char *); +void ReplyNotAccess(char *,char *); +void CheckIdleChannels(void); +void RandomChannel(char *); +void Say(char *,char *); +void RobinSay(char *,char *); +void ServNotice(char *,char *); +int IsReg(char *); +#ifdef FAKE_UWORLD +void IntroduceUworld(void); +void KillUworld(char *); +void Uworld_switch(char *,char *,char *); +void parse_uworld_command(char *,char *); +void Uworld_opcom(char *,char *); +void ClearChan(char *, char *); +void Uworld_reop(char *, char *); +void OperSuspend(char *, char *); +int IsOperSuspended(char *); +#endif +#ifdef NICKSERV +void IntroduceNickserv(void); +#endif +#ifdef DOHTTP +void open_http(void); +void remove_httpsock(http_socket *old); +void http_accept(int sock); +void parse_http(http_socket *hsock, char *buf); +void readfrom_file(http_file_pipe *fpipe); +void destroy_file_pipe(http_file_pipe *old); +void read_http_conf(char *); +long sendto_http(http_socket *sck, char *format, ...); +int readfrom_http(http_socket *); +int flush_http_buffer(http_socket *); +#endif +void upgrade(char *,char *); +void open_patch_socket(char *); +int readfrom_misc(misc_socket *); +int flush_misc_buffer(misc_socket *); +long sendto_misc(misc_socket *, char *, ...); +void send_misc_handshake(misc_socket *); + +struct buffer_block *get_buffer_block(void); +void return_buffer_block(struct buffer_block *); +int copy_from_buffer(struct buffer_block **, char *, char, int); +int look_in_buffer(struct buffer_block **, char *, char, int); +long copy_to_buffer(struct buffer_block **, char *,int); +int zap_buffer(struct buffer_block **); +int find_char_in_buffer(struct buffer_block **, char,int); +int skip_char_in_buffer(struct buffer_block **, int); +char *make_dbfname(char *); +int db_fetch(char *,unsigned int,char *,char *,int,void *,void *,DBCALLBACK(x)); +void read_db(dbquery *); +void end_db_read(dbquery *); +void db_sync(char *); +void db_sync_ready(dbsync *); +void end_db_sync(dbsync *); +void db_test(char *, char *,char *); +void gather_sync_channels(void); +void sync_next_channel(void); +void do_cold_sync(void); +void do_cold_sync_slice(void); +#ifdef HISTORY +void History(char *); +#endif + + +int ul_hash(char *); +int sl_hash(char *); +int lu_hash(char *); +int cl_hash(char *); +int su_hash(char *); + + +#ifdef NICKSERV +void IntroduceNickserv(void); +void KillNickserv(char *msg); +void nserv_nickserv(char *source, char *args); +void nserv_addnick(char *source, char *args); +void nserv_addmask(char *source, char *args); +void nserv_remnick(char *source, char *args); +void nserv_remmask(char *source, char *args); +void nserv_nickinfo(char *source, char *args); +void nserv_identify(char *source, char *args); +void nserv_ghost(char *source, char *args); +void nserv_nicknewpass(char *source, char *args); +void nserv_nicknewemail(char *source, char *args); +void nserv_save(void); +void nserv_load(void); +void nserv_checkregnick(char *nick); +void nserv_quit(aluser *user); +void nserv_nick(char *newnick, aluser *user); +void nserv_onop(char *channel, auser *user); +#endif +void DccMe(char *, char *); diff --git a/Sources/replies.c b/Sources/replies.c new file mode 100644 index 0000000..23ffed0 --- /dev/null +++ b/Sources/replies.c @@ -0,0 +1,614 @@ +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + + +/* Very appreciated contribution from: (just add your name here) + Stephan Mantler aka Step + Carlo Kid aka Run + nirvana + */ + +#include "h.h" + +alang Lang[NO_LANG] = +{ + {L_ENGLISH, "en", "english"}, + {L_DUTCH, "nl", "dutch"}, + {L_FRENCH, "fr", "français"}, + {L_SPANISH, "es", "español"}, + {L_GERMAN, "de", "deutsch"} +}; + +/* the %s will be expanded to the channel name + notaccessreply is only english for now */ +char *notaccessreply[] = +{ + "%s: Nice try. But I'm not a fool!", + "%s: Cheating is very bad you know!", + "%s: Do I know you?", + "You should come on %s more often", + "Ha! Ha! I don't think people on %s would like that!", + "%s: Pfft! Nice try!", + "%s: No, I don't think so.. you're not my type :P", + "go read the %s manual.. then I might consider it", + "I would.. but.. one teensy problem. You're not in %s's database", + "Oh.. are you trying to communicate with me?", + "You see, %s is some kinda private thing...", + NULL +}; + +void ReplyNotAccess(char *nick, char *channel) +{ + static int index = 0; + register int i; + char buffer[200]; + + for (i = rand() % 5 + 1; i > 0; i--) + if (notaccessreply[++index] == NULL) + index = 0; + + sprintf(buffer, notaccessreply[index], channel); + notice(nick, buffer); +} + +void RandomChannel(char *source) +{ + register int hash, offset; + register achannel *chan; + char buffer[200]; + + hash = rand() % 1000; + offset = rand() % 100; + + chan = ChannelList[hash]; + while (chan == NULL) + { + chan = ChannelList[(++hash) % 1000]; + if (hash > 2000) + return; + } + while (offset > 0 && !chan->on) + { + chan = chan->next; + if (chan == NULL) + { + while (chan == NULL) + { + chan = ChannelList[(++hash) % 1000]; + if (hash > 2000) + return; + } + } + offset--; + } + sprintf(buffer, "%s is cool!", chan->name); + notice(source, buffer); +} + +void Say(char *source, char *args) +{ + char buffer[1024], target[80], global[] = "*"; + + if (Access(global, source) < 900) + { + return; /*silently */ + } + + GetWord(0, args, target); + args = ToWord(1, args); + + if (!*target || !*args) + { + notice(source, "Syntax: say [#channel] [whatever]"); + return; + } + + sprintf(buffer, ":%s PRIVMSG %s :%s\n", mynick, target, args); + sendtoserv(buffer); +} + + +void ServNotice(char *source, char *args) +{ + char buffer[1024], target[80], global[] = "*"; + + if (Access(global, source) < 600) + { + return; /*silently */ + } + + GetWord(0, args, target); + args = ToWord(1, args); + + if (!*target || !*args) + { + notice(source, "SYNTAX: servnotice [#channel] [whatever]"); + return; + } + + sprintf(buffer, "[Channel Service: %s] %s", source, args); + servnotice(target, buffer); +} + + +char *replies[][NO_LANG] = +{ +/* RPL_NOTONCHANNEL */ + {"I am not on that channel!", /* english */ + "Ik zit niet op dat kanaal!", /* dutch */ + "Je ne suis pas sur ce canal!", /* french */ + "No estoy en ese canal!", /* spanish */ + "Ich bin nicht auf diesem Kanal!" /* german */ + }, + +/* RPL_NOTCHANOP */ + {"I am not channel operator", /* english */ + "Ik ben geen channel operator", /* dutch */ + "Je ne suis pas opérateur de canal", /* french */ + "No soy operador del canal", /* spanish */ + "Ich bin kein Betreiber auf diesem Kanal" /* german */ + }, + +/* RPL_OPONLY */ + {"This channel is in OpOnly Mode", /* english */ + "Dit kanaal is in OpOnly Mode", /* dutch */ + "Ce canal est en mode OpOnly", /* french */ + "Ese canal está en modo OpOnly", /* spanish */ + "Dieser Kanal is im OpOnly-Modus" /* german */ + }, + +/* RPL_OPSELFONLY */ + {"You can only op yourself in OpOnly mode", /* english */ + "In OpOnly mode mag je alleen jezelf operator maken", /* dutch */ + "Vous ne pouvez opper que vous-même en mode OpOnly", /* french */ + "Solo puedes ser operador en modo OpOnly", /* spanish */ + "Sie koennen nur sich selbst zum Betreiber machen (Kanal im OpOnly-Modus)" /* german */ + }, + +/* RPL_NOSUCHNICK */ + {"No such nickname", /* english */ + "Deze NICK is niet in gebruik", /* dutch */ + "Ce nick n'existe pas", /* french */ + "Ese nick no existe", /* spanish */ + "Diesen Nickname gibt es nicht" /* german */ + }, + +/* RPL_ALREADYONCHANNEL */ + {"This user is already on channel", /* english */ + "Deze persoon is al op dat kanaal", /* dutch */ + "Cet usager est déjà sur le canal", /* french */ + "Ese usuario ya está en el canal", /* spanish */ + "Dieser Benutzer ist bereits auf dem Kanal" /* german */ + }, + +/* RPL_IINVITED */ + {"I invited %s to %s", /* english */ + "%s is uitgenodigd naar %s te komen", /* dutch */ + "J'ai invité %s sur %s", /* french */ + "Yo he invitado a %s en %s", /* spanish */ + "Ich haben %s eingeladen, auf %s zu kommen" /* german */ + }, + +/* RPL_YOUAREINVITED */ + {"%s invites you to %s", /* english */ + "%s vraagt of naar %s komt", /* dutch */ + "%s vous invite sur %s", /* french */ + "%s te invita en %s", /* spanish */ + "%s laedt Sie ein, auf %s zu kommen" /* german */ + }, + +/* RPL_ALWAYSOPWASACTIVE */ + {"AlwaysOp was active! It's now deactivated", /* english */ + "AlwaysOp was actief! Het is nu uitgeschakeld", /* dutch */ + "AlwaysOp était actif! Il est maintenant désactivé", /* french */ + "AlwaysOp estaba activado! Ahora ya esta desactivado", /* spanish */ + "AlwaysOp war aktiv! Es wurde ausgeschalten" /* german */ + }, + +/* RPL_ALWAYSOP */ + {"This channel is in AlwaysOp mode!", /* english */ + "Dit kanaal is in AlwaysOp mode!", /* dutch */ + "Ce canal est en mode AlwaysOp!", /* french */ + "Este canal está en modo AlwaysOp!", /* spanish */ + "Dieser Kanal is im AlwaysOp-Modus!" /* german */ + }, + +/* RPL_KICK1ST */ + {"You are not allowed to KICK me!", /* english */ + "Het is niet toegestaan mij te KICKen!", /* dutch */ + "Vous n'avez pas le droit de me kicker!", /* french */ + "No estas autorizado para kickearme!", /* spanish */ + "Sie duerfen mich nicht kicken!" /* german */ + }, + +/* RPL_KICK2ND */ + {"Please STOP kicking me!", /* english */ + "STOP mij te KICKen!", /* dutch */ + "Veuillez arrêter de me kicker!", /* french */ + "Por favor ¡para de kickearme!", /* spanish */ + "Bitte hoeren Sie auf, mich zu kicken!" /* german */ + }, + +/* RPL_CHANNOTEXIST */ + {"That channel does not exist!", /* english */ + "Dat kanaal bestaat niet!", /* dutch */ + "Ce canal n'existe pas!", /* french */ + "Ese canal no existe!", /* spanish */ + "Diesen Kanal gibt es nicht!" /* german */ + }, + +/* RPL_BADFLOODLIMIT */ + {"value of FLOODPRO must be in the range [3-20] or 0 to turn it off", + "FLOODPRO moet een waarde hebben tussen 3 en 20 of 0 om het uit te schakelen", + "la valeur de FLOODPRO doit être entre 3 et 20 ou 0 pour le désactiver", + "El valor de FLOODPRO tiene que estar entre 3 y 20 ó 0 para desactivarlo", + "der Wert fon FLOODPRO muss im Bereich von 3 und 20 sein (oder 0 um es abzuschalten)" + }, + +/* RPL_SETFLOODLIMIT */ + {"value of FLOODPRO is now %d", /* english */ + "De waarde van FLOODPRO is nu %d", /* dutch */ + "la valeur de FLOODPRO est maintenant %d", /* french */ + "El valor de FLOOPRO está ahora %d", /* spanish */ + "FLOODPRO hat jetzt den Wert %d" /* german */ + }, + +/* RPL_BADNICKFLOODLIMIT */ + {"value of NICKFLOODPRO must be in the range [3-10] or 0 to turn it off", + "NICKFLOODPRO moet een waarde hebben tussen 3 en 10 of 0 om het uit te schakelen", + "la valeur de NICKFLOODPRO doit être entre 3 et 10 ou 0 pour le désactiver", + "El valor de NICKFLOOPRO tiene que estar entre 3 y 10 ó 0 para desactivarlo", + "Werte fuer NICKFLOODPRO muessen im Bereich von 3 bis 10 sein. Oder 0 um es abzuschalten" + }, + +/* RPL_SETNICKFLOODLIMIT */ + {"value of NICKFLOODPRO is now %d", /* english */ + "De waarde van NICKFLOODPRO is nu %d", /* dutch */ + "la valeur de NICKFLOODPRO est maintenant %d", /* french */ + "El valor de NICKFLOOPRO está ahora en %d", /* spanish */ + "der Wert fuer NICKFLOODPRO ist jetzt %d" /* german */ + }, + +/* RPL_BADMASSDEOPLIMIT */ + {"value of MASSDEOPPRO must be in the range [3-10] or 0 to turn it off", + "MASSDEOPPRO moet een waarde hebben tussen 3 en 10 of 0 om het uit te schakelen", + "la valeur de MASSDEOPPRO doit être entre 3 et 10 ou 0 pour le désactiver", + "El valor de MASSDEOPPRO tiene que estar entre 3 y 10 ó 0 para desactivarlo", + "der Wert von MASSDEOPPRO muss zwischen 3 und 10 liegen, oder 0 um es abzuschalten" + }, + +/* RPL_SETMASSDEOPLIMIT */ + {"value of MASSDEOPPRO is now %d", /* english */ + "De waarde van MASSDEOPPRO is nu %d", /* dutch */ + "la valeur de MASSDEOPPRO est maintenant %d", /* french */ + "El valor de MASSDEOPPRO está ahora en %d", /* spanish */ + "MASSDEOPPRO ist jetzt %d" /* german */ + }, + +/* RPL_NOOPON */ + {"value of NOOP is now ON", /* english */ + "NOOP mode is nu ingeschakeld", /* dutch */ + "la valeur de NOOP est maintenant ON", /* french */ + "El valor de NOOP está ahora en ON", /* spanish */ + "NOOP hat jetzt den Wert EIN" /* german */ + }, + +/* RPL_NOOPOFF */ + {"value of NOOP is now OFF", /* english */ + "NOOP mode is nu uit", /* dutch */ + "la valeur de NOOP est maintenant OFF", /* french */ + "El valor de NOOP está ahora en OFF", /* spanish */ + "NOOP hat jetzt den Wert AUS" /* german */ + }, + +/* RPL_BADNOOP */ + {"value of NOOP must be ON or OFF", /* english */ + "Kies 'ON' of 'OFF' voor de waarde van NOOP", /* dutch */ + "la valeur de NOOP doit être ON ou OFF", /* french */ + "El valor de NOOP debe ser ON o OFF", /* spanish */ + "NOOP kann nur EIN oder AUS sein" /* german */ + }, + +/* RPL_ALWAYSOPON */ + {"value of ALWAYSOP is now ON", /* english */ + "ALWAYSOP mode is nu ingeschakeld", /* dutch */ + "la valeur de ALWAYSOP est maintenant ON", /* french */ + "El valor de ALWAYSOP es ahora ON", /* spanish */ + "ALWAYSOP ist jetzt EIN" /* german */ + }, + +/* RPL_ALWAYSOPOFF */ + {"value of ALWAYSOP is now OFF", /* english */ + "ALWAYSOP mode is nu uit", /* dutch */ + "la valeur de ALWAYSOP est maintenant OFF", /* french */ + "El valor de ALWAYSOP es ahora OFF", /* spanish */ + "ALWAYSOP ist jetzt AUS" /* german */ + }, + +/* RPL_BADALWAYSOP */ + {"value of ALWAYSOP must be ON or OFF", /* english */ + "Kies 'ON' of 'OFF' voor de waarde van ALWAYSOP", /* dutch */ + "la valeur de ALWAYSOP doit être ON ou OFF", /* french */ + "El valor de ALWAYSOP debe ser ON o OFF", /* spanish */ + "Werte fuer ALWAYSOP sind EIN oder AUS" /* german */ + }, + +/* RPL_OPONLYON */ + {"value of OPONLY is now ON", /* english */ + "OPONLY mode is nu ingeschakeld", /* dutch */ + "la valeur de OPONLY est maintenant ON", /* french */ + "El valor de OPONLY es ahora ON", /* spanish */ + "der Wert fuer OPONLY ist jetzt EIN" /* german */ + }, + +/* RPL_OPONLYOFF */ + {"value of OPONLY is now OFF", /* english */ + "OPONLY mode is nu uit", /* dutch */ + "la valeur de OPONLY est maintenant OFF", /* french */ + "El valor de OPONLY es ahora OFF", /* spanish */ + "der Wert fuer OPONLY ist jetzt AUS" /* german */ + }, + +/* RPL_BADOPONLY */ + {"value of OPONLY must be ON or OFF", /* english */ + "Kies 'ON' of 'OFF' voor de waarde van OPONLY", /* dutch */ + "la valeur de OPONLY doit être ON ou OFF", /* french */ + "El valor de OPONLY debe ser ON o OFF", /* spanish */ + "Werte fuer OPONLY sind EIN oder AUS" /* german */ + }, + +/* RPL_AUTOTOPICON */ + {"value of AUTOTOPIC is now ON", /* english */ + "AUTOTOPIC mode is nu ingeschakeld", /* dutch */ + "la valeur de AUTOTOPIC est maintenant ON", /* french */ + "El valor de AUTOTOPIC es ahora ON", /* spanish */ + "der Wert fuer AUTOTOPIC ist jetzt EIN" /* german */ + }, + +/* RPL_AUTOTOPICOFF */ + {"value of AUTOTOPIC is now OFF", /* english */ + "AUTOTOPIC mode is nu uit", /* dutch */ + "la valeur de AUTOTOPIC est maintenant OFF", /* french */ + "El valor de AUTOTOPIC es ahora OFF", /* spanish */ + "der Wert fuer AUTOTOPIC ist jetzt AUS" /* german */ + }, + +/* RPL_BADAUTOTOPIC */ + {"value of AUTOTOPIC must be ON or OFF", /* english */ + "Kies 'ON' of 'OFF' voor de waarde van AUTOTOPIC", /* dutch */ + "la valeur de AUTOTOPIC doit être ON ou OFF", /* french */ + "El valor de AUTOTOPIC debe ser ON o OFF", /* spanish */ + "Werte fuer AUTOTOPIC sind EIN oder AUS" /* german */ + }, + +/* RPL_STRICTOPON */ + {"value of STRICTOP is now ON", /* english */ + "value of STRICTOP is now ON", /* dutch */ + "value of STRICTOP is now ON", /* french */ + "El valor de STRICTOP es ahora ON", /* spanish */ + "value of STRICTOP is now ON" /* german */ + }, + +/* RPL_STRICTOPOFF */ + {"value of STRICTOP is now OFF", /* english */ + "value of STRICTOP is now OFF", /* dutch */ + "value of STRICTOP is now OFF", /* french */ + "El valor de STRICTOP es ahora OFF", /* spanish */ + "value of STRICTOP is now OFF" /* german */ + }, + +/* RPL_BADSTRICTOP */ + {"value of STRICTOP must be ON or OFF", /* english */ + "value of STRICTOP must be ON or OFF", /* dutch */ + "value of STRICTOP must be ON or OFF", /* french */ + "El valor de STRICTOP debe ser ON o OFF", /* spanish */ + "value of STRICTOP must be ON or OFF" /* german */ + }, + +/* RPL_BADUSERFLAGS */ + {"New value can be 1-AUTOOP or 0-NO AUTOOP", + "De nieuwe waarde kan zijn 1-AUTOOP, 2-PROTECT ou 3-BOTH", + "La nouvelle valeur peut être 1-AUTOOP ou 0-PAS DE AUTOOP", + "El nuevo valor puede ser 1-AUTOOP o 0- NOAUTOOP", /* spanish */ + "Der neue Wert kann 1-AUTOOP, 2-PROTECT oder 3-BEIDE sein." + }, + +/* RPL_SETUSERFLAGS */ + {"value of USERFLAGS is now %d", /* english */ + "de waarde van USERFLAGS is nu %d", /* dutch */ + "la nouvelles valeur de USERFLAGS est %d", /* french */ + "El nuevo valor de USERFLAGS es ahora %d", /* spanish */ + "USERFLAGS ist jetzt %d" /* german */ + }, + +/* RPL_KNOWNLANG */ + {"Known languages are", /* english */ + "De volgende talen zijn bekend", /* dutch */ + "Je connais les langues", /* french */ + "Yo hablo y escribo los siguientes idiomas", /* spanish */ + "Folgende Sprachen sind bekannt" /* german */ + }, + +/* RPL_SETLANG */ + {"Default language is now %s (%s)", /* english */ + "De default taal is nu %s (%s)", /* dutch */ + "La langue par défaut est maintenant %s (%s)", /* french */ + "El idioma configurado por defecto es ahora %s (%s)", /* spanish */ + "Die neue Default-Sprache ist %s (%s)" /* german */ + }, + +/* RPL_STATUS1 */ + {"Channel %s has %d user%s (%d operator%s)", /* english */ + "Kanaal %s heeft %d deelnemer%s (%d operator%s)", /* dutch */ + "Canal %s a %d usager%s (%d opérateur%s)", /* french */ + "El canal %s tiene %d usuarios%s (%d operadores%s)", /* spanish */ + "Kanal %s hat %d Benutzer (%d Betreiber)" /* german */ +/* ### NOTE the german version does not use plurals! + The code reflects this. */ + }, + +/* RPL_STATUS2 */ + {"Mode is +%s", /* english */ + "Mode is +%s", /* dutch */ + "Le mode est +%s", /* french */ + "El modo es +%s", /* spanish */ + "Der Modus ist +%s" /* german */ + }, + +/* RPL_STATUS3 */ + {"Default user flags%s", /* english */ + "Default 'user flags'%s", /* dutch */ + "Flags d'usager par défaut%s", /* french */ + "Flags por defectos son %s", /* spanish */ + "Default-Flags fuer Benutzer %s" /* german */ + }, + +/* RPL_STATUS4 */ + {"Default language is %s", /* english */ + "Default taal is %s", /* dutch */ + "Langue par défaut %s", /* french */ + "Idioma por defecto %s", /* spanish */ + "Default-Sprache ist %s" /* german */ + }, + +/* RPL_STATUS5 */ + {"Channel has been idle for %d second%s", /* english */ + "Het kanaal is %d second%s idle", /* dutch */ + "Le canal est inactif depuis %d seconde%s", /* french */ + "El canal no está activo desde hace %d segundos%s", /* spanish */ + "Der Kanal ist seit %d Sekunden inaktiv." /* german */ + }, + +/* RPL_SETCHANDEFS */ + {"Channel defaults set.", /* english */ + "Kanaal defaults geregistreerd.", /* dutch */ + "L'état du canal est enregistré", /* french */ + "Los nuevos cambios han sido registrados", /* spanish */ + "Default-Werte fuer den Kanal wurden gesetzt" /* german */ + }, + +/* RPL_NOTDEF */ + {"That channel is not in my default channel list", /* english */ + "Dat kanaal staat niet in mijn default kanaal lijst", /* dutch */ + "Ce canal n'est pas sur ma liste", /* french */ + "Ese canal no está en mi lista por defecto", /* spanish */ + "Dieser Kanal ist nicht auf meiner Liste" /* german */ + }, + +/* RPL_REMDEF */ + {"Channel removed from default channel list", /* english */ + "Het kanaal is van de default kanaal lijst verwijderd", /* dutch */ + "Ce canal n'est plus sur ma liste", /* french */ + "Canal eliminado de la lista por defecto", /* spanish */ + "Der Kanal wurde aus meiner Liste entfernt" /* german */ + }, + +/* RPL_NOMATCH */ + {"No match.", /* english */ + "Niet gevonden.", /* dutch */ + "Introuvable", /* french */ + "No se encuentra", /* spanish */ + "Nicht gefunden." /* german */ + }, + +/* RPL_NOOP */ + {"Sorry. This channel is in NoOp mode!", /* english */ + "Sorry. Dit kanaal is in NoOp mode!", /* dutch */ + "Désolé. Ce canal est en mode NoOp!", /* french */ + "Lo siento, ¡Ese canal está en modo NoOp!", /* spanish */ + "Tut mir leid, aber dieser Kanal ist im NoOp-Modus!" /* german */ + }, + +/* RPL_CANTBEOP */ + {"Sorry. You are not allowed to be chanop", /* english */ + "Sorry. Het is niet toegestaan dat u kanaal operator bent", /* dutch */ + "Désolé. Il ne vous est pas permis d'être opérateur", /* french */ + "Lo siento. No estas autorizado para ser operador en el canal", /* spanish */ + "Tut mir leid, aber Sie duerfen nicht Betreiber werden." /*german */ + }, + +/* RPL_CANTBEOPPED */ + {"This user is not allowed to be chanop", /* english */ + "Deze gebruiker is het niet toegestaan kanaal operator te zijn", /* dutch */ + "Cet usager n'a pas le droit d'être opérateur", /* french */ + "Ese usuario no está autorizado para ser operador en el canal", /* spanish */ + "Dieser Benutzer darf nicht Betreiber werden." /* german */ + }, + +/* RPL_DEOPPED1ST */ + {"You are not allowed to DEOP me!", /* english */ + "Je mag me niet deoppen!", /* dutch */ + "Vous ne pouvez pas me deopper!", /* french */ + "¡No me puedes quitar el op!", /* spanish */ + "Sie duerfen mich nicht deoppen!" /* german */ + }, + +/* RPL_DEOPPED2ND */ + {"Please STOP deopping me!", /* english */ + "STOP met me te de-oppen!", /* dutch */ + "Veuillez arrêter de me deopper!", /* french */ + "Por favor, ¡para de quitarme el op!", /* spanish */ + "Bitte hoeren Sie auf, mich zu deoppen!" /* german */ + }, + +/* RPL_DEOPPED3RD */ + {"I warned you!", /* english */ + "Je was gewaarschuwd!", /* dutch */ + "Je vous aurai prévenu!", /* french */ + "¡Te he hecho una advertencia!", /* spanish */ + "Sie wurden gewarnt!" /* german */ + }, + +/* RPL_USERISPROTECTED */ + {"This user is protected", /* english */ + "Deze gebruiker is beschermd", /* dutch */ + "Cet usager est protégé", /* french */ + "Este usuario está protegido", /* spanish */ + "Dieser Benutzer ist geschuetzt" /* german */ + }, + +/* RPL_YOUREOPPEDBY */ + {"You're opped by %s", /* english */ + "U bent kanaal operator gemaakt door %s", /* dutch */ + "Vous êtes oppé par %s", /* french */ + "El %s te ha puesto de operador en el canal", /*spanish */ + "Sie wurden von %s zum Betreiber gemacht." /* german */ + }, + +/* RPL_USERNOTONCHANNEL */ + {"User %s is not on channel %s!", /* english */ + "%s bevindt zich niet op kanaal %s!", /* dutch */ + "%s n'est pas sur %s!", /* french */ + "El usuario %s no está presente en el canal %s!", /* spanish */ + "%s ist nicht auf dem Kanal %s!" /* german */ + }, + +/* RPL_YOUREDEOPPEDBY */ + {"You're deopped by %s", /* english */ + "Het kanaal operatorschap is u ontnomen door %s", /* dutch */ + "Vous êtes déoppé par %s", /* french */ + "El %s te quitó el status de op%s", /* spanish */ + "%s hat ihnen den Betreiberstatus entzogen" /* german */ + } +}; diff --git a/Sources/replies.h b/Sources/replies.h new file mode 100644 index 0000000..9eb18ea --- /dev/null +++ b/Sources/replies.h @@ -0,0 +1,83 @@ +/* @(#)$Id: replies.h,v 1.4 1996/11/13 00:40:47 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#define RPL_NOTONCHANNEL 0 +#define RPL_NOTCHANOP 1 +#define RPL_OPONLY 2 +#define RPL_OPSELFONLY 3 +#define RPL_NOSUCHNICK 4 +#define RPL_ALREADYONCHANNEL 5 +#define RPL_IINVITED 6 +#define RPL_YOUAREINVITED 7 +#define RPL_ALWAYSOPWASACTIVE 8 +#define RPL_ALWAYSOP 9 +#define RPL_KICK1ST 10 +#define RPL_KICK2ND 11 +#define RPL_CHANNOTEXIST 12 +#define RPL_BADFLOODLIMIT 13 +#define RPL_SETFLOODLIMIT 14 +#define RPL_BADNICKFLOODLIMIT 15 +#define RPL_SETNICKFLOODLIMIT 16 +#define RPL_BADMASSDEOPLIMIT 17 +#define RPL_SETMASSDEOPLIMIT 18 +#define RPL_NOOPON 19 +#define RPL_NOOPOFF 20 +#define RPL_BADNOOP 21 +#define RPL_ALWAYSOPON 22 +#define RPL_ALWAYSOPOFF 23 +#define RPL_BADALWAYSOP 24 +#define RPL_OPONLYON 25 +#define RPL_OPONLYOFF 26 +#define RPL_BADOPONLY 27 +#define RPL_AUTOTOPICON 28 +#define RPL_AUTOTOPICOFF 29 +#define RPL_BADAUTOTOPIC 30 +#define RPL_STRICTOPON 31 +#define RPL_STRICTOPOFF 32 +#define RPL_BADSTRICTOP 33 +#define RPL_BADUSERFLAGS 34 +#define RPL_SETUSERFLAGS 35 +#define RPL_KNOWNLANG 36 +#define RPL_SETLANG 37 +#define RPL_STATUS1 38 +#define RPL_STATUS2 39 +#define RPL_STATUS3 40 +#define RPL_STATUS4 41 +#define RPL_STATUS5 42 +#define RPL_SETCHANDEFS 43 +#define RPL_NOTDEF 44 +#define RPL_REMDEF 45 +#define RPL_NOMATCH 46 +#define RPL_NOOP 47 +#define RPL_CANTBEOP 48 +#define RPL_CANTBEOPPED 49 +#define RPL_DEOPPED1ST 50 +#define RPL_DEOPPED2ND 51 +#define RPL_DEOPPED3RD 52 +#define RPL_USERISPROTECTED 53 +#define RPL_YOUREOPPEDBY 54 +#define RPL_USERNOTONCHANNEL 55 +#define RPL_YOUREDEOPPEDBY 56 diff --git a/Sources/servers.c b/Sources/servers.c new file mode 100644 index 0000000..867140d --- /dev/null +++ b/Sources/servers.c @@ -0,0 +1,265 @@ +/* @(#)$Id: servers.c,v 1.9 1998/01/25 18:35:47 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +aserver **FindServer(aserver ** head, char *name) +{ + register aserver **tmp; + + if (head == NULL || *head == NULL) + return NULL; + + while (*head != NULL) + { + if (!strcasecmp((*head)->name, name)) + { + return head; + } + if ((tmp = FindServer(&(*head)->down, name)) != NULL) + { + return tmp; + } + else + { + head = &(*head)->next; + } + } + + return NULL; +} + +aserver *ToServer(char *name) +{ + return (*FindServer(&ServerList, name)); +} + +void onserver(char *source, char *newserver, char *args) +{ + register aserver *head; + register aserver *tmp; + register int i; + char TS[80]; + + if (source[0] != '\0') + { + head = ToServer(source); + } + else + { + head = NULL; + } + +#ifdef BACKUP + if (!strcasecmp(newserver, MAIN_SERVERNAME)) + { + quit(MAIN_NICK " is back", 0); + } +#endif + + tmp = (aserver *) MALLOC(sizeof(aserver)); + tmp->name = (char *)MALLOC(strlen(newserver) + 1); + strcpy(tmp->name, newserver); + GetWord(2, args, TS); + tmp->TS = atol(TS); + if (head == NULL) + { + tmp->next = ServerList; + ServerList = tmp; + TSoffset = tmp->TS - now; +#ifdef DEBUG + printf("New connection: my time: %ld others' time %ld (%ld)\n", + now, tmp->TS, TSoffset); +#endif + } + else + { + tmp->next = head->down; + head->down = tmp; + } + tmp->up = head; + tmp->down = NULL; + for (i = 0; i < 100; i++) + tmp->users[i] = NULL; +} + +void onsquit(char *source, char *theserver, char *args) +{ + register aserver *serv, **s; + register int i; + char TS[80]; + +#ifdef FAKE_UWORLD + if (!strcasecmp(theserver, UFAKE_SERVER) && Uworld_status == 1) + { + GetWord(0, args, TS); + if (atol(TS) == UworldServTS) + { + char buffer[200]; + sprintf(buffer, "%s squitted", UFAKE_NICK); + log(buffer); + Uworld_status = 0; + } + return; + } +#endif + + s = FindServer(&ServerList, theserver); + + if (s == NULL) + { + char buffer[200]; + sprintf(buffer, "ERROR: SQUIT unknown server %s (from %s)", + theserver, source); + log(buffer); + return; + } + + serv = *s; + +#ifdef DEBUG + printf("SQUIT: %s %s\n", source, theserver); +#endif + + if (args != NULL) + { + GetWord(0, args, TS); +#ifdef DEBUG + if (s != NULL) + printf("ConnectTS: %ld SquitTS: %ld\n", serv->TS, atol(TS)); +#endif + } + + if (serv != ServerList && args != NULL && serv->TS != atol(TS)) + { +#ifdef DEBUG + printf("TS's are different.. ignoring squit!\n"); +#endif + return; + } + + while (serv->down != NULL) + { + onsquit(NULL, serv->down->name, NULL); + } + + for (i = 0; i < 100; i++) + { + while (serv->users[i] != NULL) + { + onquit(serv->users[i]->N->nick); + } + } + + TTLALLOCMEM -= strlen(serv->name) + 1; + free(serv->name); + *s = serv->next; + TTLALLOCMEM -= sizeof(aserver); + free(serv); +} + +void showmap(char *source) +{ + int count = 0; + + if (CurrentSendQ > HIGHSENDQTHRESHOLD) + { + notice(source, "Cannot process your request at this time. Try again later."); + return; + } + notice(source, SERVERNAME); + showserv(source, ServerList, &count); + CheckFloodFlood(source, count); +} + +void showserv(char *source, aserver * server, int *count) +{ + static char prefix[80] = ""; + static int offset = 0; + char buffer[200]; + register asuser *suser; + register int nbusers = 0, i; + + if (server == NULL) + { + return; + } + + (*count)++; /* number of servers */ + + /* count number of users */ + for (i = 0; i < 100; i++) + { + suser = server->users[i]; + while (suser != NULL) + { + nbusers++; + suser = suser->next; + } + } + + if (server->next == NULL) + { + sprintf(buffer, "%s`-%s (%d client%s)", prefix, server->name, nbusers, (nbusers != 1) ? "s" : ""); + } + else + { + sprintf(buffer, "%s|-%s (%d client%s)", prefix, server->name, nbusers, (nbusers != 1) ? "s" : ""); + } + notice(source, buffer); + + if (server->next != NULL) + strcpy(prefix + offset, "| "); + else + strcpy(prefix + offset, " "); + + offset += 2; + showserv(source, server->down, count); + offset -= 2; + prefix[offset] = '\0'; + + showserv(source, server->next, count); +} + +void onsettime(char *source, char *value) +{ + char buffer[200]; + + TSoffset = atol(value) - now; + sprintf(buffer, "SETTIME from %s (%s) (%ld)", source, value, TSoffset); + log(buffer); +#ifdef DEBUG + puts(buffer); +#endif +} + +void showversion(char *source) +{ + char buffer[200]; + + sprintf(buffer, ":%s 351 %s . %s :%s\n", SERVERNAME, source, SERVERNAME, VERSION); + sendtoserv(buffer); +} diff --git a/Sources/shitlist.c b/Sources/shitlist.c new file mode 100644 index 0000000..f67ee53 --- /dev/null +++ b/Sources/shitlist.c @@ -0,0 +1,791 @@ +/* @(#)$Id: shitlist.c,v 1.12 2000/01/28 01:29:14 lgm Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +typedef struct ShitDisk +{ + time_t time; + time_t expiration; + char match[80]; + char from[80]; + char reason[200]; + char channel[50]; + int level; +} +ShitDisk; + +static int active = 0; + +int sl_hash(char *channel) +{ + register int i, j = 0; + for (i = 1; i < strlen(channel); i++) + j += (unsigned char)toupper(channel[i]); + return (j % 1000); +} + +void AddToShitList(char *source, char *ch, char *args, int force) +{ + char buffer[1024]; + char srcuh[200]; + char channel[80]; + char pattern[200]; + char strtime[80]; + char strlevel[80]; + char *reason; + time_t exp; + int shitlevel; + int srcAccess; + int exact; + register char *ptr1, *ptr2; + register aluser *luser; + register ShitUser *curr; + register achannel *chan; + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + if (*source && force == 0) + { + chan = ToChannel(channel); + if (chan != NULL && (chan->flags & CFL_OPONLY)) + { + notice(source, replies[RPL_OPONLY][chan->lang]); + return; + } + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: ban <#channel> " + " "); + return; + } + + if (!*source || force > 0) + srcAccess = (MASTER_ACCESS + 1); + else + srcAccess = Access(channel, source); + + if (srcAccess < ADD_TO_SHITLIST_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + GetWord(0, args, pattern); + GetWord(1, args, strtime); + GetWord(2, args, strlevel); + reason = ToWord(3, args); + + if (strlen(reason) > 200) + reason[199] = '\0'; + + if (!*pattern || (*strtime != '\0' && !isdigit(*strtime))) + { + notice(source, "SYNTAX: ban [#channel] " + "[duration in hours] [level] [reason]"); + return; + } + + if (!*strtime) + { + exp = SHITLIST_DEFAULT_TIME; + } + else + { + exp = atoi(strtime); + } + + if (!*strlevel) + { + shitlevel = AUTO_KICK_SHIT_LEVEL; + } + else + { + shitlevel = atoi(strlevel); + } + + exp *= 3600; + if (exp < 0 || exp > (MAX_BAN_DURATION * 24 * 3600)) + { + sprintf(buffer, "Invalid duration (Max %d days)", MAX_BAN_DURATION); + notice(source, buffer); + return; + } + + if (shitlevel < 1 || shitlevel > 1000) + { + notice(source, "Ban level must be in the range 1-1000"); + return; + } + + if (srcAccess < shitlevel) + { + notice(source, "Can't ban to a higher level than your access level."); + return; + } + + exp += now; + + if ((luser = ToLuser(source)) != NULL) + { + sprintf(srcuh, "%s!%s@%s", luser->nick, luser->username, luser->site); + } + else + { + strcpy(srcuh, source); + } + + /* look if the user is on the channel, if so, take his address */ + + luser = ToLuser(pattern); + if (luser != NULL) + { + MakeBanMask(luser, pattern); + exact = 0; + } + else + { + if ((ptr2 = strchr(pattern, '@')) == NULL) + { + strcat(pattern, "@*"); + ptr2 = strchr(pattern, '@'); + } + if ((ptr1 = strchr(pattern, '!')) == NULL) + { + char tmp[200]; + sprintf(tmp, "*!%s", pattern); + strncpy(pattern, tmp, 200); + pattern[199] = '\0'; + ptr1 = pattern + 1; + } + if (ptr1 > ptr2) + { + notice(source, "Illegal ban mask"); + return; + } + exact = 1; + } + + /* count number of bans.. if it's > MAX_BAN.. refuse to add */ + if (!force && *source && shitlevel > 0) + { + register int count = 0; + curr = ShitList[sl_hash(channel)]; + while (curr) + { + if (!strcasecmp(curr->channel, channel)) + count++; + curr = curr->next; + } + if (count > MAX_BAN) + { + notice(source, "Sorry, there are too many bans on" + " your channel. You'll have to remove some first."); + return; + } + } + + /* Now, seek thru the ShitList if the pattern is already there. + if it is, only change the information already present */ + curr = ShitList[sl_hash(channel)]; + if (exact) + { + while (curr && (strcasecmp(curr->match, pattern) || strcasecmp(curr->channel, channel))) + { + curr = curr->next; + } + } + else + { + while (curr && (!match(pattern, curr->match) || strcasecmp(curr->channel, channel))) + { + curr = curr->next; + } + } + + if (curr) + { + /* if the user is already on the shitlist.. */ + + /* if this is the result of a flood protection.. we have to + make sure the user is not already shitlisted for a longer + time.. */ + + if (shitlevel == 0 || curr->expiration < exp) + curr->expiration = exp; + + curr->time = now; + + /* if this is the result of a flood protection.. we have to + make sure the user is not already shitlisted at a higher + level.. */ + + if (shitlevel == 0 || curr->level < shitlevel) + curr->level = shitlevel; + + TTLALLOCMEM -= strlen(curr->from) + 1; + free(curr->from); + curr->from = (char *)MALLOC(strlen(srcuh) + 1); + strcpy(curr->from, srcuh); + + TTLALLOCMEM -= strlen(curr->reason) + 1; + free(curr->reason); + curr->reason = (char *)MALLOC(strlen(reason) + 1); + strcpy(curr->reason, reason); + } + else + { +#ifdef DEBUG + printf("TIME: %ld EXP: %ld LEVEL %d\n", now, exp, shitlevel); +#endif + /* if the user is NOT already on the shitlist */ + /* first, create a new structure */ + + curr = (ShitUser *) MALLOC(sizeof(ShitUser)); + + curr->time = now; + curr->expiration = exp; + curr->level = shitlevel; + + curr->match = (char *)MALLOC(strlen(pattern) + 1); + strcpy(curr->match, pattern); + + curr->from = (char *)MALLOC(strlen(srcuh) + 1); + strcpy(curr->from, srcuh); + + curr->reason = (char *)MALLOC(strlen(reason) + 1); + strcpy(curr->reason, reason); + + curr->channel = (char *)MALLOC(strlen(channel) + 1); + strcpy(curr->channel, channel); + + /* Then, link it to the list.. */ + + curr->next = ShitList[sl_hash(channel)]; + ShitList[sl_hash(channel)] = curr; + + } + + /* schedule the removal of the entry.. + */ + AddEvent(EVENT_CLEANSHITLIST, exp, channel); + + + if (*source && !force) + notice(source, "Ban list updated"); + + if (shitlevel >= AUTO_KICK_SHIT_LEVEL && !force) + { +#ifdef DEBUG + printf("Calling mban(\"\",%s,%s)\n", channel, pattern); +#endif + mban("", channel, pattern); + + sprintf(buffer, "%s (%s) %s", pattern, source, reason); + kick("", channel, buffer); + } + + /* Now, clean the shitlist */ + if (!force) + CleanShitList("", channel); +} + +void RemShitList(char *source, char *ch, char *args, int force) +{ + char channel[80]; + char pattern[2][200]; + register aluser *luser; + register ShitUser *curr; + register achannel *chan; + int srcaccess, exact; + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + if (*source && force == 0) + { + chan = ToChannel(channel); + if (chan != NULL && (chan->flags & CFL_OPONLY)) + { + notice(source, replies[RPL_OPONLY][chan->lang]); + return; + } + } + + if (!strcmp(channel, "*")) + { + notice(source, "SYNTAX: unban <#channel> "); + return; + } + + if (!*source || force > 0) + srcaccess = (MASTER_ACCESS + 1); + else + srcaccess = Access(channel, source); + + if (srcaccess < ADD_TO_SHITLIST_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + GetWord(0, args, pattern[0]); + + if (!*pattern[0]) + { + notice(source, "SYNTAX: unban [#channel] "); + return; + } + + /* look if the user is on the channel, if so, take his address */ + + luser = ToLuser(pattern[0]); + if (luser != NULL) + { + sprintf(pattern[1], "%s!%s@%s", + luser->nick, luser->username, luser->site); + exact = 0; + } + else + { + exact = 1; + } + + /* Now, seek thru the ShitList if the pattern is already there. */ + + curr = ShitList[sl_hash(channel)]; + if (exact) + { + while (curr && (strcasecmp(curr->match, pattern[0]) || strcasecmp(curr->channel, channel) || srcaccess < curr->level)) + { + curr = curr->next; + } + } + else + { + while (curr && (!match(pattern[1], curr->match) || strcasecmp(curr->channel, channel) || srcaccess < curr->level)) + { + curr = curr->next; + } + } + + if (curr) + { + curr->expiration = now - 1; + if (*source && !force) + notice(source, "Ban list updated"); + CleanShitList("", channel); + } + else + { + unban("", channel, pattern[0]); + } +} + + +void CleanShitList(char *source, char *channel) +{ + char buffer[200]; + register ShitUser *curr, *prev; + register achannel *chan; + int i; + + if (*source && Access(channel, source) < CLEAN_SHITLIST_LEVEL) + { + notice(source, "Your admin Access is too low"); + return; + } + + i = sl_hash(channel); + curr = ShitList[i]; + prev = NULL; + + while (curr) + { + chan = ToChannel(curr->channel); + if (chan == NULL || (curr->expiration <= now && !strcasecmp(channel, chan->name)) + || curr->level == 0) + { + if (chan != NULL && chan->on && chan->AmChanOp) + { + unban("", curr->channel, curr->match); + } + if (prev) + { + prev->next = curr->next; + TTLALLOCMEM -= strlen(curr->match) + 1; + free(curr->match); + TTLALLOCMEM -= strlen(curr->from) + 1; + free(curr->from); + TTLALLOCMEM -= strlen(curr->reason) + 1; + free(curr->reason); + TTLALLOCMEM -= strlen(curr->channel) + 1; + free(curr->channel); + TTLALLOCMEM -= sizeof(ShitUser); + free(curr); + curr = prev->next; + } + else + { + ShitList[i] = curr->next; + TTLALLOCMEM -= strlen(curr->match) + 1; + free(curr->match); + TTLALLOCMEM -= strlen(curr->from) + 1; + free(curr->from); + TTLALLOCMEM -= strlen(curr->reason) + 1; + free(curr->reason); + TTLALLOCMEM -= strlen(curr->channel) + 1; + free(curr->channel); + TTLALLOCMEM -= sizeof(ShitUser); + free(curr); + curr = ShitList[i]; + } + } + else + { + prev = curr; + curr = curr->next; + } + } + + if (*source) + notice(source, "Ban list is now up-to-date"); + + sprintf(buffer, "Cleaned banlist on %s", channel); + log(buffer); +} + +int IsShit(char *channel, char *user, char *out, char *reason) +{ + register ShitUser *curr; + register aluser *luser; + char uh[200]; + + if (strchr(user, '!') != NULL) + { + strcpy(uh, user); + } + else + { + luser = ToLuser(user); + sprintf(uh, "%s!%s@%s", luser->nick, luser->username, luser->site); + } + + curr = ShitList[sl_hash(channel)]; + +#ifdef DEBUG + printf("IsShit(%s,%s,%s)\n", channel, user, out); +#endif + + while (curr && (!match(channel, curr->channel) || !match(uh, curr->match))) + curr = curr->next; + +#ifdef DEBUG + if (curr) + printf("Banlevel: %d\n", curr->level); +#endif + + if (curr) + { + if (out != NULL) + strcpy(out, curr->match); + if (reason != NULL) + strcpy(reason, curr->reason); + return (curr->level); + } + else + { + return 0; + } +} + +void ShowShitList(char *source, char *ch, char *args) +{ + register ShitUser *curr; + struct tm *tp; + char buffer[1024], global[] = "*"; + char channel[80]; + int found = 0; + + if (*args == '#') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + if (!strcmp(channel, "*") || !*args) + { + notice(source, "SYNTAX: lbanlist [#channel] "); + return; + } + + if (!ToUser(channel, source) && + Access(channel, source) < 500 && Access(global, source) < 500) + { + notice(source, "You are not on that channel"); + return; + } + + + curr = ShitList[sl_hash(channel)]; + while (curr) + { + if (!strcasecmp(channel, curr->channel) && match(curr->match, args)) + { + found++; + } + curr = curr->next; + } + if ((found > 15) && (source[0] != '+')) + { + sprintf(buffer, "There are %d matching entries. Please use a userhost mask to narrow down the list.", found); + notice(source, buffer); + return; + } + + if (found == 0) + { + sprintf(buffer, "*** No entry matching with %s ***", args); + notice(source, buffer); + return; + } + + + sprintf(buffer, "*** Ban List for channel %s ***", channel); + notice(source, buffer); + + curr = ShitList[sl_hash(channel)]; + + while (curr) + { + if (!strcasecmp(channel, curr->channel) && match(curr->match, args)) + { + sprintf(buffer, "%s %s Level: %d", curr->channel, + curr->match, curr->level); + notice(source, buffer); + + sprintf(buffer, "ADDED BY: %s (%s)", curr->from, + (*curr->reason) ? curr->reason : "No reason given"); + notice(source, buffer); + + tp = gmtime(&curr->time); + sprintf(buffer, "SINCE: %sUCT", asctime(tp)); + *strchr(buffer, '\n') = ' '; + notice(source, buffer); + + sprintf(buffer, "EXP: %s", time_remaining(curr->expiration - now)); + notice(source, buffer); + } + curr = curr->next; + } + + notice(source, "*** END ***"); +} + +void SaveShitList(char *source, char *channel) +{ + ShitDisk tmp; + register ShitUser *user; + register int file; + char buffer[200]; + int i; + + if (*source && Access(channel, source) < SAVE_SHITLIST_LEVEL) + { + notice(source, "Your admin Access is too low!"); + return; + } + + if (active) + return; + active = 1; + + alarm(5); /* avoid NFS hangs */ + file = open(SHITLIST_FILE ".new", O_WRONLY | O_CREAT | O_TRUNC, 0600); + alarm(0); + + if (file < 0) + { + if (*source) + notice(source, "Error opening BanList file! Aborted."); + log("Error saving shitlist"); + active = 0; + return; + } + + sprintf(buffer, ":%s AWAY :Busy saving precious ban list\n", mynick); + sendtoserv(buffer); + dumpbuff(); + + for (i = 0; i < 1000; i++) + { + user = ShitList[i]; + while (user) + { + tmp.time = user->time; + tmp.expiration = user->expiration; + strncpy(tmp.match, user->match, 79); + tmp.match[79] = '\0'; + strncpy(tmp.from, user->from, 79); + tmp.from[79] = '\0'; + strncpy(tmp.reason, user->reason, 199); + tmp.reason[199] = '\0'; + strncpy(tmp.channel, user->channel, 49); + tmp.channel[49] = '\0'; + tmp.level = user->level; + + alarm(2); + if (write(file, &tmp, sizeof(ShitDisk)) <= 0) + { + alarm(0); + close(file); + log("ERROR: Can't save banlist"); + log((char *)sys_errlist[errno]); + alarm(2); + remove(SHITLIST_FILE ".new"); + alarm(0); + active = 0; + sprintf(buffer, ":%s AWAY\n", mynick); + sendtoserv(buffer); + return; + } + alarm(0); + + user = user->next; + } + } + + close(file); + alarm(20); + rename(SHITLIST_FILE ".new", SHITLIST_FILE); + alarm(0); + if (*source) + notice(source, "banlist saved."); + active = 0; + sprintf(buffer, ":%s AWAY\n", mynick); + sendtoserv(buffer); +} + +void LoadShitList(char *source) +{ + ShitDisk tmp; + ShitUser *user; + int file; + int i; + + if (*source && Access("*", source) < LOAD_SHITLIST_LEVEL) + { + notice(source, "Your admin access is too low!"); + return; + } + + if (active) + return; + active = 1; + + file = open(SHITLIST_FILE, O_RDONLY); + if (file < 0) + { + if (*source) + notice(source, "Error opening BanList file! Aborted."); + log("ERROR loading banlist"); + active = 0; + return; + } + + /* empty existing shitlist */ + for (i = 0; i < 1000; i++) + { + while ((user = ShitList[i]) != NULL) + { + ShitList[i] = ShitList[i]->next; + TTLALLOCMEM -= strlen(user->match) + 1; + free(user->match); + TTLALLOCMEM -= strlen(user->from) + 1; + free(user->from); + TTLALLOCMEM -= strlen(user->reason) + 1; + free(user->reason); + TTLALLOCMEM -= strlen(user->channel) + 1; + free(user->channel); + TTLALLOCMEM -= sizeof(ShitUser); + free(user); + } + } + + while (read(file, &tmp, sizeof(ShitDisk)) > 0) + { + if (tmp.expiration < now) + continue; + user = (ShitUser *) MALLOC(sizeof(ShitUser)); + user->time = tmp.time; + user->expiration = tmp.expiration; + if (tmp.level > 500) + tmp.level = 500; + user->level = tmp.level; + user->match = (char *)MALLOC(strlen(tmp.match) + 1); + strcpy(user->match, tmp.match); + user->from = (char *)MALLOC(strlen(tmp.from) + 1); + strcpy(user->from, tmp.from); + user->reason = (char *)MALLOC(strlen(tmp.reason) + 1); + strcpy(user->reason, tmp.reason); + user->channel = (char *)MALLOC(strlen(tmp.channel) + 1); + strcpy(user->channel, tmp.channel); + + user->next = ShitList[sl_hash(tmp.channel)]; + ShitList[sl_hash(tmp.channel)] = user; + } + + close(file); + + if (*source) + notice(source, "BanList loaded!"); + + active = 0; +} diff --git a/Sources/show_old_managers.c b/Sources/show_old_managers.c new file mode 100644 index 0000000..ef68e2c --- /dev/null +++ b/Sources/show_old_managers.c @@ -0,0 +1,133 @@ +/* @(#)$Id: show_old_managers.c,v 1.2 1998/01/08 17:02:18 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" +#include "dirent.h" + +time_t now; + +#define HOWLONG (30*24*60*60) /* 30 days */ + +void fix_user_file(char *file, char *channel) +{ + dbuser dbu; + int fd; + + fd = open(file, O_RDONLY); + if (fd < 0) + { + fprintf(stderr, "Can't open %s [%s]\n", file, sys_errlist[errno]); + return; + } + + /* Find at least one 500 seen within the last 30 days */ + while (read(fd, &dbu, sizeof(dbuser)) == sizeof(dbuser)) + { + if (dbu.header[0] != 0xFF || dbu.header[1] != 0xFF || + dbu.footer[0] != 0xFF || dbu.footer[1] != 0xFF) + { + continue; + } + if (!strcmp(dbu.match, "!DEL!")) + continue; + + if (dbu.access == 500 && (now - dbu.lastseen) < HOWLONG) + { + close(fd); + return; + } + } + + + /* Ok.. at this point, there is no channel manager that was seen + * within 30 days. Show all of them. + */ + lseek(fd, 0L, SEEK_SET); + + while (read(fd, &dbu, sizeof(dbuser)) == sizeof(dbuser)) + { + if (dbu.header[0] != 0xFF || dbu.header[1] != 0xFF || + dbu.footer[0] != 0xFF || dbu.footer[1] != 0xFF) + { + continue; + } + if (!strcmp(dbu.match, "!DEL!")) + continue; + + if (dbu.access != 500) + continue; + + printf("%-14s %-9s %03d %-26s %.24s\n", + dbu.channel, dbu.nick, dbu.access, dbu.match, ctime(&dbu.lastseen)); + } + close(fd); +} + +void fix_user_db(void) +{ + DIR *dp; + struct dirent *ent; + char dir[256], file[256], channel[80], *ptr; + int count; + + for (count = 0; count < 1000; count++) + { + sprintf(dir, "db/channels/%04X", count); + dp = opendir(dir); + if (dp == NULL) + { + fprintf(stderr, "Can't read %s [%s]\n", dir, sys_errlist[errno]); + continue; + } + while ((ent = readdir(dp)) != NULL) + { + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + continue; + strcpy(channel, ent->d_name); + for (ptr = channel; *ptr; ptr++) + if (*ptr == ' ') + *ptr = '/'; + sprintf(file, "db/channels/%04X/%s", count, ent->d_name); + fix_user_file(file, channel); + } + closedir(dp); + } +} + +int main(void) +{ + if (chdir(HOMEDIR) < 0) + { + perror(HOMEDIR); + exit(1); + } + + time(&now); + + fix_user_db(); + + return 0; +} diff --git a/Sources/showdb.c b/Sources/showdb.c new file mode 100644 index 0000000..71e443b --- /dev/null +++ b/Sources/showdb.c @@ -0,0 +1,110 @@ +/* @(#)$Id: showdb.c,v 1.6 1999/01/18 04:17:40 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" +#include "dirent.h" + +time_t now; + + +void fix_user_file(char *file, char *channel) +{ + dbuser dbu; + int fd; + + fd = open(file, O_RDONLY); + if (fd < 0) + { + fprintf(stderr, "Can't open %s [%s]\n", file, sys_errlist[errno]); + return; + } + + while (read(fd, &dbu, sizeof(dbuser)) == sizeof(dbuser)) + { + if (dbu.header[0] != 0xFF || dbu.header[1] != 0xFF || + dbu.footer[0] != 0xFF || dbu.footer[1] != 0xFF) + { + continue; + } + if (!strcmp(dbu.match, "!DEL!")) + continue; + + printf("%-14s %-9s %03d %-26s %.24s\n", + dbu.channel, dbu.nick, dbu.access, dbu.match, ctime(&dbu.lastseen)); + } + close(fd); +} + +void fix_user_db(void) +{ + DIR *dp; + struct dirent *ent; + char dir[256], file[256], channel[80], *ptr; + int count; + + for (count = 0; count < 1000; count++) + { + sprintf(dir, "db/channels/%04X", count); + dp = opendir(dir); + if (dp == NULL) + { + fprintf(stderr, "Can't read %s [%s]\n", dir, sys_errlist[errno]); + continue; + } + while ((ent = readdir(dp)) != NULL) + { + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + continue; + strcpy(channel, ent->d_name); + for (ptr = channel; *ptr; ptr++) + if (*ptr == ' ') + *ptr = '/'; + sprintf(file, "db/channels/%04X/%s", count, ent->d_name); + fix_user_file(file, channel); + } + closedir(dp); + } +} + +int main(int argc, char **argv) +{ + if (chdir(HOMEDIR) < 0) + { + perror(HOMEDIR); + exit(1); + } + + time(&now); + + if (argc == 3) + { + fix_user_file(argv[1], argv[2]); + } + else + fix_user_db(); + + return 0; +} diff --git a/Sources/socketio.c b/Sources/socketio.c new file mode 100644 index 0000000..f110db6 --- /dev/null +++ b/Sources/socketio.c @@ -0,0 +1,183 @@ +/* @(#)$Id: socketio.c,v 1.7 1998/06/23 23:35:08 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +/* These routines were first developed for the telnet3d project. + * Special thanks to Danny Mitchell (wildthang@irc) for his help. + */ + + +#include "h.h" + +#ifdef DOHTTP +#include + +extern void chat_close(http_socket *, char *); + +int readfrom_http(http_socket * client) +{ + void http_log(char *fmt,...); + char buf[1024]; + int length; + + if ((length = read(client->fd, buf, 1023)) <= 0) + { + if (errno == EWOULDBLOCK || errno == EAGAIN) + { + return 0; + } + else + { + if (client->status == HTTP_CHAT) + chat_close(client, "read error"); + close(client->fd); + client->fd = -1; + client->status = HTTP_ERROR; + return -1; + } + } + buf[length] = '\0'; +#ifdef DEBUG + printf("AA: |%s|\n", buf); +#endif + + if (copy_to_buffer(&client->inbuf, buf, length) >= 4096) + { + http_log("ERROR: Recv'd more than 4K from client! (flood?)"); + if (client->status == HTTP_CHAT) + chat_close(client, "Input packet too big"); + client->status = HTTP_ERROR; + close(client->fd); + client->fd = -1; + return -1; + } + + if (find_char_in_buffer(&client->inbuf, '\n', 1023)) + { + while (find_char_in_buffer(&client->inbuf, '\n', 1023) && + client->status != HTTP_PIPE && + client->status != HTTP_ENDING && + client->status != HTTP_ERROR) + { + copy_from_buffer(&client->inbuf, buf, '\n', 1023); + parse_http(client, buf); + } + /* Check for STUPID MSIE! who doesn't send a \n after post data + ** so check for a = in the first 10 chars, assume *ugh* it's post data + */ + if (find_char_in_buffer(&client->inbuf, '=', 10)) + { + if (client->status != HTTP_PIPE && + client->status != HTTP_ENDING && + client->status != HTTP_ERROR) + { +#ifdef DEBUG + printf("SEND\n"); +#endif + copy_from_buffer(&client->inbuf, buf, '\0', 1023); + parse_http(client, buf); + } + } + } + else if (length > 200) + { + if (client->status == HTTP_CHAT) + chat_close(client, "line too long"); + client->status = HTTP_ERROR; + close(client->fd); + client->fd = -1; + return -1; + } + return 1; +} + +int flush_http_buffer(http_socket * client) +{ + http_file_pipe *fpipe; + char buf[1024]; + int length; + int count; + + if (client == NULL || client->outbuf == NULL) + return -1; + + while ((count = look_in_buffer(&client->outbuf, buf, '\0', 1023)) > 0) + { + if ((length = write(client->fd, buf, count)) <= 0) + { + if ((errno == EWOULDBLOCK || errno == EAGAIN) && length != 0) + { + return 0; + } + else + { + if (client->status == HTTP_PIPE) + { + for (fpipe = FilePipes; fpipe != NULL; fpipe = fpipe->next) + { + if (fpipe->hsock == client) + { + close(fpipe->fd); + destroy_file_pipe(fpipe); + break; + } + } + } + if (client->status == HTTP_CHAT) + chat_close(client, "write error"); + close(client->fd); + client->fd = -1; + client->status = HTTP_ERROR; + return -1; + } + } + else + { + skip_char_in_buffer(&client->outbuf, length); + HTTPTTLSENTBYTES += length; + } + } + + return 0; +} + +/* sendto_client() by SeKs + * args (struct buffer_block **block, char *format, args...) + * adds 'args' according to 'format' to the client's output + * buffer. + */ +long sendto_http(http_socket * sck, char *format,...) +{ + va_list args; + char string[1024]; + + va_start(args, format); + vsprintf(string, format, args); + va_end(args); + + return copy_to_buffer(&sck->outbuf, string, strlen(string)); +} + +#endif /* DOHTTP */ diff --git a/Sources/special.c b/Sources/special.c new file mode 100644 index 0000000..a9d3269 --- /dev/null +++ b/Sources/special.c @@ -0,0 +1,198 @@ +/* @(#)$Id: special.c,v 1.3 1996/11/13 00:40:49 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +#define SPECFILE "special.log" + +void SpecLog(char *text) +{ + int fd; + char date[80],buffer[1024]; + strcpy(date,ctime(&now)); + *strchr(date,'\n')='\0'; + + alarm(2); + if((fd=open(SPECFILE,O_WRONLY|O_CREAT|O_APPEND,0600))>=0){ + alarm(0); + sprintf(buffer,"%s: %s\n",date,text); + alarm(2); + write(fd,buffer,strlen(buffer)); + alarm(0); + close(fd); + } + alarm(0); +} + + +void logmap(aserver *server,FILE *fp) +{ + static char prefix[80]=""; + static int offset=0; + asuser *suser; + int nbusers=0,i; + + + if(server==NULL){ + return; + } + + /* count number of users */ + for(i=0;i<100;i++){ + suser=server->users[i]; + while(suser!=NULL){ + nbusers++; + suser=suser->next; + } + } + + if(server->next==NULL){ + fprintf(fp,"%s`-%s (%d user%s)\n",prefix,server->name,nbusers,(nbusers>1)?"s":""); + }else{ + fprintf(fp,"%s|-%s (%d user%s)\n",prefix,server->name,nbusers,(nbusers>1)?"s":""); + } + + if(server->next!=NULL) + strcpy(prefix+offset,"| "); + else + strcpy(prefix+offset," "); + + offset+=2; + logmap(server->down,fp); + offset-=2; + prefix[offset]='\0'; + + logmap(server->next,fp); +} + +void SpecMap(void) +{ + FILE *fp; + if((fp=fopen(SPECFILE,"a"))!=NULL){ + logmap(ServerList,fp); + fclose(fp); + } +} + +#ifdef CHANNEL_LOG +void LogChan(void) +{ + register achannel *chan; + register auser *user; + register aluser *luser; + register int i,isreg,count; + register FILE *fp; + char mode[80]; + char flag; + + if((fp=fopen(CHANNEL_LOG,"a"))==NULL) + return; + + fprintf(fp,"%ld %s",now,ctime(&now)); + + for(i=0;i<1000;i++){ + for(chan=ChannelList[i];chan!=NULL;chan=chan->next){ + count=isreg=(chan->on)?1:0; + + for(user=chan->users;user;user=user->next){ + count++; + if(!isreg && + !strcasecmp(user->N->username,DEFAULT_USERNAME)&& + !strcasecmp(user->N->site,DEFAULT_HOSTNAME)){ + isreg=1; + } + } + GetWord(0,chan->mode,mode); + if(strchr(mode,'s')) + flag='S'; + else if(strchr(mode,'p')) + flag='P'; + else + flag='+'; + + fprintf(fp,"%s %c %d %s\n", + chan->name,flag,count,isreg?"REG'D":""); + } + } + count=0; + for(i=0;i<1000;i++){ + luser=Lusers[i]; + while(luser!=NULL){ + count++; + luser=luser->next; + } + } + fprintf(fp,"* %d \n",count); + + fclose(fp); +} +#endif + +#ifdef HISTORY +void HistLog(char *text) +{ + int fd; + char date[80],buffer[1024]; + strcpy(date,ctime(&now)); + *strchr(date,'\n')='\0'; + + alarm(2); + if((fd=open("hist.log",O_WRONLY|O_CREAT|O_APPEND,0600))>=0){ + alarm(0); + sprintf(buffer,"%s: %s\n",date,text); + alarm(2); + write(fd,buffer,strlen(buffer)); + alarm(0); + close(fd); + } + alarm(0); +} + +void History(char *line) +{ + static char Log[25][512]; + static int offset=0; + + if(line==NULL){ + int i=offset,top=offset-1; + if(top==-1) + top=25; + while(i!=top){ + if(i==25) + i=0; + HistLog(Log[i]); + i++; + } + } + else + { + strncpy(Log[offset],line,511); + Log[offset][511]='\0'; + if(++offset==25) + offset=0; + } +} +#endif diff --git a/Sources/struct.h b/Sources/struct.h new file mode 100644 index 0000000..681299f --- /dev/null +++ b/Sources/struct.h @@ -0,0 +1,303 @@ +/* @(#)$Id: struct.h,v 1.6 1997/07/01 21:51:09 cvs Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#ifdef NICKSERV +#include "nickserv.h" +#endif + +typedef struct filehdr { + unsigned char magic; + unsigned int no; +} filehdr; + +typedef struct RegUser { + char *realname; + char *match; + char *channel; + char *passwd; + char *modif; + int access; + unsigned long flags; + time_t suspend; + time_t lastseen; + off_t offset; + int modified; + int inuse; + time_t lastused; + struct RegUser *next; +} RegUser; + + +typedef struct dbuser { + unsigned char header[2]; + char nick[80]; + char match[80]; + char passwd[20]; + char channel[50]; + char modif[80]; + int access; + unsigned long flags; + time_t suspend; + time_t lastseen; + unsigned char footer[2]; +} dbuser; + + +typedef struct achannel { + char *name; + int AmChanOp; + int on; + int MassDeopPro; + int NickFloodPro; + int MsgFloodPro; + int lang; + time_t TS; + time_t lastact; + time_t lasttopic; + unsigned long flags; + unsigned long uflags; + char mode[80]; + char lastjoin[20]; + struct modequeue *modebuff; + struct aban *bans; + struct auser *users; + struct achannel *next; +} achannel; + +typedef struct adefchan { + char name[50]; + char mode[80]; + char url[80]; + char topic[80]; + int MassDeopPro; + int NickFloodPro; + int MsgFloodPro; + int lang; + time_t TS; + unsigned long flags; + unsigned long uflags; + struct adefchan *next; +} adefchan; + +typedef struct achannelnode { + struct achannel *N; + struct anickchange *nickhist; + struct achannelnode *next; +} achannelnode; + +typedef struct aserver { + char *name; + time_t TS; + struct asuser *users[100]; + struct aserver *up; + struct aserver *down; + struct aserver *next; +} aserver; + +typedef struct asuser { + struct aluser *N; + struct asuser *next; +} asuser; + +typedef struct aluser { + char *nick; + char *username; + char *site; + time_t time; + char mode; + struct aserver *server; + struct achannelnode *channel; + struct avalchan *valchan; + struct aluser *next; +#ifdef NICKSERV + struct aregnick *regnick; + time_t reglimit; +#endif +} aluser; + +typedef struct avalchan { + char *name; + RegUser *reg; + struct avalchan *next; +} avalchan; + +typedef struct auser { + struct aluser *N; + char chanop; + time_t lastact; + struct amsg *msghist; + struct adeop *deophist; + struct auser *next; +} auser; + +typedef struct aban { + char pattern[80]; + struct aban *next; +} aban; + +typedef struct adeop { + time_t time; + char nick[NICK_LENGTH]; + struct adeop *next; +} adeop; + +typedef struct anickchange { + time_t time; + char nick[NICK_LENGTH]; + struct anickchange *next; +} anickchange; + +typedef struct modequeue { + int AsServer; + char flag[3]; + char arg[80]; + struct modequeue *prev; + struct modequeue *next; +} modequeue; + +typedef struct amsg { + time_t time; + int length; + struct amsg *next; +} amsg; + +typedef struct ShitUser { + time_t time; + time_t expiration; + char *match; + char *from; + char *reason; + char *channel; + int level; + struct ShitUser *next; +} ShitUser; + +typedef struct anevent { + time_t time; + int event; + char param[80]; + struct anevent *next; +} anevent; + +typedef struct alang { + int no; + char *abbr; + char *name; +} alang; + +struct buffer_block { + char buf[BUFFER_BLOCK_SIZE]; + short offset_read; + short offset_write; + struct buffer_block *next; +}; + +typedef struct irc_socket { + int fd; + time_t TS; + struct buffer_block *inbuf; + struct buffer_block *outbuf; + struct irc_socket *next; +} irc_socket; + +typedef struct http_raw { + unsigned long key; +} http_raw; + +typedef struct http_post { + char path[80]; + char protocol[80]; + int count; + int ready; +} http_post; + +typedef struct http_socket { + int fd; + int status; + int dbio; + time_t TS; + time_t since; + void *hook; + struct buffer_block *inbuf; + struct buffer_block *outbuf; + struct sockaddr_in peer; + struct http_socket *next; +} http_socket; + +typedef struct http_file_pipe { + int fd; + http_socket *hsock; + struct http_file_pipe *next; +} http_file_pipe; + +typedef struct misc_socket { + int fd; + int type; + int status; + time_t TS; + char link[80]; + struct buffer_block *inbuf; + struct buffer_block *outbuf; + struct misc_socket *next; +} misc_socket; + + +#define DBCALLBACK(X) void (*X)(int *,off_t,int,void *,void *,dbuser*,int) + +typedef struct dbquery { + int fd; + off_t offset; + time_t time; + unsigned int type; + int action; + int count; + DBCALLBACK(callback); + struct buffer_block *buf; + void *hook1; + void *hook2; + struct dbquery *next; + char channel[80]; + char info[80]; + char passwd[80]; +} dbquery; + + +typedef struct dbsync { + int fd; + off_t offset; + time_t time; + int type; /* update, delete, add */ + int status; /* pending_write, seeking_empty_slot */ + RegUser **reg; + struct buffer_block *buf; + struct dbsync *next; +} dbsync; + +typedef struct syncchan { + char name[50]; + struct syncchan *next; +} syncchan; + diff --git a/Sources/userlist.c b/Sources/userlist.c new file mode 100644 index 0000000..8f18642 --- /dev/null +++ b/Sources/userlist.c @@ -0,0 +1,2139 @@ +/* @(#)$Id: userlist.c,v 1.56 2000/10/24 16:14:43 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +#define VALIDMASK "^.+!.*[^*?]@(((.+\\.)?[^*?]+\\.[a-z]+)|([0-9]+\\.[0-9]+\\.[0-9*]+(\\.[0-9*]+)?))$" + +typedef struct OldDiskUser +{ + char realname[80]; + char match[80]; + char passwd[20]; + char channel[80]; + char modif[80]; + int Access; + unsigned long flags; + time_t suspend; + time_t lastseen; +} +OldDiskUser; + + + +struct modinfo_struct +{ + char source[20]; + char field[80]; + char newvalue[80]; +}; + + +struct showaccess_struct +{ + char source[80]; + char target[80]; + char chaninfo[80]; + char modifby[80]; + int nicksearch; + int min, max; + int mask, xmask; + int modif; +}; + + +int ul_hash(char *channel) +{ + register int i, j = 0; + for (i = 1; i < strlen(channel); i++) + j += (unsigned char)toupper(channel[i]); + return (j % 1000); +} + + +void free_user(RegUser ** head) +{ + register RegUser *tmp = *head; + + if ((*head)->inuse != 0) + log("ERROR!!!! free_user(): inuse != 0"); + + *head = (*head)->next; + TTLALLOCMEM -= strlen(tmp->realname) + 1; + free(tmp->realname); + TTLALLOCMEM -= strlen(tmp->match) + 1; + free(tmp->match); + TTLALLOCMEM -= strlen(tmp->passwd) + 1; + free(tmp->passwd); + TTLALLOCMEM -= strlen(tmp->channel) + 1; + free(tmp->channel); + TTLALLOCMEM -= strlen(tmp->modif) + 1; + free(tmp->modif); + TTLALLOCMEM -= sizeof(RegUser); + free(tmp); +} +void LoadUserList(char *source) +{ + RegUser *curr; + char fname[256]; + OldDiskUser tmp; + dbuser db; + struct stat st; + int in, out, i; + + /* store master info */ + curr = (RegUser *) MALLOC(sizeof(RegUser)); + memset(curr, 0, sizeof(RegUser)); + + curr->realname = (char *)MALLOC(strlen(MASTER_REALNAME) + 1); + strcpy(curr->realname, MASTER_REALNAME); + + curr->access = MASTER_ACCESS; + + curr->passwd = (char *)MALLOC(strlen(MASTER_PASSWD) + 1); + strcpy(curr->passwd, MASTER_PASSWD); + + curr->match = (char *)MALLOC(strlen(MASTER_MATCH) + 1); + strcpy(curr->match, MASTER_MATCH); + + curr->channel = (char *)MALLOC(strlen(MASTER_CHANNEL) + 1); + strcpy(curr->channel, MASTER_CHANNEL); + + curr->modif = (char *)MALLOC(1); + curr->modif[0] = '\0'; + + curr->flags = MASTER_FLAGS; + curr->lastseen = now; + curr->suspend = (time_t) 0; + + curr->modified = 0; + curr->lastused = now + now; /* Don't swap */ + curr->offset = (off_t) - 1; + curr->next = UserList[0]; + UserList[0] = curr; + + /* We don't *load* the database anymore. But if it doesn't + * exist, we need to create it, possibly from the old userlist.dat + * file. + */ + if (stat("db/channels/0000", &st) >= 0) + return; + + mkdir("db", 0700); + mkdir("db/channels", 0700); + + if (stat("db/channels", &st) < 0) + return; + + for (i = 0; i < 1000; i++) + { + sprintf(fname, "db/channels/%04X", i); + mkdir(fname, 0700); + } + + if ((in = open(USERFILE, O_RDONLY)) < 0) + return; + + while (read(in, &tmp, sizeof(tmp)) > 0) + { + if (tmp.Access == 0) + continue; + memset(&db, 0, sizeof(db)); + db.header[0] = 0xff; + db.header[1] = 0xff; + db.footer[0] = 0xff; + db.footer[1] = 0xff; + strcpy(db.nick, tmp.realname); + strcpy(db.match, tmp.match); + if (strcmp(tmp.passwd, "*")) + strcpy(db.passwd, tmp.passwd); + strcpy(db.channel, tmp.channel); + strcpy(db.modif, tmp.modif); + db.access = tmp.Access; + db.flags = (tmp.flags & UFL_AUTOOP); + db.suspend = tmp.suspend; + db.lastseen = tmp.lastseen; + if ((out = open(make_dbfname(tmp.channel), + O_WRONLY | O_APPEND | O_CREAT, 0600)) >= 0) + { + write(out, &db, sizeof(db)); + close(out); + } + } +} + +RegUser *IsValid(aluser * luser, char *channel) +{ + register avalchan *valchan; + + if (luser == NULL) + return NULL; + + valchan = luser->valchan; + while (valchan != NULL) + { + if (!strcasecmp(valchan->name, channel)) + break; + valchan = valchan->next; + } +#ifdef DEBUG + printf("IsValid() --> %p\n", valchan); +#endif + + return (valchan) ? valchan->reg : NULL; +} + + +void try_find(char *channel, aluser * user) +{ + register RegUser *reg; + register avalchan *vchan; + char userhost[200]; + sprintf(userhost, "%s!%s@%s", user->nick, user->username, user->site); + + if (IsValid(user, channel)) + return; + + reg = UserList[ul_hash(channel)]; + while (reg != NULL) + { + if (!strcasecmp(reg->channel, channel) && + match(userhost, reg->match) && + *reg->passwd == '\0') + { + vchan = (avalchan *) MALLOC(sizeof(avalchan)); + vchan->name = (char *)MALLOC(strlen(channel) + 1); + strcpy(vchan->name, channel); + vchan->reg = reg; + reg->inuse++; + reg->lastseen = now; + reg->modified = 1; + vchan->next = user->valchan; + user->valchan = vchan; + break; + } + reg = reg->next; + } +} + +int LAccess(char *channel, aluser * user) +{ + register avalchan *vchan; + + if (user == NULL) + return 0; + + vchan = user->valchan; + while (vchan != NULL && strcasecmp(channel, vchan->name)) + vchan = vchan->next; + +#ifdef DEBUG + printf("LAcccess()= %d\n", (vchan != NULL) ? vchan->reg->access : 0); +#endif + if (vchan == NULL || vchan->reg->suspend >= now || + vchan->reg->passwd[0] == '\0') + return 0; + + return vchan->reg->access; +} + +int Access(char *channel, char *nick) +{ + return LAccess(channel, ToLuser(nick)); +} + + +RegUser *load_dbuser(off_t offset, dbuser * dbu) +{ + register RegUser *new, *scan; + register int idx; + +#ifdef DEBUG + if (dbu) + printf("load: hdr: %X%X nick: %s match: %s passwd: %s channel: %s " + "modif: %s access: %d flags: %ld susp: %ld last: %ld ftr: %X%X\n", + dbu->header[0], dbu->header[1], dbu->nick, dbu->match, dbu->passwd, + dbu->channel, dbu->modif, dbu->access, dbu->flags, dbu->suspend, + dbu->lastseen, dbu->footer[0], dbu->footer[1]); +#endif + + idx = ul_hash(dbu->channel); + + /* Make sure that entry is not already on memory. If it is, + * there is no need to load it again. + */ + scan = UserList[idx]; + while (scan && (scan->offset != offset || + strcasecmp(scan->channel, dbu->channel))) + scan = scan->next; + + if (scan != NULL) + { + if (scan->access == 0 || strcmp(dbu->nick, scan->realname)) + return NULL; + return scan; + } + + new = (RegUser *) MALLOC(sizeof(RegUser)); + memset(new, 0, sizeof(RegUser)); + new->realname = (char *)MALLOC(strlen(dbu->nick) + 1); + strcpy(new->realname, dbu->nick); + new->match = (char *)MALLOC(strlen(dbu->match) + 1); + strcpy(new->match, dbu->match); + new->channel = (char *)MALLOC(strlen(dbu->channel) + 1); + strcpy(new->channel, dbu->channel); + new->passwd = (char *)MALLOC(strlen(dbu->passwd) + 1); + strcpy(new->passwd, dbu->passwd); + new->modif = (char *)MALLOC(strlen(dbu->modif) + 1); + strcpy(new->modif, dbu->modif); + new->access = dbu->access; + new->flags = dbu->flags; + new->suspend = dbu->suspend; + new->lastseen = dbu->lastseen; + new->offset = offset; + new->inuse = 0; + new->modified = 0; + new->lastused = now; + new->next = UserList[idx]; + UserList[idx] = new; + + return new; +} + + +static void successful_auth(aluser * luser, char *channel, RegUser * reg) +{ + char buffer[512]; + register avalchan *vchan; + register achannel *chan; + time_t last; + + vchan = (avalchan *) MALLOC(sizeof(avalchan)); + vchan->name = (char *)MALLOC(strlen(channel) + 1); + strcpy(vchan->name, channel); + vchan->reg = reg; + reg->inuse++; + reg->lastseen = now; + reg->modified = 1; + vchan->next = luser->valchan; + luser->valchan = vchan; + + if (reg->passwd[0] == '\0') + { + sprintf(buffer, "Passwords are now mandatory. " + "Please use the 'newpass' command now."); + } + else + { + sprintf(buffer, "AUTHENTICATION SUCCESSFUL ON %s!", + channel); + } + notice(luser->nick, buffer); + if (reg->suspend > now) + notice(luser->nick, "... however, your access is suspended!"); + + sprintf(buffer, "AUTH: %s!%s@%s as %s on %s", + luser->nick, luser->username, luser->site, + reg->realname, reg->channel); + log(buffer); + + last = (now - reg->lastseen) / 86400; + if (last > 1) + { + sprintf(buffer, "I last saw you %ld days ago", last); + notice(luser->nick, buffer); + } + if (strcmp(channel, "*")) + { + if (!strcmp(reg->channel, "*")) + { + sprintf(buffer, "You now have access on %s", channel); + notice(luser->nick, buffer); + sprintf(buffer, "%s is getting access on %s", + luser->nick, channel); + broadcast(buffer, 1); + } + chan = ToChannel(channel); + sprintf(buffer, "%s!%s@%s", luser->nick, luser->username, + luser->site); + if (chan && chan->on && chan->AmChanOp + && reg && (reg->flags & UFL_AUTOOP) + && reg->suspend < now + && !(chan->flags & CFL_NOOP) + && IsShit(channel, buffer, NULL, NULL) < NO_OP_SHIT_LEVEL + ) + { + op("", channel, luser->nick); + } + + } + else + { + if (reg->access < 500) + notice(luser->nick, "You are now an authenticated helper"); + else + notice(luser->nick, "You now have administrative access"); + } +} + +static void + validate_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + register aluser *luser; + register RegUser *reg; + char userhost[200]; +#ifdef DEBUG + if (dbu) + printf("vall: hdr: %X%X nick: %s match: %s passwd: %s channel: %s " + "modif: %s access: %d flags: %ld susp: %ld last: %ld ftr: %X%X\n", + dbu->header[0], dbu->header[1], dbu->nick, dbu->match, dbu->passwd, + dbu->channel, dbu->modif, dbu->access, dbu->flags, dbu->suspend, + dbu->lastseen, dbu->footer[0], dbu->footer[1]); + else + printf("vall: end.\n"); +#endif + + if (dbu != NULL) + { + luser = ToLuser((char *)hook1); + + if (luser == NULL) + { + /* It is possible the user has quit or changed his nick + * since the request for authentication was made. In + * such a situation, we load the structure anyway, but + * don't link it anywhere. + */ + return; + } + + reg = load_dbuser(off, dbu); + + sprintf(userhost, "%s!%s@%s", luser->nick, luser->username, + luser->site); + if (reg != NULL && match(userhost, reg->match)) + { + successful_auth(luser, dbu->channel, reg); + } + else + { + char buf[200]; + sprintf(buf, "AUTHENTICATION FAILED ON %s!", dbu->channel); + notice((char *)hook1, buf); + } + } + else + { + if (count == 0) + { + char buf[200]; + sprintf(buf, "AUTHENTICATION FAILED ON %s!", (char *)hook2); + notice((char *)hook1, buf); + } + free(hook1); + free(hook2); + } +} + +void validate(char *source, char *target, char *args) +{ + char channel[80], passwd[80], userhost[200], buffer[200]; + register avalchan *vchan, **pvchan; + register RegUser *ruser; + register aluser *luser; + + luser = ToLuser(source); + + if (*args == '#' || *args == '*') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, target); + GuessChannel(source, channel); + if (*channel != '#') + { + notice(source, "SYNTAX: login [password]"); + return; + } + } + + GetWord(0, args, passwd); + + if (*passwd && !strchr(target, '@')) + { + sprintf(buffer, "Please use /msg %s@%s login [channel] [password]", + mynick, SERVERNAME); + notice(source, buffer); + return; + } + + +#ifdef DEBUG + printf("Authentication request..\nFROM: %s\nCHANNEL: %s\nPASSWORD: %s\n", + source, channel, passwd); +#endif + /* remove any existing link to a userlist structure for the + * requested channel. + */ + pvchan = &luser->valchan; + while (*pvchan != NULL && strcasecmp((*pvchan)->name, channel)) + pvchan = &(*pvchan)->next; + if (*pvchan != NULL) + { + vchan = *pvchan; + *pvchan = (*pvchan)->next; + vchan->reg->inuse--; + vchan->reg->lastused = now; + TTLALLOCMEM -= strlen(vchan->name) + 1; + free(vchan->name); + TTLALLOCMEM -= sizeof(avalchan); + free(vchan); + } + + sprintf(userhost, "%s!%s@%s", luser->nick, luser->username, luser->site); + + ruser = UserList[ul_hash(channel)]; + while (ruser != NULL) + { + if (!strcasecmp(ruser->channel, channel) && + match(userhost, ruser->match) && + !strcmp(ruser->passwd, passwd)) + break; + ruser = ruser->next; + } + + if (ruser == NULL) + { /* hmm might be in the admin list too.. */ + ruser = UserList[0]; + while (ruser != NULL) + { + if (!strcasecmp(ruser->channel, "*") && + match(userhost, ruser->match) && + !strcmp(ruser->passwd, passwd)) + break; + ruser = ruser->next; + } + } + + if (ruser == NULL) + { /* ok.. not in memory.. send db query */ + char *hook1, *hook2; + hook1 = (char *)malloc(strlen(source) + 1); + hook2 = (char *)malloc(strlen(channel) + 1); + strcpy(hook1, source); + strcpy(hook2, channel); + db_fetch(channel, DBGETUHPASS, userhost, passwd, 0, + hook1, hook2, validate_callback); + } + else + { + successful_auth(luser, channel, ruser); + } +} + + +void DeAuth(char *source, char *chan, char *args) +{ + char channel[80]; + char buffer[512]; + register aluser *luser; + register avalchan *vchan, **pvchan; + + luser = ToLuser(source); + + if (*args == '#' || *args == '*') + { + GetWord(0, args, channel); + } + else + { + strcpy(channel, chan); + GuessChannel(source, channel); + } + + if (!*channel) + { + notice(source, "SYNTAX: deauth <#channel>"); + return; + } + + pvchan = &luser->valchan; + while (*pvchan != NULL && strcasecmp((*pvchan)->name, channel)) + pvchan = &(*pvchan)->next; + if (*pvchan != NULL) + { + vchan = *pvchan; + *pvchan = (*pvchan)->next; + vchan->reg->inuse--; + vchan->reg->lastused = now; + TTLALLOCMEM -= strlen(vchan->name) + 1; + free(vchan->name); + TTLALLOCMEM -= sizeof(avalchan); + free(vchan); + sprintf(buffer, "You have been successfully deauthenticated on %s",channel); + notice(source, buffer); + } + else + { + sprintf(buffer, "You do not appear to be authenticated on %s",channel); + notice(source, buffer); + } +} + + +static void + adduser_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + RegUser *newuser = (RegUser *) hook2, *scan; + char buffer[200]; + int ok = 0; + + if (dbu != NULL && count > 0) + { + /* check if entry was deleted */ + scan = UserList[ul_hash(dbu->channel)]; + while (scan != NULL && (scan->offset != off || scan->access != 0 || + strcasecmp(scan->channel, dbu->channel))) + { + scan = scan->next; + } + if (scan != NULL) + { + ok = 1; + } + else + { + if (load_dbuser(off, dbu) != NULL) + { + notice((char *)hook1, "This user is already present in the list."); + sprintf(buffer, "NICK: %s MATCH: %s ACCESS: %d", + dbu->nick, dbu->match, dbu->access); + notice((char *)hook1, buffer); + free_user(&newuser); + } + else + ok = 1; + } + } + else if (count == 0) + { + ok = 1; + } + + if (ok) + { + /* OK, go ahead and add the new entry in the list + */ + newuser->next = UserList[ul_hash(newuser->channel)]; + UserList[ul_hash(newuser->channel)] = newuser; + + sprintf(buffer, "New user %s (%s) added on %s with access %d", + newuser->realname, newuser->match, newuser->channel, + newuser->access); + notice((char *)hook1, buffer); + } + if (dbu == NULL) + free(hook1); +} + + +void AddUser(char *source, char *ch, char *args) +{ + register RegUser *newuser, *curr; + register aluser *luser, *src; + register achannel *chan; + void *hook; + char buffer[500]; + char channel[80]; + char realname[80]; + char mask[80]; + char straccess[80]; + char password[80]; + char *ptr, *ptr2; + int acc; + int srcacs; + RegUser *reg; + time_t now1 = now + 3600; + struct tm *tms = gmtime(&now1); + + src = ToLuser(source); + if (*args == '#' || (*args == '*' && *(args + 1) == ' ' && IsValid(src, ch))) + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + if(CheckAdduserFlood(source, channel)) + { + return; + } + + GetWord(0, args, realname); + GetWord(1, args, mask); + if (isdigit(*mask) || *mask == '-') + { + strcpy(straccess, mask); + GetWord(2, args, password); + luser = ToLuser(realname); + if (luser == NULL) + { + *mask = '\0'; + } + else + { + MakeBanMask(luser, mask); + } + } + else + { + GetWord(2, args, straccess); + GetWord(3, args, password); + } + + ptr = strchr(mask, '@'); + ptr2 = strchr(mask, '!'); + + if (ptr == NULL || ptr2 == NULL || ptr2 > ptr || + strchr(ptr2 + 1, '!') || strchr(ptr + 1, '@')) + { + notice(source, "Invalid nick!user@host mask"); + return; + } + + for (ptr = mask; *ptr; ptr++) + { + if (*ptr <= 32) + break; + } + + if (*ptr) + { + notice(source, "Invalid nick!user@host mask"); + return; + } + + if (!regex_cmp(VALIDMASK, mask)) + { + notice(source, "Invalid nick!user@host mask"); + return; + } + + for (ptr = realname; *ptr; ptr++) + { + if (*ptr <= 32) + break; + } + + if (*ptr) + { + notice(source, "Invalid nick!"); + return; + } + + if ((!strcmp(channel, "*") && !IsValid(src, channel)) || + !*realname || !*mask || !*straccess) + { + notice(source, "SYNTAX: adduser [#channel] [mask] "); + return; + } + + srcacs = Access(channel, source); + if (srcacs < ADD_USER_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + if (*realname == '-' || strchr(realname, '*') || strchr(realname, '?')) + { + notice(source, "Can't add user.. bogus nick"); + return; + } + + if (strlen(straccess) > 4) + { + notice(source, "Can't add user.. bogus access"); + return; + } + acc = atoi(straccess); + + /* can't add a user with a higher access than his! */ + + if (srcacs <= acc) + { + notice(source, "Can't add a user with an access higher than or equal to yours"); + return; + } + + if (acc == 0 || (*channel == '#' && acc < 0)) + { + notice(source, "Can't add a user with access <= 0"); + return; + } + + if (!*password && acc > 0) + { + notice(source, "A password must be supplied"); + return; + } + + /* password must be at least 6 chars long! why?.. hmm why not! ;) */ + + if (strlen(password) < 6) + { + notice(source, "Password must be at least 6 characters long"); + return; + } + + if (strlen(password) > 18) + { + notice(source, "Password cannot be longer than 18 characters"); + return; + } + + /* check if the user is not already in the list.. */ + curr = UserList[ul_hash(channel)]; + while (curr) + { + if (!strcasecmp(channel, curr->channel) && + !strcasecmp(curr->realname, realname)) + { + break; + } + else + { + curr = curr->next; + } + } + if (curr) + { + notice(source, "This user is already present in the list."); + sprintf(buffer, "NICK: %s MATCH: %s ACCESS: %d", + curr->realname, curr->match, curr->access); + notice(source, buffer); + return; + } + + /* OK, there is no conflict with structures in memory. Now we + * must check in the database. Create the structure and pass it + * as a hook with the db query. + */ + newuser = (RegUser *) MALLOC(sizeof(RegUser)); + memset(newuser, 0, sizeof(RegUser)); + + newuser->realname = (char *)MALLOC(strlen(realname) + 1); + strcpy(newuser->realname, realname); + + newuser->match = (char *)MALLOC(strlen(mask) + 1); + strcpy(newuser->match, mask); + + newuser->access = acc; + + newuser->passwd = (char *)MALLOC(strlen(password) + 1); + strcpy(newuser->passwd, password); + + newuser->channel = (char *)MALLOC(strlen(channel) + 1); + strcpy(newuser->channel, channel); + + reg = IsValid(src, channel); + + sprintf(buffer, "%04d%02d%02d@%03ld (%s) %s!%s@%s", + tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday, + 1000 * (now1 % 86400) / 86400, + reg ? reg->realname : "?", + src->nick, src->username, src->site); + + newuser->modif = (char *)MALLOC(strlen(buffer) + 1); + strcpy(newuser->modif, buffer); + + newuser->suspend = 0; + + newuser->lastseen = now; + + newuser->offset = (off_t) - 1; + newuser->modified = 1; + + newuser->next = NULL; + + if ((chan = ToChannel(channel)) != NULL) + { + newuser->flags = chan->uflags; + } + else + { + newuser->flags = 0; + } + + hook = (char *)malloc(strlen(source) + 1); + strcpy(hook, source); + + db_fetch(channel, DBGETNICK, newuser->realname, "", 0, hook, newuser, + adduser_callback); +} + + +static void + show_this_user_access_reg(char *source, RegUser * user, int modif) +{ + char buffer[512]; + time_t t; + int days, hours, mins, secs; + + sprintf(buffer, "USER: %s (%s) ACCESS: %d L%s%s%s", + user->realname, user->match, user->access, + (user->modified == 1) ? "M" : "", (*user->passwd) ? "P" : "", + (user->inuse > 0) ? "U" : ""); + notice(source, buffer); + sprintf(buffer, "CHANNEL: %s -- AUTOOP: %s", + user->channel, + (user->flags & UFL_AUTOOP) ? "ON" : "OFF"); + notice(source, buffer); + if (user->suspend > now) + { + sprintf(buffer, "SUSPEND EXP: %s", + time_remaining(user->suspend - now)); + notice(source, buffer); + } + if (user->lastseen + MIN_LASTSEEN < now) + { + t = now - user->lastseen; + days = (int)t / 86400; + t %= 86400; + hours = (int)t / 3600; + t %= 3600; + mins = (int)t / 60; + t %= 60; + secs = (int)t; + + *buffer = '\0'; + if (days > 0) + { + sprintf(buffer, "LAST SEEN: %d days, %02d:%02d:%02d ago", + days, hours, mins, secs); + } + else + { + sprintf(buffer, "LAST SEEN: %02d:%02d:%02d ago", + hours, mins, secs); + } + notice(source, buffer); + } + if (modif) + { + if (user->modif[0] == '\0') + sprintf(buffer, "LAST MODIF: unknown"); + else + sprintf(buffer, "LAST MODIF: %s", user->modif); + notice(source, buffer); + } +} + + + +static void + show_this_user_access_dbu(char *source, dbuser * dbu, int modif) +{ + char buffer[512]; + time_t t; + int days, hours, mins, secs; + + sprintf(buffer, "USER: %s (%s) ACCESS: %d %s", + dbu->nick, dbu->match, dbu->access, + (*dbu->passwd) ? "P" : ""); + notice(source, buffer); + sprintf(buffer, "CHANNEL: %s -- AUTOOP: %s", + dbu->channel, + (dbu->flags & UFL_AUTOOP) ? "ON" : "OFF"); + notice(source, buffer); + if (dbu->suspend > now) + { + sprintf(buffer, "SUSPEND EXP: %s", + time_remaining(dbu->suspend - now)); + notice(source, buffer); + } + if (dbu->lastseen + MIN_LASTSEEN < now) + { + t = now - dbu->lastseen; + days = (int)t / 86400; + t %= 86400; + hours = (int)t / 3600; + t %= 3600; + mins = (int)t / 60; + t %= 60; + secs = (int)t; + + *buffer = '\0'; + if (days > 0) + { + sprintf(buffer, "LAST SEEN: %d days, %02d:%02d:%02d ago", + days, hours, mins, secs); + } + else + { + sprintf(buffer, "LAST SEEN: %02d:%02d:%02d ago", + hours, mins, secs); + } + notice(source, buffer); + } + if (modif) + { + if (dbu->modif[0] == '\0') + sprintf(buffer, "LAST MODIF: unknown"); + else + sprintf(buffer, "LAST MODIF: %s", dbu->modif); + notice(source, buffer); + } +} + +static void + showaccess_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + struct showaccess_struct *ptr = (struct showaccess_struct *)hook1; + register RegUser *scan; + int *cnt = (int *)hook2; + + if (dbu == NULL) + { + if (*cnt == 0 && count != 0) + notice(ptr->source, "No match!"); + else if (*cnt != 0) + { + notice(ptr->source, "End of access list"); + CheckFloodFlood(ptr->source, (*cnt) + (*cnt)); + } + else + notice(ptr->source, + "That channel doesn't appear to be registered"); + free(hook1); + free(hook2); + return; + } + + scan = UserList[ul_hash(dbu->channel)]; + while (scan != NULL && (scan->offset != off || + strcasecmp(scan->channel, dbu->channel))) + scan = scan->next; + + if (scan != NULL) + return; + + if (((ptr->nicksearch && match(dbu->nick, ptr->target)) || + (!ptr->nicksearch && compare(ptr->target, dbu->match)) || + (ptr->nicksearch && match(ptr->chaninfo, dbu->match))) && + dbu->access >= ptr->min && dbu->access <= ptr->max && + (ptr->mask == 0 || (dbu->flags & ptr->mask) == ptr->mask) && + (ptr->xmask == 0 || (dbu->flags & ptr->xmask) == 0) && + (*ptr->modifby == '\0' || match(dbu->modif, ptr->modifby))) + { + show_this_user_access_dbu(ptr->source, dbu, ptr->modif); + + (*cnt)++; + if (*cnt > 15 && ptr->source[0] != '+') + { + notice(ptr->source, + "There are more than 15 matching entries"); + notice(ptr->source, "Please restrict your query"); + close(*fd); + *fd = -1; + } + } +} + + +void showaccess(char *source, char *ch, char *args) +{ + char buffer[500], argument[80], channel[80]; + char realname[80], chaninfo[80] = "", modifby[80] = ""; + register RegUser *scan; + register aluser *luser; + register int nicksearch; + int min = 0, max = MASTER_ACCESS, mask = 0, xmask = 0, modif = 0, srcacs, + count; + struct showaccess_struct *hook1; + int *hook2; + + /* use another channel if provided as argument */ + if (*args == '#' || *args == '*') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + /* if no name is provided.. use source */ + GetWord(0, args, realname); + if (*realname == '-') + { + strcpy(realname, "*"); + } + else if (!*realname) + { + strcpy(realname, source); + } + else + { + args = ToWord(1, args); + } + + luser = ToLuser(realname); + if (!strcmp(channel, "*") && !IsValid(ToLuser(source), channel)) + { + notice(source, "SYNTAX: access [nick]"); + return; + } + +#ifdef DEBUG + printf("SHOWACCESS:\nFROM: %s\nCHANNEL: %s\nWHO: %s\n", + source, channel, args); +#endif + + /* parse arguments */ + while (*args) + { + GetWord(0, args, argument); + args = ToWord(1, args); + if (!strcasecmp(argument, "-min")) + { + min = atoi(args); + args = ToWord(1, args); + } + else if (!strcasecmp(argument, "-max")) + { + max = atoi(args); + args = ToWord(1, args); + } + else if (!strcasecmp(argument, "-autoop")) + { + mask |= UFL_AUTOOP; + } + else if (!strcasecmp(argument, "-noautoop")) + { + xmask |= UFL_AUTOOP; + } + else if (!strcasecmp(argument, "-modif")) + { + modif = 1; + if (*args && *args != '-') + { + GetWord(0, args, modifby); + args = ToWord(1, args); + } + } + else + { + sprintf(buffer, "\"%s\": Unknown option", argument); + notice(source, buffer); + return; + } + } + + + /* store the access of the person querying */ + srcacs = Access(channel, source); + + if (*source && srcacs < SHOW_ACCESS_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + if (CurrentSendQ > HIGHSENDQTHRESHOLD) + { + notice(source, "Cannot process your request at this time. Try again later."); + return; + } + + + /* if the user is online.. use his address */ + if (luser != NULL) + { + sprintf(chaninfo, "%s!%s@%s", + luser->nick, luser->username, luser->site); + } +#ifdef DEBUG + printf("showaccess(): REALNAME= %s CHANINFO= %s\n", realname, chaninfo); +#endif + + nicksearch = 0; + if (!strchr(realname, '@')) + { + if (strchr(realname, '!')) + strcat(realname, "@*"); + else if (strchr(realname, '.')) + { + sprintf(buffer, "*!*@%s", realname); + strcpy(realname, buffer); + } + else + nicksearch = 1; + } + + + count = 0; + scan = UserList[ul_hash(channel)]; + while (scan != NULL) + { + if (strcmp(scan->realname, "!DEL!") && + !strcasecmp(scan->channel, channel) && + ((nicksearch && match(scan->realname, realname)) || + (!nicksearch && compare(realname, scan->match)) || + (nicksearch && match(chaninfo, scan->match))) && + scan->access >= min && scan->access <= max && + (mask == 0 || (scan->flags & mask) == mask) && + (xmask == 0 || (scan->flags & xmask) == 0) && + (*modifby == '\0' || match(scan->modif, modifby))) + { + if (++count > 15 && source[0] != '+') + { + notice(source, + "There are more than 15 matching entries. " + "Please restrict you search"); + return; + } + show_this_user_access_reg(source, scan, modif); + } + scan = scan->next; + } + + hook1 = (struct showaccess_struct *) + malloc(sizeof(struct showaccess_struct)); + strcpy(hook1->source, source); + strcpy(hook1->target, realname); + strcpy(hook1->chaninfo, chaninfo); + strcpy(hook1->modifby, modifby); + hook1->nicksearch = nicksearch; + hook1->min = min; + hook1->max = max; + hook1->mask = mask; + hook1->xmask = xmask; + hook1->modif = modif; + + hook2 = (int *)malloc(sizeof(int)); + *hook2 = count; + + db_fetch(channel, DBGETALLCMP, "", NULL, 0, hook1, hook2, + showaccess_callback); +} + + +static void + suspend_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + char buffer[512]; + register aluser *lusr; + register RegUser *user; + time_t exp; + + exp = action + now; + + if (count == 0) + { + if (*(char *)hook1) + notice((char *)hook1, "No match!"); + } + else if (dbu != NULL && (user = load_dbuser(off, dbu)) != NULL) + { +#ifdef DEBUG + printf("SUSPEND for %s till %ld\n", + user->realname, exp); + puts(ctime(&exp)); +#endif + + if (*(char *)hook1 && + Access(user->channel, (char *)hook1) <= user->access) + { + sprintf(buffer, "User %s's access is higher than or equal to yours", + user->realname); + notice((char *)hook1, buffer); + } + /* If the suspension is the result of a + flood protection (in which case + source==""), I want to make sure + the user is not already suspended for + a longer time! */ + + else if (*(char *)hook1 || user->suspend < exp) + { + user->suspend = exp; + user->modified = 1; + if (*(char *)hook1 && (lusr = ToLuser((char *)hook1))) + { + RegUser *reg; + time_t now1 = now + 3600; + struct tm *tms = gmtime(&now1); + + reg = IsValid(lusr, user->channel); + sprintf(buffer, "%04d%02d%02d@%03ld (%s) %s!%s@%s", + tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday, + 1000 * (now1 % 86400) / 86400, + reg ? reg->realname : "?", + lusr->nick, lusr->username, lusr->site); + + TTLALLOCMEM -= strlen(user->modif) + 1; + free(user->modif); + user->modif = (char *)MALLOC(strlen(buffer) + 1); + strcpy(user->modif, buffer); + } + } + + if (*(char *)hook1) + { + if (user->suspend > now) + { + sprintf(buffer, + "SUSPENSION for %s (%s) will expire in %s", + user->realname, user->match, + time_remaining(user->suspend - now)); + notice((char *)hook1, buffer); + } + else + { + sprintf(buffer, "SUSPENSION for %s (%s) is cancelled", + user->realname, user->match); + notice((char *)hook1, buffer); + } + } + } + if (dbu == NULL) + { + notice((char *)hook1, "Done."); + free(hook1); + } +} + + + +void unsuspend(char *source, char *ch, char *args) +{ + char channel[80]; + char target[100]; + char out[200]; + + if (*args == '#' || (*args == '*' && IsValid(ToLuser(source), ch))) + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + GetWord(0, args, target); + if (!strcmp(channel, "*") || !*target) + { + notice(source, "SYNTAX: unsuspend [#channel] "); + return; + } + sprintf(out, "%s %s 0", channel, target); + suspend(source, ch, out); +} + +void suspend(char *source, char *ch, char *args) +{ + char channel[80], target[80], timestring[80], *hook; + int timeint; + int acc; + + if (*args == '#' || (*args == '*' && IsValid(ToLuser(source), ch))) + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + if (*source) + acc = Access(channel, source); + else + acc = MASTER_ACCESS + 1; + + if (acc < LEVEL_SUSPEND) + { + ReplyNotAccess(source, channel); + return; + } + + GetWord(0, args, target); + GetWord(1, args, timestring); + + if ((!strcmp(channel, "*") && !IsValid(ToLuser(source), channel)) || + !*target || !*timestring) + { + notice(source, "SYNTAX: suspend [channel] [s|m|d]"); + return; + } + + timeint = atoi(timestring); + + switch (*ToWord(2, args)) + { + case 's': + case 'S': + case '\0': + break; + case 'm': + case 'M': + timeint *= 60; + break; + case 'h': + case 'H': + timeint *= 3600; + break; + case 'd': + case 'D': + case 'j': + case 'J': + timeint *= 86400; + break; + default: + notice(source, "Bogus time units"); + return; + } + + if (timeint < 0 || timeint > 31536000) + { + notice(source, "Invalid time"); + return; + } + + hook = (char *)malloc(strlen(source) + 1); + strcpy(hook, source); + + if (strpbrk(target, "!@") != NULL) + { + db_fetch(channel, DBGETALLCMP, target, NULL, timeint, hook, NULL, + suspend_callback); + } + else + { + db_fetch(channel, DBGETNICK, target, NULL, timeint, hook, NULL, + suspend_callback); + } +} + + +void SaveUserList(char *source, char *channel) +{ + char global[] = "*", buffer[256]; + + if (*source && Access(global, source) < SAVE_USERLIST_LEVEL) + { + notice(source, "Sorry! This command is not for you"); + return; + } + + if (DB_Save_Status == -1) + { + notice(source, "Userlist sync initiated"); + DB_Save_Status = 0; + strncpy(DB_Save_Nick, source, NICK_LENGTH - 1); + DB_Save_Nick[NICK_LENGTH - 1] = '\0'; + } + else + { + sprintf(buffer, "Userlist sync is already in progress (%d%%) [%s]", + DB_Save_Status / 10, *DB_Save_Nick ? DB_Save_Nick : "auto"); + notice(source, buffer); + } + /*do_cold_sync(); + + if(*source) + notice(source,"Userlist saved."); + */ +} + + +static void + remuser_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + register RegUser *user; + char buffer[512]; + + if (dbu == NULL) + { + if (count == 0) + { + notice((char *)hook1, "This user is not in my userlist"); + notice((char *)hook1, "Make sure you provide a full n!u@h"); + } + else + { + notice((char *)hook1, "Done."); + } + free(hook1); + } + else + { + user = load_dbuser(off, dbu); + if (user != NULL && user->access < action) + { + sprintf(buffer, "I REMOVE USER %s (%s) from %s", + user->realname, user->match, user->channel); + notice((char *)hook1, buffer); + TTLALLOCMEM -= strlen(user->realname) + 1; + free(user->realname); + user->realname = (char *)MALLOC(6); + strcpy(user->realname, "!DEL!"); + TTLALLOCMEM -= strlen(user->match) + 1; + free(user->match); + user->match = (char *)MALLOC(6); + strcpy(user->match, "!DEL!"); + user->access = 0; + user->flags = 0; + /* if new, don't save */ + if (user->offset == (off_t) - 1) + user->modified = 0; + else + user->modified = 1; + } + } +} + + +void RemoveUser(char *source, char *ch, char *arg) +{ + char buffer[500]; + char channel[80]; + char toremove[80]; + register RegUser *user; + register aluser *src; + int srcacs; + int nicksearch; + + src = ToLuser(source); + if (*arg == '#' || (*arg == '*' && *(arg + 1) == ' ' && IsValid(src, ch))) + { + GetWord(0, arg, channel); + arg = ToWord(1, arg); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + GetWord(0, arg, toremove); + if ((!strcmp(channel, "*") && !IsValid(src, channel)) || !*toremove) + { + notice(source, "SYNTAX: remuser [#channel] "); + return; + } + + if (*source) + srcacs = Access(channel, source); + else + srcacs = MASTER_ACCESS; + + if (srcacs < REMOVE_USER_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + if (strpbrk(toremove, "!@") != NULL) + nicksearch = 0; + else + nicksearch = 1; + + user = UserList[ul_hash(channel)]; + + while (user) + { + if (!strcasecmp(channel, user->channel) && ( + (!nicksearch && !strcasecmp(toremove, user->match)) || + (nicksearch && !strcasecmp(toremove, user->realname)))) + break; + user = user->next; + } + + if (user != NULL) + { + if (user->access >= srcacs) + { + notice(source, "This user's access is higher " + "than yours. Won't remove him!"); + } + else + { + sprintf(buffer, "I REMOVE USER %s (%s) from %s", + user->realname, user->match, user->channel); + notice(source, buffer); + TTLALLOCMEM -= strlen(user->realname) + 1; + free(user->realname); + user->realname = (char *)MALLOC(6); + strcpy(user->realname, "!DEL!"); + TTLALLOCMEM -= strlen(user->match) + 1; + free(user->match); + user->match = (char *)MALLOC(6); + strcpy(user->match, "!DEL!"); + user->access = 0; + user->flags = 0; + if (user->offset == (off_t) - 1) + user->modified = 0; + else + user->modified = 1; + } + } + + if ((user == NULL && nicksearch) || !nicksearch) + { + /* User entry is not found in memory. Send a database + * query for it. + */ + char *hook; + hook = (char *)malloc(strlen(source) + 1); + strcpy(hook, source); + if (nicksearch) + db_fetch(channel, DBGETNICK, toremove, NULL, srcacs, hook, + NULL, remuser_callback); + else + db_fetch(channel, DBGETALLUH, toremove, NULL, srcacs, hook, + NULL, remuser_callback); + } + else + { + notice(source, "Done."); + } +} + +void purge(char *source, char *ch, char *args) +{ + register ShitUser **shit, *tshit; + register RegUser *user; + register int index; + char buffer[1024]; + char channel[80]; + char global[] = "*"; + char *comment; + + if (Access(global, source) < XADMIN_LEVEL) + { + notice(source, "Sorry. This command is reserved to X-admins."); + return; + } + + GetWord(0, args, channel); + comment = ToWord(1, args); + if (!*channel || *channel != '#' || !*comment) + { + notice(source, "SYNTAX: purge "); + return; + } + + sprintf(buffer, "%s is purging channel %s (%s)", + source, channel, comment); + broadcast(buffer, 1); + + RemChan("", channel, ""); + part("", channel, ""); + + shit = &ShitList[sl_hash(channel)]; + while (*shit != NULL) + { + if (!strcasecmp((*shit)->channel, channel)) + { + tshit = *shit; + *shit = (*shit)->next; + TTLALLOCMEM -= strlen(tshit->match) + 1; + free(tshit->match); + TTLALLOCMEM -= strlen(tshit->from) + 1; + free(tshit->from); + TTLALLOCMEM -= strlen(tshit->reason) + 1; + free(tshit->reason); + TTLALLOCMEM -= strlen(tshit->channel) + 1; + free(tshit->channel); + TTLALLOCMEM -= sizeof(ShitUser); + free(tshit); + } + else + shit = &(*shit)->next; + } + + index = ul_hash(channel); + user = UserList[index]; + while (user != NULL) + { + if (!strcasecmp(channel, user->channel)) + { + user->access = 0; + user->flags = 0; + user->modified = 0; /* see the unlink() below */ + TTLALLOCMEM -= strlen(user->realname) + 1; + free(user->realname); + user->realname = (char *)MALLOC(6); + strcpy(user->realname, "!DEL!"); + TTLALLOCMEM -= strlen(user->match) + 1; + free(user->match); + user->match = (char *)MALLOC(6); + strcpy(user->match, "!DEL!"); + } + user = user->next; + } + + unlink(make_dbfname(channel)); + + sprintf(buffer, "Channel %s has been disintegrated.. really.", channel); + notice(source, buffer); + sprintf(buffer, "PURGE (mis)used by %s on %s (%s)", + source, channel, comment); + SpecLog(buffer); +} + + +static void + do_modinfo(char *source, RegUser * user, char *field, char *newvalue) +{ + char buffer[512]; + register aluser *luser; + register avalchan *vchan; + register char *ptr, *ptr2; + register int change = 0; + + luser = ToLuser(source); + if (luser == NULL) + return; + + vchan = luser->valchan; + while (vchan && strcasecmp(user->channel, vchan->name)) + vchan = vchan->next; + + if (vchan == NULL) + { + /* Something happened since the request was sent. + * In any case, it should be ignored now. + */ + return; + } + + if (!strcasecmp(field, "NICK")) + { + notice(source, "The NICK option was disabled."); + } + else if (!strcasecmp(field, "MATCH") || !strcasecmp(field, "MASK")) + { + if (user->access < vchan->reg->access) + { + ptr = strchr(newvalue, '@'); + ptr2 = strchr(newvalue, '!'); + if (!ptr || !ptr2 || ptr2 > ptr || strchr(ptr2 + 1, '!') || + strchr(ptr + 1, '@') || !regex_cmp(VALIDMASK, newvalue)) + { + notice(source, "Invalid nick!user@host mask"); + } + else + { + for (ptr = newvalue; *ptr; ptr++) + { + if (*ptr < 33) + break; + } + if (*ptr) + { + notice(source, "Invalid nick!user@host mask"); + } + else + { + TTLALLOCMEM -= strlen(user->match) + 1; + free(user->match); + user->match = (char *)MALLOC(strlen(newvalue) + 1); + strcpy(user->match, newvalue); + sprintf(buffer, "New MATCH for %s is %s", + user->realname, user->match); + notice(source, buffer); + change = 1; + } + } + } + } + else if (!strcasecmp(field, "ACCESS")) + { + if (user->access < vchan->reg->access) + { + if (strlen(newvalue) > 4 || + atoi(newvalue) >= vchan->reg->access || + atoi(newvalue) < 0) + { + notice(source, "Bogus access"); + } + else + { + user->access = atoi(newvalue); + sprintf(buffer, "New ACCESS for %s is %d", + user->realname, user->access); + notice(source, buffer); + change = 1; + } + } + } + else if (!strcasecmp(field, "AUTOOP")) + { + if (user->access < vchan->reg->access || + user == vchan->reg) + { + if (!strcasecmp(newvalue, "ON") || + !strcasecmp(newvalue, "YES")) + { + user->flags |= UFL_AUTOOP; + } + else if (!strcasecmp(newvalue, "OFF") || + !strcasecmp(newvalue, "NO")) + { + user->flags &= ~UFL_AUTOOP; + } + else + { + notice(source, "You must specify 'yes' or 'no'"); + } + sprintf(buffer, "AUTOOP for %s is %s", + user->realname, (user->flags & UFL_AUTOOP) ? "ON" : "OFF"); + notice(source, buffer); + change = 1; + } + } + else if (!strcasecmp(field, "PASSWORD")) + { + if (user->access < vchan->reg->access || + user == vchan->reg) + { + if (strlen(newvalue) < 6 || strlen(newvalue) > 18) + { + notice(source, "Password must be between 6 and 18 characters long"); + } + else + { + TTLALLOCMEM -= strlen(user->passwd) + 1; + free(user->passwd); + user->passwd = (char *)MALLOC(strlen(newvalue) + 1); + strcpy(user->passwd, newvalue); + sprintf(buffer, "New PASSWORD set for %s", + user->realname); + notice(source, buffer); + change = 1; + } + } + } + else if (!strcasecmp(field, "REMPASS")) + { + notice(source, "REMPASS is no longer available. Try PASSWORD."); + } + if (change) + { + RegUser *reg; + time_t now1 = now + 3600; + struct tm *tms = gmtime(&now1); + + if (strcasecmp(field, "AUTOOP")) + { + reg = IsValid(luser, user->channel); + sprintf(buffer, "%04d%02d%02d@%03ld (%s) %s!%s@%s", + tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday, + 1000 * (now1 % 86400) / 86400, + reg ? reg->realname : "?", + luser->nick, luser->username, luser->site); + TTLALLOCMEM -= strlen(user->modif) + 1; + free(user->modif); + user->modif = (char *)MALLOC(strlen(buffer) + 1); + strcpy(user->modif, buffer); + } + user->modified = 1; + user->lastused = now; + } + else + { + notice(source, "Entry was not modified"); + } +} + + +static void + modinfo_callback(int *fd, off_t off, int action, void *hook1, void *hook2, + dbuser * dbu, int count) +{ + register RegUser *user; + + struct modinfo_struct *ptr = (struct modinfo_struct *)hook1; + + if (count == 0) + { + notice(ptr->source, "No match."); + } + else if (dbu != NULL && (user = load_dbuser(off, dbu)) != NULL) + { + do_modinfo(ptr->source, user, ptr->field, ptr->newvalue); + } + if (dbu == NULL) + { + free(ptr); + } +} + + +void ModUserInfo(char *source, char *msgtarget, char *ch, char *args) +{ + char channel[80]; + char field[80]; + char target[80]; + char newvalue[80]; + register RegUser *user; + register aluser *luser; + int nicksearch, srcacs, index; + + luser = ToLuser(source); + if (*args == '#' || (*args == '*' && *(args + 1) == ' ' && IsValid(luser, ch))) + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + GetWord(0, args, field); + GetWord(1, args, target); + GetWord(2, args, newvalue); + +#ifdef DEBUG + printf("ModUserInfo()\nSOURCE: \"%s\"\nFIELD: \"%s\"\nTARGET: \"%s\"\nNEWVALUE: \"%s\"\n", + source, field, target, newvalue); +#endif + + if ((!strcmp(channel, "*") && !IsValid(luser, channel)) || + !*field || !*target || !*newvalue) + { + notice(source, "SYNTAX: modinfo [#channel] "); + return; + } + + if (!strcasecmp(field, "PASSWORD") && !strchr(msgtarget, '@')) + { + char buffer[200]; + sprintf(buffer, "Please use /msg %s@%s", mynick, SERVERNAME); + notice(source, buffer); + return; + } + + + srcacs = LAccess(channel, luser); + if (srcacs < MOD_USERINFO_LEVEL) + { + ReplyNotAccess(source, channel); + return; + } + + if (strpbrk(target, "!@") != NULL) + nicksearch = 0; + else + nicksearch = 1; + + index = ul_hash(channel); + user = UserList[index]; + + while (user) + { + if (!strcasecmp(channel, user->channel) && ( + (!nicksearch && match(target, user->match)) || + (nicksearch && !strcasecmp(target, user->realname)))) + break; + user = user->next; + } + + if (user != NULL) + { + do_modinfo(source, user, field, newvalue); + } + else + { + struct modinfo_struct *hook; + hook = (struct modinfo_struct *) + malloc(sizeof(struct modinfo_struct)); + strcpy(hook->source, source); + strcpy(hook->field, field); + strcpy(hook->newvalue, newvalue); + + if (nicksearch) + db_fetch(channel, DBGETNICK, target, NULL, 0, hook, + NULL, modinfo_callback); + else + db_fetch(channel, DBGET1STUH, target, NULL, 0, hook, + NULL, modinfo_callback); + } +} + +void ChPass(char *source, char *ch, char *args) +{ + char newpassword[80]; + char channel[80]; + char buffer[200]; + char userhost[200]; + register RegUser *user; + register aluser *luser; + RegUser *reg; + time_t now1 = now + 3600; + struct tm *tms = gmtime(&now1); + + if (*ch == '#') + { + notice(source, "Please DO NOT use the newpass command from a channel!"); + return; + } + + if (!strchr(ch, '@')) + { + sprintf(buffer, "Please use /msg %s@%s newpass [channel] ", + mynick, SERVERNAME); + notice(source, buffer); + return; + } + + if (*args == '#' || *args == '*') + { + GetWord(0, args, channel); + args = ToWord(1, args); + } + else + { + strcpy(channel, ch); + GuessChannel(source, channel); + } + + GetWord(0, args, newpassword); + + luser = ToLuser(source); + user = IsValid(luser, channel); + + if ((!strcmp(channel, "*") && !user) || + !*newpassword || *ToWord(1,args) != '\0') + { + notice(source, "SYNTAX: newpass [channel] "); + return; + } + + if(user && user->suspend > now) + { + notice(source, "You are suspended. Request is ignored."); + return; + } + + if (strlen(newpassword) < 6) + { + notice(source, "A password MUST be at least 6 characters long"); + return; + } + + if (strlen(newpassword) > 19) + { + notice(source, "Password is too long (max 19 characters)"); + return; + } + + sprintf(userhost, "%s!%s@%s", luser->nick, luser->username, luser->site); + + if (user == NULL || user->access <= 0) + { + notice(source, "You are not authenticated on that channel"); + } + else + { + TTLALLOCMEM -= strlen(user->passwd) + 1; + free(user->passwd); + user->passwd = (char *)MALLOC(strlen(newpassword) + 1); + strcpy(user->passwd, newpassword); + TTLALLOCMEM -= strlen(user->modif) + 1; + free(user->modif); + + reg = IsValid(luser, user->channel); + sprintf(buffer, "%04d%02d%02d@%03ld (%s) %s!%s@%s", + tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday, + 1000 * (now1 % 86400) / 86400, + reg ? reg->realname : "?", + luser->nick, luser->username, luser->site); + + user->modif = (char *)MALLOC(strlen(buffer) + 1); + strcpy(user->modif, buffer); + notice(source, "Password changed!"); + sprintf(buffer, "NEWPASS %s as %s on %s", + userhost, user->realname, user->channel); + log(buffer); + } + return; +} + +static void add_sync_channel(char *name) +{ + register syncchan **scan = &SyncChan; + + while (*scan != NULL && strcasecmp((*scan)->name, name)) + scan = &(*scan)->next; + + if (*scan == NULL) + { + *scan = (syncchan *) malloc(sizeof(syncchan)); + strcpy((*scan)->name, name); + (*scan)->next = NULL; + } +} + +void gather_sync_channels(void) +{ + register RegUser *reg; + register int i; + + for (i = 0; i < 1000; i++) + { + reg = UserList[i]; + while (reg != NULL) + { + if (reg->modified || + (!reg->inuse && reg->lastused + CACHE_TIMEOUT < now)) + add_sync_channel(reg->channel); + reg = reg->next; + } + } +} diff --git a/Sources/users.c b/Sources/users.c new file mode 100644 index 0000000..12e0aec --- /dev/null +++ b/Sources/users.c @@ -0,0 +1,521 @@ +/* @(#)$Id: users.c,v 1.7 1998/11/21 14:58:43 seks Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "h.h" + +int lu_hash(char *nick) +{ + register int i, j; + + for (i = 0, j = 0; i < strlen(nick); i++) + j += toupper((unsigned char)nick[i]); + + return (j % 1000); +} + +int su_hash(char *nick) +{ + register int i, j; + + for (i = 0, j = 0; i < strlen(nick); i++) + j += toupper((unsigned char)nick[i]); + + return (j % 100); +} + +aluser *ToLuser(char *nick) +{ + register aluser *curr; + curr = Lusers[lu_hash(nick)]; + while (curr && strcasecmp(nick, curr->nick)) + curr = curr->next; + + return (curr); +} + +void onnick(char *source, char *newnick, char *body) +{ + register aluser *user, **u; + register asuser *suser, **s; + register aserver *serv; + char username[80]; + char hostname[80]; + char TS[80]; + char server[80]; + register achannelnode *chan; + register anickchange *curr, *prec; + char buffer[512]; + int i = 0; + + +#ifdef DEBUG + printf("NICK: %s --> %s ...\n", source, newnick); +#endif + + /* a new user */ + if (!ToLuser(source)) + { /* Not a user, so a server or nothing */ + if (strchr(source, '.') == NULL) + { + /* Source is not a user and not a server either */ + return; + } + + if (!strcasecmp(newnick, mynick)) + { + log("ERROR: I'm nick collided"); +#ifdef DEBUG + printf("ARGH!!! I'M NICK COLLIDED!\n"); +#endif + GetWord(1, body, TS); + GetWord(2, body, username); + GetWord(3, body, hostname); + + if (atol(TS) <= logTS && + strcasecmp(username, myuser) && + strcasecmp(hostname, mysite)) + { + NickInUse(); + log(source); + log(newnick); + log(body); + } + else + { + onquit(source); + return; /*ignore */ + } +#ifdef BACKUP + } + else if (!strcasecmp(newnick, MAIN_NICK)) + { + return; /* ignore */ +#endif + } + else if (ToLuser(newnick)) + { +#ifdef DEBUG + printf("ARGH!!! NICK COLLISION\n"); +#endif + onquit(newnick); + } + GetWord(1, body, TS); + GetWord(2, body, username); + GetWord(3, body, hostname); + GetWord(4, body, server); + +#ifdef FAKE_UWORLD + if (Uworld_status == 1 && !strcasecmp(newnick, UFAKE_NICK)) + { + if (atol(TS) <= UworldTS && atol(TS) != 0 && + strcasecmp(username, UFAKE_NICK) && + strcasecmp(hostname, UFAKE_HOST)) + { + sprintf(buffer, "%s nick collided", UFAKE_NICK); + log(buffer); + Uworld_status = 0; + KillUworld("nick collision"); + return; /* ignore if younger */ + } + } +#endif + + user = (aluser *) MALLOC(sizeof(aluser)); + + user->nick = (char *)MALLOC(strlen(newnick) + 1); + strcpy(user->nick, newnick); + + user->username = (char *)MALLOC(strlen(username) + 1); + strcpy(user->username, username); + + user->site = (char *)MALLOC(strlen(hostname) + 1); + strcpy(user->site, hostname); + + if (*newnick == '+') + serv = &VirtualServer; + else + serv = ToServer(server); + + user->server = serv; + + user->time = atol(TS); + user->mode = 0; + + user->channel = NULL; + user->valchan = NULL; + + user->next = Lusers[lu_hash(newnick)]; + Lusers[lu_hash(newnick)] = user; + + /* add user in server's userlist + */ + suser = (asuser *) MALLOC(sizeof(asuser)); + suser->N = user; + suser->next = serv->users[su_hash(newnick)]; + serv->users[su_hash(newnick)] = suser; + +#ifdef NICKSERV + nserv_nick(newnick, user); +#endif + } + else + { /* nick change */ + +#if 0 + if (!strcasecmp(source, DEFAULT_NICKNAME) && + strcasecmp(newnick, DEFAULT_NICKNAME)) + { + ChNick(DEFAULT_NICKNAME); + } +#endif + if (!strcasecmp(newnick, mynick)) + { +#ifdef DEBUG + printf("ARGH!!! I'M NICK COLLIDED!\n"); +#endif + GetWord(0, body, TS); + if (atol(TS + 1) <= logTS) + { + NickInUse(); + log(source); + log(newnick); + log(body); + } + else + { + onquit(source); + return; /*ignore */ + } + } + + u = &Lusers[lu_hash(source)]; + while (*u && strcasecmp(source, (*u)->nick)) + u = &(*u)->next; + user = *u; + +#ifdef NICKSERV + nserv_nick(newnick, user); +#endif + + if (user == NULL) + quit("ERROR! onnick() can't find user", 1); + + s = &user->server->users[su_hash(source)]; + while (*s && strcasecmp((*s)->N->nick, user->nick)) + s = &(*s)->next; + suser = *s; + + /* change the nick in memory */ + + TTLALLOCMEM -= strlen(user->nick) + 1; + free(user->nick); + user->nick = (char *)MALLOC(strlen(newnick) + 1); + strcpy(user->nick, newnick); + + /* now relocate the structure */ + *u = user->next; + user->next = Lusers[lu_hash(newnick)]; + Lusers[lu_hash(newnick)] = user; + + *s = suser->next; + suser->next = user->server->users[su_hash(newnick)]; + user->server->users[su_hash(newnick)] = suser; + + /* NICK FLOOD PROTECTION */ + /* 1st wipe old nick changes off */ + chan = user->channel; + while (chan) + { + curr = chan->nickhist; + prec = NULL; + + /* if not on channel.. ignore nick flood pro */ + if (!chan->N->on) + { + chan = chan->next; + continue; /* yurk.. as bad as a goto ;) */ + } + + while (curr) + { + if (curr->time < (now - 15)) + { + if (prec) + { + prec->next = curr->next; + TTLALLOCMEM -= sizeof(anickchange); + free(curr); + curr = prec->next; + } + else + { + chan->nickhist = curr->next; + TTLALLOCMEM -= sizeof(anickchange); + free(curr); + curr = chan->nickhist; + } + } + else + { + prec = curr; + curr = curr->next; + } + } + + /* now add the new nick change to the history */ + curr = (anickchange *) MALLOC(sizeof(anickchange)); + strcpy(curr->nick, source); + curr->time = now; /* a lil confusing :( */ + curr->next = chan->nickhist; + chan->nickhist = curr; + + /* now count the nick changes in history + if there are more than allowed.. grrrr */ + for (i = 0, curr = chan->nickhist; curr; + curr = curr->next, i++); + + if (i == chan->N->NickFloodPro && chan->N->NickFloodPro != 0 + && chan->N->on) + { + sprintf(buffer, "%s!%s@%s", user->nick, user->username, user->site); + notice(newnick, + "### NICK FLOOD PROTECTION ACTIVATED ###"); + sprintf(buffer, "%s %d", newnick, + NICK_FLOOD_SUSPEND_TIME); + suspend("", chan->N->name, buffer); + ban("", chan->N->name, newnick); + } + chan = chan->next; + } + } +} + +void onquit(char *nick) +{ + register aluser *user, **u; + register asuser *suser, **s; + register avalchan *valchan; + +#ifdef DEBUG + printf("Detected user quit..\n"); +#endif + u = &Lusers[lu_hash(nick)]; + while (*u && strcasecmp(nick, (*u)->nick)) + u = &(*u)->next; + + user = *u; + + if (user == NULL) + { + log("ERROR: onquit() can't find user!"); +#ifdef HISTORY + History(NULL); +#endif + return; + } + + /* remove from memory */ + while ((valchan = user->valchan) != NULL) + { +#ifdef DEBUG + printf("\twas validated on %s\n", valchan->name); +#endif + valchan->reg->inuse--; + user->valchan = valchan->next; + TTLALLOCMEM -= strlen(valchan->name) + 1; + free(valchan->name); + TTLALLOCMEM -= sizeof(avalchan); + free(valchan); + } + while (user->channel != NULL) + { +#ifdef DEBUG + printf("\twas on %s\n", user->channel->N->name); +#endif + /* onpart() free's the chan structure + * we can't do chan=chan->next after the + * onpart() call. We must start from the + * beginning of the list every time + */ + onpart(nick, user->channel->N->name); + } + + /* remove user from server's userlist + */ + s = &user->server->users[su_hash(user->nick)]; + while (*s != NULL && strcasecmp((*s)->N->nick, user->nick)) + { + s = &(*s)->next; + } + + if (*s != NULL) + { + suser = *s; + *s = (*s)->next; + TTLALLOCMEM -= sizeof(asuser); + free(suser); + } + else + { + log("ERROR: onquit() user not found in server's userlist!"); + } + + *u = user->next; +#if 0 + if (!strcasecmp(user->nick, DEFAULT_NICKNAME)) + { + ChNick(DEFAULT_NICKNAME); + } +#endif + +#ifdef NICKSERV + nserv_quit(user); +#endif + + TTLALLOCMEM -= strlen(user->nick) + 1; + free(user->nick); + TTLALLOCMEM -= strlen(user->username) + 1; + free(user->username); + TTLALLOCMEM -= strlen(user->site) + 1; + free(user->site); + TTLALLOCMEM -= sizeof(aluser); + free(user); +} + +void onkill(char *source, char *target, char *comment) +{ + char buffer[200]; + + if (!strcasecmp(target, mynick)) + { +#if 0 + /* ignore kill for nick collisions because we + * already check in onnick() if we're collided. + * This kill is prolly a lost kill resulting of + * another nick collision.. + */ + if (strstr(comment, "older nick overruled") || + strstr(comment, "collided yourself")) + { + log("ERROR: Nick collision on me?"); + return; + } +#endif + sprintf(buffer, ":%s SQUIT %s 0 :killed by %s\n", + SERVERNAME, SERVERNAME, source); + sendtoserv(buffer); + dumpbuff(); + close(Irc.fd); + Irc.fd = -1; + if (reconnect(server)) + { + try_later(server); + } +#ifdef BACKUP + } + else if (!strcasecmp(target, MAIN_NICK)) + { + quit(MAIN_NICK " is back", 0); +#endif +#ifdef FAKE_UWORLD + } + else if (!strcasecmp(target, UFAKE_NICK)) + { + char buffer[200]; + sprintf(buffer, "%s is KILLED by %s", UFAKE_NICK, source); + log(buffer); + Uworld_status = 0; + KillUworld("Killed"); +#endif + } + else + onquit(target); +} + +void onwhois(char *source, char *nick) +{ + register aluser *user; + register auser *usr; + register achannelnode *chan; + char buffer[512]; + + user = ToLuser(nick); + + if (user == NULL) + { + sprintf(buffer, ":%s 401 %s %s :No such nick\n", SERVERNAME, source, nick); + sendtoserv(buffer); + } + else + { + sprintf(buffer, ":%s 311 %s %s %s %s * :\n", SERVERNAME, source, user->nick, + user->username, user->site); + sendtoserv(buffer); + + chan = user->channel; + if (chan != NULL && strcmp(user->nick, "X") && strcmp(user->nick, "W")) + { + sprintf(buffer, ":%s 319 %s %s :", SERVERNAME, source, nick); + while (chan != NULL) + { + /* show a channel only if it is + * not +s or +p + */ + if (!IsSet(chan->N->name, 's', "") && + !IsSet(chan->N->name, 'p', "")) + { + usr = ToUser(chan->N->name, nick); + if (usr->chanop) + strcat(buffer, "@"); + strcat(buffer, chan->N->name); + strcat(buffer, " "); + } + chan = chan->next; + if (strlen(buffer) > 300) + { + strcat(buffer, "\n"); + sendtoserv(buffer); + sprintf(buffer, ":%s 319 %s %s :", + SERVERNAME, source, nick); + } + } + strcat(buffer, "\n"); + sendtoserv(buffer); + } + sprintf(buffer, ":%s 312 %s %s %s :\n", SERVERNAME, source, source, user->server->name); + sendtoserv(buffer); + + if (user->mode & LFL_ISOPER) + { + sprintf(buffer, ":%s 313 %s %s :is an IRC Operator\n", + SERVERNAME, source, user->nick); + sendtoserv(buffer); + } + } + + sprintf(buffer, ":%s 318 %s :End of /WHOIS list.\n", SERVERNAME, source); + sendtoserv(buffer); +} diff --git a/Sources/version.SH b/Sources/version.SH new file mode 100755 index 0000000..424d384 --- /dev/null +++ b/Sources/version.SH @@ -0,0 +1,38 @@ +#!/bin/sh + +TAG="v20020715 build-`date -u '+%Y%m%d%H%M%S'`" + +echo Updating version... $TAG + +cat << NUFF > version.c +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +/* This file is generated by version.SH and any change will be + * overwritten when you recompile. + */ + +char VERSION[]="Undernet Channel Service $TAG "; + +NUFF diff --git a/Sources/version.c b/Sources/version.c new file mode 100644 index 0000000..e8d6b45 --- /dev/null +++ b/Sources/version.c @@ -0,0 +1,30 @@ +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +/* This file is generated by version.SH and any change will be + * overwritten when you recompile. + */ + +char VERSION[]="Undernet Channel Service v20020715151606 "; + diff --git a/Sources/version.h b/Sources/version.h new file mode 100644 index 0000000..14c0a70 --- /dev/null +++ b/Sources/version.h @@ -0,0 +1,4 @@ +/* @(#)$Id: version.h,v 1.3 1996/11/13 00:40:51 seks Exp $ */ + +extern char VERSION[]; + diff --git a/WARRANTY b/WARRANTY new file mode 100644 index 0000000..14cd28e --- /dev/null +++ b/WARRANTY @@ -0,0 +1,11 @@ + NO WARRANTY + +BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. diff --git a/XHELP/ACCESS b/XHELP/ACCESS new file mode 100644 index 0000000..c2cc44c --- /dev/null +++ b/XHELP/ACCESS @@ -0,0 +1,20 @@ +SYNTAX: access [channel] [nick] [-min n] [-max n] + [-autoop] [-noautoop] + [-modif [mask]] + +access shows the access of nick (or yours if no nick is +given) on channel (or current if no channel is given). The +following options can also be used to filter the list: + + -min n Show only users with access higher than + or equal to n. + -max n Show only users with access lower than or + equal to n. + -autoop Show only users with the autoop flag on. + -noautoop Show only users with the autoop flag off. + -modif [mask] Show who made the last modification. If a search + mask is given, only the entries that have been + last modified by someone matching the mask will + be given. + +Options can be combined at wish. (-autoop -noautoop == No match.) diff --git a/XHELP/ADDUSER b/XHELP/ADDUSER new file mode 100644 index 0000000..c2a2572 --- /dev/null +++ b/XHELP/ADDUSER @@ -0,0 +1,16 @@ +SYNTAX: adduser [channel] [mask] + modinfo [channel] + remuser [channel] + +adduser gives the given access to anyone matching mask. +nick is only used as a reference and should be the nickname the +person uses to most. If nick is online, mask is not necessary, +and the userhost will be looked up automatically. If default user +flags are defined (see help set), those flags are used. + +modinfo is used to modify an entry in the userlist. field can +be either of the followings: MATCH, ACCESS, AUTOOP, PASSWORD. +new value must be ON or OFF for field AUTOOP, or other +valid values for the other fields. + +remuser removes the access of the given user. diff --git a/XHELP/BAN b/XHELP/BAN new file mode 100644 index 0000000..30d0dff --- /dev/null +++ b/XHELP/BAN @@ -0,0 +1,22 @@ +SYNTAX: ban [channel] [duration] [level] [reason] + unban [channel] + cleanbanlist + +ban adds an entry to the 'banlist'. If channel is supplied, +it is used instead of the current channel. duration specifies how +long the entry should remain in the list (in hours). level is an +integer ranging from 0 to your access level on the channel. reason +is not mandatory and can be up to 80 characters long. + +The effect of this command depends on the level supplied: +  level | effect  + >= 20 | user is not allowed to be chanop + >= 75 | user is not allowed to be on the + | channel at all. +Intermediate levels are used internally to manage warnings. + +unban removes a ban from the banlist. + +cleanbanlist purges expired entries from the banlist. This should +be handled automatically, so this command should only be used as a +debug tool. diff --git a/XHELP/CHANINFO b/XHELP/CHANINFO new file mode 100644 index 0000000..dc03613 --- /dev/null +++ b/XHELP/CHANINFO @@ -0,0 +1,3 @@ +SYNTAX: chaninfo [channel] + +Gives information about channel's manager. diff --git a/XHELP/CLEARMODE b/XHELP/CLEARMODE new file mode 100644 index 0000000..700c691 --- /dev/null +++ b/XHELP/CLEARMODE @@ -0,0 +1,5 @@ +SYNTAX: clearmode [channel] + +clearmode clears all the channel modes. This +is useful when your channel is locked so you can't even +join the channel. diff --git a/XHELP/DEFCHAN b/XHELP/DEFCHAN new file mode 100644 index 0000000..3c29cc7 --- /dev/null +++ b/XHELP/DEFCHAN @@ -0,0 +1,7 @@ +SYNTAX: addchan [channel] + remchan [channel] + +addchan adds a channel to $NICK's auto-join list. + +remchan removes a channel from $NICK's auto-join list. The +userlist for that channel remains unchanged. diff --git a/XHELP/HELP b/XHELP/HELP new file mode 100644 index 0000000..20adc58 --- /dev/null +++ b/XHELP/HELP @@ -0,0 +1,18 @@ +SYNTAX: help + +help displays the help file associated with topic. +Use showcommands to get a list of commands available +to you. + +Commands must be sent by MSG and if the command has effect +on a specific channel, that channel's name must be the +first argument. ie: + /msg $NICK op #blah nick to op nick on channel #blah +or /msg $NICK op nick if you are on channel #blah + +The administration of Undernet and the provider of this service +are NOT responsible for what is going on the channels this +service is on. + +To get more information on this service, use help info + diff --git a/XHELP/HELPLIST b/XHELP/HELPLIST new file mode 100644 index 0000000..d2c1b95 --- /dev/null +++ b/XHELP/HELPLIST @@ -0,0 +1,6 @@ +X'S COMMAND LIST: +XACCESS XADDCHAN XADDUSER XBAN XBANLIST +XCHANINFO XCLEARMODE XDEOP XHELP XINVITE +XJOIN XKICK XLBANLIST XMAP XMOTD +XOP XPART XPASS XREMCHAN XREMUSER +XSET XSHOWCOMMANDS XSHOWIGNORE XSUSPEND XUNBAN diff --git a/XHELP/INFO b/XHELP/INFO new file mode 100644 index 0000000..3526603 --- /dev/null +++ b/XHELP/INFO @@ -0,0 +1,25 @@ + Undernet's Channel Service Information  +This is the Undernet Channel Service written by Robin Thellend +aka SeKs . + +A registered channel is under the responsibility of its channel +manager who has full control over it. To register a channel, +complete the registration that can be found at +http://cservice.undernet.org/regist/ and follow the instructions. + +It is also recommended that you read the Channel Service Committee +Guidelines before sending in an application. This will explain the +process of registering a channel with the Undernet Channel Service. + +The guidelines are available on the WWW at +http://cservice.undernet.org/ and by FTP at +ftp://ftp.undernet.org/pub/irc/docs/X/CSC-guidelines + +They are also available from Undernet IRC by: +/msg HelpBot get CSC-guidelines + +The number of channels one can register is currently limited to one +channel per person. Registration takes 2 to 3 weeks to complete. + +For more general info, contact cservice@undernet.org +For technical info, contact cservice-coders@undernet.org. diff --git a/XHELP/INVITE b/XHELP/INVITE new file mode 100644 index 0000000..349acfe --- /dev/null +++ b/XHELP/INVITE @@ -0,0 +1,6 @@ +SYNTAX: invite [#channel] + +invite makes $NICK invite nick to #channel for you. +This is useful on invite-only channels. For example, you can do + /msg $NICK invite #mychan mynick +to make $NICK invite you to your channel. diff --git a/XHELP/JOIN b/XHELP/JOIN new file mode 100644 index 0000000..dfa9829 --- /dev/null +++ b/XHELP/JOIN @@ -0,0 +1,8 @@ +SYNTAX: join + part [channel] + +join is used to make $NICK join channel. Obviously, one +must have access on that channel in order to do that. + +part makes $NICK leave the current channel (or channel if +it is specified). diff --git a/XHELP/KICK b/XHELP/KICK new file mode 100644 index 0000000..a9dc369 --- /dev/null +++ b/XHELP/KICK @@ -0,0 +1,6 @@ +SYNTAX: kick [channel] [reason] + kick [channel] [reason] (Level 200) + +This command kicks nick or any user matching the given +match pattern. If a reason is supplied, it will be +used as kick comment. diff --git a/XHELP/MAP b/XHELP/MAP new file mode 100644 index 0000000..5db4a64 --- /dev/null +++ b/XHELP/MAP @@ -0,0 +1,3 @@ +SYNTAX: map + +map displays how the servers are connected together. diff --git a/XHELP/MOTD b/XHELP/MOTD new file mode 100644 index 0000000..5093039 --- /dev/null +++ b/XHELP/MOTD @@ -0,0 +1,3 @@ +SYNTAX: motd + +Gives $NICK's Message Of The Day. diff --git a/XHELP/OP b/XHELP/OP new file mode 100644 index 0000000..a825ebf --- /dev/null +++ b/XHELP/OP @@ -0,0 +1,8 @@ +SYNTAX: op [channel] [nick2] [nick3] [...] + deop [channel] [nick2] [nick3] [...] + +op and deop respectively give and remove channel operator +priviledges to the specified users. + +Note that this command is disabled when the channel is in NoOp +mode (SEE help set for more information). diff --git a/XHELP/PASSWORD b/XHELP/PASSWORD new file mode 100644 index 0000000..dd2ec32 --- /dev/null +++ b/XHELP/PASSWORD @@ -0,0 +1,15 @@ +SYNTAX: login [your password] + newpass + deauth + +login is used to validate yourself. You need to use this +command even if you don't have a password. + +newpass changes your password to new password. You +have to validate yourself before using this command. + +deauth is used to deauthenticate yourself on a channel; +this is provided for the security-minded. + +Note: login and newpass must be sent to +$NICK@$SERVER for $NICK diff --git a/XHELP/SET b/XHELP/SET new file mode 100644 index 0000000..eabc0f8 --- /dev/null +++ b/XHELP/SET @@ -0,0 +1,32 @@ +SYNTAX: set [channel] + +set is used to configure $NICK's reactions upon different +situations. variable is one of the following: + MassDeopPro NickFloodPro FloodPro UserFlags + NoOp AlwaysOp OpOnly StrictOp + Description URL AutoTopic + +MassDeopPro is the maximum number of deops one can issue +before the MassDeop protection is activated. +NickFloodPro is maximum number of nick changes one can do +before the NickFlood protection is activated. +FloodPro is the limit of lines one can send to a channel. +NOTE: since $NICK is umode +d (Deaf) the floodpro doesn't work for + channels messages. It only works for TOPICs, KICKs, etc. +UserFlags is the default flags given to a newly added user. +NoOp is a special mode where only $NICK can be channel operator. +AlwaysOp makes $NICK always be op. +OpOnly disables all commands except op. +StrictOp will only allow authenticated users to be op. +Description will set the official channel description. +URL will set a link to the channel home page. +AutoTopic will reset the topic to the official URL and +description of the channel every 30 minutes *if* the channel +is active. + +MassDeopPro, NickFloodPro and FloodPro have integer values and +are all based on a 15-second period. +UserFlags can be 1 (autoop) or 0 (no autoop). +NoOp, AlwaysOp, OpOnly, StrictOp and AutoTopic have either ON or OFF +values. +Description and URL are strings up to 80 characters long. diff --git a/XHELP/SHOWCOMMANDS b/XHELP/SHOWCOMMANDS new file mode 100644 index 0000000..402b579 --- /dev/null +++ b/XHELP/SHOWCOMMANDS @@ -0,0 +1,4 @@ +SYNTAX: showcommands [channel] + +showcommands gives you the commands that are available to you +on channel (or current if no channel is given). diff --git a/XHELP/SHOWIGNORE b/XHELP/SHOWIGNORE new file mode 100644 index 0000000..0235c11 --- /dev/null +++ b/XHELP/SHOWIGNORE @@ -0,0 +1,3 @@ +SYNTAX: showignore + +Gives the list of users currently being ignored by $NICK. diff --git a/XHELP/STATUS b/XHELP/STATUS new file mode 100644 index 0000000..ea8174b --- /dev/null +++ b/XHELP/STATUS @@ -0,0 +1,3 @@ +SYNTAX: status [channel] + +status outputs informations about channel. diff --git a/XHELP/SUSPEND b/XHELP/SUSPEND new file mode 100644 index 0000000..b16a1bf --- /dev/null +++ b/XHELP/SUSPEND @@ -0,0 +1,12 @@ +SYNTAX: suspend [channel] [s|m|h|d] + unsuspend [channel] + +The command suspend is used to remove one's access to this service +for a certain time specified with the duration argument. Time units +can be specified for duration (seconds,minutes,hours or days). + +When a user is suspended he or she cannot use any command requiring +an access level greater than zero. One can only suspend a user who +has an inferior access than his. + +unsuspend removes a suspension (same as suspend with a duration 0) diff --git a/XHELP/TOPIC b/XHELP/TOPIC new file mode 100644 index 0000000..d6914c9 --- /dev/null +++ b/XHELP/TOPIC @@ -0,0 +1,4 @@ +SYNTAX: topic [channel] + +topic changes the topic on channel (or on the current +channel if none is given) to new topic. diff --git a/XHELP/VERIFY b/XHELP/VERIFY new file mode 100644 index 0000000..b370468 --- /dev/null +++ b/XHELP/VERIFY @@ -0,0 +1,7 @@ +SYNTAX: verify + +This command will tell you whether nick is an authenticated +CSERVICE representative. + +A CSERVICE representative is capable of helping you solve problems +you may have with the channel service. diff --git a/XHELP/X b/XHELP/X new file mode 100644 index 0000000..d2c1b95 --- /dev/null +++ b/XHELP/X @@ -0,0 +1,6 @@ +X'S COMMAND LIST: +XACCESS XADDCHAN XADDUSER XBAN XBANLIST +XCHANINFO XCLEARMODE XDEOP XHELP XINVITE +XJOIN XKICK XLBANLIST XMAP XMOTD +XOP XPART XPASS XREMCHAN XREMUSER +XSET XSHOWCOMMANDS XSHOWIGNORE XSUSPEND XUNBAN diff --git a/XHELP/Xscript b/XHELP/Xscript new file mode 100644 index 0000000..e5dbf54 --- /dev/null +++ b/XHELP/Xscript @@ -0,0 +1,179 @@ +# This little script is intended to *ease* the use +# of the channel service interface "X". It works pretty +# much like the /help command, except that it's called +# /xhelp :) +# +# NB. Most aliases are X's commands prefixed by 'X'. +# +# Feel free to distribute this package to your friends, but +# just make sure my name stays on it. I want to make sure +# people know where to send their complaints ;) +# +# seks +# 95/07/13 +# update 95/12/11 + +^SET DISPLAY OFF +SET EXEC_PROTECTION OFF +SET NOVICE OFF + +ASSIGN XHELP_DIR ~/XHELP +#ASSIGN XHELP_DIR /usr/local/lib/irc/XHELP +ASSIGN CAT /bin/cat + +ALIAS XX //QUOTE PRIVMSG X@CHANNELS.UNDERNET.ORG :$* +ALIAS WW //QUOTE PRIVMSG W@CHANNELS2.UNDERNET.ORG :$* + +ALIAS XACCESS XX ACCESS +ALIAS XADDCHAN XX ADDCHAN +ALIAS XADDUSER XX ADDUSER +ALIAS XBAN XX BAN +ALIAS XBANLIST XX BANLIST +ALIAS XCHANINFO XX CHANINFO +ALIAS XCLEARMODE XX CLEARMODE +ALIAS XCOMMANDS XX SHOWCOMMANDS +ALIAS XDEOP XX DEOP +ALIAS XINFO XHELP INFO +ALIAS XINVITE XX INVITE +ALIAS XJOIN XX JOIN +ALIAS XKICK XX KICK +ALIAS XLBANLIST XX LBANLIST +ALIAS XMAP XX MAP +ALIAS XMODINFO XX MODINFO +ALIAS XMOTD XX MOTD +ALIAS XNEWPASS XX NEWPASS +ALIAS XOP XX OP +ALIAS XPART XX PART +ALIAS XPASS XX PASS +ALIAS XREMCHAN XX REMCHAN +ALIAS XREMUSER XX REMUSER +ALIAS XSET XX SET +ALIAS XSHOWCOMMANDS XX SHOWCOMMANDS +ALIAS XSTATUS XX STATUS +ALIAS XSUSPEND XX SUSPEND +ALIAS XTOPIC XX TOPIC +ALIAS XUNBAN XX UNBAN +ALIAS XUNSUSPEND XX UNSUSPEND + +ALIAS WACCESS WW ACCESS +ALIAS WADDCHAN WW ADDCHAN +ALIAS WADDUSER WW ADDUSER +ALIAS WBAN WW BAN +ALIAS WBANLIST WW BANLIST +ALIAS WCHANINFO WW CHANINFO +ALIAS WCLEARMODE WW CLEARMODE +ALIAS WCOMMANDS WW SHOWCOMMANDS +ALIAS WDEOP WW DEOP +ALIAS WINFO WHELP INFO +ALIAS WINVITE WW INVITE +ALIAS WJOIN WW JOIN +ALIAS WKICK WW KICK +ALIAS WLBANLIST WW LBANLIST +ALIAS WMAP WW MAP +ALIAS WMODINFO WW MODINFO +ALIAS WMOTD WW MOTD +ALIAS WNEWPASS WW NEWPASS +ALIAS WOP WW OP +ALIAS WPART WW PART +ALIAS WPASS WW PASS +ALIAS WREMCHAN WW REMCHAN +ALIAS WREMUSER WW REMUSER +ALIAS WSET WW SET +ALIAS WSHOWCOMMANDS WW SHOWCOMMANDS +ALIAS WSTATUS WW STATUS +ALIAS WSUSPEND WW SUSPEND +ALIAS WTOPIC WW TOPIC +ALIAS WUNBAN WW UNBAN +ALIAS WUNSUSPEND WW UNSUSPEND + +ALIAS XHELP +{ + @_COUNT=0 + @_HELPFILES=[HELPLIST ACCESS DEFCHAN ADDUSER BAN BAN CHANINFO OP HELP INVITE INFO JOIN KICK BAN MAP MOTD OP JOIN PASSWORD DEFCHAN ADDUSER SET SHOWCOMMANDS SHOWIGNORE SUSPEND SUSPEND TOPIC BAN CLEARMODE] + @_HELPCOMMS=[XACCESS XADDCHAN XADDUSER XBAN XBANLIST XCHANINFO XDEOP XHELP XINVITE XINFO XJOIN XKICK XLBANLIST XMAP XMOTD XOP XPART XPASS XREMCHAN XREMUSER XSET XSHOWCOMMANDS XSHOWIGNORE XSUSPEND XUNSUSPEND XTOPIC XUNBAN XCLEARMODE] + ^SET HOLD_MODE ON + ^ON ^EXEC XHELP { + @_COUNT=(_COUNT+1) + IF ( _COUNT == 22 ) + { + INPUT "More? " @_COUNT=0 + } + ECHO *** $1- + } + ^ON ^EXEC_EXIT XHELP { + ^ON ^EXIT_EXIT -XHELP + ^ON ^EXEC -XHELP + ^ASSIGN -_COUNT + ^ASSIGN -_HELPFILES + ^ASSIGN -_HELPCOMMS + ^SET HOLD_MODE OFF + INPUT "XHelp? " IF ( [$0] ) { XHELP $* } + } + + IF ( [$0] ) + { + ECHO ***  HELP on $[55]0 + IF ( [$[1]0] == [X] ) + { + EXEC -NAME XHELP $CAT $XHELP_DIR/$WORD($RMATCH($0 $_HELPCOMMS) $_HELPFILES) + } + { + EXEC -NAME XHELP $CAT $XHELP_DIR/$WORD($RMATCH(X$0 $_HELPCOMMS) $_HELPFILES) + } + } + { + EXEC -NAME XHELP $CAT $XHELP_DIR/HELPLIST + } +} + +ALIAS WHELP +{ + @_COUNT=0 + @_HELPFILES=[HELPLIST ACCESS DEFCHAN ADDUSER BAN BAN CHANINFO OP HELP INVITE INFO JOIN KICK BAN MAP MOTD OP JOIN PASSWORD DEFCHAN ADDUSER SET SHOWCOMMANDS SHOWIGNORE SUSPEND SUSPEND TOPIC BAN CLEARMODE] + @_HELPCOMMS=[WACCESS WADDCHAN WADDUSER WBAN WBANLIST WCHANINFO WDEOP WHELP WINVITE WINFO WJOIN WKICK WLBANLIST WMAP WMOTD WOP WPART WPASS WREMCHAN WREMUSER WSET WSHOWCOMMANDS WSHOWIGNORE WSUSPEND WUNSUSPEND WTOPIC WUNBAN WCLEARMODE] + ^SET HOLD_MODE ON + ^ON ^EXEC XHELP { + @_COUNT=(_COUNT+1) + IF ( _COUNT == 22 ) + { + INPUT "More? " @_COUNT=0 + } + ECHO *** $1- + } + ^ON ^EXEC_EXIT WHELP { + ^ON ^EXIT_EXIT -WHELP + ^ON ^EXEC -WHELP + ^ASSIGN -_COUNT + ^ASSIGN -_HELPFILES + ^ASSIGN -_HELPCOMMS + ^SET HOLD_MODE OFF + INPUT "WHelp? " IF ( [$0] ) { WHELP $* } + } + + IF ( [$0] ) + { + ECHO ***  HELP on $[55]0 + IF ( [$[1]0] == [W] ) + { + EXEC -NAME WHELP $CAT $XHELP_DIR/$WORD($RMATCH($0 $_HELPCOMMS) $_HELPFILES) + } + { + EXEC -NAME WHELP $CAT $XHELP_DIR/$WORD($RMATCH(W$0 $_HELPCOMMS) $_HELPFILES) + } + } + { + EXEC -NAME XHELP $CAT $XHELP_DIR/HELPLIST + } +} + + + +ON ^NOTICE X ECHO X** $1- +ON ^NOTICE W ECHO W** $1- +#ON ^SERVER_NOTICE "% % % % HACK% UWORLD%.UNDERNET.ORG MODE #% +o X*" ECHO *** X reop on $7 +#ON ^SERVER_NOTICE "% % % % HACK% UWORLD%.UNDERNET.ORG MODE #% +o W*" ECHO *** W reop on $7 +ON ^401 "% X@CHANNELS%.UNDERNET.ORG *" ECHO *** X is unreachable at the moment +ON ^401 "% W@CHANNELS%.UNDERNET.ORG *" ECHO *** W is unreachable at the moment + +^SET DISPLAY ON +ECHO *** X script loaded! (try /xhelp) diff --git a/XHELP/readme b/XHELP/readme new file mode 100644 index 0000000..7a8b4e6 --- /dev/null +++ b/XHELP/readme @@ -0,0 +1,30 @@ +This is the undernet channel service help package. + +To install it, execute this command in your home +directory: + tar zxf Xhelp.tgz +OR, gzip -cd < Xhelp.tgz | tar xf + +Then, you only have to load the file ~/XHELP/Xscript +in your IRC session. The easiest way to do it is to +add it in your .ircrc with this command: + + echo "//LOAD ~/XHELP/Xscript" >> ~/.ircrc + +Make sure you type both '>'. Otherwise, your .ircrc +file will be lost. + +To install it for your whole system, uncompress the +archive in your IRCLIB directory, edit the Xscript +file so XHELP_DIR points to the correct directory and +add the proper /LOAD in your script/local. + +This package is likely to require updates. +The latest version of this package is always +available from: + ftp://ca.undernet.org/pub/undernet/X/Xhelp.tgz + +----- +Robin Thellend (SeKs@IRC) + + diff --git a/config.h.dist b/config.h.dist new file mode 100644 index 0000000..079e45a --- /dev/null +++ b/config.h.dist @@ -0,0 +1,304 @@ +/* @(#)CS/config.h.dist $Id: config.h.dist,v 1.16 2000/06/13 05:08:40 lgm Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + + +/* BINDADDR is the local address that all the sockets should be + * bound to. + */ +#define BINDADDR "12.34.56.78" + + +/* DEFAULT_PORTNUM is the port X will try to + * connect to. This can be overridden by + * DEFAULT_SERVER + */ +#ifdef MAIN +int DEFAULT_PORTNUM = 6667; +#else +extern int DEFAULT_PORTNUM; +#endif + +/* DEFAULT_NICKNAME is the nick of the channel service interface + * DEFAULT_USERNAME, its username + * DEFAULT_HOSTNAME, its hostname + * DEFAULT_REALNAME, its realname. + */ +#define DEFAULT_NICKNAME "X" +#define DEFAULT_REALNAME "For help type: \002/msg X help\002" + +/* If is very important that all the channel services running + * on the same net use the same user@host :) + */ +#define DEFAULT_USERNAME "cservice" +#define DEFAULT_HOSTNAME "undernet.org" + +#ifdef MAIN +char UMODE[10] = "+kid"; +#else +extern char UMODE[10]; +#endif + +/* DEFAULT_SERVER is the server X should connect to. + * It can be either "server" or "server:port" + */ +#define DEFAULT_SERVER "localhost" + +/* SERVERNAME and SERVERINFO are for + * X's servername. + * PASSWORD is the password sent before the SERVER command. + */ +#ifdef MAIN +char SERVERNAME[80] = "channels.undernet.org"; +char SERVERINFO[80] = "Channel Service"; +char PASSWORD[80] = "pizza"; +#else +extern char SERVERNAME[80]; +extern char SERVERINFO[80]; +extern char PASSWORD[80]; +#endif + +/* HOMEDIR is X's home directory. + * A chdir() is issued at the very beginning of + * the execution. + */ +#ifdef MAIN +char HOMEDIR[256] = "/home/seks/CS"; +#else +extern char HOMEDIR[256]; +#endif +/*#define HOMEDIR "/usr/home/adm/undernet/CS"*/ +/*#define HOMEDIR "/usr/ircd/q/CS"*/ +/*#define HOMEDIR "/home/intru/CS"*/ + +/* UMASK is the umask used when creating new files + */ +#ifdef MAIN +int UMASK = 0077; +#else +extern int UMASK; +#endif + +/* USERFILE is where user lists are stored. + */ +#define USERFILE "userlist.dat" + +/* DEFAULT_CHANNELS_FILE is the file containing the + * list of channel that should be joined by default. + * In other words, those that have been addchan'ed :) + */ +#define DEFAULT_CHANNELS_FILE "channellist.dat" + +/* SHITLIST_FILE is the file where bans are stored + */ +#define SHITLIST_FILE "shitlist.dat" + +/* EXEC_FILE is the name of the executable for the restart function + * (added by Kev) + */ +#ifdef MAIN +char EXEC_FILE[256] = "./cs"; +#else +extern char EXEC_FILE[256]; +#endif + +/* Other useful files.. + */ +#ifdef MAIN +char MOTD_FILE[256] = "cs.motd"; +char LOGFILE[256] = "cs.log"; +char LOGFILEBAK[256] = "cs.log.old"; +#undef CHANNEL_LOG +#define CHANNEL_LOG_FREQ 3600 +char PIDFILE[256] = "cs.pid"; +char HELP_DIR[256] = "XHELP"; /* must be non-empty */ +#else +extern char MOTD_FILE[256]; +extern char LOGFILE[256]; +extern char LOGFILEBAK[256]; +extern char PIDFILE[256]; +extern char HELP_DIR[256]; +#endif + +/* Information on the main administrator + */ +#ifdef MAIN +char MASTER_REALNAME[80] = "SeKs"; +char MASTER_PASSWD[20] = "XXXXXXXXXX"; +char MASTER_MATCH[80] = "*!*seks@*.*"; +#else +extern char MASTER_REALNAME[80]; +extern char MASTER_PASSWD[20]; +extern char MASTER_MATCH[80]; +#endif +#define MASTER_ACCESS 1000 +#define MASTER_CHANNEL "*" +#define MASTER_FLAGS 0 + + +/* Other stuff... + */ +#define PING_FREQ 120 /* seconds */ +#define USERLIST_SAVE_FREQ 7200 /* seconds */ +#define SHITLIST_SAVE_FREQ 7200 /* seconds */ +#define DEFS_SAVE_FREQ 7200 /* seconds */ +#define SYNC_FREQ 7200 /* seconds */ +#define MODE_DELAY 2 /* seconds */ + +#ifdef MAIN +char BROADCAST_CHANNEL[80] = "#cservice_info"; +char VERIFY_ID[256] = "CSERVICE"; +#else +extern char BROADCAST_CHANNEL[80]; +extern char VERIFY_ID[256]; +#endif + +#ifdef MAIN +char UWORLD[10] = "Uworld"; +char UWORLD_HOST[80] = "*.nssl.uoknor.edu"; +char UWORLD_SERVER[80] = "Uworld.undernet.org"; +#else +extern char UWORLD[10]; +extern char UWORLD_HOST[80]; +extern char UWORLD_SERVER[80]; +#endif + +#define UWORLD2 UWORLD2_NICK +#ifdef UWORLD2 +#ifdef MAIN +char UWORLD2_NICK[10] = "Uworld2"; +char UWORLD2_HOST[80] = "undernet.org"; +char UWORLD2_SERVER[80] = "Uworld2.undernet.org"; +#else +extern char UWORLD2_NICK[10]; +extern char UWORLD2_HOST[80]; +extern char UWORLD2_SERVER[80]; +#endif +#endif + +#ifdef BACKUP +# define MAIN_NICK DEFAULT_NICKNAME +# define MAIN_REALNAME ":X's backup: ^B/msg Q motd^B" +# undef DEFAULT_NICKNAME +# undef DEFAULT_REALNAME +# define DEFAULT_NICKNAME "Q" +# define DEFAULT_REALNAME ":X's backup: ^B/msg Q help^B" +# define MAIN_SERVERNAME SERVERNAME +# undef SERVERNAME +# undef SERVERINFO +# define SERVERNAME "channels2.undernet.org" +# define SERVERINFO "Channel Service Backup" +#endif + + +#define UWORLD_COMMAND "reop %s" + +#define FAKE_UWORLD +#ifdef FAKE_UWORLD +# define UFAKE_NICK UWORLD2 +# define UFAKE_HOST DEFAULT_HOSTNAME +# define UFAKE_SERVER UWORLD2_SERVER +# define UFAKE_INFO "Uworld" +#endif + +#define GETOPS_FREQ 600 /* seconds */ +#define GETOPS_ONJOIN_DELAY 30 /* seconds */ + +#define MAX_IDLE_TIME (48*3600) /* seconds */ +#define CHECK_IDLE_FREQ (3 *3600) /* seconds */ +#define USERLIST_EXP_TIME (90*24*3600) /* seconds (90 days) */ +#define RENAME_LOGFILE_FREQ (3*24*3600) /* seconds (3 days) */ + +#ifdef MAIN +char CALMDOWNTOPIC[512] = + "This channel is in NoOp mode because of repeated abuse. Please contact " + "the channel manager to have this fixed. For more info, mail " + "cservice@undernet.org"; +#else +extern char CALMDOWNTOPIC[512]; +#endif + +/* Define this if you want the 'upgrade' command + */ +#undef UPGRADE + +#ifdef UPGRADE +#define PATCH_SERVER "apache.wildstar.net:7358" +#define GETPATCHPASS "TEST" +#define RECPATCHPASS "BLAH" +#define MISC_TIMEOUT 60 +#define PATCH "/usr/bin/patch" +#define MAKE "/usr/bin/make" +#endif + +#define MAX_CONNECTIONS 50 +#define MAX_SENDQ 300000 +#define HIGHSENDQTHRESHOLD 10000 +/* Max Ban Duration in days. + */ +#define MAX_BAN_DURATION 14 + +/* Define this if you want the built-in http server + */ +#undef DOHTTP + +#ifdef DOHTTP +#define HTTP_PORT 7357 +#define HTTP_TIMEOUT 60 +#define HTTP_LOG "http.log" +#define HTTP_DENY "http.deny" +#define HTTP_REDIRECT "http://cservice.undernet.org/" +#define HTTP_FOOTER "\n"\ +"Back to main page

\n"\ +"This page is automatically generated by the Undernet Channel Service.\n"\ +"If you are experiencing any problem, please contact the \n"\ +"Undernet Channel Service \n"\ +"Committee.

\n"\ +"This service is maintained by:
\n"\ +"

Robin Thellend (SeKs@IRC) <\n"\ +"seks@alias.undernet.org\n"\ +">
\n" + +#define HTTP_HEADER "Undernet Channel Service: %s\n" +#define HTTP_BODY "\n" +#define HTTP_BAN_DISCLAIMER "Disclaimer: The Undernet Channel Service\n" \ + "Committee and the maintainer of this service in no way\n" \ + "support/endorse actions of channel operators, or regulate\n" \ + "channel content in any way. Channel bans shown in no way\n" \ + "reflect the views of the Channel Service Committee, and belong\n" \ + "solely to the indvidual making them. No editorial control is\n" \ + "excised by the committee on either the channel or the webpage.\n" \ + "

\n" + +#define check_referer(x) (strncasecmp((x),"http://cservice.undernet.org/",28) \ + && strncasecmp((x),"http://www.cservice.undernet.org/",28) \ + && strncasecmp((x),"http://cservice.wildstar.net/",28)) +#ifdef check_referer +#define HTTP_BAD_REFERER "http://cservice.undernet.org/bad_referer.html" +#endif + +#endif + + diff --git a/count b/count new file mode 100755 index 0000000..bdd273b --- /dev/null +++ b/count @@ -0,0 +1,3 @@ +#!/bin/sh + +./listall | cut -d" " -f1 | sort | uniq -c diff --git a/cs.conf.dist b/cs.conf.dist new file mode 100644 index 0000000..d9bf1d7 --- /dev/null +++ b/cs.conf.dist @@ -0,0 +1,62 @@ +# $Id: cs.conf.dist,v 1.5 1998/01/22 09:33:38 chaos Exp $ +# Channel Service Runtime Configuration File +# +# Identity +# +NICKNAME X +USERNAME cservice +HOSTNAME undernet.org +REALNAME For help type: /msg X help +UMODE +kid +# +# Server to which X connects +# +UPLINK cheetah +PORT 6667 +# +# How X introduces itself +# +SERVERNAME channels.undernet.org +SERVERINFO Undernet Channel Service +PASSWORD pizza +# +# Files and directories +# +HOMEDIR /home/seks/CS +#UMASK +EXEC ./cs +MOTD cs.motd +LOG cs.log +LOGBAK cs.log.old +PID cs.pid +HELPDIR XHELP +# +# ID of level 1000 user +# +MASTER_NICK seks +MASTER_MASK *!*seks@*.* +MASTER_PASSWD qwerty +# +# Channel where broadcast messages go +# +BROADCAST #cservice_info +# +# ID to put in verify replies +# +VERIFYID CSERVICE +# +# Uworld informations +# +UWORLD_NICK Uworld +UWORLD_HOST *.nssl.uoknor.edu +UWORLD_SERVER Uworld.undernet.org +# +UWORLD2_NICK Uworld2 +UWORLD2_HOST undernet.org +UWORLD2_SERVER Uworld2.undernet.org +# +# Topic to set when CALMDOWN is used +# +CALMDOWNTOPIC CALMDOWN was used on this channel +# +# End of configuration file diff --git a/http.count b/http.count new file mode 100755 index 0000000..f89d1de --- /dev/null +++ b/http.count @@ -0,0 +1,5 @@ +#!/bin/sh +# @(#)CS/http.count $Id: http.count,v 1.3 1996/10/20 16:23:25 seks Exp $ + +grep CONNECTION http.log | cut -d: -f4 | cut -d" " -f5 | sort | uniq -c | sort + diff --git a/http.deny b/http.deny new file mode 100644 index 0000000..645fa53 --- /dev/null +++ b/http.deny @@ -0,0 +1,8 @@ +# @(#)CS/http.deny $Id: http.deny,v 1.3 1996/10/20 16:23:25 seks Exp $ +# +# This file contains the ip addresses that are not granted +# connection. The first '0' ends the mask and the rest isn't +# considered. +# i.e. 132.207.0.0 will block all connections from 132.207.* +# +#127.0.0.0 diff --git a/java/XChat.java b/java/XChat.java new file mode 100644 index 0000000..4d3a0fd --- /dev/null +++ b/java/XChat.java @@ -0,0 +1,222 @@ +// XChat.java + +// Undernet Channel Service (X) +// Copyright (C) 1995-2002 Robin Thellend +// +// 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 +// +// The author can be contact by email at +// +// Please note that this software is unsupported and mostly +// obsolete. It was replaced by GNUworld/CMaster. See +// http://gnuworld.sourceforge.net/ for more information. +// + +import java.awt.*; +import java.applet.Applet; +import java.io.*; +import java.net.*; + +public class XChat extends Applet { + static Connection sock; + static TextField Input; + static TextArea Output; + static Button ConnectButton; + static Button DisconnectButton; + + public void init() { + sock = null; + Input = new TextField(50); + Output = new TextArea(10, 50); + ConnectButton = new Button("Connect"); + DisconnectButton = new Button("Disconnect"); + + DisconnectButton.disable(); + + Output.setEditable(false); + + setLayout(new FlowLayout(FlowLayout.CENTER)); + + add(ConnectButton); + add(DisconnectButton); + add(Output); + add(Input); + + validate(); + } + + public boolean action(Event evt, Object arg) { + if(evt.target == Input) { + if(sock == null) { + Output.appendText("### Not connected!\n"); + Input.selectAll(); + } + else if(sock.status == 0) { // Need Username + sock.username = Input.getText(); + Output.appendText(sock.username + "\nPassword: "); + Input.setText(""); + sock.status = 1; + } + else if(sock.status == 1) { // Need Password + sock.password = Input.getText(); + Input.setText(""); + Output.appendText("\nConnecting...\n"); + Input.selectAll(); + sock.status = 2; + try { + sock.os.writeBytes("CHAT " + sock.username + "/" + + sock.password + "\n"); + } + catch (IOException e) { + Output.appendText("Connection failed!\n"); + try { + sock.socket.close(); + } + catch (IOException ee) { + Output.appendText("### Error closing socket!\n"); + } + sock = null; + } + } + else { // Active connection + try { + sock.os.writeBytes(Input.getText() + "\n"); + } + catch (IOException e) { + LostConn(); + } + Input.selectAll(); + } + return true; + } + else if(evt.target == ConnectButton) { + ConnectButton.disable(); + DisconnectButton.enable(); + sock = new Connection(getCodeBase().getHost(),7357); + return true; + } + else if(evt.target == DisconnectButton) { + LostConn(); + + return true; + } + + return false; + } + + static public void LostConn() { + ConnectButton.enable(); + DisconnectButton.disable(); + if(sock != null) { + sock.close(); + sock = null; + } + } + public void destroy() { + if(sock!= null) { + sock.close(); + sock = null; + } + } +} + + +class Connection { + Socket socket; + TextArea Output; + ReadFromServer read; + DataOutputStream os; + public int status; + String username; + String password; + + Connection(String host, int port) { + try { + Output = XChat.Output; + socket = new Socket(host,port); + status = 0; + os = new DataOutputStream(socket.getOutputStream()); + read = new ReadFromServer(socket); + read.start(); + Output.appendText("Username: "); + } + catch (UnknownHostException e1) { + Output.appendText("### Can't resolve host name!\n"); + } + catch (IOException e2) { + Output.appendText("### Can't connect!\n"); + } + } + + public void close() { + try { + socket.close(); + Output.appendText("### Disconnected!\n"); + } + catch (IOException e) { + Output.appendText("### Error closing socket\n"); + } + read.stop(); + } +} + + +class ReadFromServer extends Thread { + DataInputStream is; + Socket sock; + TextArea Output; + + ReadFromServer(Socket sock) { + try { + is = new DataInputStream(sock.getInputStream()); + this.Output = XChat.Output; + this.sock = sock; + } + catch (IOException e) { + try { + is.close(); + sock.close(); + } + catch (IOException ee) { + Output.appendText("### Error closing input stream!\n"); + } + Output.appendText("### Could not open input stream!\n"); + stop(); + } + } + public void run() { + while(true){ + try { + String in = is.readLine(); + if(in == null){ + XChat.LostConn(); + stop(); + } + Output.appendText(in + "\n"); + } + catch (IOException e) { + try { + is.close(); + sock.close(); + } + catch (IOException ee) { + Output.appendText("### Error closing input stream!\n"); + } + stop(); + } + } + } +} + diff --git a/mkhtpasswd.c b/mkhtpasswd.c new file mode 100644 index 0000000..6173fc1 --- /dev/null +++ b/mkhtpasswd.c @@ -0,0 +1,123 @@ +/* @(#)$Id: mkhtpasswd.c,v 1.1 1997/04/09 14:04:01 cvs Exp $ */ + +/* Undernet Channel Service (X) + * Copyright (C) 1995-2002 Robin Thellend + * + * 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 + * + * The author can be contact by email at + * + * Please note that this software is unsupported and mostly + * obsolete. It was replaced by GNUworld/CMaster. See + * http://gnuworld.sourceforge.net/ for more information. + */ + +#include "Sources/h.h" + +struct node { + dbuser dbu; + struct node *next; +}; + +time_t now; + +int ul_hash(char *channel) +{ + register int i,j=0; + for(i=1;i\n",argv[0]); + exit(1); + } + + time(&now); + srandom(now); + + do_channel(argv[1]); +} +