diff --git a/wmpop3lb/CHANGE_LOG b/wmpop3lb/CHANGE_LOG new file mode 100644 index 0000000..3f1a8e6 --- /dev/null +++ b/wmpop3lb/CHANGE_LOG @@ -0,0 +1,93 @@ +WMPOP3 CHANGE_LOG + +WMPOP3LB + +Version 2.4.2: + * fixed a bug in pop3WriteOneMail: the first line of a received buffer was + always removed, so the received mail was incomplete and corrupted. +Version 2.4.1: + * %c with newmailcommand only applies to new mails + * final dot of messages removed when saving to a temporary file. + * optmized connecting/disconnecting when using %c or %C +Version 2.4: + * switch directly in the summary view mode from total number of messages + to number of unread messages. + * selectedmesgcommand configuation option: specify a command per server + to launch only on selected messages. + * wilcard implemented for newmailcommand, mailclient and + selectedmesgcommand. + * maxdlsize configuration option: in the case of the %c, %C and %m + wildcards, will not download messages bigger than this value. + * mailseparator configuration option: specify a separator to include + between each mail when using %c or %C wildcards. + * configuration options specified between double quotes ('"') can now be + spread among multiple lines. Usefull for mailseparator option... +Version 2.3: skipped +Version 2.2: + * now unlimited (i.e. not limited by wmpop3lb...) number of messages per + server listed. + * new scrollbar for fast browsing. + * newmailcommand configuration option : allows to specify (per server) a + command, per server, to run if a new mail has arrived. + * progress bar shown when retrieving the messages off the server. +Version 2.1: + * smooth scrolling. +Version 2.0: !! new, multi pop3 checker !! + * can check up to 6 pop3 servers + * you can choose in the configuration, for each server, + to display the number of unread messages only or the total number + of messages. + * put back the ability to launch a mail client from WMPop3lb. + You can specify one mail client per account! + To launch your mail client, switch to the counter view mode and click on + the desired server line. + +Version 1.0: based on WMPop3 + * completely changed the GUI. + * display information when contacting the POP3 server. + * fixed the button behaviour (buttons now "react" to the clicks). + * now displays the From: and Subject: header fields of each mail in the + mailbox instead of just a picture telling there is new messages. + * you can no longer launch your mail browser from the interface, as this is + a feature I didn't need. If anyone needs it, please send a mail to + lb@jourdain.org. + +The changelog below is from the original work of Scott Holden + ( scotth@thezone.net ) on WMPop3. + +======================================================================= +Version 0.5.6a : Minor additions + * Added extra checking when connecting to pop-server. + * Fixed some variable addressing problems. + * updated the version number int the source.. :) oops. + +Version 0.5.5a : Minor additions + * Fixed Pop3Client, it now closes the socket after use. + * Fixed Comment missing in the default config file. + +Version 0.5.0a : Minor additions + * Added arrows to left toggle button. ( very minor ). + +Version 0.4.2a : Minor Fixes and additions + * Fixed the problem with "::error::" not being properly removed + from the display after refresh. + * Added the optional ability for unread and read messages to + be shown. ( uuu/rrr ). + * WMPop3 will now check the pop server 30 sec's after a mail + browser has been activated using Wmpop3. ( This will give + the mail browser a chance to download messages from the + server). + +Version 0.4.1a : Minor Fixes and additions + * Fixed the problem with the right button showing "AC" when + pressed. + +Version 0.4.0a : Minor Fixes and additions + * Messages shown are now unread messages instead total messages + +Version 0.3.5a : Minor Fixes and additions + * Fixed messages reading 3 when not connected to the net. + Now shows up as "::Error::" when something is wrong. + * Added ability to enable/disable autochecking at program + startup. + * Added text to the "Check Now" and "autochecking" buttons diff --git a/wmpop3lb/COPYING b/wmpop3lb/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/wmpop3lb/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 + + Appendix: 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) 19yy + + 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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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/wmpop3lb/INSTALL b/wmpop3lb/INSTALL new file mode 100644 index 0000000..59b0a5d --- /dev/null +++ b/wmpop3lb/INSTALL @@ -0,0 +1,39 @@ +Installation instructions. + +This has only been tested and compiled on a i386 Linux machine. + + + There are two methods to install WMPop3lb, either a system install +where all users have access to this file, OR a single user install +which installs WMPop3lb in the users home directory, this is useful +if you have an account on someone else's computer. + + First thing you should do is the following: + + 1> Remember you are using this at your own risk. + 2> tar zxvf wmpop3lbx.x.tar.gz + 3> cd wmpop3lb/wmpop3 + + +Method 1. System install + +A system install will place the WMPop3lb binary in "/usr/local/bin", +this can be done as follows (must be root for this ) : + + make install1 + +Method 2. Single user install + +A single user install will create a directory called wmpop3lbx.x in the users +home directory, and copy the wmpop3 binary there. This install is as +follows: + + make install2 + +Make sure you put this new directory in your path. +This usually can be done by placing the following in your login +shell setup file,( .bashrc, .bashrc_profile, .profile, etc ). + + PATH=$PATH:~/wmpop3 + + diff --git a/wmpop3lb/README b/wmpop3lb/README new file mode 100644 index 0000000..331874c --- /dev/null +++ b/wmpop3lb/README @@ -0,0 +1,168 @@ +WMpop3LB2.4 +================================= + +Written by Louis-Benoit JOURDAIN (lb@jourdain.org) + +This software is based on Wmpop3-0.5.6 by Scott Holden ( scotth@thezone.net ) + +WARNING!!! WMPop3LB is to be used at your own risk. I will not be held +responsible for any damages this application may cause to your system. + +1) WHAT IS THIS + WMPop3LB is a multi POP3 mail box checker. It will connect to up to 6 + POP3 servers to check if you have mail, get the "From:" and "Subject:" + header fields of each mail and display them in a 7 lines window. + If there are more than 7 mails, they can be read by scrolling the window + up and down. + Messages can be deleted directly off the servers by selecting the mails + to delete and clicking the "delete" button. + A command to spawn can be specified for each new received message, for + selected messages (by clicking on the "open" button) or to launch a + mailclient. + +2) How do I configure WMPop3LB + WMPop3LB when first executed will check if there is a .wmpop3rc file in + the user's home directory, it will create it if it can not be located. + This file must be edited and the following fields must be changed : + +-- before any [server] section: + 1) autochecking: This allows to disable or enable auto mail checking. + 1 enables, 0 disables + 2) displaydelay: this will determine how long error messages show up + before the screen is cleaned up. + 3) scrollspeed: this is a percentage of the original scrolling speed. + Higher than 100, the text will scroll faster, lower than 100, the + text will scroll more slowly. + 4) tempdir: directory to put temporary mails retrieved when using %c, %C or + %m wildcards (default: /tmp). + 5) viewallmessages: This allows for alternating mail views upon startup, + 0 shows the From: and Subject: header fields of each mail, (message + view mode) + 1 shows the total number of messages or the number of unread + messages, per domain, and the number of selected messages (summary view + mode). + +-- for each [server] section (you can list up to 6 [server] sections): + + 1) popserver: this is the name of the pop3 server to contact. + 2) port: this is the port the pop3 server is on ( default 110). + 3) username: user's pop3 login name. + 4) password: user's pop3 login password. + 5) alias: 3 alphanum characters server alias name, to + differentiate servers in the display window. + 6) mailcheckdelay: Number of minutes, before checking mail on this server. + (default = 10 minutes) + 7) countunreadonly: in the counter view, 0 displays the total number of + messages on the server, 1 displays only the number of unread + messages. + 8) mailclient: command to launch when clicking on the server alias name in + summary view mode. + The command, if it contains spaces or special characters + must be written between double quotes (`"'). + See "template substitution" for more options. + 9) newmailcommand: command to launch when a new mail has arrived on the + server. + See "template substitution" for more options. + 10) selectedmesgcommand: command to launch on selected messages. + See "template substitution" for more options. + 11) mailseparator: specify a separator to include between each mail when + using %c or %C template substitutions. + 12) maxdlsize: in the case of the %c, %C and %m template substitutions, will + not download messages bigger than this value (-1: no limit). + + +3) Using WMPop3. + + 1) If you have no mail, WMPop3LB will show "No mesg" and will count down + the time before the next cheking. + If none of the configured server can be contacted, WMPop3LB will + show "ERROR" and will count down the time before the next checking. + + 2) If you have mails, WMPop3LB will display a line for each mail, and will + start scrolling the display, showing the server alias identifier, the + "From:" and "Subject:" header fields in the following format: + "alias:/ * " + + * each time a new mail is received, wmpop3lb will try to launch the + newmailcommand if it is specified in the configuration file. + + 3) Depending on the option chosen for viewallmessages, it will display + either: + + a) the alias, The From: and Subject: fields of each mail as + described above. + b) The total number of messages or the number of unread messages + (depending on the configuration parameter "countunreadonly") on + the POP3 server (if the server has been contacted successfully) + as well as the number of messages selected. + Switching between number of unread messages and total number of + messages can be done by clicking on the right side of each server + line (':' means total number, '-' means total number of unread). + If the server cannot be contacted, it will show one of the + following error message: + - alias: C*ER --> connection error + - alias: L*ER --> login error (wrong login or passwd) + - alias: M*ER --> can't get mails. + + * The far most right button is used to toggle both views. + + 4) To delete one or more messages directly off one or more servers, + select the messages you want to delete and then click on the bottom + left "DEL" button. + + You can check how many messages are selected by switching view + mode. + + A status per server will show up during "displaydelay" seconds with the + following error codes: + - OK: messages were deleted successfully from the server + - NONE: no message was selected for this server + - D:nb: nb messages failed to be deleted. + - Err: an error has occured (connection or else). + + WMPop3LB will not allow you to delete messages if the content of the + mailbox on the server has changed since last checking. + It will instead display an error message ("mailbox content has + changed between updates del can.") and reload the content of the + mailbox from the server. + + 5) If a message is selected in the message view mode, the "reload" button + will change to represent an "open" button. + Clicking on this button will launch the command specified in the + configuration file by the selectedmesgcommand parameter. + + 6) to select all the messages, go to the summary view mode and click on + "sel:" (left side of the last displayed line). + to unselect all the messages, click on the right side of that line. + + 7) To manually check for mail at any time, mouse click on the + 2nd button from the left, with a round arrow, if no message is selected. + + 8) To turn off auto mail checking, mouse click on the "ch" button (second + from the right). + + 9) If you have more than 7 messages on all your servers you can scroll the + window up and down using the up and down arrows or by using the + scrollbar. + + +4) known problems / TODO + + 1) wmpop3lb was built on the existing source code of wmpop3, written by + Scott Holden (scotth@thezone.net). + I didn't touch a lot the network functions, which are still using + blocking sockets and connections. + Because of that, if there is any network problem while waiting for some + data, wmpop3lb will hang forever. + The only solution, for the moment, is to restart wmpop3lb. + + Next version will use non-blocking sockets. + + + + + + + + + diff --git a/wmpop3lb/wmgeneral/list.c b/wmpop3lb/wmgeneral/list.c new file mode 100644 index 0000000..f804b2c --- /dev/null +++ b/wmpop3lb/wmgeneral/list.c @@ -0,0 +1,169 @@ +/* Generic single linked list to keep various information + Copyright (C) 1993, 1994 Free Software Foundation, Inc. + + +Author: Kresten Krab Thorup + +Many modifications by Alfredo K. Kojima + + +This file is part of GNU CC. + +GNU CC 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, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "list.h" +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include + +/* Return a cons cell produced from (head . tail) */ + +INLINE LinkedList* +list_cons(void* head, LinkedList* tail) +{ + LinkedList* cell; + + cell = (LinkedList*)malloc(sizeof(LinkedList)); + cell->head = head; + cell->tail = tail; + return cell; +} + +/* Return the length of a list, list_length(NULL) returns zero */ + +INLINE int +list_length(LinkedList* list) +{ + int i = 0; + while(list) + { + i += 1; + list = list->tail; + } + return i; +} + +/* Return the Nth element of LIST, where N count from zero. If N + larger than the list length, NULL is returned */ + +INLINE void* +list_nth(int index, LinkedList* list) +{ + while(index-- != 0) + { + if(list->tail) + list = list->tail; + else + return 0; + } + return list->head; +} + +/* Remove the element at the head by replacing it by its successor */ + +INLINE void +list_remove_head(LinkedList** list) +{ + if (!*list) return; + if ((*list)->tail) + { + LinkedList* tail = (*list)->tail; /* fetch next */ + *(*list) = *tail; /* copy next to list head */ + free(tail); /* free next */ + } + else /* only one element in list */ + { + free(*list); + (*list) = 0; + } +} + + +/* Remove the element with `car' set to ELEMENT */ +/* +INLINE void +list_remove_elem(LinkedList** list, void* elem) +{ + while (*list) + { + if ((*list)->head == elem) + list_remove_head(list); + *list = (*list ? (*list)->tail : NULL); + } +}*/ + +INLINE LinkedList * +list_remove_elem(LinkedList* list, void* elem) +{ + LinkedList *tmp; + + if (list) { + if (list->head == elem) { + tmp = list->tail; + free(list); + return tmp; + } + list->tail = list_remove_elem(list->tail, elem); + return list; + } + return NULL; +} + + +/* Return element that has ELEM as car */ + +INLINE LinkedList* +list_find(LinkedList* list, void* elem) +{ + while(list) + { + if (list->head == elem) + return list; + list = list->tail; + } + return NULL; +} + +/* Free list (backwards recursive) */ + +INLINE void +list_free(LinkedList* list) +{ + if(list) + { + list_free(list->tail); + free(list); + } +} + +/* Map FUNCTION over all elements in LIST */ + +INLINE void +list_mapcar(LinkedList* list, void(*function)(void*)) +{ + while(list) + { + (*function)(list->head); + list = list->tail; + } +} diff --git a/wmpop3lb/wmgeneral/list.h b/wmpop3lb/wmgeneral/list.h new file mode 100644 index 0000000..af0f22c --- /dev/null +++ b/wmpop3lb/wmgeneral/list.h @@ -0,0 +1,59 @@ +/* Generic single linked list to keep various information + Copyright (C) 1993, 1994 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC 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, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#ifndef __LIST_H_ +#define __LIST_H_ + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +# define INLINE inline +#else +# define INLINE +#endif + +typedef struct LinkedList { + void *head; + struct LinkedList *tail; +} LinkedList; + +INLINE LinkedList* list_cons(void* head, LinkedList* tail); + +INLINE int list_length(LinkedList* list); + +INLINE void* list_nth(int index, LinkedList* list); + +INLINE void list_remove_head(LinkedList** list); + +INLINE LinkedList *list_remove_elem(LinkedList* list, void* elem); + +INLINE void list_mapcar(LinkedList* list, void(*function)(void*)); + +INLINE LinkedList*list_find(LinkedList* list, void* elem); + +INLINE void list_free(LinkedList* list); + +#endif diff --git a/wmpop3lb/wmgeneral/misc.c b/wmpop3lb/wmgeneral/misc.c new file mode 100644 index 0000000..34281e2 --- /dev/null +++ b/wmpop3lb/wmgeneral/misc.c @@ -0,0 +1,164 @@ +/* dock.c- built-in Dock module for WindowMaker + * + * WindowMaker window manager + * + * Copyright (c) 1997 Alfredo K. Kojima + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "list.h" +#include "misc.h" + +/* + *---------------------------------------------------------------------- + * parse_command-- + * Divides a command line into a argv/argc pair. + *---------------------------------------------------------------------- + */ +#define PRC_ALPHA 0 +#define PRC_BLANK 1 +#define PRC_ESCAPE 2 +#define PRC_DQUOTE 3 +#define PRC_EOS 4 +#define PRC_SQUOTE 5 + +typedef struct { + short nstate; + short output; +} DFA; + + +static DFA mtable[9][6] = { + {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}}, + {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}}, + {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}}, + {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}}, + {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */ + {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}}, + {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}}, + {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */ +}; + +char* +next_token(char *word, char **next) +{ + char *ptr; + char *ret, *t; + int state, ctype; + + t = ret = malloc(strlen(word)+1); + ptr = word; + + state = 0; + *t = 0; + while (1) { + if (*ptr==0) + ctype = PRC_EOS; + else if (*ptr=='\\') + ctype = PRC_ESCAPE; + else if (*ptr=='"') + ctype = PRC_DQUOTE; + else if (*ptr=='\'') + ctype = PRC_SQUOTE; + else if (*ptr==' ' || *ptr=='\t') + ctype = PRC_BLANK; + else + ctype = PRC_ALPHA; + + if (mtable[state][ctype].output) { + *t = *ptr; t++; + *t = 0; + } + state = mtable[state][ctype].nstate; + ptr++; + if (mtable[state][0].output<0) { + break; + } + } + + if (*ret==0) + t = NULL; + else + t = strdup(ret); + + free(ret); + + if (ctype==PRC_EOS) + *next = NULL; + else + *next = ptr; + + return t; +} + + +extern void +parse_command(char *command, char ***argv, int *argc) +{ + LinkedList *list = NULL; + char *token, *line; + int count, i; + + line = command; + do { + token = next_token(line, &line); + if (token) { + list = list_cons(token, list); + } + } while (token!=NULL && line!=NULL); + + count = list_length(list); + *argv = malloc(sizeof(char*)*count); + i = count; + while (list!=NULL) { + (*argv)[--i] = list->head; + list_remove_head(&list); + } + *argc = count; +} + +extern pid_t +execCommand(char *command) +{ + pid_t pid; + char **argv; + int argc; + + parse_command(command, &argv, &argc); + + if (argv==NULL) { + return 0; + } + + if ((pid=fork())==0) { + char **args; + int i; + + args = malloc(sizeof(char*)*(argc+1)); + if (!args) + exit(10); + for (i=0; i + +extern void parse_command(char *, char ***, int *); + +extern pid_t execCommand(char *); +#endif /* __MISC_H */ diff --git a/wmpop3lb/wmgeneral/wmgeneral.c b/wmpop3lb/wmgeneral/wmgeneral.c new file mode 100644 index 0000000..6364956 --- /dev/null +++ b/wmpop3lb/wmgeneral/wmgeneral.c @@ -0,0 +1,480 @@ +/* + Best viewed with vim5, using ts=4 + + wmgeneral was taken from wmppp. + + It has a lot of routines which most of the wm* programs use. + + ------------------------------------------------------------ + + Author: Martijn Pieterse (pieterse@xs4all.nl) + + --- + CHANGES: + --- + 14/09/1998 (Dave Clark, clarkd@skyia.com) + * Updated createXBMfromXPM routine + * Now supports >256 colors + 11/09/1998 (Martijn Pieterse, pieterse@xs4all.nl) + * Removed a bug from parse_rcfile. You could + not use "start" in a command if a label was + also start. + * Changed the needed geometry string. + We don't use window size, and don't support + negative positions. + 03/09/1998 (Martijn Pieterse, pieterse@xs4all.nl) + * Added parse_rcfile2 + 02/09/1998 (Martijn Pieterse, pieterse@xs4all.nl) + * Added -geometry support (untested) + 28/08/1998 (Martijn Pieterse, pieterse@xs4all.nl) + * Added createXBMfromXPM routine + * Saves a lot of work with changing xpm's. + 02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl) + * changed the read_rc_file to parse_rcfile, as suggested by Marcelo E. Magallon + * debugged the parse_rc file. + 30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl) + * Ripped similar code from all the wm* programs, + and put them in a single file. + +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wmgeneral.h" + + /*****************/ + /* X11 Variables */ +/*****************/ + +Window Root; +int screen; +int x_fd; +int d_depth; +XSizeHints mysizehints; +XWMHints mywmhints; +Pixel back_pix, fore_pix; +char *Geometry = ""; +Window iconwin, win; +GC NormalGC; +XpmIcon wmgen; +Pixmap pixmask; + + /*****************/ + /* Mouse Regions */ +/*****************/ + +typedef struct { + int enable; + int top; + int bottom; + int left; + int right; +} MOUSE_REGION; + +MOUSE_REGION mouse_region[MAX_MOUSE_REGION]; + + /***********************/ + /* Function Prototypes */ +/***********************/ + +static void GetXPM(XpmIcon *, char **); +static Pixel GetColor(char *); +void RedrawWindow(void); +void AddMouseRegion(int, int, int, int, int); +int CheckMouseRegion(int, int); + +/*******************************************************************************\ +|* parse_rcfile *| +\*******************************************************************************/ + +void parse_rcfile(const char *filename, rckeys *keys) { + + char *p,*q; + char temp[128]; + char *tokens = " :\t\n"; + FILE *fp; + int i,key; + + fp = fopen(filename, "r"); + if (fp) { + while (fgets(temp, 128, fp)) { + key = 0; + q = strdup(temp); + q = strtok(q, tokens); + while (key >= 0 && keys[key].label) { + if ((!strcmp(q, keys[key].label))) { + p = strstr(temp, keys[key].label); + p += strlen(keys[key].label); + p += strspn(p, tokens); + if ((i = strcspn(p, "#\n"))) p[i] = 0; + free(*keys[key].var); + *keys[key].var = strdup(p); + key = -1; + } else key++; + } + free(q); + } + fclose(fp); + } +} + +/*******************************************************************************\ +|* parse_rcfile2 *| +\*******************************************************************************/ + +void parse_rcfile2(const char *filename, rckeys2 *keys) { + + char *p; + char temp[128]; + char *tokens = " :\t\n"; + FILE *fp; + int i,key; + char *family = NULL; + + fp = fopen(filename, "r"); + if (fp) { + while (fgets(temp, 128, fp)) { + key = 0; + while (key >= 0 && keys[key].label) { + if ((p = strstr(temp, keys[key].label))) { + p += strlen(keys[key].label); + p += strspn(p, tokens); + if ((i = strcspn(p, "#\n"))) p[i] = 0; + free(*keys[key].var); + *keys[key].var = strdup(p); + key = -1; + } else key++; + } + } + fclose(fp); + } + free(family); +} + + +/*******************************************************************************\ +|* GetXPM *| +\*******************************************************************************/ + +static void GetXPM(XpmIcon *wmgen, char *pixmap_bytes[]) { + + XWindowAttributes attributes; int err; + + /* For the colormap */ + XGetWindowAttributes(display, Root, &attributes); + + wmgen->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); + + err = XpmCreatePixmapFromData(display, Root, pixmap_bytes, &(wmgen->pixmap), + &(wmgen->mask), &(wmgen->attributes)); + + if (err != XpmSuccess) { + fprintf(stderr, "Not enough free colorcells.\n"); + exit(1); + } +} + +/*******************************************************************************\ +|* GetColor *| +\*******************************************************************************/ + +static Pixel GetColor(char *name) { + + XColor color; + XWindowAttributes attributes; + + XGetWindowAttributes(display, Root, &attributes); + + color.pixel = 0; + if (!XParseColor(display, attributes.colormap, name, &color)) { + fprintf(stderr, "wm.app: can't parse %s.\n", name); + } else if (!XAllocColor(display, attributes.colormap, &color)) { + fprintf(stderr, "wm.app: can't allocate %s.\n", name); + } + return color.pixel; +} + +/*******************************************************************************\ +|* flush_expose *| +\*******************************************************************************/ + +static int flush_expose(Window w) { + + XEvent dummy; + int i=0; + + while (XCheckTypedWindowEvent(display, w, Expose, &dummy)) + i++; + + return i; +} + +/*******************************************************************************\ +|* RedrawWindow *| +\*******************************************************************************/ + +void RedrawWindow(void) { + + flush_expose(iconwin); + XCopyArea(display, wmgen.pixmap, iconwin, NormalGC, + 0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0); + flush_expose(win); + XCopyArea(display, wmgen.pixmap, win, NormalGC, + 0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0); +} + +/*******************************************************************************\ +|* RedrawWindowXY *| +\*******************************************************************************/ + +void RedrawWindowXY(int x, int y) { + + flush_expose(iconwin); + XCopyArea(display, wmgen.pixmap, iconwin, NormalGC, + x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0); + flush_expose(win); + XCopyArea(display, wmgen.pixmap, win, NormalGC, + x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0); +} + +/*******************************************************************************\ +|* AddMouseRegion *| +\*******************************************************************************/ + +void AddMouseRegion(int index, int left, int top, int right, int bottom) { + + if (index < MAX_MOUSE_REGION) { + mouse_region[index].enable = 1; + mouse_region[index].top = top; + mouse_region[index].left = left; + mouse_region[index].bottom = bottom; + mouse_region[index].right = right; + } +} + +/*******************************************************************************\ +|* CheckMouseRegion *| +\*******************************************************************************/ + +int CheckMouseRegion(int x, int y) { + + int i; + int found; + + found = 0; + + for (i=0; i= mouse_region[i].left && + y <= mouse_region[i].bottom && + y >= mouse_region[i].top) + found = 1; + } + if (!found) return -1; + return (i-1); +} + +/*******************************************************************************\ +|* createXBMfromXPM *| +\*******************************************************************************/ +void createXBMfromXPM(char *xbm, char **xpm, int sx, int sy) { + + int i,j,k; + int width, height, numcol, depth; + int zero=0; + unsigned char bwrite; + int bcount; + int curpixel; + + sscanf(*xpm, "%d %d %d %d", &width, &height, &numcol, &depth); + + + for (k=0; k!=depth; k++) + { + zero <<=8; + zero |= xpm[1][k]; + } + + for (i=numcol+1; i < numcol+sy+1; i++) { + bcount = 0; + bwrite = 0; + for (j=0; j>= 1; + + curpixel=0; + for (k=0; k!=depth; k++) + { + curpixel <<=8; + curpixel |= xpm[i][j+k]; + } + + if ( curpixel != zero ) { + bwrite += 128; + } + bcount++; + if (bcount == 8) { + *xbm = bwrite; + xbm++; + bcount = 0; + bwrite = 0; + } + } + } +} + +/*******************************************************************************\ +|* copyXPMArea *| +\*******************************************************************************/ + +void copyXPMArea(int x, int y, int sx, int sy, int dx, int dy) { + + XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy); + +} + +/*******************************************************************************\ +|* copyXBMArea *| +\*******************************************************************************/ + +void copyXBMArea(int x, int y, int sx, int sy, int dx, int dy) { + + XCopyArea(display, wmgen.mask, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy); +} + + +/*******************************************************************************\ +|* setMaskXY *| +\*******************************************************************************/ + +void setMaskXY(int x, int y) { + + XShapeCombineMask(display, win, ShapeBounding, x, y, pixmask, ShapeSet); + XShapeCombineMask(display, iconwin, ShapeBounding, x, y, pixmask, ShapeSet); +} + +/*******************************************************************************\ +|* openXwindow *| +\*******************************************************************************/ +void openXwindow(int argc, char *argv[], char *pixmap_bytes[], char *pixmask_bits, int pixmask_width, int pixmask_height) { + + unsigned int borderwidth = 1; + XClassHint classHint; + char *display_name = NULL; + char *wname = argv[0]; + XTextProperty name; + + XGCValues gcv; + unsigned long gcm; + + char *geometry = NULL; + + int dummy=0; + int i, wx, wy; + + for (i=1; argv[i]; i++) { + if (!strcmp(argv[i], "-display")) { + display_name = argv[i+1]; + i++; + } + if (!strcmp(argv[i], "-geometry")) { + geometry = argv[i+1]; + i++; + } + } + + if (!(display = XOpenDisplay(display_name))) { + fprintf(stderr, "%s: can't open display %s\n", + wname, XDisplayName(display_name)); + exit(1); + } + screen = DefaultScreen(display); + Root = RootWindow(display, screen); + d_depth = DefaultDepth(display, screen); + x_fd = XConnectionNumber(display); + + /* Convert XPM to XImage */ + GetXPM(&wmgen, pixmap_bytes); + + /* Create a window to hold the stuff */ + mysizehints.flags = USSize | USPosition; + mysizehints.x = 0; + mysizehints.y = 0; + + back_pix = GetColor("white"); + fore_pix = GetColor("black"); + + XWMGeometry(display, screen, Geometry, NULL, borderwidth, &mysizehints, + &mysizehints.x, &mysizehints.y,&mysizehints.width,&mysizehints.height, &dummy); + + mysizehints.width = 64; + mysizehints.height = 64; + + win = XCreateSimpleWindow(display, Root, mysizehints.x, mysizehints.y, + mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix); + + iconwin = XCreateSimpleWindow(display, win, mysizehints.x, mysizehints.y, + mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix); + + /* Activate hints */ + XSetWMNormalHints(display, win, &mysizehints); + classHint.res_name = wname; + classHint.res_class = wname; + XSetClassHint(display, win, &classHint); + + XSelectInput(display, win, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask); + XSelectInput(display, iconwin, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask); + + if (XStringListToTextProperty(&wname, 1, &name) == 0) { + fprintf(stderr, "%s: can't allocate window name\n", wname); + exit(1); + } + + XSetWMName(display, win, &name); + + /* Create GC for drawing */ + + gcm = GCForeground | GCBackground | GCGraphicsExposures; + gcv.foreground = fore_pix; + gcv.background = back_pix; + gcv.graphics_exposures = 0; + NormalGC = XCreateGC(display, Root, gcm, &gcv); + + /* ONLYSHAPE ON */ + + pixmask = XCreateBitmapFromData(display, win, pixmask_bits, pixmask_width, pixmask_height); + + XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet); + XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet); + + /* ONLYSHAPE OFF */ + + mywmhints.initial_state = WithdrawnState; + mywmhints.icon_window = iconwin; + mywmhints.icon_x = mysizehints.x; + mywmhints.icon_y = mysizehints.y; + mywmhints.window_group = win; + mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint; + + XSetWMHints(display, win, &mywmhints); + + XSetCommand(display, win, argv, argc); + XMapWindow(display, win); + + if (geometry) { + if (sscanf(geometry, "+%d+%d", &wx, &wy) != 2) { + fprintf(stderr, "Bad geometry string.\n"); + exit(1); + } + XMoveWindow(display, win, wx, wy); + } +} diff --git a/wmpop3lb/wmgeneral/wmgeneral.h b/wmpop3lb/wmgeneral/wmgeneral.h new file mode 100644 index 0000000..83b0f09 --- /dev/null +++ b/wmpop3lb/wmgeneral/wmgeneral.h @@ -0,0 +1,59 @@ +#ifndef WMGENERAL_H_INCLUDED +#define WMGENERAL_H_INCLUDED + + /***********/ + /* Defines */ +/***********/ + +#define MAX_MOUSE_REGION (16) + + /************/ + /* Typedefs */ +/************/ + +typedef struct _rckeys rckeys; + +struct _rckeys { + const char *label; + char **var; +}; + +typedef struct _rckeys2 rckeys2; + +struct _rckeys2 { + const char *family; + const char *label; + char **var; +}; + +typedef struct sXpmIcon{ + Pixmap pixmap; + Pixmap mask; + XpmAttributes attributes; +} XpmIcon; + + /*******************/ + /* Global variable */ +/*******************/ + +Display *display; + + /***********************/ + /* Function Prototypes */ +/***********************/ + +void AddMouseRegion(int index, int left, int top, int right, int bottom); +int CheckMouseRegion(int x, int y); + +void openXwindow(int argc, char *argv[], char **, char *, int, int); +void RedrawWindow(void); +void RedrawWindowXY(int x, int y); + +void createXBMfromXPM(char *, char **, int, int); +void copyXPMArea(int, int, int, int, int, int); +void copyXBMArea(int, int, int, int, int, int); +void setMaskXY(int, int); + +void parse_rcfile(const char *, rckeys *); + +#endif diff --git a/wmpop3lb/wmpop3/.wmpop3rc_test b/wmpop3lb/wmpop3/.wmpop3rc_test new file mode 100644 index 0000000..efdc236 --- /dev/null +++ b/wmpop3lb/wmpop3/.wmpop3rc_test @@ -0,0 +1,62 @@ +# Replace all < > with appropriate data +# +autochecking 1 # 1 enables, 0 disables +viewallmessages 0 # 0 Shows both read and unread messages +# and 1 shows only unread messages +displaydelay 2 +scrollspeed 150 +tempdir "/tmp" +#[server] +#popserver pop.free.fr +#port 110 # default port +#username lbj +#password 42vm90cx +#mailcheckdelay 3 # default mail check time in minutes +#alias flb +#countunreadonly 0 +#mailclient "netscape -mail" + +[server] +popserver aaricia.france.sun.com +port 110 +username test2 +password test +alias a2 +countunreadonly 0 +mailcheckdelay 10 +newmailcommand "echo aa5 %T %t %f %s %m %n %S %a %P" +maxdlsize 2000 +mailclient "echo aa5 %T %t %f %s %m %n %S %a %P" + +[server] +popserver aaricia.france.sun.com +port 110 +username test4 +password test +alias 4 +countunreadonly 0 +mailcheckdelay 1 +newmailcommand "echo %c %C" +maxdlsize 650 +mailclient "echo %c %C" +selectedmesgcommand "echo %c %C" +mailseparator " +From - +" + +[server] +popserver aaricia.france.sun.com +port 110 +username test3 +password test +alias aa3 +countunreadonly 0 +mailcheckdelay 1 +newmailcommand "echo %f %s %m" +maxdlsize -1 +mailclient "echo %f %s %m" +selectedmesgcommand "emacs %C" + + + + diff --git a/wmpop3lb/wmpop3/.wmpop3rc_test~ b/wmpop3lb/wmpop3/.wmpop3rc_test~ new file mode 100644 index 0000000..dd02565 --- /dev/null +++ b/wmpop3lb/wmpop3/.wmpop3rc_test~ @@ -0,0 +1,62 @@ +# Replace all < > with appropriate data +# +autochecking 1 # 1 enables, 0 disables +viewallmessages 0 # 0 Shows both read and unread messages +# and 1 shows only unread messages +displaydelay 2 +scrollspeed 150 +tempdir "/tmp" +#[server] +#popserver pop.free.fr +#port 110 # default port +#username lbj +#password 42vm90cx +#mailcheckdelay 3 # default mail check time in minutes +#alias flb +#countunreadonly 0 +#mailclient "netscape -mail" + +[server] +popserver aaricia.france.sun.com +port 110 +username test2 +password test +alias a2 +countunreadonly 0 +mailcheckdelay 10 +newmailcommand "echo aa5 %T %t %f %s %m %n %S %a %P" +maxdlsize 2000 +mailclient "echo aa5 %T %t %f %s %m %n %S %a %P" + +[server] +popserver aaricia.france.sun.com +port 110 +username test4 +password test +alias 4 +countunreadonly 0 +mailcheckdelay 1 +newmailcommand "echo %c" +maxdlsize 650 +mailclient "echo %T %t %c %S %a %P %u %w" +selectedmesgcommand "emacs %C" +mailseparator " +From - +" + +[server] +popserver aaricia.france.sun.com +port 110 +username test3 +password test +alias aa3 +countunreadonly 0 +mailcheckdelay 1 +newmailcommand "echo %f %s %m" +maxdlsize -1 +mailclient "echo %f %s %m" +selectedmesgcommand "emacs %C" + + + + diff --git a/wmpop3lb/wmpop3/Makefile b/wmpop3lb/wmpop3/Makefile new file mode 100644 index 0000000..f154d25 --- /dev/null +++ b/wmpop3lb/wmpop3/Makefile @@ -0,0 +1,47 @@ +LIBDIR = -L/usr/X11R6/lib +LIBS = -lXpm -lXext -lX11 +FLAGS = -g2 -D_DEBUG +OBJS = wmpop3.o \ + Pop3Client.o \ + ../wmgeneral/wmgeneral.o \ + ../wmgeneral/misc.o \ + ../wmgeneral/list.o + + +.c.o: + cc -I/usr/X11R6/share/include $(FLAGS) -c -Wall $< -o $*.o + +wmpop3lb: $(OBJS) + cc $(FLAGS) -o wmpop3lb $^ -lXext $(LIBDIR) $(LIBS) + +all:: wmpop3lb + +clean:: + for i in $(OBJS) ; do \ + rm -f $$i ; \ + done + rm -f wmpop3lb + rm -f *~ + +install:: wmpop3lb + @echo "Use 'make install1' for system install." + @echo "Use 'make install2' for single user install." + @echo + +install1:: wmpop3lb + cp -f wmpop3lb /usr/local/bin/ + chmod 755 /usr/local/bin/wmpop3lb + chown root:root /usr/local/bin/wmpop3lb + @echo + @echo "WMPop3 Installation finished..." + +install2:: wmpop3lb + mkdir $(HOME)/wmpop3lb + cp -f wmpop3lb $(HOME)/wmpop3lb + chmod 755 $(HOME)/wmpop3lb + @echo "WMPop3 Installation finished..." + @echo + @echo "Make sure ~/wmpop3 is in your path" + @echo + @echo "Please run wmpop3lb once and then edit ~/.wmpop3rc" + diff --git a/wmpop3lb/wmpop3/Pop3Client.c b/wmpop3lb/wmpop3/Pop3Client.c new file mode 100644 index 0000000..184eeec --- /dev/null +++ b/wmpop3lb/wmpop3/Pop3Client.c @@ -0,0 +1,591 @@ +/* Author : Louis-Benoit JOURDAIN (lb@jourdain.org) + * based on the original work by Scott Holden ( scotth@thezone.net ) + * + * multi Pop3 Email checker. + * + * Last Updated : Feb 7th, 2002 + * + */ + + +#include "Pop3Client.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../wmgeneral/misc.h" +#include "../wmgeneral/wmgeneral.h" + +#include "Pop3Client.h" + +/* return size if all goes well, -1 if not expected answer */ +int send_command(char *exp_answer, char **retour, Pop3 pc) +{ + int size; + + send(pc->s, &pc->outBuf,strlen(pc->outBuf),0); + size = recv(pc->s,pc->inBuf,1024,0); + memset(*retour,0,1024); + memcpy(*retour,pc->inBuf,size); + if (strncmp(pc->inBuf, exp_answer, strlen(exp_answer))) { + return (-1); + } + return (size); +} + +Pop3 pop3Create(int num) +{ + Pop3 pc; + + pc = (Pop3)malloc( sizeof(*pc) ); + if( pc == 0) + return 0; + memset(pc, 0, sizeof(*pc)); + pc->connected = NOT_CONNECTED; + pc->serverport = 110; + pc->mailCheckDelay = 10; + /* make sure we perform an action first time we receive mail */ + pc->forcedCheck = 1; + pc->sizechanged = -1; + pc->maxdlsize = -1; + sprintf(pc->alias, "nb%d", num); + return (pc); +} +int pop3MakeConnection(Pop3 pc, char *serverName, int port){ + + pc->s = socket(AF_INET, SOCK_STREAM, 0 ); + memset( &(pc->server), 0 , sizeof(pc->server)); + pc->server.sin_family = AF_INET; + pc->hp = gethostbyname(serverName); + if( pc->hp == 0) + return -1; + memcpy( &(pc->server.sin_addr), pc->hp->h_addr, pc->hp->h_length); + pc->server.sin_port = htons(port); + if ( connect(pc->s, (struct sockaddr *)&(pc->server) + , sizeof(pc->server)) < 0 ) + return -1; + pc->connected = CONNECTED; + return 0; +} + +int pop3IsConnected(Pop3 pc){ + + if( pc->connected == CONNECTED) + return 1; + return 0; +} + +int pop3Login(Pop3 pc, char *name, char *pass){ + + int size; + char temp[1024]; + + if( pc->connected == NOT_CONNECTED ){ + perror("Not Connected To Server\n"); + return -1; + } + + size = recv(pc->s,&pc->inBuf,1024,0); + memset(temp,0,1024); + memcpy(temp,pc->inBuf,size); + if( temp[0] != '+' ){ + fprintf(stderr,"Error Logging in\n"); + return -1; + } + + sprintf(pc->outBuf,"USER %s\r\n",name); + send(pc->s, &pc->outBuf,strlen(pc->outBuf),0); + size =recv(pc->s,pc->inBuf,1024,0); + memset(temp,0,1024); + memcpy(temp,pc->inBuf,size); + if( temp[0] != '+' ){ + fprintf(stderr,"Invalid User Name\n"); + return -1; + } + + memset(pc->outBuf,0,1024); + sprintf(pc->outBuf,"PASS %s\r\n",pass); + send(pc->s, pc->outBuf, strlen(pc->outBuf),0 ); + size =recv(pc->s,&pc->inBuf,1024,0); + memset(temp,0,1024); + memcpy(temp,pc->inBuf,size); + if( temp[0] != '+' ){ + fprintf(stderr,"Incorrect Password\n"); + return -1; + } + + return 0; +} + +int store_from(char *buf, int pos, int buflen, int num, Pop3 pc) { + int end; + int deb_addr; + int fin_addr; + int i; + + /* strip the white spaces */ + for (; (pos < buflen) && isspace(buf[pos]); pos++); + /* get the end of the line */ + for (end = pos; (end + 1 < buflen) && + (buf[end] != '\r') && (buf[end + 1] != '\n'); end++); + /* try to find the '@' sign for the address */ + for (i = pos; (i < end) && buf[i] != '@'; i++); + if (i < end) { /* we found a @ sign before the end of the line */ + for (deb_addr = i; deb_addr > pos && !isspace(buf[deb_addr]); deb_addr--); + while (isspace(buf[deb_addr]) || ('<' == buf[deb_addr])) + deb_addr++; + for (fin_addr = i; fin_addr < end && !isspace(buf[fin_addr]); fin_addr++); + if ('>' == buf[fin_addr - 1]) + fin_addr--; + memcpy(pc->mails[num].from, buf + deb_addr, + (fin_addr - deb_addr > MAIL_BUFLEN) ? + MAIL_BUFLEN : fin_addr - deb_addr); + } + else { + memcpy(pc->mails[num].from, buf + pos, + (end - pos > MAIL_BUFLEN) ? MAIL_BUFLEN : end - pos); + } + return (end + 2); +} + +int store_subject(char *buf, int pos, int buflen, int num, Pop3 pc) { + int end; + int i; + + /* get the end of the line */ + for (end = pos, i = 0; (i < MAIL_BUFLEN) && (end + 1 < buflen) && + (buf[end] != '\r') && (buf[end + 1] != '\n'); end++, i++); + for (; (pos < buflen) && (buf[pos] == ' '); pos++); + memcpy(pc->mails[num].subject, buf + pos, end - pos); + return (end + 2); +} + +int parse_header(char *buf, int buflen, int num, Pop3 pc) { + int pos = 0; + int retour = 1; + + /* parse the header for the from and subject fields */ +#ifdef _DEBUG + printf(" parse_header, buflen: %d, num %d, buf:\n%s\n", + buflen, num, buf); +#endif + while (pos < buflen) { + if ((buflen > (pos + 2)) && !strncmp(".\r\n", buf + pos, 3)) { + /* this is the end */ + pos = buflen; + retour = 0; + } + else if ((buflen > (pos + 4)) && !strncmp("From:", buf + pos, 5)) { + pos += 5; + pos = store_from(buf, pos, buflen, num, pc); + } + else if ((buflen > (pos + 7)) && !strncmp("Subject:", buf + pos, 8)) { + pos += 8; + pos = store_subject(buf, pos, buflen, num, pc); + } + else { + for( ; (buflen > (pos + 2)) && (buf[pos] != '\r') && + (buf[pos + 1] != '\n'); pos++); + pos += 2; + } + } + return (retour); +} + +int pop3VerifStats(Pop3 pc) +{ + int retour = 0; + char *ptr; + int size; + + if( pc->connected == NOT_CONNECTED ) + return (-1); + + /* Find total number of messages in mail box */ + sprintf(pc->outBuf,"STAT\r\n"); + send(pc->s, pc->outBuf, strlen(pc->outBuf),0 ); + size = recv(pc->s,pc->inBuf,1024,0); + if( pc->inBuf[0] != '+' ){ + perror("Error Receiving Stats"); + return (-1); + } + ptr = strtok(pc->inBuf, " "); + ptr = strtok( 0," "); + ptr = strtok( 0, " "); + if (ptr) + retour = atoi(ptr); + return (retour); +} + +long calculate_cksum(char *buf, int len) { + int i; + long cumul; + + for (i = 0, cumul = 0; i < len; i++) { + cumul += (long) buf[i]; + } + return (cumul); +} + +int is_in_old_mails(long cksum, t_mail *oldmails, int numold) { + int i; + + for (i = 0; i < numold; i++) { + if (oldmails[i].cksum == cksum) + return (1); + } + return (0); +} + +int pop3CheckMail(Pop3 pc) { + int size; + char temp[4096]; + char *ptr; + int i; + int pass; + int go; + int old_sizeOfAllMessages; + int old_numOfMessages; + int progressbarpos = 0; + t_mail *oldmails; + + if( pc->connected == NOT_CONNECTED ) + return -1; + /* save the old values */ + old_sizeOfAllMessages = pc->sizeOfAllMessages; + old_numOfMessages = pc->numOfMessages; + /* Find total number of messages in mail box */ + sprintf(pc->outBuf,"STAT\r\n"); + send(pc->s, pc->outBuf, strlen(pc->outBuf),0 ); + size = recv(pc->s,pc->inBuf,1024,0); + pc->inBuf[size] = '\0'; +#ifdef _DEBUG + printf(" pop3CheckMail, stat received buf (size=%d): [%s]\n", + size, pc->inBuf); +#endif + memset(temp,0,1024); + memcpy(temp,pc->inBuf,size); + if( temp[0] != '+' ){ +#ifdef _DEBUG + printf(" Error Receiving Stats: [%s]\n", temp); +#endif + return (-1); + } + + ptr = strtok(temp, " "); + ptr = strtok( 0," "); + pc->numOfMessages = atoi(ptr); + + /* save the old messages */ + oldmails = pc->mails; + pc->mails = NULL; + /* allocate space for the new ones */ + if (pc->numOfMessages) { + if (NULL == + (pc->mails = (t_mail *) malloc (sizeof(t_mail) * pc->numOfMessages))) { + fprintf(stderr, "can't allocate memory for message structure\n"); + /* clear the old messages */ + if (oldmails) { + free (oldmails); + } + return (-1); + } + /* Display the progress bar */ + copyXPMArea(ORIG_PB_TX, ORIG_PB_TY, PROGRESSBAR_LEN, PROGRESSBAR_HEI, + PROGRESSBAR_HPOS, PROGRESSBAR_VPOS); + RedrawWindow(); + } + + ptr = strtok( 0, " "); + pc->sizeOfAllMessages = atoi(ptr); + /* -1 means first time */ + if (-1 != pc->sizechanged) + pc->sizechanged = (old_sizeOfAllMessages != pc->sizeOfAllMessages); + + sprintf(pc->outBuf,"LAST\r\n"); + send(pc->s, pc->outBuf, strlen(pc->outBuf),0 ); + size = recv(pc->s,pc->inBuf,1024,0); + pc->inBuf[size] = '\0'; +#ifdef _DEBUG + printf(" pop3CheckMail, last received buf (size=%d): [%s]\n", + size, pc->inBuf); +#endif + memset(temp,0,1024); + memcpy(temp,pc->inBuf,size); + if( temp[0] != '+' ){ +#ifdef _DEBUG + printf(" Error Receiving LAST: [%s]\n", temp); +#endif + pc->numOfUnreadMessages = pc->numOfMessages; + } + else { + ptr = strtok(temp, " "); + ptr = strtok( 0," "); + pc->numOfUnreadMessages = pc->numOfMessages - atoi(ptr); + } + /* get the subject and From fields of numOfMessages mails */ + for (i = 0; i < pc->numOfMessages; i++) { +#ifdef _DEBUG + printf(" ---- message %d ---\n", i); +#endif + /* increment the progress bar by 1 message */ + progressbarpos = (int) ((i + 1) * (PROGRESSBAR_LEN - 2)) / + pc->numOfMessages; + copyXPMArea(ORIG_PB_BARX, ORIG_PB_BARY, progressbarpos, 2, + PROGRESSBAR_HPOS + 1, PROGRESSBAR_VPOS + 2); + RedrawWindow(); + /* reset the from and subject fields for num */ + memset(&pc->mails[i], 0, sizeof(t_mail)); + sprintf(pc->outBuf, "TOP %d 0\r\n", i + 1); + send(pc->s, pc->outBuf, strlen(pc->outBuf), 0); + pass = 0; + go = 1; + while (go && (0 < (size = recv(pc->s,pc->inBuf,4096,0)))) { + memset(temp, 0, 4096); + memcpy(temp, pc->inBuf, size); + if (!pass && (temp[0] != '+')) { + fprintf(stderr, "Error while getting TOP %d 0\n", i + 1); + go = 0; + /* must set the from and subject fields to correct value */ + strncpy(pc->mails[i].from, "::error::", 9); + continue; + } + /* calculate the checksum */ + pc->mails[i].cksum += calculate_cksum(temp, size); + pass++; + go = parse_header(temp, size, i, pc); + } + pc->mails[i].todelete = 0; + /* verify if this message is new or not */ + pc->mails[i].new = !is_in_old_mails(pc->mails[i].cksum, oldmails, + old_numOfMessages); +#ifdef _DEBUG + printf(" mess %d, cksum: %ld, new: %d\n", + i, pc->mails[i].cksum, pc->mails[i].new); +#endif + } + /* clear the old messages */ + if (oldmails) { + free (oldmails); + } + return 1; +} + +int pop3WriteOneMail(int nb, int dest_fd, Pop3 pc) +{ + int len; + int retour = 0; + char buf[4096]; + char temp[4096]; + int size; + int pass = 0; + int go = 1; + char *deb, *fin; + int theemailsize = 0; + int mustdisconnect = 0; + + + if (NOT_CONNECTED == pc->connected) { +#ifdef _DEBUG + printf(" pop3WriteOneMail not connected, connecting\n"); +#endif + if (pop3MakeConnection(pc,pc->popserver,pc->serverport) == -1){ + return (1); + } + if (pop3Login(pc, pc->username, pc->password) == -1) { + return (1); + } + mustdisconnect = 1; + } + /* check the size */ +#ifdef _DEBUG + printf(" pc->maxdlsize = [%d]\n", pc->maxdlsize); +#endif + if (-1 != pc->maxdlsize) { + sprintf(pc->outBuf, "LIST %d\r\n", nb); +#ifdef _DEBUG + printf(" pop3WriteOneMail: %s", pc->outBuf); +#endif + send(pc->s, pc->outBuf, strlen(pc->outBuf), 0); + size = recv(pc->s, pc->inBuf, 4096, 0); +#ifdef _DEBUG + printf(" received %d bytes\n", size); +#endif + memset(temp, 0, 4096); + memcpy(temp, pc->inBuf, size); +#ifdef _DEBUG + printf(" pop3WriteOneMail: answer [%s]\n", temp); +#endif + if (temp[0] != '+') { + sprintf(buf, TXT_ERROR, pc->mails[nb - 1].from, + pc->mails[nb - 1].subject, pc->outBuf); + write (dest_fd, buf, strlen(buf)); +#ifdef _DEBUG + printf(" bad answer: [%s]\n", pc->inBuf); +#endif + return (0); + } + /* go get the size of the email, strip +OK */ + for (deb = temp; *deb && !isspace(*deb); deb++); + /* strip the spaces */ + for (; *deb && isspace(*deb); deb++); + /* strip the email number */ + for (; *deb && !isspace(*deb); deb++); + /* strip the last spaces */ + for (; *deb && isspace(*deb); deb++); + /* go to the end of the size */ + for (fin = deb; *fin && !isspace(*fin); fin++); + if (*deb && *fin) { + memcpy(buf, deb, fin - deb); + buf[fin - deb] = '\0'; + theemailsize = atoi(buf); +#ifdef _DEBUG + printf(" email retrieved size: %d\n", theemailsize); +#endif + if (theemailsize > pc->maxdlsize) { + sprintf(buf, TXT_MESSAGETOOBIG, pc->mails[nb - 1].from, + pc->mails[nb - 1].subject, theemailsize, pc->maxdlsize); + write (dest_fd, buf, strlen(buf)); +#ifdef _DEBUG + printf(" email too big, return\n"); +#endif + return (0); + } + } + /* else {} + the command is screwed up, never mind, continue to download the mail */ + } + + + sprintf(pc->outBuf, "RETR %d\r\n", nb); +#ifdef _DEBUG + printf(" pop3WriteOneMail: %s", pc->outBuf); +#endif + send(pc->s, pc->outBuf, strlen(pc->outBuf), 0); + while (go && (size = recv(pc->s, pc->inBuf, 4096, 0))) { +#ifdef _DEBUG + printf(" received %d bytes\n", size); +#endif + memset(temp, 0, 4096); + memcpy(temp, pc->inBuf, size); + deb = temp; + if (!pass) { + if (temp[0] != '+') { + sprintf(buf, TXT_ERROR, pc->mails[nb - 1].from, + pc->mails[nb - 1].subject, pc->outBuf); + write (dest_fd, buf, strlen(buf)); + retour = 1; + go = 0; + continue; + } +#ifdef _DEBUG + printf(" first pass, skeep RETR answer ([%s])\n", deb); +#endif + /* skip the RETR answer, go to the end of the line; */ + for (;*deb && ('\n' != *deb); deb++); + deb++; + } + /* check if these are the final bits of the message */ + fin = temp + size - 5; +#ifdef _DEBUG + printf(" size: %d, fin: [%s]\n", size, fin); +#endif + if (size >= 5) { + if (!strncmp(fin, "\r\n.\r\n", 5)) { + go = 0; + /* don't write the final '.' into the message, skip it*/ + size -= 3; +#ifdef _DEBUG + printf(" skeeping final '.', new size=%d\n", size); +#endif + } + } + else + go = 0; +#ifdef _DEBUG + printf(" buffer (long: %d):\n[%s]\n", (temp + size) - deb, deb); +#endif + len = 0; + while (deb < (temp + size)) { + len = write(dest_fd, deb, (temp + size) - deb); + deb += len; + } +#ifdef _DEBUG + printf(" wrote %d bytes\n", len); +#endif + pass++; + } + if (mustdisconnect) { +#ifdef _DEBUG + printf(" pop3WriteOneMail disconnecting\n"); +#endif + pop3Quit(pc); + } +#ifdef _DEBUG + printf(" pop3WriteOneMail, return\n"); +#endif + return (retour); +} + +int pop3DeleteMail(int num, Pop3 pc) +{ + int size; + + sprintf(pc->outBuf, "DELE %d\r\n", num); +#ifdef _DEBUG + printf(" %s\n", pc->outBuf); +#endif + send(pc->s, pc->outBuf, strlen(pc->outBuf), 0); + size = recv(pc->s, pc->inBuf, 4096, 0); + if ('+' != pc->inBuf[0]) { + perror("error while deleting mail"); + return (1); + } + return (0); +} + + + + +int pop3GetTotalNumberOfMessages( Pop3 pc ){ + if( pc != 0 ) + return pc->numOfMessages; + return -1; +} + +int pop3GetNumberOfUnreadMessages( Pop3 pc ){ + if( pc != 0) + return pc->numOfUnreadMessages; + return -1; +} + +int pop3Quit(Pop3 pc){ + int size; + +#ifdef _DEBUG + printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"); + printf("XXXXXX pop3Quit -------- disconneting XXXXXXXXX\n"); + printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"); +#endif + if( pc->connected == NOT_CONNECTED ) + return -1; + send(pc->s, "quit\r\n", 6,0 ); + size =recv(pc->s,&pc->inBuf,1024,0); + pc->connected = NOT_CONNECTED; + if(pc->s != 0) + close(pc->s); + return 0; + +} + + + diff --git a/wmpop3lb/wmpop3/Pop3Client.h b/wmpop3lb/wmpop3/Pop3Client.h new file mode 100644 index 0000000..043a62a --- /dev/null +++ b/wmpop3lb/wmpop3/Pop3Client.h @@ -0,0 +1,146 @@ +/* Author : Louis-Benoit JOURDAIN (lb@jourdain.org) + * based on the original work by Scott Holden ( scotth@thezone.net ) + * + * multi Pop3 Email checker. + * + * Last Updated : Feb 7th, 2002 + * + */ + + +#ifndef POP3CLIENT +#define POP3CLIENT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAIL_BUFLEN 64 +#define CONF_BUFLEN 256 + +#define RSET_COLOR color = 0 +#define SWAP_COLOR color = 1 - color +#define CH_COLOR(a) (color) ? a + 24 : a + +#define WMPOP3_VERSION "2.4.2" + +#define CHAR_WIDTH 5 +#define CHAR_HEIGHT 5 +#define TOP_MARGIN 5 +#define LEFT_MARGIN 4 +#define NUMBERS 93 +#define LETTERS 85 +#define SMALL_NUM 77 +#define SN_CHAR_W 3 +#define NB_DISP 8 +#define EXTRA 1 +#define NB_LINE 7 +#define SEC_IN_MIN 60 +#define YES 1 +#define NO 0 +#define SELECTONLY 1 +#define NOSELECTONLY 0 + +/* get mail progress bar */ +#define PROGRESSBAR_LEN 48 +#define PROGRESSBAR_HEI 6 +#define PROGRESSBAR_HPOS 10 +#define PROGRESSBAR_VPOS ((6*6) + TOP_MARGIN) + +#define ORIG_PB_TX 72 +#define ORIG_PB_TY 65 + +#define ORIG_PB_BARX 73 +#define ORIG_PB_BARY 71 + +#define SCROLL_LX 4 /* left X coordinate */ +#define SCROLL_RX 6 /* right X coordinate */ +#define SCROLL_TY 4 /* top Y coordinate */ +#define SCROLL_BY 45 /* botton Y coordinate */ +#define SCROLL_W 3 +#define SCROLL_H 38 /* this is without SCROLL_EXT at each end */ +#define SCROLL_EXT 2 + +#define TMPPREFIX "Pop3tmp" +#define TMPPREFIXLEN 7 +#define TXT_MESSAGETOOBIG "From: %s\n\ +Subject: %s\n\n\ +\ +The size of this email (%d) is above the configured maxdlsize value (%d) and\ + was not downloaded\n" + +#define TXT_ERROR "From: %s\n\ +Subject: %s\n\n\ +\ +There was an error (%s) while getting this email from the server\n" + +#define TXT_SEPARATOR "--------------------------------------------------------------------\n" + +typedef struct s_scrollbar +{ + int top; + int bottom; + int orig_y; + int orig_index_vert; + int allowedspace; +} t_scrollbar; + +typedef struct s_mail +{ + char from[MAIL_BUFLEN]; + char subject[MAIL_BUFLEN]; + char todelete; + long cksum; /* checksum of the header */ + int new; /* mail is new */ +} t_mail; + +struct pop3_struct{ + struct sockaddr_in server; + struct hostent *hp; + enum {CONNECTED, NOT_CONNECTED} connected; + char **mailclient; /* argv[] type of command */ + char **newmailcommand; /* argv[] type of command */ + char **selectedmesgcommand; /* argv[] type of command */ + char username[256]; + char popserver[128]; + char password[256]; + char mailseparator[256]; + char inBuf[4096]; + char outBuf[1024]; + char alias[4]; + char delstatus[9]; + int s; /* socket */ + int serverport; + int localPort; + int numOfMessages; + int numOfUnreadMessages; + int countunreadonly; + int sizeOfAllMessages; + int sizechanged; + int mailCheckDelay; + int forcedCheck; + int status; + int maxdlsize; + long nextCheckTime; + t_mail *mails; +}; +typedef struct pop3_struct *Pop3; + + +Pop3 pop3Create(int nb_conf); +int pop3MakeConnection( Pop3 pc, char *serverName, int port); +int pop3IsConnected(Pop3 pc); +int pop3Login(Pop3 pc, char *name, char *pass); +int pop3Quit(Pop3 pc); +int pop3CheckMail(Pop3 pc); +int pop3GetTotalNumberOfMessages( Pop3 pc ); +int pop3GetNumberOfUnreadMessages( Pop3 pc ); +int pop3WriteOneMail(int nb, int dest_fd, Pop3 pc); +#endif diff --git a/wmpop3lb/wmpop3/wmpop3.c b/wmpop3lb/wmpop3/wmpop3.c new file mode 100644 index 0000000..a7f4649 --- /dev/null +++ b/wmpop3lb/wmpop3/wmpop3.c @@ -0,0 +1,1707 @@ +/* + * wmpop3.c + * multi pop3 mail checker. + * written by Louis-Benoit JOURDAIN (lb@jourdain.org) + * based on the original work by Scott Holden (scotth@thezone.net) + * +*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "../wmgeneral/misc.h" +#include "../wmgeneral/wmgeneral.h" +#include "Pop3Client.h" + +#include "wmpop3.xpm" + +char wminet_mask_bits[64*64]; +int wminet_mask_width = 64; +int wminet_mask_height = 64; + +char *ProgName; + +char mailclient[32] = "pine"; +char password[32]; +char username[32]; +char popserver[128]; +int serverport = 110; +int mailCheckDelay = 10; /* default */ +int autoChecking = YES; /* default */ +int newMessagesOnly = YES; /* default */ +int displaydelay = 1; +char tempdir[1024]; +char config_file[256] = "not-defined"; +int scrollspeed = 100; + +Pop3 conf[6]; +int nb_conf; /* number of configured pop servers */ +int summess; /* total number of messages */ +int color; + +#ifdef _DEBUG +int haspassed = 0; +#endif + +t_scrollbar scrollbar; + +void usage(void); +void printversion(void); +void wmCheckMail_routine(int, char **); +int readConfigFile( char *filename ); + +void BlitString(char *name, int x, int y, int fragment); +void BlitNum(int num, int x, int y, int todelete); + +int pop3DeleteMail(int num, Pop3 pc); +int pop3VerifStats(Pop3 pc); + +/******************************** + * Main Program + ********************************/ +void deleteoldtmpfiles() +{ + char buf[1024]; + DIR *dir; + struct dirent *dp; + + if (tempdir) { + if ((dir = opendir(tempdir))) { + chdir(tempdir); + while((dp = readdir(dir))) { + if (!strncmp(dp->d_name, TMPPREFIX, TMPPREFIXLEN)) { + sprintf(buf, "%s/%s", tempdir, dp->d_name); +#ifdef _DEBUG + printf(" delete old tmp file: %s\n", buf); +#endif + unlink(buf); + } + } + closedir(dir); + } + } +} + +int main(int argc, char *argv[]) { + + int i; + + ProgName = argv[0]; + if (strlen(ProgName) >= 5) + ProgName += (strlen(ProgName) - 5); + + for (i=1; i (i+1)) + { + strcpy(config_file, argv[i+1]); + i++; + } + break; + default: + usage(); + exit(0); + break; + } + } + } + wmCheckMail_routine(argc, argv); + + return 0; +} + +void build_line(char *buf, int num, int index, Pop3 pc) +{ + int len; + int pos; + char tmp[256]; + + /* display spaces in case alias is less than 3 char long */ + memset(tmp, ' ', sizeof(char) * 3); + memset(tmp + 3, 0, sizeof(char) * (256 - 3)); + memcpy(tmp, pc->alias, strlen(pc->alias)); + tmp[3] = ':'; + pos = 4; + for (len = 0; len < MAIL_BUFLEN && pc->mails[num].from[len]; len++); + memcpy(tmp + pos, pc->mails[num].from, len); + tmp[pos + len] = '/'; + pos += len + 1; + for (len = 0; len < MAIL_BUFLEN && pc->mails[num].subject[len]; len++); + memcpy(tmp + pos, pc->mails[num].subject, len); + len += pos; + tmp[len++] = ' '; + tmp[len++] = '*'; + tmp[len++] = ' '; + tmp[len] = '\0'; + pos = index % len; + if (len - pos < (NB_DISP + EXTRA)) { /* We are at the end of the string */ + memcpy(buf, tmp + pos, len - pos); + memcpy(buf + len - pos, tmp, (NB_DISP + EXTRA) - len + pos); + } + else { + memcpy(buf, tmp + pos, NB_DISP + EXTRA); + } +} + +void display_index(int mail_index, int line, Pop3 pc) +{ +#ifdef _DEBUG + if (haspassed) { + printf(" mail_index: %d, line: %d, todelete: %d\n", + mail_index, line, pc->mails[mail_index].todelete); + } +#endif + if (pc->mails[mail_index].todelete) { + copyXPMArea(67, 12, 2, 5, 7, (line * 6) + TOP_MARGIN); + } + else { + copyXPMArea(69, 11, 2, 6, 7, (line * 6) + TOP_MARGIN - 1); + } +} + +void ClearDisplay() { + int i; + + copyXPMArea(72, 4, 3, 42, LEFT_MARGIN, 4); + copyXPMArea(72, 4, 50, 42, 9, 4 ); + for (i = 0; i < NB_LINE; i++) { + copyXPMArea(69, 11, 2, 6, 7, (i * 6) + TOP_MARGIN - 1); + } +} + +/* return < 0 if error + 0 if no pb + else nb of mails which couldn't be deleted */ +int DeleteMail(Pop3 pc) +{ + int etat = 0; + int old_sizeOfAllMessages; + int i; + + old_sizeOfAllMessages = pc->sizeOfAllMessages; + BlitString(pc->alias, 10, TOP_MARGIN, 0); + BlitString("connect", 10, 6*2 + TOP_MARGIN, 0); + RedrawWindow(); + etat = pop3MakeConnection(pc, pc->popserver, pc->serverport); + if (-1 != etat) { + BlitString("login", 10, (6*3) + TOP_MARGIN, 0); + RedrawWindow(); + etat = pop3Login(pc, pc->username, pc->password); + } + if (-1 != etat) { + BlitString("chk cont", 10, (6*4) + TOP_MARGIN, 0); + RedrawWindow(); + etat = pop3VerifStats(pc); + } + if (-1 != etat) { + if (etat != old_sizeOfAllMessages) { + BlitString("mailbox", 10, TOP_MARGIN, 0); + BlitString("content", 10, 6 + TOP_MARGIN, 0); + BlitString("changed", 10, 6*2 + TOP_MARGIN, 0); + BlitString("between", 10, 6*3 + TOP_MARGIN, 0); + BlitString("updates", 10, 6*4 + TOP_MARGIN, 0); + BlitString("del can.", 10, 6*6 + TOP_MARGIN, 0); + RedrawWindow(); + sleep(displaydelay); + for (i = 0, etat = 0; i < pc->numOfMessages; i++) { + etat += pc->mails[i].todelete; + } + } + else { + etat = 0; + for (i = 0; i < pc->numOfMessages; i++) { + if (pc->mails[i].todelete) { + etat += pop3DeleteMail(i + 1, pc); + } + } + } + } + pop3Quit(pc); + return (etat); +} + +/* +void launch_mail_client(int iS) +{ + int i; + int j; + char str[16]; + char **args; + + ClearDisplay(); + if ((args = conf[iS]->mailclient)) { + BlitString("starting", 10, TOP_MARGIN, 0); + for (i = 0; i < 5 && args[i]; i++) { + for (j = 0; j < 8 && args[i][j]; j++); + memcpy(str, args[i], j); + str[j] = '\0'; + BlitString(str, 10, (i + 2)*6 + TOP_MARGIN, 0); + } + if (0 == fork()) { + if (execvp(args[0], args)) { + perror("execvp"); + copyXPMArea(72, 4, 3, 42, LEFT_MARGIN, 4); + copyXPMArea(72, 4, 50, 6, 9, 4 ); + copyXPMArea(69, 11, 2, 6, 7, TOP_MARGIN - 1); + BlitString("Error", 10, TOP_MARGIN, 0); + } + } + else { + conf[iS]->nextCheckTime = time(0) + 30; + } + } + else { + BlitString(" mail", 10, TOP_MARGIN, 0); + BlitString(" client", 10, 6 + TOP_MARGIN, 0); + BlitString("not set", 10, 6*2 + TOP_MARGIN, 0); + BlitString(" check", 15, 6*5 + TOP_MARGIN, 0); + BlitString("wmpop3rc", 10, 6*6 + TOP_MARGIN, 0); + } + RedrawWindow(); + sleep(displaydelay); +} +*/ + +void display_scrollbar(int index, int totalmessages, + int maxlines, int scrollmode) +{ + int delta; + int scrollen; + int vertpos; + + if (totalmessages <= maxlines) { +#ifdef _DEBUG + if (haspassed) + printf(" full scrollbar\n"); +#endif + copyXPMArea((scrollmode) ? 68 : 65, 18, SCROLL_W, + SCROLL_H + (2 * SCROLL_EXT), SCROLL_LX, SCROLL_TY); + scrollbar.top = SCROLL_TY; + scrollbar.bottom = SCROLL_TY + SCROLL_H; + scrollbar.allowedspace = SCROLL_H; + } + else { + delta = totalmessages - maxlines; + /* determine the size of the scrollbar */ + if (0 >= (scrollen = SCROLL_H - ((SCROLL_H / maxlines) * delta))) + scrollen = 1; + /* determine the position */ + scrollbar.allowedspace = SCROLL_H - scrollen; + vertpos = scrollbar.allowedspace * index / delta; + copyXPMArea((scrollmode) ? 68 : 65, 18, SCROLL_W, SCROLL_EXT, + SCROLL_LX, vertpos + SCROLL_TY); + copyXPMArea((scrollmode) ? 68 : 65, 18 + SCROLL_EXT, SCROLL_W, scrollen, + SCROLL_LX, vertpos + SCROLL_TY + SCROLL_EXT); + copyXPMArea((scrollmode) ? 68 : 65, 18 + SCROLL_EXT + SCROLL_H, + SCROLL_W, SCROLL_EXT, + SCROLL_LX, vertpos + SCROLL_TY + SCROLL_EXT + scrollen); + scrollbar.top = vertpos + SCROLL_TY; + scrollbar.bottom = vertpos + SCROLL_TY + (SCROLL_EXT * 2) + scrollen; + +#ifdef _DEBUG + if (haspassed) { + printf(" index: %d, totalmess:%d, mxli: %d, delta: %d, vertpos: %d, allowedspace: %d, sl:%d\n", + index, totalmessages, maxlines, delta, vertpos, + scrollbar.allowedspace, scrollen); + } +#endif + } + /* RedrawWindow(); */ +} + +int is_for_each_mail(char **command) +{ + int i; + + if (command) { + for (i = 0; command[i]; i++) { + if ('%' == command[i][0]) { + if (('f' == command[i][1]) || + ('s' == command[i][1]) || + ('m' == command[i][1]) || + ('n' == command[i][1])) + return (1); + } + } + } + return (0); +} + +char *quotify(char *str) +{ + char *retour; + int len; + + len = strlen(str); + if (NULL != (retour = (char *) malloc(sizeof(char) * len + 3))) { + retour[0] = '\''; + memcpy(retour + 1, str, len); + retour[len + 1] = '\''; + retour[len + 2] = '\0'; + } + return (retour); +} + +/* nb: number of the mail on the server - 1 (if -1: for all mails) + path: allocated buffer to store path of tmp file + newonly: only for new messages + onlyselected: only for selected messages + pc: main struct. + on success return 0 */ +int writemailstofile(int nb, char *path, int newonly, + int onlyselected, Pop3 pc) +{ + int fd; + int len; + int i; + int retour = 0; + int goforwritemail = 0; + int mustdisconnect = 0; + + len = strlen(tempdir); + if (len) { + path[0] = '\0'; + strcat(path, tempdir); + if ('/' != tempdir[len - 1]) + strcat(path, "/"); + strcat(path, TMPPREFIX); + strcat(path, "XXXXXX"); +#ifdef _DEBUG + printf(" creating temporary file [%s]\n", path); + printf(" nb=%d, newonly=%d, onlyselected=%d\n", + nb, newonly, onlyselected); +#endif + if (-1 == (fd = mkstemp(path))) { + fprintf(stderr, "Error: writing mail to file\n"); + perror(path); + retour++; + } + else { + /* to prevent connecting many times, do it now. */ + if (NOT_CONNECTED == pc->connected) { +#ifdef _DEBUG + printf(" writemailstofile not connected, connecting\n"); +#endif + if (pop3MakeConnection(pc,pc->popserver,pc->serverport) == -1){ + return (1); + } + if (pop3Login(pc, pc->username, pc->password) == -1) { + return (1); + } + mustdisconnect = 1; + } + + if (nb < 0) { + /* concatenate all the mails into 1 file */ + for (i = 0; i < pc->numOfMessages; i++) { + goforwritemail = 0; +#ifdef _DEBUG + printf(" mail %d:", i); +#endif + if (!newonly && !onlyselected) { +#ifdef _DEBUG + printf(" !newonly && !onlyselected\n"); +#endif + goforwritemail = 1; + } + else if (newonly) { + if (pc->mails[i].new && + (!onlyselected || (onlyselected && pc->mails[i].todelete))) { +#ifdef _DEBUG + printf(" newonly\n"); +#endif + goforwritemail = 1; + } + } + else if (onlyselected && pc->mails[i].todelete) { +#ifdef _DEBUG + printf(" onlyselected\n"); +#endif + goforwritemail = 1; + } + if (goforwritemail) { + /* put the mail separator */ + if (strlen(pc->mailseparator)) { +#ifdef _DEBUG + printf(" pc->mailseparator: [%s]\n", pc->mailseparator); +#endif + write(fd, pc->mailseparator, strlen(pc->mailseparator)); + } + else { +#ifdef _DEBUG + printf(" TXT_SEPARATOR: [%s]\n", TXT_SEPARATOR); +#endif + write(fd, TXT_SEPARATOR, strlen(TXT_SEPARATOR)); + } + if (pop3WriteOneMail(i + 1, fd, pc)) { + retour++; + } + } + } + + } + else { + if (pop3WriteOneMail(nb + 1, fd, pc)) + retour++; + } + close(fd); + /* close the connection if we've opened it */ + if (mustdisconnect) { +#ifdef _DEBUG + printf(" writemailstofile disconnecting\n"); +#endif + pop3Quit(pc); + } + } + } + else { + fprintf(stderr, "no tempdir configured, can't create file\n"); + retour++; + } + return (retour); +} + +/* + * do_command_completion + * returned array should be freed by calling function + * if nbnewmail == 0, for %c option concatenate _all_ the messages + */ +char **do_command_completion(int num, char **command, + int nbnewmail, Pop3 pc) +{ + char **retour; + int i; + int yaerreur = 0; + char path[1024]; + + for (i = 0; command[i]; i++); +#ifdef _DEBUG + printf(" %d args to the command, mail num %d\n", i, num); +#endif + if (NULL == (retour = (char **) malloc (sizeof(char *) * i + 1))) { + return (NULL); + } + memset(retour, 0, sizeof(char *) * i + 1); + for (i = 0; command[i]; i++) { +#ifdef _DEBUG + printf(" arg %d: [%s]\n", i, command[i]); +#endif + if ('%' == command[i][0]) { + switch (command[i][1]) { + case 'T': /* total nb of mails */ + if (NULL != (retour[i] = (char *) malloc(sizeof(char) * 8))) + sprintf(retour[i], "%d", pc->numOfMessages); + else + yaerreur = 1; + break; + case 't': /* total nb of new mails */ + if (NULL != (retour[i] = (char *) malloc(sizeof(char) * 8))) + sprintf(retour[i], "%d", (nbnewmail < 0) ? 0 : 1); + else + yaerreur = 1; + break; + case 'C': /* concatenate all the selected mails in 1 file */ + if (writemailstofile(-1, path, 0, SELECTONLY, pc)) + yaerreur = 1; + else + if (NULL == (retour[i] = strdup(path))) { + yaerreur = 1; + } + break; + case 'c': /* concatenate all the mails in 1 file */ + if (writemailstofile(-1, path, (nbnewmail > 0), NOSELECTONLY, pc)) + yaerreur = 1; + else + if (NULL == (retour[i] = strdup(path))) { + yaerreur = 1; + } + break; + case 'f': /* from field */ +#ifdef _DEBUG + printf(" from field: [%s]\n", pc->mails[num].from); +#endif + if (NULL == (retour[i] = quotify(pc->mails[num].from))) + yaerreur = 1; + break; + case 's': /* subject of the mail */ +#ifdef _DEBUG + printf(" subject field: [%s]\n", pc->mails[num].subject); +#endif + if (NULL == (retour[i] = quotify(pc->mails[num].subject))) + yaerreur = 1; + break; + case 'm': /* copy the mail to tmp file */ + if (0 <= num) { + if (writemailstofile(num, path, (nbnewmail > 0), NOSELECTONLY, pc)) + yaerreur = 1; + else + if (NULL == (retour[i] = strdup(path))) { + yaerreur = 1; + } + } + break; + case 'n': /* number of the message on the mail server */ + if (NULL != (retour[i] = (char *) malloc(sizeof(char) * 8))) + sprintf(retour[i], "%d", num + 1); + else + yaerreur = 1; + break; + case 'S': /* server name */ + if (NULL == (retour[i] = strdup(pc->popserver))) + yaerreur = 1; + break; + case 'a': /* server alias */ + if (NULL == (retour[i] = strdup(pc->alias))) + yaerreur = 1; + break; + case 'u': /* user name */ + if (NULL == (retour[i] = strdup(pc->username))) + yaerreur = 1; + break; + case 'w': /* user password */ + if (NULL == (retour[i] = strdup(pc->password))) + yaerreur = 1; + break; + case 'P': /* server port */ + if (NULL != (retour[i] = (char *) malloc(sizeof(char) * 8))) + sprintf(retour[i], "%d", pc->serverport); + else + yaerreur = 1; + break; + case '%': /* % character, leave in place */ + if (NULL == (retour[i] = strdup(command[i]))) + yaerreur = 1; + break; + default: + break; + } + } + else { +#ifdef _DEBUG + printf(" just copying arg [%s]\n", command[i]); +#endif + if (NULL == (retour[i] = strdup(command[i]))) + yaerreur = 1; + } + } + retour[i] = NULL; +#ifdef _DEBUG + printf(" retour: %ld\n", (long) retour); +#endif + if (!yaerreur) + return (retour); + else + return (NULL); +} + +/* num is the index of the mail in the mail array + if num == -1, means that the command isn't for each mail */ + + +void spawn_command(int num, char **command, int nbnewmail, + char *display, Pop3 pc) +{ + char **tmpcommand; + char str[16]; + int i, j; + + if (display) { + ClearDisplay(); + if (!command) { + BlitString(display, 10, 6 + TOP_MARGIN, 0); + BlitString("not set", 10, 6*2 + TOP_MARGIN, 0); + BlitString(" check", 15, 6*5 + TOP_MARGIN, 0); + BlitString("wmpop3rc", 10, 6*6 + TOP_MARGIN, 0); + } + else { + BlitString("starting", 10, TOP_MARGIN, 0); + for (i = 0; i < 5 && command[i]; i++) { + for (j = 0; j < 8 && command[i][j]; j++); + memcpy(str, command[i], j); + str[j] = '\0'; + BlitString(str, 10, (i + 2)*6 + TOP_MARGIN, 0); + } + RedrawWindow(); + } + } + if (command) { + /* check for any '%' sign in the command and complete it */ + tmpcommand = do_command_completion(num, command, nbnewmail, pc); + if (tmpcommand) { + /* launch the command in a new process */ + if (0 == fork()) { +#ifdef _DEBUG + printf(" spawning command: ["); + for (i = 0; tmpcommand[i]; i++) { + printf(" %s ", tmpcommand[i]); + } + printf("]\n"); +#endif + if (execvp(tmpcommand[0], tmpcommand)) { + perror("execvp"); + } + } + else { + if (display) { + /* set the check delay to 30 seconds */ + pc->nextCheckTime = time(0) + 30; + } + /* free the memory (in the parent process...) */ + for (i = 0; tmpcommand[i]; i++) { + free (tmpcommand[i]); + } + free (tmpcommand); + } + } + else { + if (display) { + ClearDisplay(); + BlitString(" Error", 15, TOP_MARGIN, 0); + BlitString(" While", 15, 6*2 + TOP_MARGIN, 0); + BlitString("parsing", 15, 6*3 + TOP_MARGIN, 0); + BlitString("command", 15, 6*4 +TOP_MARGIN, 0); + BlitString(display, 10, 6*6 + TOP_MARGIN, 0); + fprintf(stderr, "Error while parsing %s\n", display); + } + else + fprintf(stderr, "Error while parsing command\n"); + } + } + if (display) { + RedrawWindow(); + sleep(displaydelay); + } +} + +/* + * wmCheckMail_routine : This function is used to set up the X display + * for wmpop3 and check for mail every n number of minutes. + */ + +void wmCheckMail_routine(int argc, char **argv){ + + int buttonStatus = -1; + int iS; + Pop3 pc; + int i, j, k; + XEvent Event; + char str[256]; + int index = 0; + int fragment = 0; + int index_vert = 0; + int oldnbmess = 0; + int nbsel; + int selectedmess; + int justreloaded; + long thistime; + char *linestodel[7]; + int unreachable; + long sleeplenght; + int scrollmode = 0; + int nbnewmail; + char separ; + + if( !strcmp( config_file, "not-defined") ) + sprintf(config_file, "%s/.wmpop3rc", getenv("HOME")); + + if( readConfigFile(config_file) == -1){ + exit(0); + } + /* Set up timer for checking mail */ + createXBMfromXPM(wminet_mask_bits, wmpop3_xpm + , wminet_mask_width, wminet_mask_height); + + openXwindow(argc, argv, wmpop3_xpm, wminet_mask_bits + , wminet_mask_width, wminet_mask_height); + + AddMouseRegion(0, 19, 49, 30, 58); /* check button */ + AddMouseRegion(1, 46, 49, 50, 58 ); /* autocheck button */ + AddMouseRegion(2, 53, 49, 57, 58 ); /* switch display button */ + AddMouseRegion(3, 5, 49, 16, 58 ); /* delete button */ + AddMouseRegion(4, 33, 49, 44, 53); /* top arrow */ + AddMouseRegion(5, 33, 54, 44, 58); /* botton arrow */ + /* add the mouse regions for each line */ + for (i = 0; i < NB_LINE; i++) { + AddMouseRegion(6 + i, 9, (i*6) + TOP_MARGIN, + 58, (i*6) + TOP_MARGIN + CHAR_HEIGHT); + } + + + /* Check if Autochecking is on or off */ + if(autoChecking == NO ){ + copyXPMArea(142, 38, 7, 11, 45, 48); + } + else { + copyXPMArea(142, 49, 7, 11, 45, 48); + } + + RedrawWindow(); + + summess = 0; + + deleteoldtmpfiles(); + + sleeplenght = (long) 20000L + (20000L - (20000L * scrollspeed / 100)); + while (1) { + RSET_COLOR; + for (iS = 0; iS < nb_conf; iS++) { + pc = conf[iS]; + if( (((time(0) > pc->nextCheckTime) || + (pc->nextCheckTime == 0)) && ( autoChecking == YES)) + || (pc->forcedCheck == YES)){ + justreloaded = 1; + ClearDisplay(); + BlitString(pc->alias, 10, TOP_MARGIN, 0); + BlitString("connect", 10, (6*2) + TOP_MARGIN, 0); + RedrawWindow(); + pc->status = 0; + if(pop3MakeConnection(pc,pc->popserver,pc->serverport) == -1){ + pc->status = 1; + } + if (!pc->status) { + BlitString("login", 10, (6*3) + TOP_MARGIN, 0); + RedrawWindow(); + if (pop3Login(pc, pc->username, pc->password) == -1 ) + pc->status = 2; + } + if (!pc->status) { + BlitString("get mail", 10, (6*4) + TOP_MARGIN, 0); + RedrawWindow(); + if (pop3CheckMail(pc) == -1) + pc->status = 3; + } + pc->nextCheckTime = time(0) + (pc->mailCheckDelay * SEC_IN_MIN); + index = 0; + pc->forcedCheck = NO; + /* check if new mail has arrived */ + for (i = 0, nbnewmail = 0; i < pc->numOfMessages; i++) + if (pc->mails[i].new) + nbnewmail++; + /* launch the new mail command */ + if (pc->newmailcommand && (-1 != pc->sizechanged)) { + if (nbnewmail) { +#ifdef _DEBUG + printf(" %d New mail(s) ha(s)(ve) arrived!\n", nbnewmail); +#endif + if (is_for_each_mail(pc->newmailcommand)) { + for (i = 0; i < pc->numOfMessages; i++) + if (pc->mails[i].new) + spawn_command(i, pc->newmailcommand, nbnewmail, NULL, pc); + } + else { + spawn_command(-1, pc->newmailcommand, nbnewmail, NULL, pc); + } + } + } + /* close the connection */ + pop3Quit(pc); + pc->sizechanged = 0; + } + } + waitpid(0, NULL, WNOHANG); + /* reset the number of messages */ + unreachable = 1; + for (summess = 0, iS = 0; iS < nb_conf; iS++) { + pc = conf[iS]; + if (!pc->status) { + unreachable = 0; + summess += pc->numOfMessages; + } + } + /* set the offset from the beginning of the list */ + if (summess != oldnbmess) { + oldnbmess = summess; + if (summess < NB_LINE) + index_vert = 0; + else { + index_vert = summess - NB_LINE; + } + } + memset(str, 0, 128); + /* clear the display */ + ClearDisplay(); + nbsel = 0; + for (iS = 0; iS < nb_conf; iS++) { + pc = conf[iS]; + for (i = 0; i < summess && i < pc->numOfMessages; i++) { +#ifdef _DEBUG + if (haspassed) { + printf(" %s, mails[%d], todelete=%d\n", + pc->alias, i, pc->mails[i].todelete); + } +#endif + nbsel += pc->mails[i].todelete; + } + } + if (justreloaded) { + /* make sure we display the correct buttons */ + justreloaded = 0; + if ((NO == newMessagesOnly) && nbsel) + copyXPMArea(128,49 ,14 ,11 ,18 ,48 ); + else + copyXPMArea(128,27 ,14 ,11 ,18 ,48 ); + } + if (newMessagesOnly == YES ){ + /* Show messages waiting */ + RSET_COLOR; + for (color = 0, iS = 0; iS < nb_conf; iS++) { + pc = conf[iS]; + if (pc->countunreadonly) + separ = '-'; + else + separ = ':'; + switch(pc->status) { + case 1: + sprintf(str, "%-3s%cC*ER", pc->alias, separ); + break; + case 2: + sprintf(str, "%-3s%cL*ER", pc->alias, separ); + break; + case 3: + sprintf(str, "%-3s%cM*ER", pc->alias, separ); + break; + default: + sprintf(str, "%-3s%c %3d", pc->alias, separ, + (pc->countunreadonly) ? pc->numOfUnreadMessages : + pc->numOfMessages); + break; + } + BlitString(str, 10, (int) (6*iS) + TOP_MARGIN, 0); + SWAP_COLOR; + } + RSET_COLOR; + sprintf(str, "sel.: %2d", nbsel); + BlitString(str, 10, (int) (6*6) + TOP_MARGIN, 0); + } + else { + RSET_COLOR; + if (0 == summess) { + if (unreachable) { + BlitString(" error", 10, TOP_MARGIN, 0); + } + else { + BlitString("No Mesg", 10, TOP_MARGIN, 0); + } + if (autoChecking == YES) { + BlitString(" next", 10, 6*2 + TOP_MARGIN, 0); + BlitString(" update", 10, 6*3 + TOP_MARGIN, 0); + j = SEC_IN_MIN * 1000; + thistime = time(0); + for (i = 0, k = 0; i < nb_conf; i++) { + if ((conf[i]->nextCheckTime - thistime) < j) { + j = conf[i]->nextCheckTime - thistime; + k = i; + } + } + sprintf(str, " is:%s", conf[k]->alias); + BlitString(str, 10, 6*4 + TOP_MARGIN, 0); + BlitString(" in", 10, 6*5 + TOP_MARGIN, 0); + sprintf(str, "%-5d s.", j); + BlitString(str, 10, 6*6 + TOP_MARGIN, 0); + } + } + else { + RSET_COLOR; + /* iS = index in the conf struct + i = index of the mail + j = line nb on display */ + memset(linestodel, 0, sizeof(char *)); + for (iS = 0, j = 0; iS < nb_conf && j < NB_LINE + index_vert; iS++) { + pc = conf[iS]; + for (i = 0; (j < NB_LINE + index_vert) && i < pc->numOfMessages; + j++, i++) { + if (j >= index_vert) { + build_line(str, i, index, pc); + BlitString(str, 10, ((j - index_vert) * 6) + TOP_MARGIN, + fragment); + display_index(i, (j - index_vert), pc); + /* store the address of the delete flag, so that it will */ + /* be easier to modify it afterwards */ + linestodel[j - index_vert] = &(pc->mails[i].todelete); + } + } + SWAP_COLOR; + } + display_scrollbar(index_vert, summess, NB_LINE, scrollmode); + } + fragment++; + if (0 == (fragment % (CHAR_WIDTH + 1))) { + index++; + fragment = 0; + /* printf("index=%d, fragment=%d\n", index, fragment); */ + } + } +#ifdef _DEBUG + haspassed = 0; +#endif + + RedrawWindow(); + + RSET_COLOR; + /* X Events */ + while (XPending(display)){ + XNextEvent(display, &Event); + switch (Event.type) { + case Expose: + RedrawWindow(); + break; + case DestroyNotify: + XCloseDisplay(display); + exit(0); + break; + case MotionNotify: + if (scrollmode) { +#ifdef _DEBUG + printf(" ca bouge... index_vert before = %d, %d x %d, allowedspace: %d, summess: %d\n", + index_vert, + Event.xbutton.x, Event.xbutton.y, + scrollbar.allowedspace, + summess); + +#endif + if (summess > NB_LINE) { + index_vert = scrollbar.orig_index_vert + + ((Event.xbutton.y - scrollbar.orig_y) * (summess - NB_LINE) / + scrollbar.allowedspace); + if (0 > index_vert) + index_vert = 0; + if (index_vert + NB_LINE > summess) + index_vert = summess - NB_LINE; + } +#ifdef _DEBUG + printf(" deplacement de %d pixels --> index_vert = %d\n", + Event.xbutton.y - scrollbar.orig_y, index_vert); +#endif + } + break; + case ButtonPress: + buttonStatus = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + if (buttonStatus >= 0){ + switch (buttonStatus){ + case 0 : /* check / open button pressed */ + if ((NO == newMessagesOnly) && nbsel) + copyXPMArea(128, 60 ,14 ,11 ,18 ,48 ); + else + copyXPMArea(128,38 ,14 ,11 ,18 ,48 ); + break; + case 1 : /* autocheck button pressed */ + break; + case 2: /* switch display button pressed */ + break; + case 3: /* delete button pressed */ + copyXPMArea(127, 15, 14, 11, 4, 48); + break; + case 4: /* top arrow button pressed */ + break; + case 5: /* bottom arrow button pressed */ + break; + default: + break; + } + RedrawWindow(); + } + else if (SCROLL_LX <= Event.xbutton.x && SCROLL_RX >= Event.xbutton.x + && scrollbar.top <= Event.xbutton.y && + scrollbar.bottom >= Event.xbutton.y) { + scrollbar.orig_y = Event.xbutton.y; + scrollbar.orig_index_vert = index_vert; + scrollmode = 1; + } + break; + case ButtonRelease: + i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + + if (buttonStatus == i && buttonStatus >= 0){ + switch (buttonStatus){ + case 0 : /* check button */ + if (nbsel && !newMessagesOnly) { + copyXPMArea(128,49 ,14 ,11 ,18 ,48 ); + /* this is where you launch the open mail command */ + for (iS = 0; iS < nb_conf; iS++) { + pc = conf[iS]; + for (i = 0, selectedmess = 0; i < pc->numOfMessages; i++) { + if (pc->mails[i].todelete) { + selectedmess = 1; + break; + } + } + if (selectedmess) { +#ifdef _DEBUG + printf(" launching selectedmesgcommand command for conf %d\n", + iS); +#endif + + if (is_for_each_mail(pc->selectedmesgcommand)) { +#ifdef _DEBUG + if (!pc->numOfMessages) { + printf(" command is for each mail but there's no mail\n"); + } + else + printf(" command is for each mail\n"); +#endif + for (i = 0; i < pc->numOfMessages; i++) + spawn_command(i, pc->selectedmesgcommand, 0, + "selectm.", pc); + } + else { + spawn_command(-1, pc->selectedmesgcommand, 0, + "selectm.", pc); + } + } + } + } + else { + copyXPMArea(128,27 ,14 ,11 ,18 ,48 ); + for (iS = 0; iS < nb_conf; iS++) + conf[iS]->forcedCheck = YES; + } + break; + case 1 : /* autocheck Button */ + if (autoChecking == YES){ + autoChecking = NO; + copyXPMArea(142, 38, 7, 11, 45, 48); + } + else { + autoChecking = YES; + for (iS = 0; iS < nb_conf; iS++) + conf[iS]->nextCheckTime = time(0) + + (conf[iS]->mailCheckDelay * SEC_IN_MIN); + copyXPMArea(142, 49, 7, 11, 45, 48); + } + break; + case 2: /* switch display Button */ + index = 0; + /* change view on # of messages */ + if( newMessagesOnly == YES ) { + newMessagesOnly = NO; + copyXPMArea(149,38 , 7 , 11, 52, 48); + if (nbsel) { + copyXPMArea(128,49,14,11,18,48); + } + else { + copyXPMArea(128,27,14,11,18,48); + } + } + else { + newMessagesOnly = YES; + copyXPMArea(149,49 , 7 , 11, 52, 48); + copyXPMArea(128,27,14,11,18,48); + } +#ifdef _DEBUG + haspassed = 1; +#endif + break; + case 3: /* delete button */ + copyXPMArea(143, 15, 14, 11, 4, 48); + j = 0; + RSET_COLOR; + for (iS = 0; iS < nb_conf; iS++) { + pc = conf[iS]; + for (i = 0, k = 0; i < pc->numOfMessages; i++) + k += pc->mails[i].todelete; + if (k) { + /* clear the display */ + ClearDisplay(); + k = DeleteMail(pc); + if (k < 0) { + sprintf(pc->delstatus, "%-3s: Err", pc->alias); + } + else if (k > 0) { + sprintf(pc->delstatus, "%-3s/D:%2d", pc->alias, k); + } + else + sprintf(pc->delstatus, "%-3s: ok", pc->alias); + pc->forcedCheck = YES; + } + else { + sprintf(pc->delstatus, "%-3s:none", pc->alias); + } + } + /* clear the display */ + ClearDisplay(); + RSET_COLOR; + for (iS = 0; iS < nb_conf; iS++) { + BlitString(conf[iS]->delstatus, 10, 6*iS + TOP_MARGIN, 0); + SWAP_COLOR; + } + RedrawWindow(); + sleep(displaydelay); + break; + case 4: /* top arrow button pressed */ + index_vert--; + if (0 > index_vert) + index_vert = 0; +#ifdef _DEBUG + haspassed = 1; +#endif + break; + case 5: /* bottom arrow button pressed */ + if (summess > NB_LINE) { + index_vert++; + if (index_vert + NB_LINE > summess) + index_vert = summess - NB_LINE; + } +#ifdef _DEBUG + haspassed = 1; +#endif + break; + default: + if (newMessagesOnly == NO) { /* message view mode */ + if ((5 < buttonStatus) && (buttonStatus <= 5 + NB_LINE)) { + if ((buttonStatus - 6 + index_vert) < summess) { + /* first update lines to del */ + *(linestodel[buttonStatus - 6]) = + 1 - *(linestodel[buttonStatus - 6]); +#ifdef _DEBUG + printf(" button %d pressed, j'update lines to del\n", + buttonStatus - 6); + haspassed = 1; +#endif + nbsel = 0; + for (iS = 0; iS < nb_conf; iS++) { + pc = conf[iS]; + for (i = 0; i < pc->numOfMessages; i++) { + nbsel += pc->mails[i].todelete; +#ifdef _DEBUG + printf(" conf %d, mail %d, todelete = %d\n", + iS, i, pc->mails[i].todelete); +#endif + } + } + /* display open or reload buttons */ + if (nbsel) { + copyXPMArea(128,49,14,11,18,48); + } + else { + copyXPMArea(128,27,14,11,18,48); + } + } + } + } + else { /* summary view mode */ + if ((5 < buttonStatus) && (buttonStatus <= 5 + nb_conf)) { + if ((Event.xbutton.x > 10) && + (Event.xbutton.x < (10 + (4 * (CHAR_WIDTH + 1))))) { +#ifdef _DEBUG + printf(" launching command for conf %d\n", + buttonStatus - 6); +#endif + pc = conf[buttonStatus - 6]; + if (is_for_each_mail(pc->mailclient)) { +#ifdef _DEBUG + if (!pc->numOfMessages) { + printf(" command is for each mail but there's no mail\n"); + } +#endif + for (i = 0; i < pc->numOfMessages; i++) + spawn_command(i, pc->mailclient, nbnewmail, + "mailcli.", pc); + } + else { + spawn_command(-1, pc->mailclient, nbnewmail, + "mailcli.", pc); + } + } + else if ((Event.xbutton.x > (10 + (4 * (CHAR_WIDTH + 1)))) && + (Event.xbutton.x < (10 + (8 * (CHAR_WIDTH + 1))))) { + /* swap view mode */ + conf[buttonStatus - 6]->countunreadonly = + 1 - conf[buttonStatus - 6]->countunreadonly; +#ifdef _DEBUG + printf(" swapping view mode for conf %d: %s\n", + buttonStatus - 6, + (conf[buttonStatus - 6]->countunreadonly) ? + "UnreadMessages" : "TotalMessages"); + +#endif + } + } + else if ((5 + NB_LINE) == buttonStatus) { + /* status summary line pressed */ + if ((Event.xbutton.x > 10) && + (Event.xbutton.x < (10 + (4 * (CHAR_WIDTH + 1))))) { + /* select all messages */ + for (iS = 0; iS < nb_conf; iS++) { + for (pc = conf[iS], i = 0; i < pc->numOfMessages; i++) { + pc->mails[i].todelete = 1; + } + } + } + else if ((Event.xbutton.x > (10 + (4 * (CHAR_WIDTH + 1)))) && + (Event.xbutton.x < (10 + (8 * (CHAR_WIDTH + 1))))) { + /* unselect all messages */ + for (iS = 0; iS < nb_conf; iS++) { + for (pc = conf[iS], i = 0; i < pc->numOfMessages; i++) { + pc->mails[i].todelete = 0; + } + } + } + } + } + break; + } + } + else { + if (buttonStatus >= 0) { + /* button has been pressed correctly but released somewhere else */ + switch(buttonStatus) { + case 0: /* check button was pressed */ + if ((NO == newMessagesOnly) && nbsel) + copyXPMArea(128,49 ,14 ,11 ,18 ,48 ); + else + copyXPMArea(128,27 ,14 ,11 ,18 ,48 ); + break; + case 3: /* delete button was pressed */ + copyXPMArea(143, 15, 14, 11, 4, 48); + break; + } + } + } + RedrawWindow(); + buttonStatus = -1; + scrollmode = 0; + break; + } + } + usleep(sleeplenght); + } +} + + +/* + * usage : Prints proper command parameters of wmpop3. + */ +void usage(void) +{ + fprintf(stdout, "\nWMPop3LB - Louis-Benoit JOURDAIN (wmpop3lb@jourdain.org)\n"); + fprintf(stdout, "based on the work by Scott Holden \n\n"); + fprintf(stdout, "usage:\n"); + fprintf(stdout, " -display \n"); + fprintf(stdout, " -geometry +XPOS+YPOS initial window position\n"); + fprintf(stdout, " -c use specified config file\n"); + fprintf(stdout, " -h this help screen\n"); + fprintf(stdout, " -v print the version number\n"); + fprintf(stdout, "\n"); +} + +void printversion(void) +{ + fprintf(stdout, "wmpop3 v%s\n", WMPOP3_VERSION); +} + +// Blits a string at given co-ordinates +void BlitString(char *name, int x, int y, int fragment) +{ + int i; + int c; + int k; + int row; + + /* printf("--name: [%s] \n", name); */ + for (i = 0, k = x; name[i]; i++) { + c = toupper(name[i]); + if (c >= 'A' && c <= 'Z') { /* its a letter */ + c -= 'A'; + row = LETTERS; + } + else if (c >= '0' && c <= '9') { /* its a number */ + c -= '0'; + row = NUMBERS; + } + else switch(c) { + case '-': + c = 26; + row = LETTERS; + break; + case '*': + c = 27; + row = LETTERS; + break; + case ':': + c = 10; + row = NUMBERS; + break; + case '/': + c = 11; + row = NUMBERS; + break; + case '@': + c = 12; + row = NUMBERS; + break; + case '%': + c = 15; + row = NUMBERS; + break; + case ' ': + c = 13; + row = NUMBERS; + break; + case '.': + c = 28; + row = LETTERS; + break; + default: + c = 14; + row = NUMBERS; + break; + } + /* printf("c:%2d (%c), fragment: %d, i:%d, k=%d ", + c, name[i], fragment, i, k); */ + if (i > 0 && i < NB_DISP) { + copyXPMArea(c * CHAR_WIDTH, CH_COLOR(row), CHAR_WIDTH + 1, CHAR_HEIGHT, + k, y); + /* printf(" - k1: %d += %d + 1", k, CHAR_WIDTH); */ + k += CHAR_WIDTH + 1; + } + else if (0 == i) { + copyXPMArea(c * CHAR_WIDTH + fragment, CH_COLOR(row), + CHAR_WIDTH + 1 - fragment, CHAR_HEIGHT, + k, y); + /* printf(" - k2: %d += %d + 1 - %d", k, CHAR_WIDTH, fragment); */ + k += CHAR_WIDTH + 1 - fragment; + } + else if (fragment && (NB_DISP == i)) { + copyXPMArea(c * CHAR_WIDTH, CH_COLOR(row), fragment + 1, CHAR_HEIGHT, + k, y); + /* printf(" - k3: %d += %d ", k, fragment); */ + k += fragment; + } + /* printf(" -- apres k=%d\n", k); */ + } +} + + +/* Blits number to given coordinates...*/ + +void BlitNum(int num, int x, int y, int todelete) +{ + if (todelete) + num += 19; + copyXPMArea(((num - 1) * (SN_CHAR_W + 1)) + 1, CH_COLOR(SMALL_NUM), + SN_CHAR_W, CHAR_HEIGHT + 1, x, y); +} + +int parsestring(char *buf, char *data, int max, FILE *fp) +{ + char *deb; + char *end; + char *bal; + int go = 1; + int linelen = 0; + + /* trim the leading spaces */ + memset(data, 0, max); + for (deb = buf; *deb && isspace(*deb); deb++); + if (!*deb) + return (-1); + if ('"' == *deb) { + ++deb; + bal = data; + while (go) { +#ifdef _DEBUG + printf(" line to parse: [%s]\n", deb); +#endif + /* get to the end of the line */ + for (end = deb; *end && ('"' != *end); end++); + if (!*end) { /* this is a multiline entry */ + linelen += (int) (end - deb); + if (linelen > max) { +#ifdef _DEBUG + printf(" maximum line length reached\n"); +#endif + return (-1); + } + memcpy(bal, deb, (int) (end - deb)); + bal = data + linelen; + if (fgets(buf, CONF_BUFLEN, fp)) { + deb = buf; + } + else { /* end of file reached */ + return (-1); + } + } + else { + memcpy(bal, deb, end - deb); + go = 0; + } + } + } + else { + for (end = deb; *end && !isspace(*end); end++); + memcpy(data, deb, ((end - deb) > max) ? max : end - deb); + } +#ifdef _DEBUG + printf(" parsed string (len=%d) : [%s]\n", strlen(data), data); +#endif + return (0); +} + +int parsenum(char *buf, int *data) +{ + char *deb; + char *end; + char temp[32]; + + memset(temp, 0, 32); + for (deb = buf; *deb && isspace(*deb); deb++); + if (!*deb) + return (-1); + if ('"' == *deb) { + for (end = ++deb; *end && ('"' != *end); end++); + if (!*end) + return (-1); + memcpy(temp, deb, end - deb); + *data = atoi(temp); + } + else { + for (end = deb; *end && !isspace(*end); end++); + memcpy(temp, deb, end - deb); + *data = atoi(temp); + } + return (0); +} + +char **build_arg_list(char *buf, int len) +{ + int espaces; + int i, j; + char **retour; + + /* count number of args */ + for (espaces = 0, i = 0; buf[i] && i < len; i++) + if (isspace(buf[i])) + espaces++; + /* allocate space for the structure */ + if (NULL == (retour = (char **) malloc(sizeof(char *) * espaces + 2))) + return (NULL); + /* get each arg one by one */ + for (i = 0, j = 0; j < len && i < 256; i++) { + /* get the end of the arg */ + for (espaces = j; espaces < len && !isspace(buf[espaces]); espaces++); + /* allocate space for the arg */ + if (0 == (retour[i] = malloc(sizeof(char) * (espaces - j) + 1))) { + /* free what has been allocated */ + for (j = 0; j < i; j++) + free(retour[j]); + return (NULL); + } + memcpy(retour[i], buf + j, espaces - j); + retour[i][espaces - j] = '\0'; + j = espaces + 1; + } + retour[i] = 0; + return (retour); +} + + +int readConfigFile( char *filename ){ + char buf[CONF_BUFLEN]; + char tmp[CONF_BUFLEN]; + FILE *fp; + char *bal; + + if( (fp = fopen( filename, "r")) == 0 ){ + sprintf(config_file, "%s/.wmpop3rc", getenv("HOME")); + fprintf(stderr, "-Config file does not exit : %s\n",config_file); + fprintf(stderr, "+Trying to create new config file.\n"); + if((fp = fopen(config_file,"w")) == 0){ + fprintf(stderr, "-Error creating new config file\n"); + return -1; + } + fprintf(fp, "#####################################################\n"); + fprintf(fp, "# wmpop3lb configuration file #\n"); + fprintf(fp, "# #\n"); + fprintf(fp, "# for more information about wmpop3lb, please see: #\n"); + fprintf(fp, "# http://wmpop3lb.jourdain.org #\n"); + fprintf(fp, "# or send a mail to #\n"); + fprintf(fp, "# wmpop3lb@jourdain.org #\n"); + fprintf(fp, "#####################################################\n"); + fprintf(fp, "autochecking 0 # 1 enables, 0 disables\n"); + fprintf(fp, "displaydelay 2 # nb of seconds error info is displayed\n"); + fprintf(fp, "scrollspeed 100 # percentage of original scrool speed\n"); + fprintf(fp, "tempdir /tmp # directory for tmp files\n"); + fprintf(fp, "viewallmessages 0 # 0 Shows the from and subject\n"); + fprintf(fp, "# 1 Shows the number of messages\n"); + fprintf(fp, "#\n# Replace all values with appropriate data\n#\n"); + fprintf(fp, "[Server] # server section\n"); + fprintf(fp, "alias \"3 alphanum. char. long alias\"\n"); + fprintf(fp, "popserver \" pop3 server name \"\n"); + fprintf(fp, "port 110 # default port\n"); + fprintf(fp, "username \" pop3 login name \"\n"); + fprintf(fp, "password \" pop3 password \"\n"); + fprintf(fp, "mailcheckdelay 10 # default mail check time in minutes\n"); + fprintf(fp, "countUnreadOnly 0 # count unread messages only\n"); + fprintf(fp, "mailclient \"netscape -mail\" # for example...\n"); + fprintf(fp, "newmailcommand \" specify new mail command \"\n"); + fprintf(fp, "selectedmesgcommand \"specify command for selected mess\"\n"); + fprintf(fp, "mailseparator \" separator when concatening messages\"\n"); + fprintf(fp, "maxdlsize -1 # (no limit)\n"); + fprintf(fp, "#\n# start new [server] section below (up to a total of 6)\n"); + fprintf(stderr, "+New config file created : ~/.wmpop3rc\n\n"); + fprintf(stderr, "+ ~/.wmpop3rc must be configured before running wmpop3.\n"); + fclose(fp); + return -1; + } + + nb_conf = 0; + tempdir[0] = '\0'; + + while ((nb_conf < 7) && fgets(buf, CONF_BUFLEN, fp) != 0) { + if (buf[0] != '#') { + if (!nb_conf && !strncasecmp( buf, "autochecking", 12) ){ + if (parsenum(buf + 12, &autoChecking)) + fprintf(stderr, "syntax error for parameter autochecking\n"); + } + else if (!nb_conf && !strncasecmp( buf, "scrollspeed", 11) ){ + if (parsenum(buf + 11, &scrollspeed)) + fprintf(stderr, "syntax error for parameter scrollspeed\n"); + } + else if (!nb_conf && !strncasecmp( buf, "displaydelay", 12) ){ + if (parsenum(buf + 12, &displaydelay)) + fprintf(stderr, "syntax error for parameter displaydelay\n"); + } + else if (!nb_conf && !strncasecmp(buf, "tempdir", 7)) { + if (parsestring(buf + 7, tempdir, 1024, fp)) + fprintf(stderr, "syntax error for parameter tempdir\n"); + } + else if (!strncasecmp(buf, "[server]", 8)) { + nb_conf++; + if (!(conf[nb_conf - 1] = pop3Create(nb_conf))) { + fprintf(stderr, "Can't allocate memory for config structure\n"); + fclose(fp); + return (-1); + } + } + else if (nb_conf && !strncasecmp(buf, "username", 8) ) { + if (parsestring(buf + 8, conf[nb_conf -1]->username, 256, fp)) + fprintf(stderr, "section %d: invalid syntax for username\n", + nb_conf); + } + else if (nb_conf && !strncasecmp( buf, "password", 8) ){ + if (parsestring(buf + 8, conf[nb_conf - 1]->password, 256, fp)) + fprintf(stderr, "section %d: invalid syntax for password\n", + nb_conf); + } + else if (nb_conf && !strncasecmp(buf, "alias", 5) ) { + if (parsestring(buf + 5, conf[nb_conf -1]->alias, 3, fp)) + fprintf(stderr, "section %d: invalid syntax for alias\n", nb_conf); + } + else if (nb_conf && !strncasecmp( buf, "popserver", 9) ){ + if (parsestring(buf + 9, conf[nb_conf - 1]->popserver, 128, fp)) + fprintf(stderr, "section %d: invalid syntax for popserver\n", + nb_conf); + } + else if (nb_conf && !strncasecmp( buf, "port", 4) ){ + if (parsenum(buf + 4, &(conf[nb_conf - 1]->serverport))) + fprintf(stderr, "section %d: Invalid popserver port number.\n", + nb_conf); + } + else if (!nb_conf && !strncasecmp( buf, "viewallmessages", 15) ){ + if (parsenum(buf + 15, &newMessagesOnly)) + fprintf(stderr, "section %d: Invalid number ( viewallmessages )\n", + nb_conf); + } + else if (nb_conf && !strncasecmp(buf, "countunreadonly", 15)) { + if (parsenum(buf + 15, &(conf[nb_conf - 1]->countunreadonly))) + fprintf(stderr, "section %d: Invalid number ( countunreadonly )\n", + nb_conf); + } + else if (nb_conf && !strncasecmp( buf, "mailcheckdelay", 14) ){ + if (parsenum(buf + 14, &(conf[nb_conf -1]->mailCheckDelay))) + fprintf(stderr, "section %d: Invalid delay time.\n", nb_conf); + } + else if (nb_conf && !strncasecmp(buf, "mailclient", 10)) { + if (parsestring(buf + 10, tmp, 256, fp)) + fprintf(stderr, "section %d: Invalid syntax for mailclient.\n", + nb_conf); + else + conf[nb_conf - 1]->mailclient = build_arg_list(tmp, strlen(tmp)); + } + else if (nb_conf && !strncasecmp(buf, "newmailcommand", 14)) { + if (parsestring(buf + 14, tmp, 256, fp)) + fprintf(stderr,"section %d: Invalid syntax for newmailcommand.\n", + nb_conf); + else + conf[nb_conf - 1]->newmailcommand = + build_arg_list(tmp, strlen(tmp)); + } + else if (nb_conf && !strncasecmp(buf, "selectedmesgcommand", 19)) { + if (parsestring(buf + 19, tmp, 256, fp)) + fprintf(stderr, + "section %d: Invalid syntax for selectedmesgcommand.\n", + nb_conf); + else + conf[nb_conf - 1]->selectedmesgcommand = + build_arg_list(tmp, strlen(tmp)); + } + else if (nb_conf && !strncasecmp(buf, "mailseparator", 13)) { + if (parsestring(buf + 13, conf[nb_conf - 1]->mailseparator, 256, fp)) + fprintf(stderr, "section %d: Invalid syntax for mailseparator\n", + nb_conf); + } + else if (nb_conf && !strncasecmp( buf, "maxdlsize", 9) ){ + if (parsenum(buf + 9, &(conf[nb_conf -1]->maxdlsize))) + fprintf(stderr, "section %d: Invalid maxdlsize.\n", nb_conf); + } + else if (nb_conf) { + if (*buf && (isalpha(*buf) || isalnum(*buf))) + fprintf(stderr, "section %d: Unknown indentifier : [%s]\n", + nb_conf, buf); + } + else { + for (bal = buf; *bal && !isalnum(*bal); bal++); + if (*bal) + fprintf(stderr, "identifier outside Server section: [%s]\n", buf); + } + } + } + fclose(fp); + return 0; +} + + + + + + + diff --git a/wmpop3lb/wmpop3/wmpop3.xpm b/wmpop3lb/wmpop3/wmpop3.xpm new file mode 100644 index 0000000..75bea69 --- /dev/null +++ b/wmpop3lb/wmpop3/wmpop3.xpm @@ -0,0 +1,152 @@ +/* XPM */ +static char * wmpop3_xpm[] = { +"160 130 19 1", +" c None", +". c #202020", +"+ c #0000FF", +"@ c #00EB00", +"# c #000000", +"$ c #F7F3FF", +"% c #727072", +"& c #C7C3C7", +"* c #86828E", +"= c #AEAAAE", +"- c #B60418", +"; c #873A45", +"> c #C44457", +", c #636363", +"' c #20B2AE", +") c #2164A8", +"! c #E02A8B", +"~ c #AD206B", +"{ c #575B5E", +" .+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +" .+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +" .+++@@++......................................................+#.############++#.############+++", +" .++@$@@+......................................................+#%%%%%%%%%%%%.++#$$$$$$$$$$$$.+++", +" ...&*..................................................& .++@@@@+......................................................+#%==========$#++#$==========%#+++", +" ...&*..................................................& .+++@@++......................................................+#%===.==#===$#++#$===#==.===%#+++", +" ...&*..................................................& .+++++++......................................................+#%==#.==##==$#++#$==##==.#==%#+++", +" ...&*..................................................& .+++--++......................................................+#%=##.==###=$#++#$=.##==.##=%#+++", +" ...&*..................................................& .++-$--+......................................................+#%==#.==##==$#++#$==##==.#==%#+++", +" ...&*..................................................& .++----+......................................................+#%===.==#===$#++#$===#==.===%#+++", +" ...&*..................................................& .+++--++......................................................+#%==========$#++#$==========%#+++", +" ...&*..................................................& .++++&*+......................................................+#$$$$$$$$$$$$#++#%%%%%%%%%%%%#+++", +" ...&*..................................................& .++;>&*+......................................................+#.############++#.############+++", +" ...&*..................................................& .++;>&*+......................................................++++++++++++++++++++++++++++++++++", +" ...&*..................................................& .++;>&*+......................................................++++++++++++++++++++++++++++++++++", +" ...&*..................................................& .++;>&*+......................................................+##############++##############+++", +" ...&*..................................................& .++;>&*+......................................................+#%%%%%%%%%%%%#++#$$$$$$$$$$$$#+++", +" ...&*..................................................& .+++++++......................................................+#%==========$#++#$==========%#+++", +" ...&*..................................................& .$$$**$+......................................................+#%####=##=#=$#++#$####=##=#=%#+++", +" ...&*..................................................& .$&**&$+......................................................+#%=#=#=#==#=$#++#$=#=#=#==#=%#+++", +" ...&*..................................................& .$&**&$+......................................................+#%=#=#=##=#=$#++#$=#=#=##=#=%#+++", +" ...&*..................................................& .$&**&$+......................................................+#%=#=#=#==#=$#++#$=#=#=#==#=%#+++", +" ...&*..................................................& .$&**&$+......................................................+#%####=##=##$#++#$####=##=##%#+++", +" ...&*..................................................& .$&**&$+......................................................+#%==========$#++#$==========%#+++", +" ...&*..................................................& .$&**&$+......................................................+#$$$$$$$$$$$$#++#%%%%%%%%%%%%#+++", +" ...&*..................................................& .$&**&$+......................................................+##############++##############+++", +" ...&*..................................................& .$&**&$+......................................................++++++++++++++++++++++++++++++++++", +" ...&*..................................................& .$&**&$+......................................................++############################++++", +" ...&*..................................................& .$&**&$+......................................................++#$$$$$$$$$$$$##$$$$$$$$$$$$#++++", +" ...&*..................................................& .$&**&$+......................................................++#$==========%##$====..====%#++++", +" ...&*..................................................& .$&**&$+......................................................++#$==......==%##$==......==%#++++", +" ...&*..................................................& .$&**&$+......................................................++#$=..====..=%##%%%%%%%%%%%%#++++", +" ...&*..................................................& .$&**&$+......................................................++#$========.=%##............#++++", +" ...&*..................................................& .$&**&$+......................................................++#$=....===.=%##$$$$$$$$$$$$#++++", +" ...&*..................................................& .$&**&$+....................................................##++#$=...===..=%##$==......==%#++++", +" ...&*..................................................& .$&**&$+......................................................++#$=.=.....==%##$====..====%#++++", +" ...&*..................................................& .$&**&$+......................................................++#%%%%%%%%%%%%##%%%%%%%%%%%%#++++", +" ...&*..................................................& .$&**&$+......................................................++############################++++", +" ...&*..................................................& .$&**&$+......................................................++############################++++", +" ...&*..................................................& .$&**&$+......................................................++#%%%%%%%%%%%%##$$$$$..$$$$$#++++", +" ...&*..................................................& .$&**&$+.....................................................#++#%==========$##$###%..$=##%#++++", +" ...&*..................................................& .$&**&$+.....................................................#++#%==......==$##$#==%..$###%#++++", +" ...&*..................................................& .$&**&$+.....................................................#++#%=..====..=$##$###%..$=##%#++++", +" ...&*..................................................& .$&**&$+.....................................................#++#%========.=$##$===%..$===%#++++", +" ...&*..................................................& .$&**&$+.....................................................#++#%=....===.=$##$#=#%..$##=%#++++", +" ...&*..................................................& .$&**&$+......................................................++#%=...===..=$##$###%..$###%#++++", +" & .$&**&$+......................................................++#%=.=.....==$##$#=#%..$##=%#++++", +" & .$&**&$+......................................................++#$$$$$$$$$$$$##%%%%%..%%%%%#++++", +" #######################################################& .$&**&$+......................................................++############################++++", +" #$$$$$$$$$$$$##$$$$$$$$$$$$##$$$$$$$$$$$$#$$$$$..$$$$$#& .$&**&$+......................................................++############################++++", +" #$==========%##$==========%##$====..====%#$###%..$=##%#& .$&**&$+......................................................++#$$$$$$$$$$$$##%%%%%..%%%%%#++++", +" #$####=##=#=%##$==......==%##$==......==%#$#==%..$###%#& .$&**&$+......................................................++#$####======%##%###$..%=##$#++++", +" #$=#=#=#==#=%##$=..====..=%##%%%%%%%%%%%%#$###%..$=##%#& .$&**&$+......................................................++#$#==#####==%##%#==$..%###$#++++", +" #$=#=#=##=#=%##$========.=%##............#$===%..$===%#& .$&**&$+......................................................++#$#======#==%##%###$..%=##$#++++", +" #$=#=#=#==#=%##$=....===.=%##$$$$$$$$$$$$#$#=#%..$##=%#& .$&**&$+......................................................++#$#==#######%##%===$..%===$#++++", +" #$####=##=##%##$=...===..=%##$==......==%#$###%..$###%#& .$&**&$+......................................................++#$#=#,,,,,,#%##%#=#$..%##=$#++++", +" #$==========%##$=.=.....==%##$====..====%#$#=#%..$##=%#& .$&**&$+......................................................++#$##,,,,,,#=%##%###$..%###$#++++", +" #%%%%%%%%%%%%##%%%%%%%%%%%%##%%%%%%%%%%%%#%%%%%..%%%%%#& .$&**&$+......................................................++#$########==%##%#=#$..%##=$#++++", +" #######################################################& .$&**&$+......................................................++#%%%%%%%%%%%%##%$$$$..%$$$$#++++", +" &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& .$**$$$+......................................................++############################++++", +" .+++++++......................................................++##############++++++++++++++++++", +" .+++++++......................................................++#%%%%%%%%%%%%#++++++++++++++++++", +" .+++++++......................................................++#%####======$#++++++++++++++++++", +" .+++++++ ++#%#==#####==$#++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#%#======#==$#++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................................................++++++++#%#==#######$#++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++''''''''''''''''''''''''''''''''''''''''''''''''++++++++#%#=#,,,,,,#$#++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'))))))))))))))))))))))))))))))))))))))))))))))'++++++++#%##,,,,,,#=$#++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'))))))))))))))))))))))))))))))))))))))))))))))'++++++++#%########==$#++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++''''''''''''''''''''''''''''''''''''''''''''''''++++++++#$$$$$$$$$$$$#++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++................................................++++++++##############++++++++++++++++++", +"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++''''''''''''''''''''''''''''''''''''''''''''''+++++++++++++++++++++++++++++++++++++++++", +"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++''''''''''''''''''''''''''''''''''''''''''''''+++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"...............................................................................................................................................................+", +"..'..'''.'''.'.'.'''.'''.'''.'''.'''.)))..)..))).))).).).))).))).))).))).)))..!..!!!.!!!.!.!.!!!.!!!.!!!.!!!.!!!.~~~..~..~~~.~~~.~.~.~~~.~~~.~~~.~~~.~~~.~~~...+", +".''....'...'.'.'.'...'.....'.'.'.'.'.).).))....)...).).).)...).....).).).).).!!....!...!.!.!.!...!.....!.!.!.!.!.~.~.~~....~...~.~.~.~...~.....~.~.~.~.~.~.~...+", +"..'..'''..''.'''.'''.'''...'.'''.'''.).)..)..)))..)).))).))).)))...).))).)))..!..!!!..!!.!!!.!!!.!!!...!.!!!.!!!.~.~..~..~~~..~~.~~~.~~~.~~~...~.~~~.~~~.~~~...+", +"..'..'.....'...'...'.'.'..'..'.'...'.).)..)..).....)...)...).).)..)..).)...)..!..!.....!...!...!.!.!..!..!.!...!.~.~..~..~.....~...~...~.~.~..~..~.~...~...~...+", +".'''.'''.'''...'.'''.'''..'..'''.'''.))).))).))).)))...).))).)))..)..))).))).!!!.!!!.!!!...!.!!!.!!!..!..!!!.!!!.~~~.~~~.~~~.~~~...~.~~~.~~~..~..~~~.~~~.~~~...+", +"...............................................................................................................................................................+", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"...............................................................................................................................................................+", +"..''..'''...'''.'''..''''.''''..'''.'..'.'''..''''.'..'.'....'..'.'..'..''..''''..''..''''.''''.'''..'..'.'..'.'..'.'..'.'..'.''''......'..'...................+", +".'..'.'..'.'....'..'.'....'....'....'..'..'.....'..'.'..'....''''.''.'.'..'.'..'.'..'.'..'.'.....'...'..'.'..'.'..'.'..'.'..'....'.......''....................+", +".''''.'''..'....'..'.'''..'''..'.''.''''..'.....'..''...'....'..'.''''.'..'.''''.''.'.''''.''''..'...'..'.'..'.'..'..''..''''..''..''''.''''...................+", +".'..'.'..'.'....'..'.'....'....'..'.'..'..'.....'..'.'..'....'..'.'.''.'..'.'....'.''.'.'.....'..'...'..'..''..''''.'..'....'.'..........''....................+", +".'..'.''''..'''.'''..''''.'.....''..'..'.'''..''...'..'.''''.'..'.'..'..''..'.....'''.'..'.''''..'...''''..''..'..'.'..'.''''.''''......'..'...'...............+", +"...............................................................................................................................................................+", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"...............................................................................................................................................................+", +".''''..''..''''.''''.'..'.''''.''''.''''.''''.''''.###.....'..''............'..'...............................................................................+", +".'..'.'.'.....'....'.'..'.'....'.......'.'..'.'..'.#''....''.''.'.............''...............................................................................+", +".'..'...'..''''..'''.''''.''''.''''...'..''''.''''..##...''..'.''.......'....''................................................................................+", +".'..'...'..'.......'....'....'.'..'..'...'..'....'.#''..''...'..............''.................................................................................+", +".''''.''''.''''.''''....'.''''.''''..'...''''.''''.##...'.....'''...........'..'...............................................................................+", +"...............................................................................................................................................................+", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"{{'{{'''{'''{'{'{'''{'''{'''{'''{'''{))){{){{))){))){){){))){))){))){))){))){{!{{!!!{!!!{!{!{!!!{!!!{!!!{!!!{!!!{~~~{{~{{~~~{~~~{~{~{~~~{~~~{~~~{~~~{~~~{~~~{{{ ", +"{''{{{{'{{{'{'{'{'{{{'{{{{{'{'{'{'{'{){){)){{{{){{{){){){){{{){{{{{){){){){){!!{{{{!{{{!{!{!{!{{{!{{{{{!{!{!{!{!{~{~{~~{{{{~{{{~{~{~{~{{{~{{{{{~{~{~{~{~{~{~{{{ ", +"{{'{{'''{{''{'''{'''{'''{{{'{'''{'''{){){{){{))){{)){))){))){))){{{){))){))){{!{{!!!{{!!{!!!{!!!{!!!{{{!{!!!{!!!{~{~{{~{{~~~{{~~{~~~{~~~{~~~{{{~{~~~{~~~{~~~{{{ ", +"{{'{{'{{{{{'{{{'{{{'{'{'{{'{{'{'{{{'{){){{){{){{{{{){{{){{{){){){{){{){){{{){{!{{!{{{{{!{{{!{{{!{!{!{{!{{!{!{{{!{~{~{{~{{~{{{{{~{{{~{{{~{~{~{{~{{~{~{{{~{{{~{{{ ", +"{'''{'''{'''{{{'{'''{'''{{'{{'''{'''{))){))){))){))){{{){))){))){{){{))){))){!!!{!!!{!!!{{{!{!!!{!!!{{!{{!!!{!!!{~~~{~~~{~~~{~~~{{{~{~~~{~~~{{~{{~~~{~~~{~~~{{{ ", +"{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ", +"{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"{{''{{'''{{{'''{'''{{''''{''''{{'''{'{{'{'''{{''''{'{{'{'{{{{'{{'{'{{'{{''{{''''{{''{{''''{''''{'''{{'{{'{'{{'{'{{'{'{{'{'{{'{''''{{{{{{'{{'{{{{{{{{{{{{{{{{{{{ ", +"{'{{'{'{{'{'{{{{'{{'{'{{{{'{{{{'{{{{'{{'{{'{{{{{'{{'{'{{'{{{{''''{''{'{'{{'{'{{'{'{{'{'{{'{'{{{{{'{{{'{{'{'{{'{'{{'{'{{'{'{{'{{{{'{{{{{{{''{{{{{{{{{{{{{{{{{{{{ ", +"{''''{'''{{'{{{{'{{'{'''{{'''{{'{''{''''{{'{{{{{'{{''{{{'{{{{'{{'{''''{'{{'{''''{''{'{''''{''''{{'{{{'{{'{'{{'{'{{'{{''{{''''{{''{{''''{''''{{{{{{{{{{{{{{{{{{{ ", +"{'{{'{'{{'{'{{{{'{{'{'{{{{'{{{{'{{'{'{{'{{'{{{{{'{{'{'{{'{{{{'{{'{'{''{'{{'{'{{{{'{''{'{'{{{{{'{{'{{{'{{'{{''{{''''{'{{'{{{{'{'{{{{{{{{{{''{{{{{{{{{{{{{{{{{{{{ ", +"{'{{'{''''{{'''{'''{{''''{'{{{{{''{{'{{'{'''{{''{{{'{{'{''''{'{{'{'{{'{{''{{'{{{{{'''{'{{'{''''{{'{{{''''{{''{{'{{'{'{{'{''''{''''{{{{{{'{{'{{{'{{{{{{{{{{{{{{{ ", +"{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ", +"{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"{''''{{''{{''''{''''{'{{'{''''{''''{''''{''''{''''{{{{{{{{{'{{''{{{{{{{{{{{{'{{'{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"{'{{'{'{'{{{{{'{{{{'{'{{'{'{{{{'{{{{{{{'{'{{'{'{{'{{''{{{{''{''{'{{{{{{{{{{{{{''{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"{'{{'{{{'{{''''{{'''{''''{''''{''''{{{'{{''''{''''{{{{{{{''{{'{''{{{{{{{'{{{{''{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"{'{{'{{{'{{'{{{{{{{'{{{{'{{{{'{'{{'{{'{{{'{{'{{{{'{{''{{''{{{'{{{{{{{{{{{{{{''{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"{''''{''''{''''{''''{{{{'{''''{''''{{'{{{''''{''''{{{{{{'{{{{{'''{{{{{{{{{{{'{{'{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ", +"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ", +" ", +" ", +" ", +" ", +" ", +" "};