version 0.0.1
authorSomeDude <SomeDude@NuBL7aaJ6Cn4fB7GXFb9Zfi8w1FhPyW3oKgU9TweZMw>
Wed, 16 Jan 2008 17:34:00 +0000 (18:34 +0100)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Wed, 16 Jan 2008 17:34:00 +0000 (18:34 +0100)
91 files changed:
admin/addpeeridentity.php [new file with mode: 0644]
admin/config.php [new file with mode: 0644]
admin/createidentity.php [new file with mode: 0644]
admin/index.php [new file with mode: 0644]
admin/introduce.php [new file with mode: 0644]
admin/layout_deneva.css [new file with mode: 0644]
admin/linkbar.php [new file with mode: 0644]
admin/options.php [new file with mode: 0644]
admin/showcaptcha.php [new file with mode: 0644]
admin/style_deneva.css [new file with mode: 0644]
admin/template.php [new file with mode: 0644]
include/base64.h [new file with mode: 0644]
include/commandthread.h [new file with mode: 0644]
include/datetime.h [new file with mode: 0644]
include/db/sqlite3db.h [new file with mode: 0644]
include/db/sqlite3db/sqlite3db.h [new file with mode: 0644]
include/db/sqlite3db/sqlite3recordset.h [new file with mode: 0644]
include/db/sqlite3db/sqlite3statement.h [new file with mode: 0644]
include/freenet/captcha/easybmp/BSD_(revised)_license.txt [new file with mode: 0644]
include/freenet/captcha/easybmp/EasyBMP.h [new file with mode: 0644]
include/freenet/captcha/easybmp/EasyBMP_BMP.h [new file with mode: 0644]
include/freenet/captcha/easybmp/EasyBMP_DataStructures.h [new file with mode: 0644]
include/freenet/captcha/easybmp/EasyBMP_Font.h [new file with mode: 0644]
include/freenet/captcha/easybmp/EasyBMP_Geometry.h [new file with mode: 0644]
include/freenet/captcha/easybmp/EasyBMP_VariousBMPutilities.h [new file with mode: 0644]
include/freenet/captcha/icaptcha.h [new file with mode: 0644]
include/freenet/captcha/simplecaptcha.h [new file with mode: 0644]
include/freenet/fcpv2.h [new file with mode: 0644]
include/freenet/freenetmasterthread.h [new file with mode: 0644]
include/freenet/freenetssk.h [new file with mode: 0644]
include/freenet/identityinserter.h [new file with mode: 0644]
include/freenet/identityintroductioninserter.h [new file with mode: 0644]
include/freenet/identityintroductionrequester.h [new file with mode: 0644]
include/freenet/identityintroductionxml.h [new file with mode: 0644]
include/freenet/identityrequester.h [new file with mode: 0644]
include/freenet/identityxml.h [new file with mode: 0644]
include/freenet/ifcpconnected.h [new file with mode: 0644]
include/freenet/ifcpmessagehandler.h [new file with mode: 0644]
include/freenet/ifreenetregistrable.h [new file with mode: 0644]
include/freenet/introductionpuzzleinserter.h [new file with mode: 0644]
include/freenet/introductionpuzzleremover.h [new file with mode: 0644]
include/freenet/introductionpuzzlerequester.h [new file with mode: 0644]
include/freenet/introductionpuzzlexml.h [new file with mode: 0644]
include/freenet/iperiodicprocessor.h [new file with mode: 0644]
include/freenet/unkeyedidcreator.h [new file with mode: 0644]
include/hex.h [new file with mode: 0644]
include/idatabase.h [new file with mode: 0644]
include/identitytestglobal.h [new file with mode: 0644]
include/ifmsxmldocument.h [new file with mode: 0644]
include/ilogger.h [new file with mode: 0644]
include/logfile.h [new file with mode: 0644]
include/option.h [new file with mode: 0644]
include/pstdint.h [new file with mode: 0644]
include/socketdefines.h [new file with mode: 0644]
include/stringfunctions.h [new file with mode: 0644]
include/uuidgenerator.h [new file with mode: 0644]
include/xyssl/config.h [new file with mode: 0644]
include/xyssl/sha1.h [new file with mode: 0644]
src/base64.cpp [new file with mode: 0644]
src/commandthread.cpp [new file with mode: 0644]
src/datetime.cpp [new file with mode: 0644]
src/db/sqlite3db.cpp [new file with mode: 0644]
src/db/sqlite3recordset.cpp [new file with mode: 0644]
src/db/sqlite3statement.cpp [new file with mode: 0644]
src/freenet/captcha/easybmp/EasyBMP.cpp [new file with mode: 0644]
src/freenet/captcha/easybmp/EasyBMP_Font.cpp [new file with mode: 0644]
src/freenet/captcha/easybmp/EasyBMP_Geometry.cpp [new file with mode: 0644]
src/freenet/captcha/simplecaptcha.cpp [new file with mode: 0644]
src/freenet/fcpv2.cpp [new file with mode: 0644]
src/freenet/freenetmasterthread.cpp [new file with mode: 0644]
src/freenet/freenetssk.cpp [new file with mode: 0644]
src/freenet/identityinserter.cpp [new file with mode: 0644]
src/freenet/identityintroductioninserter.cpp [new file with mode: 0644]
src/freenet/identityintroductionrequester.cpp [new file with mode: 0644]
src/freenet/identityintroductionxml.cpp [new file with mode: 0644]
src/freenet/identityrequester.cpp [new file with mode: 0644]
src/freenet/identityxml.cpp [new file with mode: 0644]
src/freenet/introductionpuzzleinserter.cpp [new file with mode: 0644]
src/freenet/introductionpuzzleremover.cpp [new file with mode: 0644]
src/freenet/introductionpuzzlerequester.cpp [new file with mode: 0644]
src/freenet/introductionpuzzlexml.cpp [new file with mode: 0644]
src/freenet/unkeyedidcreator.cpp [new file with mode: 0644]
src/hex.cpp [new file with mode: 0644]
src/identitytestglobal.cpp [new file with mode: 0644]
src/identitytestmain.cpp [new file with mode: 0644]
src/logfile.cpp [new file with mode: 0644]
src/option.cpp [new file with mode: 0644]
src/socketdefines.cpp [new file with mode: 0644]
src/stringfunctions.cpp [new file with mode: 0644]
src/uuidgenerator.cpp [new file with mode: 0644]
src/xyssl/sha1.c [new file with mode: 0644]

diff --git a/admin/addpeeridentity.php b/admin/addpeeridentity.php
new file mode 100644 (file)
index 0000000..5d24f0c
--- /dev/null
@@ -0,0 +1,51 @@
+<?php\r
+\r
+       include_once('config.php');\r
+       include_once('linkbar.php');\r
+       \r
+function content()\r
+{\r
+       global $dblocation;\r
+       \r
+       if(isset($_REQUEST["formaction"]) && $_REQUEST["formaction"]=="addpeer" && $_REQUEST["publickey"]!="")\r
+       {\r
+               $message="";\r
+               $db=new PDO('sqlite:'.$dblocation);\r
+               $st=$db->prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");\r
+               $st->bindParam(1,$_REQUEST["publickey"]);\r
+               $st->execute();\r
+               if($record=$st->fetch())\r
+               {\r
+                       $message="This peer already exists";\r
+               }\r
+               else\r
+               {\r
+                       $st2=$db->prepare("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES(?,?);");\r
+                       $st2->bindParam(1,$_REQUEST["publickey"]);\r
+                       $st2->bindParam(2,gmdate('Y-m-d H:i:s'));\r
+                       $st2->execute();\r
+                       $message="Peer added";  \r
+               }\r
+?>\r
+       <h2><?php print($message) ?></h2>\r
+<?php\r
+       }\r
+       else\r
+       {\r
+?>\r
+       <h2>Add Peer</h2>\r
+       <form name="frmaddpeer" method="POST">\r
+       <input type="hidden" name="formaction" value="addpeer">\r
+       Peer Public Key<input type="text" name="publickey" size="100">\r
+       <br>\r
+       The public key must be a valid SSK public key and include the / at the end\r
+       <br>\r
+       <input type="submit" value="Add">\r
+       </form>\r
+<?php\r
+       }\r
+}\r
+       \r
+       include_once('template.php');\r
+\r
+?>
\ No newline at end of file
diff --git a/admin/config.php b/admin/config.php
new file mode 100644 (file)
index 0000000..8f8947e
--- /dev/null
@@ -0,0 +1,7 @@
+<?php\r
+\r
+       session_start();\r
+\r
+       $dblocation='./fms.db3';\r
+\r
+?>
\ No newline at end of file
diff --git a/admin/createidentity.php b/admin/createidentity.php
new file mode 100644 (file)
index 0000000..b3b76f7
--- /dev/null
@@ -0,0 +1,36 @@
+<?php\r
+       \r
+       include_once('config.php');\r
+       include_once('linkbar.php');\r
+\r
+function content()\r
+{\r
+       \r
+       global $dblocation;\r
+       \r
+       if(isset($_REQUEST["formaction"]) && $_REQUEST["formaction"]=="create" && $_REQUEST["name"]!="")\r
+       {\r
+               $db=new PDO('sqlite:'.$dblocation);\r
+               $st=$db->prepare("INSERT INTO tblLocalIdentity(Name) VALUES(?);");\r
+               $st->bindParam(1,$_REQUEST["name"]);\r
+               $st->execute();\r
+?>\r
+       <h2>Identity Created</h2>\r
+<?php\r
+       }\r
+       else\r
+       {\r
+?>\r
+       <h2>Create Identity</h2>\r
+       <form name="frmcreateidentity" method="POST">\r
+       <input type="hidden" name="formaction" value="create">\r
+       Name : <input type="text" name="name">\r
+       <input type="submit" value="Create">\r
+       </form>\r
+<?php\r
+       }\r
+}\r
+       \r
+       include_once('template.php');\r
+\r
+?>
\ No newline at end of file
diff --git a/admin/index.php b/admin/index.php
new file mode 100644 (file)
index 0000000..12c1653
--- /dev/null
@@ -0,0 +1,17 @@
+<?php\r
+       include_once('config.php');\r
+\r
+function content()\r
+{\r
+?>\r
+               <h2>Home</h2>\r
+               <p class="paragraph">\r
+               Use these pages to administer your FMS installation.  Make sure to set $dblocation correctly in config.php, and that the database is writable to your web service user account.  While you should be able to safely use these pages while FMS is running, it is recommended that you shut down FMS prior to make any changes here.\r
+               </p>\r
+<?php\r
+}\r
+\r
+       include_once('linkbar.php');\r
+       include_once('template.php');\r
+\r
+?>
\ No newline at end of file
diff --git a/admin/introduce.php b/admin/introduce.php
new file mode 100644 (file)
index 0000000..29fe5e7
--- /dev/null
@@ -0,0 +1,75 @@
+<?php\r
+\r
+       include_once('config.php');\r
+       include_once('linkbar.php');\r
+       \r
+function localiddropdown($name)\r
+{\r
+       global $dblocation;\r
+       \r
+       $db=new PDO('sqlite:'.$dblocation);\r
+       \r
+       $st=$db->prepare("SELECT LocalIdentityID, Name FROM tblLocalIdentity ORDER BY Name;");  \r
+       $st->execute();\r
+       \r
+       print "<select name=\"".$name."\">";\r
+       while($record=$st->fetch())\r
+       {\r
+               print "<option value=\"".$record[0]."\">".$record[1]."</option>";\r
+       }\r
+       print "</select>";\r
+}\r
+       \r
+function content()\r
+{\r
+       global $dblocation;\r
+       \r
+       $db=new PDO('sqlite:'.$dblocation);\r
+       \r
+       if(isset($_REQUEST["formaction"]) && $_REQUEST["formaction"]=="announce" && $_REQUEST["localidentityid"]!="")\r
+       {\r
+               $st=$db->prepare("INSERT INTO tblIdentityIntroductionInserts(LocalIdentityID,Day,UUID,Solution) VALUES(?,?,?,?);");\r
+               \r
+               for($i=0; $i<count($_REQUEST["uuid"]); $i++)\r
+               {\r
+                       if($_REQUEST["solution"][$i]!="")\r
+                       {\r
+                               $st->bindParam(1,$_REQUEST["localidentityid"]);\r
+                               $st->bindParam(2,$_REQUEST["day"][$i]);\r
+                               $st->bindParam(3,$_REQUEST["uuid"][$i]);\r
+                               $st->bindParam(4,$_REQUEST["solution"][$i]);\r
+                               $st->execute(); \r
+                       }\r
+               }\r
+       }\r
+       \r
+       ?>\r
+       <h2>Announce Identity</h2>\r
+       <form name="frmannounce" method="POST">\r
+       <input type="hidden" name="formaction" value="announce">\r
+       Select Identity to announce\r
+       <?php\r
+       localiddropdown("localidentityid");\r
+       print "<br>Type answers for a few puzzles and submit<br>";\r
+       \r
+       \r
+       $st=$db->prepare("SELECT UUID,Day FROM tblIntroductionPuzzleRequests  WHERE UUID NOT IN (SELECT UUID FROM tblIdentityIntroductionInserts) AND Day>='".gmdate('Y-m-d',strtotime('-1 day'))."' AND Found='true';");\r
+       $st->execute();\r
+       \r
+       while($record=$st->fetch())\r
+       {\r
+               print "<img src=\"showcaptcha.php?UUID=".$record[0]."\">";\r
+               print "<input type=\"hidden\" name=\"uuid[]\" value=\"".$record[0]."\">";\r
+               print "<input type=\"hidden\" name=\"day[]\" value=\"".$record[1]."\">";\r
+               print "<input type=\"text\" name=\"solution[]\">";\r
+               print "<br>";\r
+       }\r
+       ?>\r
+       <input type="submit">\r
+       </form> \r
+       <?php   \r
+}\r
+       \r
+       include_once('template.php');\r
+\r
+?>
\ No newline at end of file
diff --git a/admin/layout_deneva.css b/admin/layout_deneva.css
new file mode 100644 (file)
index 0000000..f3a8172
--- /dev/null
@@ -0,0 +1,65 @@
+body {\r
+       width: auto;\r
+       margin: 1em;\r
+}\r
+p, div {\r
+       margin: 0em 0em 0em 0em;\r
+       padding: 0em;\r
+}\r
+h1, h2, h3, h4, h5, h6 {\r
+       margin: 0em 0em .2em 0em;\r
+       padding: 0em 0em .1em 0em;\r
+}\r
+\r
+.banner { \r
+       margin: 0em;\r
+       padding: .5em;\r
+\r
+}\r
+.navigation {\r
+       margin: 0em 0em 0em 0em;\r
+       padding: .3em;\r
+}\r
+\r
+.content_main {\r
+       margin: 0em;\r
+       padding: 0em;\r
+}\r
+\r
+.content_left {\r
+       float: left;\r
+       width: 200px;\r
+       margin: 1em 0em 0em 0em;\r
+       padding: 0em;\r
+}\r
+.content_left .box {\r
+       margin: 0em 0em 1em 0em;\r
+}\r
+.content_left .box .header {\r
+       padding: .5em;\r
+}\r
+.content_left .box p {\r
+       padding: 0em .3em 0em .3em;\r
+       margin: .0em 0em .5em 0em;\r
+}\r
+\r
+.content_right {\r
+       position:absolute;\r
+       left:220px;\r
+       margin: 0px 0px 0px 0px;\r
+       padding: 1em;\r
+}\r
+\r
+.meta-info {\r
+       text-align: right;\r
+}\r
+\r
+.footer {\r
+       clear: both;\r
+       padding: 1em;\r
+       margin: 0em;\r
+}\r
+\r
+.paragraph             {\r
+                                       margin-bottom:.5em;\r
+                               }
\ No newline at end of file
diff --git a/admin/linkbar.php b/admin/linkbar.php
new file mode 100644 (file)
index 0000000..8876cf0
--- /dev/null
@@ -0,0 +1,19 @@
+<?php\r
+\r
+function linkbar()\r
+{\r
+?>\r
+               <div class="box">\r
+               <div class="header">Links</div>\r
+               <ul>\r
+                       <li><a href="index.php">Home</a></li>\r
+                       <li><a href="options.php">Options</a></li>\r
+                       <li><a href="createidentity.php">Create Identity</a></li>\r
+                       <li><a href="introduce.php">Introduce Identity</a></li>\r
+                       <li><a href="addpeeridentity.php">Manually Add Peer</a></li>\r
+               </ul>\r
+               </div>\r
+<?php\r
+};\r
+\r
+?>
\ No newline at end of file
diff --git a/admin/options.php b/admin/options.php
new file mode 100644 (file)
index 0000000..b4f3757
--- /dev/null
@@ -0,0 +1,58 @@
+<?php\r
+\r
+       include_once('config.php');\r
+       \r
+       if(isset($_REQUEST['formaction']) && $_REQUEST['formaction']=='saveoptions')\r
+       {\r
+               $db=new PDO('sqlite:'.$dblocation);\r
+               $st=$db->prepare("UPDATE tblOption SET OptionValue=? WHERE Option=?;");\r
+               foreach($_REQUEST as $key=>$val)\r
+               {\r
+                       $st->bindParam(1,$val);\r
+                       $st->bindParam(2,$key);\r
+                       $st->execute();\r
+               }\r
+       }\r
+\r
+function content()\r
+{\r
+       global $dblocation;\r
+       $db=new PDO('sqlite:'.$dblocation);\r
+       \r
+       $rs=$db->query("SELECT Option, OptionValue, OptionDescription FROM tblOption;");\r
+       \r
+?>\r
+       <h2 style="text-align:center;">Options</h2>\r
+       <form name="frmoptions" method="post">\r
+       <input type="hidden" name="formaction" value="saveoptions">\r
+       <table>\r
+               <tr>\r
+                       <th>Option</th>\r
+                       <th>Value</th>\r
+                       <th>Description</th>\r
+               </tr>\r
+               <?php\r
+               while($record=$rs->fetch())\r
+               {\r
+                       print '<tr>';\r
+                       print '<td valign="TOP">'.$record[0].'</td>';\r
+                       print '<td valign="TOP"><input type="text" name="'.$record[0].'" value="'.$record[1].'"></td>';\r
+                       print '<td valign="TOP">'.$record[2].'</td>';\r
+                       print '</tr>';\r
+               }\r
+               ?>\r
+               <tr>\r
+                       <td colspan="3">\r
+                               <center>\r
+                               <input type="submit" value="Save">\r
+                               </center>\r
+                       </td>\r
+               </tr>\r
+       </table>\r
+<?php\r
+}\r
+\r
+       include_once('linkbar.php');\r
+       include_once('template.php');\r
+\r
+?>
\ No newline at end of file
diff --git a/admin/showcaptcha.php b/admin/showcaptcha.php
new file mode 100644 (file)
index 0000000..81a01dd
--- /dev/null
@@ -0,0 +1,22 @@
+<?php\r
+\r
+       require_once('config.php');\r
+       \r
+       $db=new PDO('sqlite:'.$dblocation);\r
+       \r
+       if(isset($_REQUEST['UUID']))\r
+       {\r
+               $st=$db->prepare("SELECT MimeType,PuzzleData FROM tblIntroductionPuzzleRequests WHERE UUID=?;");\r
+               $st->bindParam(1,$_REQUEST['UUID']);\r
+               $st->execute();\r
+               \r
+               if($record=$st->fetch())\r
+               {\r
+                       $data=base64_decode($record[1]);\r
+                       header("Content-type: ".$record[0]);\r
+                       header("Content-Length: ".strlen($data));\r
+                       print $data;\r
+               }\r
+       }\r
+\r
+?>
\ No newline at end of file
diff --git a/admin/style_deneva.css b/admin/style_deneva.css
new file mode 100644 (file)
index 0000000..ffe4673
--- /dev/null
@@ -0,0 +1,110 @@
+body {\r
+       background-color: #FFF;\r
+       color: #000;\r
+       font-family: Verdana, Arial, Helvetica, sans-serif;\r
+       font-size: 90%;\r
+}\r
+a, a:link, a:active { color: #0000FF; text-decoration: none; }\r
+a:visited { color: #003399; text-decoration: none; }\r
+a:hover { color: #990000; text-decoration: underline; }\r
+p      {}\r
+div {\r
+}\r
+h1 {}\r
+h2 { color: #003366;}\r
+h3 { color: #336699; border-bottom: 1px solid #336699;}\r
+h4 { color: #6699CC; border-bottom: 1px solid #6699CC;}\r
+h5 { color: #99CCFF;}\r
+\r
+ul             {\r
+                       padding:0px;\r
+                       margin-top:5px;\r
+                       margin-bottom:5px;\r
+                       margin-left:25px;\r
+               }\r
+\r
+.banner { \r
+       background-color: #003366;\r
+       color: #FFFFFF;\r
+       font-weight: bolder;\r
+}\r
+.navigation {\r
+       background-color: #CCDDEE;\r
+       border: 1px solid #999999;\r
+       font-size: 80%;\r
+}\r
+.content_main { background-color: #FFFFFF;}\r
+.content_left {\r
+               font-size: 90%;\r
+}\r
+.content_left .box {\r
+       border: 1px solid #336699;\r
+       background-color: #DDEEFF;\r
+       font-size: 85%;\r
+}\r
+.content_left .box .header {\r
+       background-color: #003366;      \r
+       color: #FFFFFF;\r
+       font-weight: bold;\r
+       font-size: 1em;\r
+}\r
+.content_left .box p {\r
+}\r
+.content_right {\r
+}\r
+.footer {      \r
+       color: #999;\r
+       font-size: smaller;\r
+       text-align: center;\r
+       border-top: 1px dashed #CCCCCC;\r
+}\r
+.meta-info {\r
+       font-size: 80%;\r
+}\r
+.paragraph {\r
+       line-height: 1.4em;\r
+}\r
+\r
+.smaller { font-size: 65%; }\r
+.darkest { background-color: #003366; }\r
+.darker { background-color: #336699; }\r
+.dark { background-color: #6699CC; }\r
+.light { background-color: #99CCFF; }\r
+.lighter { background-color: #DDEEFF; }\r
+.lightest { background-color: #FFFFFF; }\r
+\r
+.xml1-attributename { color: #800000; }\r
+.xml1-attributevalue { color: #FF0000; }\r
+.xml1-cdatasection { color: #808000; }\r
+.xml1-comment { color: #808080; font-style: italic; }\r
+.xml1-currentline { color: #000000; }\r
+.xml1-doctypesection { color: #008080; }\r
+.xml1-elementname { color: #000080; }\r
+.xml1-entityreference { color: #0000FF; }\r
+.xml1-matchedbraces { color: #FF0000; }\r
+.xml1-namespaceattributename { color: #008000; }\r
+.xml1-namespaceattributevalue { color: #0000FF; }\r
+.xml1-processinginstruction { color: #000080; }\r
+.xml1-rightedge { color: #C0C0C0; }\r
+.xml1-selection { color: #FFFFFF; }\r
+.xml1-symbol { color: #808080; }\r
+.xml1-text { color: #000000; }\r
+.xml1-whitespace { color: #FFFFFF; }\r
+\r
+.calcheading   {\r
+                                       font-weight:bold;\r
+                               }\r
+                               \r
+.calcheading td        {\r
+                                       padding-left:10px;\r
+                                       padding-right:10px;\r
+                               }\r
+                               \r
+.calcrow td            {\r
+                                       background-color:#EEEEEE;\r
+                                       text-align:right;\r
+                               }\r
+                               \r
+.totalrow td   {\r
+                                       text-align:right;\r
+                               }
\ No newline at end of file
diff --git a/admin/template.php b/admin/template.php
new file mode 100644 (file)
index 0000000..91f308d
--- /dev/null
@@ -0,0 +1,44 @@
+<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+       <title>FMS : Freenet Message System</title>\r
+       <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />\r
+       <link rel="stylesheet" href="layout_deneva.css" type="text/css" media="screen" />\r
+       <link rel="stylesheet" href="style_deneva.css" type="text/css" media="screen" />\r
+</head>\r
+\r
+<body>\r
+       \r
+       <div class="banner">\r
+\r
+       FMS : Freenet Message System\r
+       </div>\r
+       \r
+       <div class="content_main">\r
+\r
+       <div class="content_left">\r
+\r
+               <?php\r
+               if(function_exists('linkbar'))\r
+               {\r
+                       linkbar();      \r
+               }\r
+               ?>\r
+       \r
+       </div>\r
+       \r
+       <div class="content_right">\r
+       \r
+               <?php\r
+               if(function_exists('content'))\r
+               {\r
+                       content();      \r
+               }\r
+               ?>\r
+               \r
+       </div>\r
+       \r
+       </div>\r
+\r
+\r
+</body>\r
+</html>\r
diff --git a/include/base64.h b/include/base64.h
new file mode 100644 (file)
index 0000000..276f7da
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _base64_\r
+#define _base64_\r
+\r
+#include <string>\r
+#include <vector>\r
+\r
+namespace Base64\r
+{\r
+\r
+const bool Encode(const std::vector<unsigned char> &data, std::string &encoded);\r
+const bool Decode(const std::string &encoded, std::vector<unsigned char> &data);\r
+\r
+}      // namespace\r
+\r
+#endif _base64_\r
diff --git a/include/commandthread.h b/include/commandthread.h
new file mode 100644 (file)
index 0000000..0d51366
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _commandthread_\r
+#define _commandthread_\r
+\r
+#include "ilogger.h"\r
+#include "idatabase.h"\r
+\r
+#include <zthread/Thread.h>\r
+\r
+class CommandThread:public ZThread::Runnable,public ILogger, public IDatabase\r
+{\r
+public:\r
+\r
+       void run();\r
+\r
+private:\r
+\r
+       void HandleInput(const std::string &input);\r
+       \r
+       // methods to handle commands\r
+       void HandleHelpCommand();\r
+       void HandleQuit();\r
+       \r
+       bool m_running;\r
+\r
+};\r
+\r
+#endif // _commandthread_\r
diff --git a/include/datetime.h b/include/datetime.h
new file mode 100644 (file)
index 0000000..032fe5d
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef _date_time_\r
+#define _date_time_\r
+\r
+#include <ctime>\r
+#include <string>\r
+\r
+/*\r
+       Year    actual year\r
+       Month   1=Jan,2=Feb,etc\r
+       Day             1 to last day of month\r
+       Hour    0 to 23\r
+       Minute  0 to 59\r
+       Second  0 to 59\r
+\r
+       WeekDay 0=Sunday,1=Monday,etc\r
+       YearDay 1=Jan 1st, 2=Jan 2nd, etc\r
+\r
+*/\r
+\r
+class DateTime\r
+{\r
+public:\r
+       DateTime();\r
+       DateTime(const time_t &timet);\r
+       DateTime(const struct tm *stm);\r
+       ~DateTime() {}\r
+\r
+       void Add(const int seconds=0, const int minutes=0, const int hours=0, const int days=0, const int months=0, const int years=0);\r
+       \r
+       void Set(const int year=1970, const int month=1, const int day=1, const int hour=0, const int minute=0, const int second=0);\r
+       void Set(const time_t &timet);\r
+       void Set(const struct tm *stm);\r
+       void Set(const std::string &datestring);        // method only will work with a select few basic input formats\r
+       \r
+       void SetToLocalTime();\r
+       void SetToGMTime();\r
+       \r
+       const int GetYear() const                       { return m_tm.tm_year+1900; }\r
+       void SetYear(const int year)            { m_tm.tm_year=year-1900; }\r
+       const int GetMonth() const                      { return m_tm.tm_mon+1; }\r
+       void SetMonth(const int month)          { m_tm.tm_mon=month-1; }\r
+       const int GetDay() const                        { return m_tm.tm_mday; }\r
+       void SetDay(const int day)                      { m_tm.tm_mday=day; }\r
+       const int GetWeekDay() const            { return m_tm.tm_wday; }\r
+       void SetWeekDay(const int weekday)      { m_tm.tm_wday=weekday; }\r
+       const int GetYearDay() const            { return m_tm.tm_yday+1; }\r
+       void SetYearDay(const int yearday)      { m_tm.tm_yday=yearday-1; }\r
+       const int GetHour() const                       { return m_tm.tm_hour; }\r
+       void SetHour(const int hour)            { m_tm.tm_hour=hour; }\r
+       const int GetMinute() const                     { return m_tm.tm_min; }\r
+       void SetMinute(const int minute)        { m_tm.tm_min=minute; }\r
+       const int GetSecond() const                     { return m_tm.tm_sec; }\r
+       void SetSecond(const int second)        { m_tm.tm_sec=second; }\r
+       const int GetIsDaylightTime() const     { return m_tm.tm_isdst; }\r
+       void SetIsDaylightTime(const int daylighttime) { m_tm.tm_isdst=daylighttime; }\r
+\r
+       void Normalize();                       // normalizes any date changes that were made\r
+       \r
+       std::string Format(const std::string &formatstring) const;\r
+\r
+       DateTime operator+(const double &rhs);\r
+       DateTime operator+(const DateTime &rhs);\r
+       DateTime &operator+=(const double &rhs);\r
+       DateTime &operator+=(const DateTime &rhs);\r
+       DateTime operator-(const double &rhs);\r
+       DateTime operator-(const DateTime &rhs);\r
+       DateTime &operator-=(const double &rhs);\r
+       DateTime &operator-=(const DateTime &rhs);\r
+       \r
+       const bool operator==(const DateTime &rhs) const { return m_timet==rhs.m_timet; }\r
+       const bool operator==(const time_t &rhs) const { return m_timet==rhs; }\r
+       const bool operator==(const struct tm &rhs) const;\r
+       \r
+       const bool operator<(const DateTime &rhs) const { return (m_timet<rhs.m_timet); }\r
+       const bool operator<(const time_t &rhs) const { return (m_timet<rhs); }\r
+       \r
+       const bool operator<=(const DateTime &rhs) const { return (*this<rhs || *this==rhs); }\r
+       const bool operator<=(const time_t &rhs) const { return (m_timet<=rhs); }\r
+       \r
+       const bool operator>(const DateTime &rhs) const { return (m_timet>rhs.m_timet); }\r
+       const bool operator>(const time_t &rhs) const { return (m_timet>rhs); }\r
+       \r
+       const bool operator>=(const DateTime &rhs) const { return (*this>rhs || *this==rhs); }\r
+       const bool operator>=(const time_t &rhs) const { return (m_timet>=rhs); }\r
+       \r
+private:\r
+\r
+       time_t m_timet;\r
+       struct tm m_tm;\r
+};\r
+\r
+#endif // _date_time_\r
diff --git a/include/db/sqlite3db.h b/include/db/sqlite3db.h
new file mode 100644 (file)
index 0000000..5e3b63d
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _sqlite3db_base_\r
+#define _sqlite3db_base_\r
+\r
+namespace SQLite3DB\r
+{\r
+\r
+class DB;\r
+class Recordset;\r
+class Statement;\r
+\r
+}      // namespace\r
+\r
+#include "sqlite3db/sqlite3db.h"\r
+#include "sqlite3db/sqlite3recordset.h"\r
+#include "sqlite3db/sqlite3statement.h"\r
+\r
+#endif // _sqlite3db_base_\r
diff --git a/include/db/sqlite3db/sqlite3db.h b/include/db/sqlite3db/sqlite3db.h
new file mode 100644 (file)
index 0000000..24c4a3a
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _sqlite3db_\r
+#define _sqlite3db_\r
+\r
+#include <zthread/Singleton.h>\r
+#include <zthread/Mutex.h>\r
+#include <sqlite3.h>\r
+#include <string>\r
+\r
+#include "../sqlite3db.h"\r
+\r
+namespace SQLite3DB\r
+{\r
+\r
+class DB:public ZThread::Singleton<DB>\r
+{\r
+public:\r
+       DB();\r
+       DB(std::string filename);\r
+       ~DB();\r
+       \r
+       const bool Open(const std::string &filename);\r
+       const bool Close();\r
+       \r
+       const int GetLastResult() { return m_lastresult; }      // gets result of last action taken - standard sqlite3 return codes\r
+       const int GetLastError(std::string &errormessage);      // gets last error of this database\r
+       \r
+       const bool IsOpen();\r
+       \r
+       const bool Execute(const std::string &sql);     // executes a statement returing true if successful\r
+       const bool ExecuteInsert(const std::string &sql, long &insertid);       // call when inserting data and the insertid of the row inserted is needed, otherwise Execute can be called if the row id is not needed\r
+       Recordset Query(const std::string &sql);                // executes a statement returning a recordset\r
+       Statement Prepare(const std::string &sql);      // prepares a statement returning the statement object\r
+\r
+       const int SetBusyTimeout(const int ms);         // sets busy timeout in ms.  SQLite will wait for a lock up to this many ms before returning SQLITE_BUSY\r
+\r
+       sqlite3 *GetDB() { return m_db; }\r
+\r
+       ZThread::Mutex m_mutex;                 // public so that recordset and statment can lock this mutex themselves\r
+\r
+private:\r
+       void Initialize();\r
+       \r
+       sqlite3 *m_db;\r
+       int m_lastresult;\r
+};\r
+\r
+}      // namespace\r
+\r
+#endif // _sqlite3db_\r
diff --git a/include/db/sqlite3db/sqlite3recordset.h b/include/db/sqlite3db/sqlite3recordset.h
new file mode 100644 (file)
index 0000000..69ad5e5
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef _sqlite3recordset_\r
+#define _sqlite3recordset_\r
+\r
+#include "sqlite3db.h"\r
+\r
+namespace SQLite3DB\r
+{\r
+\r
+class Recordset\r
+{\r
+public:\r
+       Recordset();\r
+       Recordset(char **rs, int rows, int cols);\r
+       virtual ~Recordset();\r
+\r
+       virtual void Free() { if(m_rs) { sqlite3_free_table(m_rs); m_rs=NULL; } }\r
+       virtual const bool Empty() { return (m_rs==NULL || m_rows==0) ? true : false ; }\r
+\r
+       virtual const int Count() { return m_rows; }\r
+       virtual const bool AtBeginning() { return m_currentrow==0; }\r
+       virtual const bool AtEnd() { return m_currentrow>=m_rows; }\r
+\r
+       virtual const bool Next() { if(m_currentrow<m_rows) { m_currentrow++; return true; } else { return false; } }\r
+       virtual const bool Previous() { if(m_currentrow-1>=0) { m_currentrow--; return true; } else { return false; } }\r
+       virtual void Beginning() { m_currentrow=0; }\r
+\r
+       virtual const char *Get(const int row, const int field);\r
+       virtual const char *GetField(const int field);\r
+       virtual const int GetInt(const int field);\r
+       virtual const double GetDouble(const int field);\r
+\r
+       virtual void Open(const std::string &sql, DB *db);\r
+\r
+private:\r
+       char **m_rs;\r
+       int m_rows;\r
+       int m_cols;\r
+       int m_currentrow;\r
+\r
+};     // class Recordset\r
+\r
+}      // namespace\r
+\r
+#endif // _sqlite3recordset_\r
diff --git a/include/db/sqlite3db/sqlite3statement.h b/include/db/sqlite3db/sqlite3statement.h
new file mode 100644 (file)
index 0000000..835d359
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef _sqlite3dbstatement_\r
+#define _sqlite3dbstatement_\r
+\r
+#include "sqlite3db.h"\r
+\r
+#include <vector>\r
+#include <map>\r
+\r
+namespace SQLite3DB\r
+{\r
+\r
+class Statement\r
+{\r
+public:\r
+       Statement();\r
+       Statement(sqlite3_stmt *statement);\r
+       Statement(Statement &rhs);\r
+       virtual ~Statement();\r
+\r
+       virtual const int ParameterCount() { return m_parametercount; }\r
+       virtual const int ResultColumnCount() { return m_resultcolumncount; }\r
+\r
+       virtual const bool Valid();\r
+\r
+       virtual void Finalize();\r
+\r
+       virtual const bool Reset();\r
+       virtual const bool Step(const bool saveinsertrowid=false);\r
+\r
+       virtual const bool RowReturned() { return m_rowreturned; }\r
+\r
+       virtual const long GetLastInsertRowID() { return m_lastinsertrowid; }\r
+\r
+       // both Bind and Result have column index starting at 0\r
+       // Blob results are not copied, user must make a copy in memory if it needs to be used in the future\r
+\r
+       virtual const bool Bind(const int column);\r
+       virtual const bool Bind(const int column, const int value);\r
+       virtual const bool Bind(const int column, const double value);\r
+       virtual const bool Bind(const int column, const std::string &value);\r
+       virtual const bool Bind(const int column, const void *data, const int length);\r
+\r
+       virtual const bool ResultNull(const int column);\r
+       virtual const bool ResultInt(const int column, int &result);\r
+       virtual const bool ResultDouble(const int column, double &result);\r
+       virtual const bool ResultText(const int column, std::string &result);\r
+       virtual const bool ResultBlob(const int column, void *data, int &length);\r
+       \r
+       Statement &operator=(const Statement &rhs);\r
+\r
+private:\r
+       sqlite3_stmt *m_statement;\r
+       int m_parametercount;\r
+       int m_resultcolumncount;\r
+       bool m_rowreturned;\r
+       long m_lastinsertrowid;\r
+\r
+       static std::map<sqlite3_stmt *, long> m_statementcount;\r
+       std::vector<char *> textptrs;\r
+\r
+};     //class\r
+\r
+}      // namespace\r
+\r
+#endif // _sqlite3dbstatement_\r
diff --git a/include/freenet/captcha/easybmp/BSD_(revised)_license.txt b/include/freenet/captcha/easybmp/BSD_(revised)_license.txt
new file mode 100644 (file)
index 0000000..6785262
--- /dev/null
@@ -0,0 +1,10 @@
+Copyright (c) 2005, The EasyBMP Project (http://easybmp.sourceforge.net)\r
+All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\r
+\r
+   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\r
+   2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\r
+   3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/include/freenet/captcha/easybmp/EasyBMP.h b/include/freenet/captcha/easybmp/EasyBMP.h
new file mode 100644 (file)
index 0000000..ead98c1
--- /dev/null
@@ -0,0 +1,86 @@
+/*************************************************
+*                                                *
+*  EasyBMP Cross-Platform Windows Bitmap Library * 
+*                                                *
+*  Author: Paul Macklin                          *
+*   email: macklin01@users.sourceforge.net       *
+* support: http://easybmp.sourceforge.net        *
+*                                                *
+*          file: EasyBMP.h                       * 
+*    date added: 01-31-2005                      *
+* date modified: 12-01-2006                      *
+*       version: 1.06                            *
+*                                                *
+*   License: BSD (revised/modified)              *
+* Copyright: 2005-6 by the EasyBMP Project       * 
+*                                                *
+* description: Main include file                 *
+*                                                *
+*************************************************/
+
+#ifdef _MSC_VER 
+// MS Visual Studio gives warnings when using 
+// fopen. But fopen_s is not going to work well 
+// with most compilers, and fopen_s uses different 
+// syntax than fopen. (i.e., a macro won't work) 
+// So, we'lll use this:
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#include <iostream>
+#include <cmath>
+#include <cctype>
+#include <cstring>
+
+#ifndef EasyBMP
+#define EasyBMP
+
+#ifdef __BCPLUSPLUS__ 
+// The Borland compiler must use this because something
+// is wrong with their cstdio file. 
+#include <stdio.h>
+#else 
+#include <cstdio>
+#endif
+
+#ifdef __GNUC__
+// If g++ specific code is ever required, this is 
+// where it goes. 
+#endif
+
+#ifdef __INTEL_COMPILER
+// If Intel specific code is ever required, this is 
+// where it goes. 
+#endif
+
+#ifndef _DefaultXPelsPerMeter_
+#define _DefaultXPelsPerMeter_
+#define DefaultXPelsPerMeter 3780
+// set to a default of 96 dpi 
+#endif
+
+#ifndef _DefaultYPelsPerMeter_
+#define _DefaultYPelsPerMeter_
+#define DefaultYPelsPerMeter 3780
+// set to a default of 96 dpi
+#endif
+
+#include "EasyBMP_DataStructures.h"
+#include "EasyBMP_BMP.h"
+#include "EasyBMP_VariousBMPutilities.h"
+
+#ifndef _EasyBMP_Version_
+#define _EasyBMP_Version_ 1.06
+#define _EasyBMP_Version_Integer_ 106
+#define _EasyBMP_Version_String_ "1.06"
+#endif
+
+#ifndef _EasyBMPwarnings_
+#define _EasyBMPwarnings_
+#endif
+
+void SetEasyBMPwarningsOff( void );
+void SetEasyBMPwarningsOn( void );
+bool GetEasyBMPwarningState( void );
+
+#endif
diff --git a/include/freenet/captcha/easybmp/EasyBMP_BMP.h b/include/freenet/captcha/easybmp/EasyBMP_BMP.h
new file mode 100644 (file)
index 0000000..819a976
--- /dev/null
@@ -0,0 +1,86 @@
+/*************************************************
+*                                                *
+*  EasyBMP Cross-Platform Windows Bitmap Library * 
+*                                                *
+*  Author: Paul Macklin                          *
+*   email: macklin01@users.sourceforge.net       *
+* support: http://easybmp.sourceforge.net        *
+*                                                *
+*          file: EasyBMP_VariousBMPutilities.h   *
+*    date added: 05-02-2005                      *
+* date modified: 12-01-2006                      *
+*       version: 1.06                            *
+*                                                *
+*   License: BSD (revised/modified)              *
+* Copyright: 2005-6 by the EasyBMP Project       * 
+*                                                *
+* description: Defines BMP class                 *
+*                                                *
+*************************************************/
+
+#ifndef _EasyBMP_BMP_h_
+#define _EasyBMP_BMP_h_
+
+bool SafeFread( char* buffer, int size, int number, FILE* fp );
+bool EasyBMPcheckDataSize( void );
+
+class BMP
+{private:
+
+ int BitDepth;
+ int Width;
+ int Height;
+ RGBApixel** Pixels;
+ RGBApixel* Colors;
+ int XPelsPerMeter;
+ int YPelsPerMeter;
+
+ ebmpBYTE* MetaData1;
+ int SizeOfMetaData1;
+ ebmpBYTE* MetaData2;
+ int SizeOfMetaData2;
+   
+ bool Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );   
+ bool Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );   
+ bool Read8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row );  
+ bool Read4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row );  
+ bool Read1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row );
+   
+ bool Write32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );   
+ bool Write24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row );   
+ bool Write8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row );  
+ bool Write4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row );  
+ bool Write1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row );
+ ebmpBYTE FindClosestColor( RGBApixel& input );
+
+ public: 
+
+ int TellBitDepth( void );
+ int TellWidth( void );
+ int TellHeight( void );
+ int TellNumberOfColors( void );
+ void SetDPI( int HorizontalDPI, int VerticalDPI );
+ int TellVerticalDPI( void );
+ int TellHorizontalDPI( void );
+  
+ BMP();
+ BMP( BMP& Input );
+ ~BMP();
+ RGBApixel* operator()(int i,int j);
+ RGBApixel GetPixel( int i, int j ) const;
+ bool SetPixel( int i, int j, RGBApixel NewPixel );
+ bool CreateStandardColorTable( void );
+ bool SetSize( int NewWidth, int NewHeight );
+ bool SetBitDepth( int NewDepth );
+ bool WriteToFile( const char* FileName );
+ bool ReadFromFile( const char* FileName );
+ RGBApixel GetColor( int ColorNumber );
+ bool SetColor( int ColorNumber, RGBApixel NewColor ); 
+};
+
+#endif
diff --git a/include/freenet/captcha/easybmp/EasyBMP_DataStructures.h b/include/freenet/captcha/easybmp/EasyBMP_DataStructures.h
new file mode 100644 (file)
index 0000000..82b6179
--- /dev/null
@@ -0,0 +1,104 @@
+/*************************************************
+*                                                *
+*  EasyBMP Cross-Platform Windows Bitmap Library * 
+*                                                *
+*  Author: Paul Macklin                          *
+*   email: macklin01@users.sourceforge.net       *
+* support: http://easybmp.sourceforge.net        *
+*                                                *
+*          file: EasyBMP_DataStructures.h        *
+*    date added: 05-02-2005                      *
+* date modified: 12-01-2006                      *
+*       version: 1.06                            *
+*                                                *
+*   License: BSD (revised/modified)              *
+* Copyright: 2005-6 by the EasyBMP Project       * 
+*                                                *
+* description: Defines basic data structures for *
+*              the BMP class                     *
+*                                                *
+*************************************************/
+
+#ifndef _EasyBMP_Custom_Math_Functions_
+#define _EasyBMP_Custom_Math_Functions_
+inline double Square( double number )
+{ return number*number; }
+
+inline int IntSquare( int number )
+{ return number*number; }
+#endif
+
+int IntPow( int base, int exponent );
+
+#ifndef _EasyBMP_Defined_WINGDI
+#define _EasyBMP_Defined_WINGDI
+ typedef unsigned char  ebmpBYTE;
+ typedef unsigned short ebmpWORD;
+ typedef unsigned int  ebmpDWORD;
+#endif
+
+#ifndef _EasyBMP_DataStructures_h_
+#define _EasyBMP_DataStructures_h_
+
+inline bool IsBigEndian()
+{
+ short word = 0x0001;
+ if((*(char *)& word) != 0x01 )
+ { return true; }
+ return false;
+}
+
+inline ebmpWORD FlipWORD( ebmpWORD in )
+{ return ( (in >> 8) | (in << 8) ); }
+
+inline ebmpDWORD FlipDWORD( ebmpDWORD in )
+{
+ return ( ((in&0xFF000000)>>24) | ((in&0x000000FF)<<24) | 
+          ((in&0x00FF0000)>>8 ) | ((in&0x0000FF00)<<8 )   );
+}
+
+// it's easier to use a struct than a class
+// because we can read/write all four of the bytes 
+// at once (as we can count on them being continuous 
+// in memory
+
+typedef struct RGBApixel {
+       ebmpBYTE Blue;
+       ebmpBYTE Green;
+       ebmpBYTE Red;
+       ebmpBYTE Alpha;
+} RGBApixel; 
+
+class BMFH{
+public:
+ ebmpWORD  bfType;
+ ebmpDWORD bfSize;
+ ebmpWORD  bfReserved1;
+ ebmpWORD  bfReserved2;
+ ebmpDWORD bfOffBits; 
+
+ BMFH();
+ void display( void );
+ void SwitchEndianess( void );
+};
+
+class BMIH{
+public:
+ ebmpDWORD biSize;
+ ebmpDWORD biWidth;
+ ebmpDWORD biHeight;
+ ebmpWORD  biPlanes;
+ ebmpWORD  biBitCount;
+ ebmpDWORD biCompression;
+ ebmpDWORD biSizeImage;
+ ebmpDWORD biXPelsPerMeter;
+ ebmpDWORD biYPelsPerMeter;
+ ebmpDWORD biClrUsed;
+ ebmpDWORD biClrImportant;
+
+ BMIH();
+ void display( void );
+ void SwitchEndianess( void );
+};
+
+#endif
diff --git a/include/freenet/captcha/easybmp/EasyBMP_Font.h b/include/freenet/captcha/easybmp/EasyBMP_Font.h
new file mode 100644 (file)
index 0000000..067903e
--- /dev/null
@@ -0,0 +1,30 @@
+/*************************************************\r
+*                                                *\r
+*  EasyBMP Cross-Platform Windows Bitmap Library * \r
+*                                                *\r
+*  Author: Paul Macklin                          *\r
+*   email: pmacklin@math.uci.edu                 *\r
+*                                                *\r
+*    file: EasyBMP_Font.h                        *\r
+*    date: 2-21-2005                             *\r
+* version: 1.05.00                               *\r
+*                                                *\r
+*   License: BSD (revised)                       *\r
+* Copyright: 2005-2006 by the EasyBMP Project    * \r
+*                                                *\r
+* description: draw a simple font                *\r
+*                                                *\r
+*************************************************/\r
+\r
+#include "EasyBMP.h"\r
+\r
+#ifndef COPYRIGHT_SYMBOL\r
+#define COPYRIGHT_SYMBOL -100 \r
+#endif \r
+\r
+int PrintCopyright( BMP& Image, int TopLeftX, int TopLeftY , int Height , \r
+                  RGBApixel Color );\r
+int PrintLetter( BMP& Image, char Letter , int TopLeftX, int TopLeftY, int Height , \r
+                 RGBApixel Color );\r
+int PrintString( BMP& Image, char* String , int TopLeftX, int TopLeftY , int Height , \r
+                  RGBApixel Color );\r
diff --git a/include/freenet/captcha/easybmp/EasyBMP_Geometry.h b/include/freenet/captcha/easybmp/EasyBMP_Geometry.h
new file mode 100644 (file)
index 0000000..cc97365
--- /dev/null
@@ -0,0 +1,33 @@
+/*************************************************\r
+*                                                *\r
+*  EasyBMP Cross-Platform Windows Bitmap Library * \r
+*                                                *\r
+*  Author: Paul Macklin                          *\r
+*   email: pmacklin@math.uci.edu                 *\r
+*                                                *\r
+*    file: EasyBMP_Geometry.h                    *\r
+*    date: 2-21-2005                             *\r
+* version: 1.05.00                               *\r
+*                                                *\r
+*   License: BSD (revised)                       *\r
+* Copyright: 2005-2006 by the EasyBMP Project    * \r
+*                                                *\r
+* description: draw simple geometric objects     *\r
+*                                                *\r
+*************************************************/\r
+\r
+#include "EasyBMP.h"\r
+\r
+int ebmpRound( double input );\r
+double InverseAngle( double Xdir, double Ydir );\r
+double LineFunction( double SlopeX , double SlopeY, \r
+                     int StartX, int StartY, double TestX, double TestY );\r
+void DrawAALine( BMP &Image , int FromX, int FromY, \r
+                 int ToX, int ToY , RGBApixel Color );\r
+void DrawFastLine( BMP &Image , int FromX, int FromY, \r
+                   int ToX, int ToY , RGBApixel Color );\r
+void DrawArc( BMP &Image , double CenterX, double CenterY , double Radius, \r
+              double FromTheta, double ToTheta , RGBApixel Color );\r
+void DrawLine( BMP &Image , int FromX , int FromY, \r
+               int ToX, int ToY, RGBApixel Color );\r
+\r
diff --git a/include/freenet/captcha/easybmp/EasyBMP_VariousBMPutilities.h b/include/freenet/captcha/easybmp/EasyBMP_VariousBMPutilities.h
new file mode 100644 (file)
index 0000000..349dda6
--- /dev/null
@@ -0,0 +1,43 @@
+/*************************************************
+*                                                *
+*  EasyBMP Cross-Platform Windows Bitmap Library * 
+*                                                *
+*  Author: Paul Macklin                          *
+*   email: macklin01@users.sourceforge.net       *
+* support: http://easybmp.sourceforge.net        *
+*                                                *
+*          file: EasyBMP_VariousBMPutilities.h   *
+*    date added: 05-02-2005                      *
+* date modified: 12-01-2006                      *
+*       version: 1.06                            *
+*                                                *
+*   License: BSD (revised/modified)              *
+* Copyright: 2005-6 by the EasyBMP Project       * 
+*                                                *
+* description: Various utilities.                *
+*                                                *
+*************************************************/
+
+#ifndef _EasyBMP_VariousBMPutilities_h_
+#define _EasyBMP_VariousBMPutilities_h_
+
+BMFH GetBMFH( const char* szFileNameIn );
+BMIH GetBMIH( const char* szFileNameIn );
+void DisplayBitmapInfo( const char* szFileNameIn );
+int GetBitmapColorDepth( const char* szFileNameIn );
+void PixelToPixelCopy( BMP& From, int FromX, int FromY,  
+                       BMP& To, int ToX, int ToY);
+void PixelToPixelCopyTransparent( BMP& From, int FromX, int FromY,  
+                                  BMP& To, int ToX, int ToY,
+                                  RGBApixel& Transparent );
+void RangedPixelToPixelCopy( BMP& From, int FromL , int FromR, int FromB, int FromT, 
+                             BMP& To, int ToX, int ToY );
+void RangedPixelToPixelCopyTransparent( 
+     BMP& From, int FromL , int FromR, int FromB, int FromT, 
+     BMP& To, int ToX, int ToY ,
+     RGBApixel& Transparent );
+bool CreateGrayscaleColorTable( BMP& InputImage );
+
+bool Rescale( BMP& InputImage , char mode, int NewDimension );
+
+#endif
diff --git a/include/freenet/captcha/icaptcha.h b/include/freenet/captcha/icaptcha.h
new file mode 100644 (file)
index 0000000..a3a23b4
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _icaptcha_\r
+#define _icaptcha_\r
+\r
+#include <vector>\r
+\r
+class ICaptcha\r
+{\r
+public:\r
+\r
+       virtual void Generate()=0;\r
+       \r
+       virtual const bool GetPuzzle(std::vector<unsigned char> &puzzle)=0;\r
+       virtual const bool GetSolution(std::vector<unsigned char> &solution)=0;\r
+       \r
+};\r
+\r
+#endif // _icaptcha_\r
diff --git a/include/freenet/captcha/simplecaptcha.h b/include/freenet/captcha/simplecaptcha.h
new file mode 100644 (file)
index 0000000..4dec4dc
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _simple_captcha_\r
+#define _simple_captcha_\r
+\r
+#include "icaptcha.h"\r
+\r
+class SimpleCaptcha:public ICaptcha\r
+{\r
+public:\r
+\r
+       void Generate();\r
+\r
+       const bool GetPuzzle(std::vector<unsigned char> &puzzle);\r
+       const bool GetSolution(std::vector<unsigned char> &solution);\r
+\r
+private:\r
+       const std::string GenerateRandomString(const int len);\r
+       void ReadPuzzleData(const std::string &filename);\r
+\r
+       std::vector<unsigned char> m_puzzle;\r
+       std::vector<unsigned char> m_solution;\r
+\r
+};\r
+\r
+#endif // _simple_captcha_\r
diff --git a/include/freenet/fcpv2.h b/include/freenet/fcpv2.h
new file mode 100644 (file)
index 0000000..864b14f
--- /dev/null
@@ -0,0 +1,92 @@
+/*\r
+\r
+       FCPv2 C++ library\r
+       \r
+       link with ws2_32.lib in Windows\r
+\r
+*/\r
+\r
+#ifndef _fcpv2_\r
+#define _fcpv2_\r
+\r
+#ifdef _WIN32\r
+       #include <winsock2.h>\r
+       #include <windows.h>\r
+#else\r
+       #include <sys/types.h>\r
+       #include <sys/socket.h>\r
+       #include <netinet/in.h>\r
+       #include <arpa/inet.h>\r
+#endif\r
+\r
+#include <string>\r
+#include <vector>\r
+#include <map>\r
+\r
+\r
+class FCPMessage:public std::map<std::string, std::string >\r
+{\r
+public:\r
+       FCPMessage() {};\r
+       FCPMessage(const std::string &name) {m_name=name;}\r
+\r
+       const std::string GetName() const { return m_name; }\r
+       void SetName(const std::string &name) { m_name=name; }\r
+       \r
+       void Reset() { m_name=""; clear(); }\r
+\r
+protected:\r
+       std::string m_name;\r
+};\r
+\r
+class FCPv2\r
+{\r
+public:\r
+       FCPv2();\r
+       ~FCPv2();\r
+\r
+       const bool Connect(const char *host, const int port);\r
+       const bool Disconnect();\r
+\r
+       const bool Connected() const { return m_serversocket!=-1 ? true : false ; }\r
+\r
+       const bool Update(const long waittime);\r
+\r
+       const int SendMessage(const char *messagename, const int fieldcount, ...);\r
+       const int SendMessage(FCPMessage &message);\r
+       const int SendRaw(const char *data, const int datalen);\r
+       const std::vector<char>::size_type SendBufferSize()     const { return m_sendbuffer.size(); }\r
+\r
+       FCPMessage ReceiveMessage();\r
+       const long ReceiveRaw(char *data, long &datalen);       // data must be preallocated, with datalen being max length of data.  Returns length of data received\r
+       const std::vector<char>::size_type ReceiveBufferSize() const { return m_receivebuffer.size(); }\r
+\r
+private:\r
+       \r
+       void SocketReceive();\r
+       void SocketSend();\r
+\r
+       void SendBufferedText(const char *text);                // puts text on send buffer\r
+       void SendBufferedRaw(const char *data, const long len); // puts raw data on send buffer\r
+\r
+       int FindOnReceiveBuffer(const char *text);              // finds text string on receive buffer and returns index to first char position, -1 if not found\r
+\r
+\r
+#ifdef _WIN32\r
+       static bool m_wsastartup;\r
+#endif\r
+\r
+       int m_serversocket;\r
+\r
+       char *m_tempbuffer;                     // temp buffer used for recv\r
+\r
+       std::vector<char> m_sendbuffer;\r
+       std::vector<char> m_receivebuffer;\r
+\r
+       fd_set m_readfs;\r
+       fd_set m_writefs;\r
+       struct timeval m_timeval;\r
+\r
+};\r
+\r
+#endif // _fcpv2_\r
diff --git a/include/freenet/freenetmasterthread.h b/include/freenet/freenetmasterthread.h
new file mode 100644 (file)
index 0000000..f84acc1
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _freenetmasterthread_\r
+#define _freenetmasterthread_\r
+\r
+#include "../ilogger.h"\r
+#include "ifreenetregistrable.h"\r
+#include "ifcpmessagehandler.h"\r
+#include "ifcpconnected.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+#include <zthread/Runnable.h>\r
+\r
+// forward declaration\r
+class IFreenetRegistrable;\r
+\r
+class FreenetMasterThread:public ZThread::Runnable,public ILogger, public IFCPMessageHandler\r
+{\r
+public:\r
+       FreenetMasterThread();\r
+       ~FreenetMasterThread();\r
+       \r
+       const bool HandleMessage(FCPMessage &message);\r
+\r
+       void run();\r
+\r
+       // registration methods for children objects\r
+       void RegisterPeriodicProcessor(IPeriodicProcessor *obj);\r
+       void RegisterFCPConnected(IFCPConnected *obj);\r
+       void RegisterFCPMessageHandler(IFCPMessageHandler *obj);\r
+\r
+private:\r
+       const bool FCPConnect();\r
+       void Setup();\r
+       void Shutdown();\r
+\r
+       std::string m_fcphost;\r
+       long m_fcpport;\r
+       FCPv2 m_fcp;\r
+       std::vector<IFreenetRegistrable *> m_registrables;\r
+       std::vector<IPeriodicProcessor *> m_processors;\r
+       std::vector<IFCPConnected *> m_fcpconnected;\r
+       std::vector<IFCPMessageHandler *> m_fcpmessagehandlers;\r
+       bool m_receivednodehello;\r
+\r
+};\r
+\r
+#endif // _freenetmasterthread_\r
diff --git a/include/freenet/freenetssk.h b/include/freenet/freenetssk.h
new file mode 100644 (file)
index 0000000..d7829f8
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _freenetssk_\r
+#define _freenetssk_\r
+\r
+#include <string>\r
+\r
+class FreenetSSK\r
+{\r
+public:\r
+\r
+       const bool ValidBaseKey(const std::string &key) const;\r
+       const bool ValidPublicKey() const;\r
+       const bool ValidPrivateKey() const;\r
+\r
+       const bool SetPublicKey(const std::string &publickey);\r
+       const bool SetPrivateKey(const std::string &privatekey);\r
+\r
+private:\r
+\r
+       std::string m_publickey;\r
+       std::string m_privatekey;\r
+       \r
+};\r
+\r
+#endif // _freenetssk_\r
diff --git a/include/freenet/identityinserter.h b/include/freenet/identityinserter.h
new file mode 100644 (file)
index 0000000..9c5e328
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _identity_inserter_\r
+#define _identity_inserter_\r
+\r
+#include "../idatabase.h"\r
+#include "../ilogger.h"\r
+#include "../datetime.h"\r
+#include "ifreenetregistrable.h"\r
+#include "ifcpconnected.h"\r
+#include "ifcpmessagehandler.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+class IdentityInserter:public IFreenetRegistrable,public IFCPConnected,public IFCPMessageHandler,public IPeriodicProcessor,public IDatabase,public ILogger\r
+{\r
+public:\r
+       IdentityInserter();\r
+       IdentityInserter(FCPv2 *fcp);\r
+\r
+       void FCPConnected();\r
+       void FCPDisconnected();\r
+\r
+       const bool HandleMessage(FCPMessage &message);\r
+\r
+       void Process();\r
+\r
+       void RegisterWithThread(FreenetMasterThread *thread);\r
+\r
+private:\r
+       void Initialize();\r
+       void CheckForNeededInsert();\r
+       void StartInsert(const long localidentityid);\r
+\r
+       DateTime m_lastchecked;\r
+\r
+};\r
+\r
+#endif // _identity_inserter_\r
diff --git a/include/freenet/identityintroductioninserter.h b/include/freenet/identityintroductioninserter.h
new file mode 100644 (file)
index 0000000..d975104
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _identityintroductioninserter_\r
+#define _identityintroductioninserter_\r
+\r
+#include "../idatabase.h"\r
+#include "../datetime.h"\r
+#include "../ilogger.h"\r
+#include "ifreenetregistrable.h"\r
+#include "ifcpconnected.h"\r
+#include "ifcpmessagehandler.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+class IdentityIntroductionInserter:public IFreenetRegistrable,public IFCPConnected,public IFCPMessageHandler,public IPeriodicProcessor,public IDatabase,public ILogger\r
+{\r
+public:\r
+       IdentityIntroductionInserter();\r
+       IdentityIntroductionInserter(FCPv2 *fcp);\r
+\r
+       void FCPConnected();\r
+       void FCPDisconnected();\r
+\r
+       const bool HandleMessage(FCPMessage &message);\r
+\r
+       void Process();\r
+\r
+       void RegisterWithThread(FreenetMasterThread *thread);\r
+\r
+private:\r
+       void Initialize();\r
+       void CheckForNewInserts();\r
+       void StartInsert(const long localidentityid, const std::string &day, const std::string &UUID, const std::string &solution);\r
+\r
+       std::string m_messagebase;\r
+       DateTime m_lastchecked;\r
+       bool m_inserting;\r
+       \r
+};\r
+\r
+#endif // _identityintroductioninserter_\r
diff --git a/include/freenet/identityintroductionrequester.h b/include/freenet/identityintroductionrequester.h
new file mode 100644 (file)
index 0000000..a7b236f
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _identityintroduction_requester_\r
+#define _identityintroduction_requester_\r
+\r
+#include "../idatabase.h"\r
+#include "../ilogger.h"\r
+#include "../datetime.h"\r
+#include "ifreenetregistrable.h"\r
+#include "ifcpconnected.h"\r
+#include "ifcpmessagehandler.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+class IdentityIntroductionRequester:public IFreenetRegistrable,public IFCPConnected,public IFCPMessageHandler,public IPeriodicProcessor,public IDatabase,public ILogger\r
+{\r
+public:\r
+       IdentityIntroductionRequester();\r
+       IdentityIntroductionRequester(FCPv2 *fcp);\r
+\r
+       void FCPDisconnected();\r
+       void FCPConnected();\r
+       const bool HandleMessage(FCPMessage &message);\r
+\r
+       void Process();\r
+\r
+       void RegisterWithThread(FreenetMasterThread *thread);\r
+\r
+private:\r
+       void Initialize();\r
+       void StartRequests(const long localidentityid);\r
+       void StartRequest(const std::string &UUID);\r
+       void PopulateIDList();\r
+       void RemoveFromRequestList(const std::string &UUID);\r
+       const bool HandleGetFailed(FCPMessage &message);\r
+       const bool HandleAllData(FCPMessage &message);\r
+\r
+       DateTime m_tempdate;\r
+       std::map<long,bool> m_ids;\r
+       std::vector<std::string> m_requesting;\r
+       std::string m_messagebase;\r
+       long m_maxrequests;\r
+\r
+};\r
+\r
+#endif // _identityintroduction_requester_\r
diff --git a/include/freenet/identityintroductionxml.h b/include/freenet/identityintroductionxml.h
new file mode 100644 (file)
index 0000000..0f2a827
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _identityintroductionxml_\r
+#define _identityintroductionxml_\r
+\r
+#include "../ifmsxmldocument.h"\r
+\r
+class IdentityIntroductionXML:public IFMSXMLDocument\r
+{\r
+public:\r
+       IdentityIntroductionXML();\r
+\r
+       std::string GetXML();\r
+\r
+       const bool ParseXML(const std::string &xml);\r
+\r
+       const std::string GetIdentity() const                   { return m_identity; }\r
+       void SetIdentity(const std::string &identity)   { m_identity=identity; }\r
+\r
+private:\r
+       void Initialize();\r
+       \r
+       std::string m_identity;\r
+       \r
+};\r
+\r
+#endif // _identityintroductionxml_\r
diff --git a/include/freenet/identityrequester.h b/include/freenet/identityrequester.h
new file mode 100644 (file)
index 0000000..ebea425
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _identity_requester_\r
+#define _identity_requester_\r
+\r
+#include "../idatabase.h"\r
+#include "../ilogger.h"\r
+#include "../datetime.h"\r
+#include "ifreenetregistrable.h"\r
+#include "ifcpconnected.h"\r
+#include "ifcpmessagehandler.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+class IdentityRequester:public IFreenetRegistrable,public IFCPConnected,public IFCPMessageHandler,public IPeriodicProcessor,public IDatabase,public ILogger\r
+{\r
+public:\r
+       IdentityRequester();\r
+       IdentityRequester(FCPv2 *fcp);\r
+\r
+       void FCPConnected();\r
+       void FCPDisconnected();\r
+\r
+       const bool HandleMessage(FCPMessage &message);\r
+\r
+       void Process();\r
+\r
+       void RegisterWithThread(FreenetMasterThread *thread);\r
+\r
+private:\r
+       void Initialize();\r
+       void PopulateIDList();                          // clear and re-populate m_ids with identities we want to query\r
+       void StartRequest(const long identityid);\r
+       const bool HandleAllData(FCPMessage &message);\r
+       const bool HandleGetFailed(FCPMessage &message);\r
+       void RemoveFromRequestList(const long identityid);\r
+\r
+       DateTime m_tempdate;\r
+       std::string m_messagebase;\r
+       long m_maxrequests;\r
+       std::vector<long> m_requesting;         // list of ids we are currently requesting from\r
+       std::map<long,bool> m_ids;                      // map of all ids we know and whether we have requested file from them yet\r
+\r
+};\r
+\r
+#endif // _identity_requester_\r
diff --git a/include/freenet/identityxml.h b/include/freenet/identityxml.h
new file mode 100644 (file)
index 0000000..cc37c76
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _identityxml_\r
+#define _identityxml_\r
+\r
+#include "../ifmsxmldocument.h"\r
+\r
+class IdentityXML:public IFMSXMLDocument\r
+{\r
+public:\r
+\r
+       IdentityXML();\r
+\r
+       std::string GetXML();\r
+       const bool ParseXML(const std::string &xml);\r
+\r
+       const std::string GetName()                                             { return m_name; }\r
+       void SetName(const std::string &name)                   { m_name=name; }\r
+\r
+       const bool GetPublishTrustList()                                { return m_publishtrustlist; }\r
+       void SetPublishTrustList(const bool publish)    { m_publishtrustlist=publish; }\r
+\r
+       const bool GetPublishBoardList()                                { return m_publishboardlist; }\r
+       void SetPublishBoardList(const bool publish)    { m_publishboardlist=publish; }\r
+\r
+       const bool GetSingleUse()                                               { return m_singleuse; }\r
+       void SetSingleUse(const bool singleuse)                 { m_singleuse=singleuse; }\r
+\r
+private:\r
+       void Initialize();\r
+\r
+       std::string m_name;\r
+       bool m_publishtrustlist;\r
+       bool m_publishboardlist;\r
+       bool m_singleuse;\r
+\r
+};\r
+\r
+#endif // _identityxml_\r
diff --git a/include/freenet/ifcpconnected.h b/include/freenet/ifcpconnected.h
new file mode 100644 (file)
index 0000000..19bea17
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _ifcpconnected_\r
+#define _ifcpconnected_\r
+\r
+#include "fcpv2.h"\r
+\r
+/**\r
+       \brief Defines interface for classes that use an existing FCP Connection\r
+*/\r
+class IFCPConnected\r
+{\r
+public:\r
+       IFCPConnected():m_fcp(NULL) {}\r
+       IFCPConnected(FCPv2 *fcp):m_fcp(fcp)    {}\r
+       \r
+       virtual void SetFCPConnection(FCPv2 *fcp)       { m_fcp=fcp; }\r
+       virtual FCPv2 *GetFCPConnection()                       { return m_fcp; }\r
+       \r
+       /**\r
+               \brief called when the FCP connection becomes disconnected\r
+               \r
+               Parent object is responsible for calling this whenever the FCP connection becomes disconnected\r
+       */\r
+       virtual void FCPDisconnected()=0;\r
+       /**\r
+               \brief called when the FCP connection becomes connected\r
+               \r
+               Parent object is responsible for calling this whenever the FCP connection is established\r
+       */\r
+       virtual void FCPConnected()=0;\r
+       \r
+protected:\r
+       FCPv2 *m_fcp;\r
+};\r
+\r
+#endif // _ifcpconnected_\r
diff --git a/include/freenet/ifcpmessagehandler.h b/include/freenet/ifcpmessagehandler.h
new file mode 100644 (file)
index 0000000..01525d7
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _ifcpmessagehandler_\r
+#define _ifcpmessagehandler_\r
+\r
+#include "fcpv2.h"\r
+\r
+/**\r
+       \brief Defines interface for classes that handle FCP messages\r
+*/\r
+class IFCPMessageHandler\r
+{\r
+public:\r
+       /**\r
+               \brief Handles an FCP message\r
+               \param message FCP message to handle\r
+               \return true if the message was handled, false if it was not\r
+       */\r
+       virtual const bool HandleMessage(FCPMessage &message)=0;\r
+};\r
+\r
+#endif // _ifcpmessagehandler_\r
diff --git a/include/freenet/ifreenetregistrable.h b/include/freenet/ifreenetregistrable.h
new file mode 100644 (file)
index 0000000..78e4508
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _freenet_registrable_\r
+#define _freenet_registrable_\r
+\r
+#include "freenetmasterthread.h"\r
+\r
+// forward declaration\r
+class FreenetMasterThread;\r
+\r
+class IFreenetRegistrable\r
+{\r
+public:\r
+\r
+       virtual void RegisterWithThread(FreenetMasterThread *thread)=0;\r
+       \r
+};\r
+\r
+#endif // _freenet_registrable_\r
diff --git a/include/freenet/introductionpuzzleinserter.h b/include/freenet/introductionpuzzleinserter.h
new file mode 100644 (file)
index 0000000..af66a50
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _introductionpuzzle_inserter_\r
+#define _introductionpuzzle_inserter_\r
+\r
+#include "../idatabase.h"\r
+#include "../ilogger.h"\r
+#include "../datetime.h"\r
+#include "ifreenetregistrable.h"\r
+#include "ifcpconnected.h"\r
+#include "ifcpmessagehandler.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+class IntroductionPuzzleInserter:public IFreenetRegistrable,public IFCPConnected,public IFCPMessageHandler,public IPeriodicProcessor,public IDatabase,public ILogger\r
+{\r
+public:\r
+       IntroductionPuzzleInserter();\r
+       IntroductionPuzzleInserter(FCPv2 *fcp);\r
+\r
+       void FCPConnected();\r
+       void FCPDisconnected();\r
+\r
+       const bool HandleMessage(FCPMessage &message);\r
+\r
+       void Process();\r
+\r
+       void RegisterWithThread(FreenetMasterThread *thread);\r
+\r
+private:\r
+       void Initialize();\r
+       void CheckForNeededInsert();\r
+       void StartInsert(const long localidentityid);\r
+       void GenerateCaptcha(std::string &encodeddata, std::string &solution);\r
+       const bool HandlePutSuccessful(FCPMessage &message);\r
+       const bool HandlePutFailed(FCPMessage &message);\r
+\r
+       DateTime m_lastchecked;\r
+\r
+};\r
+\r
+#endif // _introductionpuzzle_inserter_\r
diff --git a/include/freenet/introductionpuzzleremover.h b/include/freenet/introductionpuzzleremover.h
new file mode 100644 (file)
index 0000000..65fa39d
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _introductionpuzzleremover_\r
+#define _introductionpuzzleremover_\r
+\r
+#include "../idatabase.h"\r
+#include "../ilogger.h"\r
+#include "../datetime.h"\r
+#include "ifreenetregistrable.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+/**\r
+       \brief Removes stale IntroductionPuzzles from database\r
+*/\r
+class IntroductionPuzzleRemover:public IFreenetRegistrable,public IPeriodicProcessor,public IDatabase,public ILogger\r
+{\r
+public:\r
+       IntroductionPuzzleRemover();\r
+\r
+       void Process();\r
+\r
+       void RegisterWithThread(FreenetMasterThread *thread);\r
+\r
+private:\r
+\r
+       DateTime m_lastchecked;\r
+\r
+};\r
+\r
+#endif // _introductionpuzzleremover_\r
diff --git a/include/freenet/introductionpuzzlerequester.h b/include/freenet/introductionpuzzlerequester.h
new file mode 100644 (file)
index 0000000..9d7e3ab
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _introductionpuzzlerequester_\r
+#define _introductionpuzzlerequester_\r
+\r
+#include "../idatabase.h"\r
+#include "../ilogger.h"\r
+#include "../datetime.h"\r
+#include "ifreenetregistrable.h"\r
+#include "ifcpconnected.h"\r
+#include "ifcpmessagehandler.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+class IntroductionPuzzleRequester:public IFreenetRegistrable,public IFCPConnected,public IFCPMessageHandler,public IPeriodicProcessor,public IDatabase,public ILogger\r
+{\r
+public:\r
+       IntroductionPuzzleRequester();\r
+       IntroductionPuzzleRequester(FCPv2 *fcp);\r
+\r
+       void FCPDisconnected();\r
+       void FCPConnected();\r
+\r
+       const bool HandleMessage(FCPMessage &message);\r
+\r
+       void RegisterWithThread(FreenetMasterThread *thread);\r
+\r
+       void Process();\r
+\r
+private:\r
+       void Initialize();\r
+       void RemoveFromRequestList(const long identityid);\r
+       void StartRequest(const long identityid);\r
+       void PopulateIDList();                          // clear and re-populate m_ids with identities we want to query\r
+       const bool HandleAllData(FCPMessage &message);\r
+       const bool HandleGetFailed(FCPMessage &message);\r
+\r
+       DateTime m_tempdate;\r
+       std::string m_messagebase;\r
+       long m_maxrequests;\r
+       std::vector<long> m_requesting;         // list of ids we are currently requesting from\r
+       std::map<long,bool> m_ids;                      // map of all ids we know and whether we have requested file from them yet\r
+       \r
+};\r
+\r
+#endif // _introductionpuzzlerequester_\r
diff --git a/include/freenet/introductionpuzzlexml.h b/include/freenet/introductionpuzzlexml.h
new file mode 100644 (file)
index 0000000..3d2428d
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _introductionpuzzlexml_\r
+#define _introductionpuzzlexml_\r
+\r
+#include "../ifmsxmldocument.h"\r
+\r
+class IntroductionPuzzleXML:public IFMSXMLDocument\r
+{\r
+public:\r
+       IntroductionPuzzleXML();\r
+\r
+       std::string GetXML();\r
+\r
+       const bool ParseXML(const std::string &xml);\r
+\r
+       void SetType(const std::string &type)           { m_type=type; }\r
+       void SetUUID(const std::string &uuid)           { m_uuid=uuid; }\r
+       void SetPuzzleData(const std::string &puzzledata)       { m_puzzledata=puzzledata; }\r
+       void SetMimeType(const std::string &mimetype)           { m_mimetype=mimetype; }\r
+\r
+       const std::string GetType() const                       { return m_type; }\r
+       const std::string GetUUID() const                       { return m_uuid; }\r
+       const std::string GetPuzzleData() const         { return m_puzzledata; }\r
+       const std::string GetMimeType() const           { return m_mimetype; }\r
+\r
+private:\r
+       void Initialize();\r
+\r
+       std::string m_type;\r
+       std::string m_uuid;\r
+       std::string m_puzzledata;\r
+       std::string m_mimetype;\r
+       \r
+};\r
+\r
+#endif // _introductionpuzzlexml_\r
diff --git a/include/freenet/iperiodicprocessor.h b/include/freenet/iperiodicprocessor.h
new file mode 100644 (file)
index 0000000..0856c38
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _iperiodicprocessor_\r
+#define _iperiodicprocessor_\r
+\r
+/**\r
+       \brief Defines interface for classes that are periodically processed\r
+*/\r
+class IPeriodicProcessor\r
+{\r
+public:\r
+       /**\r
+               \brief Lets class do any needed processing\r
+       */\r
+       virtual void Process()=0;\r
+};\r
+\r
+#endif // _iperiodicprocessor_\r
diff --git a/include/freenet/unkeyedidcreator.h b/include/freenet/unkeyedidcreator.h
new file mode 100644 (file)
index 0000000..7f9fb15
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _unkeyedidcreator_\r
+#define _unkeyedidcreatorr_\r
+\r
+#include "../ilogger.h"\r
+#include "../datetime.h"\r
+#include "../idatabase.h"\r
+#include "ifreenetregistrable.h"\r
+#include "ifcpconnected.h"\r
+#include "ifcpmessagehandler.h"\r
+#include "iperiodicprocessor.h"\r
+\r
+\r
+/**\r
+       \brief Looks for any unkeyed Local Identities and requests SSK keys for them\r
+*/\r
+class UnkeyedIDCreator:public IFreenetRegistrable,public IFCPConnected,public IFCPMessageHandler,public IDatabase,public IPeriodicProcessor,public ILogger\r
+{\r
+public:\r
+       UnkeyedIDCreator();\r
+       UnkeyedIDCreator(FCPv2 *fcp);\r
+\r
+       const bool HandleMessage(FCPMessage &message);\r
+\r
+       void FCPDisconnected();\r
+       void FCPConnected();\r
+\r
+       void Process();\r
+\r
+       void RegisterWithThread(FreenetMasterThread *thread);\r
+       \r
+private:\r
+       void Initialize();\r
+       void CheckForUnkeyedID();\r
+       void SaveKeys(const long localidentityid, const std::string &publickey, const std::string &privatekey);\r
+\r
+       DateTime m_lastchecked;\r
+       bool m_waiting;\r
+};\r
+\r
+#endif // _unkeyedidcreator_\r
diff --git a/include/hex.h b/include/hex.h
new file mode 100644 (file)
index 0000000..a57bf6e
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _hex_funcs_\r
+#define _hex_funcs_\r
+\r
+#include <string>\r
+#include <vector>\r
+\r
+namespace Hex\r
+{\r
+       \r
+const bool Encode(const std::vector<unsigned char> &data, std::string &encoded);\r
+const bool Decode(const std::string &encoded, std::vector<unsigned char> &data);\r
+               \r
+};\r
+\r
+#endif _hex_funcs_\r
diff --git a/include/idatabase.h b/include/idatabase.h
new file mode 100644 (file)
index 0000000..6138d08
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _idatabase_\r
+#define _idatabase_\r
+\r
+#include "db/sqlite3db.h"\r
+\r
+/**\r
+       \brief Base class for classes that need to access the Singleton SQLite 3 database object\r
+*/\r
+class IDatabase\r
+{\r
+public:\r
+       IDatabase():m_db(SQLite3DB::DB::instance()) {}\r
+       \r
+protected:\r
+       SQLite3DB::DB *m_db;\r
+};\r
+\r
+#endif // _idatabase_\r
diff --git a/include/identitytestglobal.h b/include/identitytestglobal.h
new file mode 100644 (file)
index 0000000..eff73b9
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _global_\r
+#define _global_\r
+\r
+#include <vector>\r
+#include <zthread/Thread.h>\r
+\r
+#define FMS_VERSION    "0.0.1"\r
+\r
+// opens database and creates tables and initial inserts if necessary\r
+void SetupDB();\r
+// inserts default options into the database\r
+void SetupDefaultOptions();\r
+// opens logfile and sets it up\r
+void SetupLogFile();\r
+\r
+void StartThreads(std::vector<ZThread::Thread *> &threads);\r
+void ShutdownThreads(std::vector<ZThread::Thread *> &threads);\r
+\r
+// needed for Windows to setup network\r
+void SetupNetwork();\r
+// cleanup network on Windows\r
+void ShutdownNetwork();\r
+\r
+#endif // _global_\r
diff --git a/include/ifmsxmldocument.h b/include/ifmsxmldocument.h
new file mode 100644 (file)
index 0000000..24484ec
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef _ifmsxmldocument_\r
+#define _ifmsxmldocument_\r
+\r
+#include <string>\r
+#include <tinyxml.h>\r
+\r
+/**\r
+       \brief Interface for objects that represent an XML document\r
+*/\r
+class IFMSXMLDocument\r
+{\r
+public:\r
+       \r
+       /**\r
+               \brief Returns xml document represented by this object\r
+               \r
+               \return xml document\r
+       */\r
+       virtual std::string GetXML()=0;\r
+       \r
+       /**\r
+               \brief Parses an xml document into this object\r
+               \r
+               \return true if the document was parsed successfully, false if it was not\r
+       */\r
+       virtual const bool ParseXML(const std::string &xml)=0;\r
+\r
+protected:\r
+       /**\r
+               \brief Creates and returns an element with a boolean value\r
+       */\r
+       virtual TiXmlElement *XMLCreateBooleanElement(const std::string &name, const bool value)\r
+       {\r
+               TiXmlText *txt=new TiXmlText(value ? "true" : "false");\r
+               TiXmlElement *el=new TiXmlElement(name);\r
+               el->LinkEndChild(txt);\r
+               return el;\r
+       }\r
+\r
+       /**\r
+               \brief Creates and returns an element with a CDATA value\r
+       */\r
+       virtual TiXmlElement *XMLCreateCDATAElement(const std::string &name, const std::string &data)\r
+       {\r
+               TiXmlText *txt=new TiXmlText(data);\r
+               txt->SetCDATA(true);\r
+               TiXmlElement *el=new TiXmlElement(name);\r
+               el->LinkEndChild(txt);\r
+               return el;\r
+       }\r
+\r
+       /**\r
+               \brief Creates and returns a text element\r
+       */\r
+       virtual TiXmlElement *XMLCreateTextElement(const std::string &name, const std::string &data)\r
+       {\r
+               TiXmlText *txt=new TiXmlText(data);\r
+               TiXmlElement *el=new TiXmlElement(name);\r
+               el->LinkEndChild(txt);\r
+               return el;\r
+       }\r
+\r
+       virtual const bool XMLGetBooleanElement(TiXmlElement *parent, const std::string &name)\r
+       {\r
+               TiXmlHandle hnd(parent);\r
+               TiXmlText *txt=hnd.FirstChild(name).FirstChild().ToText();\r
+               if(txt)\r
+               {\r
+                       if(txt->ValueStr()=="true")\r
+                       {\r
+                               return true;\r
+                       }\r
+                       else\r
+                       {\r
+                               return false;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       \r
+};\r
+\r
+#endif // _ifmsxmldocument_\r
diff --git a/include/ilogger.h b/include/ilogger.h
new file mode 100644 (file)
index 0000000..797c024
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _ilogger_\r
+#define _ilogger_\r
+\r
+#include "logfile.h"\r
+\r
+/**\r
+       \brief Base class for classes that want to use the singleton LogFile object\r
+*/\r
+class ILogger\r
+{\r
+public:\r
+       ILogger():m_log(LogFile::instance()) {}\r
+       \r
+protected:\r
+       LogFile *m_log;\r
+};\r
+\r
+#endif // _ilogger_\r
diff --git a/include/logfile.h b/include/logfile.h
new file mode 100644 (file)
index 0000000..a076d65
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _logfile_\r
+#define _logfile_\r
+\r
+#include <zthread/Singleton.h>\r
+#include <zthread/Mutex.h>\r
+\r
+class LogFile:public ZThread::Singleton<LogFile>\r
+{\r
+public:\r
+       LogFile();\r
+       LogFile(const std::string &filename);\r
+       ~LogFile();\r
+\r
+       enum LogLevel\r
+       {\r
+               LOGLEVEL_FATAL=0,\r
+               LOGLEVEL_ERROR=1,\r
+               LOGLEVEL_WARNING=2,\r
+               LOGLEVEL_INFO=3,\r
+               LOGLEVEL_DEBUG=4\r
+       };\r
+       \r
+       bool OpenFile();\r
+       bool CloseFile();\r
+       \r
+       std::string GetFileName() { return m_filename; }\r
+       void SetFileName(std::string filename) { m_filename=filename; }\r
+       \r
+       const bool GetWriteDate() { return m_writedate; }\r
+       void SetWriteDate(const bool writedate) { m_writedate=writedate; }\r
+       \r
+       const bool GetWriteLogLevel() { return m_writeloglevel; }\r
+       void SetWriteLogLevel(const bool writeloglevel) { m_writeloglevel=writeloglevel; }\r
+       \r
+       const LogLevel GetLogLevel() { return m_loglevel; }\r
+       void SetLogLevel(const LogLevel loglevel) { m_loglevel=loglevel; }\r
+\r
+       const bool GetWriteNewLine() { return m_writenewline; }\r
+       void SetWriteNewLine(const bool writenewline) { m_writenewline=writenewline; }\r
+       \r
+       void WriteLog(const char *format, ...);\r
+       void WriteLog(const std::string &text);\r
+       void WriteLog(const LogLevel level, const char *format, ...);\r
+       void WriteLog(const LogLevel level, const std::string &text);\r
+\r
+       void WriteNewLine();\r
+       \r
+private:\r
+       void WriteDate();\r
+       void WriteLogLevel(LogLevel level);\r
+\r
+       FILE *m_fileptr;\r
+       std::string m_filename;\r
+       LogLevel m_loglevel;\r
+       bool m_writedate;\r
+       bool m_writeloglevel;\r
+       bool m_writenewline;\r
+       char *m_datebuffer;\r
+\r
+       ZThread::Mutex m_logmutex;\r
+       \r
+};\r
+\r
+#endif // _logfile_\r
diff --git a/include/option.h b/include/option.h
new file mode 100644 (file)
index 0000000..abe1a58
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _option_\r
+#define _option_\r
+\r
+#include "db/sqlite3db.h"\r
+\r
+#include <sstream>\r
+#include <zthread/Singleton.h>\r
+\r
+//just a wrapper around the database for the options table\r
+class Option:public ZThread::Singleton<Option>\r
+{\r
+public:\r
+       const bool Get(const std::string &option, std::string &value);\r
+       template<class T>\r
+       void Set(const std::string &option, const T &value);\r
+private:\r
+};\r
+\r
+template<class T>\r
+void Option::Set(const std::string &option, const T &value)\r
+{\r
+       std::ostringstream valuestr;\r
+       valuestr << value;\r
+\r
+       std::string tempval;\r
+       if(Get(option,tempval)==true)\r
+       {\r
+               SQLite3DB::Statement st=SQLite3DB::DB::instance()->Prepare("UPDATE tblOption SET OptionValue=? WHERE Option=?;");\r
+               st.Bind(0,valuestr.str());\r
+               st.Bind(1,option);\r
+               st.Step();\r
+       }\r
+       else\r
+       {\r
+               SQLite3DB::Statement st=SQLite3DB::DB::instance()->Prepare("INSERT INTO tblOption(Option,OptionValue) VALUES(?,?);");\r
+               st.Bind(0,option);\r
+               st.Bind(1,valuestr.str());\r
+               st.Step();\r
+       }\r
+}\r
+\r
+#endif // _option_\r
diff --git a/include/pstdint.h b/include/pstdint.h
new file mode 100644 (file)
index 0000000..af9b14f
--- /dev/null
@@ -0,0 +1,679 @@
+/*  A portable stdint.h\r
+ *\r
+ *  Copyright (c) 2005-2007 Paul Hsieh\r
+ *\r
+ *  Redistribution and use in source and binary forms, with or without\r
+ *  modification, are permitted provided that the following conditions\r
+ *  are met:\r
+ *\r
+ *      Redistributions of source code must retain the above copyright\r
+ *      notice, this list of conditions and the following disclaimer.\r
+ *\r
+ *      Redistributions in binary form must not misrepresent the orignal\r
+ *      source in the documentation and/or other materials provided\r
+ *      with the distribution.\r
+ *\r
+ *      The names of the authors nor its contributors may be used to\r
+ *      endorse or promote products derived from this software without\r
+ *      specific prior written permission.\r
+ *\r
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
+ *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
+ *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\r
+ *  OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ ****************************************************************************\r
+ *\r
+ *  Version 0.1.8\r
+ *\r
+ *  The ANSI C standard committee, for the C99 standard, specified the\r
+ *  inclusion of a new standard include file called stdint.h.  This is\r
+ *  a very useful and long desired include file which contains several\r
+ *  very precise definitions for integer scalar types that is\r
+ *  critically important for making portable several classes of\r
+ *  applications including cryptography, hashing, variable length\r
+ *  integer libraries and so on.  But for most developers its likely\r
+ *  useful just for programming sanity.\r
+ *\r
+ *  The problem is that most compiler vendors have decided not to\r
+ *  implement the C99 standard, and the next C++ language standard\r
+ *  (which has a lot more mindshare these days) will be a long time in\r
+ *  coming and its unknown whether or not it will include stdint.h or\r
+ *  how much adoption it will have.  Either way, it will be a long time\r
+ *  before all compilers come with a stdint.h and it also does nothing\r
+ *  for the extremely large number of compilers available today which\r
+ *  do not include this file, or anything comparable to it.\r
+ *\r
+ *  So that's what this file is all about.  Its an attempt to build a\r
+ *  single universal include file that works on as many platforms as\r
+ *  possible to deliver what stdint.h is supposed to.  A few things\r
+ *  that should be noted about this file:\r
+ *\r
+ *    1) It is not guaranteed to be portable and/or present an identical\r
+ *       interface on all platforms.  The extreme variability of the\r
+ *       ANSI C standard makes this an impossibility right from the\r
+ *       very get go. Its really only meant to be useful for the vast\r
+ *       majority of platforms that possess the capability of\r
+ *       implementing usefully and precisely defined, standard sized\r
+ *       integer scalars.  Systems which are not intrinsically 2s\r
+ *       complement may produce invalid constants.\r
+ *\r
+ *    2) There is an unavoidable use of non-reserved symbols.\r
+ *\r
+ *    3) Other standard include files are invoked.\r
+ *\r
+ *    4) This file may come in conflict with future platforms that do\r
+ *       include stdint.h.  The hope is that one or the other can be\r
+ *       used with no real difference.\r
+ *\r
+ *    5) In the current verison, if your platform can't represent\r
+ *       int32_t, int16_t and int8_t, it just dumps out with a compiler\r
+ *       error.\r
+ *\r
+ *    6) 64 bit integers may or may not be defined.  Test for their\r
+ *       presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX.\r
+ *       Note that this is different from the C99 specification which\r
+ *       requires the existence of 64 bit support in the compiler.  If\r
+ *       this is not defined for your platform, yet it is capable of\r
+ *       dealing with 64 bits then it is because this file has not yet\r
+ *       been extended to cover all of your system's capabilities.\r
+ *\r
+ *    7) (u)intptr_t may or may not be defined.  Test for its presence\r
+ *       with the test: #ifdef PTRDIFF_MAX.  If this is not defined\r
+ *       for your platform, then it is because this file has not yet\r
+ *       been extended to cover all of your system's capabilities, not\r
+ *       because its optional.\r
+ *\r
+ *    8) The following might not been defined even if your platform is\r
+ *       capable of defining it:\r
+ *\r
+ *       WCHAR_MIN\r
+ *       WCHAR_MAX\r
+ *       (u)int64_t\r
+ *       PTRDIFF_MIN\r
+ *       PTRDIFF_MAX\r
+ *       (u)intptr_t\r
+ *\r
+ *    9) The following have not been defined:\r
+ *\r
+ *       WINT_MIN\r
+ *       WINT_MAX\r
+ *\r
+ *   10) The criteria for defining (u)int_least(*)_t isn't clear,\r
+ *       except for systems which don't have a type that precisely\r
+ *       defined 8, 16, or 32 bit types (which this include file does\r
+ *       not support anyways). Default definitions have been given.\r
+ *\r
+ *   11) The criteria for defining (u)int_fast(*)_t isn't something I\r
+ *       would trust to any particular compiler vendor or the ANSI C\r
+ *       committee.  It is well known that "compatible systems" are\r
+ *       commonly created that have very different performance\r
+ *       characteristics from the systems they are compatible with,\r
+ *       especially those whose vendors make both the compiler and the\r
+ *       system.  Default definitions have been given, but its strongly\r
+ *       recommended that users never use these definitions for any\r
+ *       reason (they do *NOT* deliver any serious guarantee of\r
+ *       improved performance -- not in this file, nor any vendor's\r
+ *       stdint.h).\r
+ *\r
+ *   12) The following macros:\r
+ *\r
+ *       PRINTF_INTMAX_MODIFIER\r
+ *       PRINTF_INT64_MODIFIER\r
+ *       PRINTF_INT32_MODIFIER\r
+ *       PRINTF_INT16_MODIFIER\r
+ *       PRINTF_LEAST64_MODIFIER\r
+ *       PRINTF_LEAST32_MODIFIER\r
+ *       PRINTF_LEAST16_MODIFIER\r
+ *       PRINTF_INTPTR_MODIFIER\r
+ *\r
+ *       are strings which have been defined as the modifiers required\r
+ *       for the "d", "u" and "x" printf formats to correctly output\r
+ *       (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t,\r
+ *       (u)least32_t, (u)least16_t and (u)intptr_t types respectively.\r
+ *       PRINTF_INTPTR_MODIFIER is not defined for some systems which\r
+ *       provide their own stdint.h.  PRINTF_INT64_MODIFIER is not\r
+ *       defined if INT64_MAX is not defined.  These are an extension\r
+ *       beyond what C99 specifies must be in stdint.h.\r
+ *\r
+ *       In addition, the following macros are defined:\r
+ *\r
+ *       PRINTF_INTMAX_HEX_WIDTH\r
+ *       PRINTF_INT64_HEX_WIDTH\r
+ *       PRINTF_INT32_HEX_WIDTH\r
+ *       PRINTF_INT16_HEX_WIDTH\r
+ *       PRINTF_INT8_HEX_WIDTH\r
+ *       PRINTF_INTMAX_DEC_WIDTH\r
+ *       PRINTF_INT64_DEC_WIDTH\r
+ *       PRINTF_INT32_DEC_WIDTH\r
+ *       PRINTF_INT16_DEC_WIDTH\r
+ *       PRINTF_INT8_DEC_WIDTH\r
+ *\r
+ *       Which specifies the maximum number of characters required to\r
+ *       print the number of that type in either hexadecimal or decimal.\r
+ *       These are an extension beyond what C99 specifies must be in\r
+ *       stdint.h.\r
+ *\r
+ *  Compilers tested (all with 0 warnings at their highest respective\r
+ *  settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32\r
+ *  bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio\r
+ *  .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3\r
+ *\r
+ *  This file should be considered a work in progress.  Suggestions for\r
+ *  improvements, especially those which increase coverage are strongly\r
+ *  encouraged.\r
+ *\r
+ *  Acknowledgements\r
+ *\r
+ *  The following people have made significant contributions to the\r
+ *  development and testing of this file:\r
+ *\r
+ *  Chris Howie\r
+ *  John Steele Scott\r
+ *  Dave Thorup\r
+ *\r
+ */\r
+\r
+#include <stddef.h>\r
+#include <limits.h>\r
+#include <signal.h>\r
+\r
+/*\r
+ *  For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and\r
+ *  do nothing else.  On the Mac OS X version of gcc this is _STDINT_H_.\r
+ */\r
+\r
+#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) )) && !defined (_PSTDINT_H_INCLUDED)\r
+#include <stdint.h>\r
+#define _PSTDINT_H_INCLUDED\r
+# ifndef PRINTF_INT64_MODIFIER\r
+#  define PRINTF_INT64_MODIFIER "ll"\r
+# endif\r
+# ifndef PRINTF_INT32_MODIFIER\r
+#  define PRINTF_INT32_MODIFIER "l"\r
+# endif\r
+# ifndef PRINTF_INT16_MODIFIER\r
+#  define PRINTF_INT16_MODIFIER "h"\r
+# endif\r
+# ifndef PRINTF_INTMAX_MODIFIER\r
+#  define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER\r
+# endif\r
+# ifndef PRINTF_INT64_HEX_WIDTH\r
+#  define PRINTF_INT64_HEX_WIDTH "16"\r
+# endif\r
+# ifndef PRINTF_INT32_HEX_WIDTH\r
+#  define PRINTF_INT32_HEX_WIDTH "8"\r
+# endif\r
+# ifndef PRINTF_INT16_HEX_WIDTH\r
+#  define PRINTF_INT16_HEX_WIDTH "4"\r
+# endif\r
+# ifndef PRINTF_INT8_HEX_WIDTH\r
+#  define PRINTF_INT8_HEX_WIDTH "2"\r
+# endif\r
+# ifndef PRINTF_INT64_DEC_WIDTH\r
+#  define PRINTF_INT64_DEC_WIDTH "20"\r
+# endif\r
+# ifndef PRINTF_INT32_DEC_WIDTH\r
+#  define PRINTF_INT32_DEC_WIDTH "10"\r
+# endif\r
+# ifndef PRINTF_INT16_DEC_WIDTH\r
+#  define PRINTF_INT16_DEC_WIDTH "5"\r
+# endif\r
+# ifndef PRINTF_INT8_DEC_WIDTH\r
+#  define PRINTF_INT8_DEC_WIDTH "3"\r
+# endif\r
+# ifndef PRINTF_INTMAX_HEX_WIDTH\r
+#  define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH\r
+# endif\r
+# ifndef PRINTF_INTMAX_DEC_WIDTH\r
+#  define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH\r
+# endif\r
+#endif\r
+\r
+#ifndef _PSTDINT_H_INCLUDED\r
+#define _PSTDINT_H_INCLUDED\r
+\r
+#ifndef SIZE_MAX\r
+# define SIZE_MAX (~(size_t)0)\r
+#endif\r
+\r
+/*\r
+ *  Deduce the type assignments from limits.h under the assumption that\r
+ *  integer sizes in bits are powers of 2, and follow the ANSI\r
+ *  definitions.\r
+ */\r
+\r
+#ifndef UINT8_MAX\r
+# define UINT8_MAX 0xff\r
+#endif\r
+#ifndef uint8_t\r
+# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S)\r
+    typedef unsigned char uint8_t;\r
+#   define UINT8_C(v) ((uint8_t) v)\r
+# else\r
+#   error "Platform not supported"\r
+# endif\r
+#endif\r
+\r
+#ifndef INT8_MAX\r
+# define INT8_MAX 0x7f\r
+#endif\r
+#ifndef INT8_MIN\r
+# define INT8_MIN INT8_C(0x80)\r
+#endif\r
+#ifndef int8_t\r
+# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S)\r
+    typedef signed char int8_t;\r
+#   define INT8_C(v) ((int8_t) v)\r
+# else\r
+#   error "Platform not supported"\r
+# endif\r
+#endif\r
+\r
+#ifndef UINT16_MAX\r
+# define UINT16_MAX 0xffff\r
+#endif\r
+#ifndef uint16_t\r
+#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S)\r
+  typedef unsigned int uint16_t;\r
+# ifndef PRINTF_INT16_MODIFIER\r
+#  define PRINTF_INT16_MODIFIER ""\r
+# endif\r
+# define UINT16_C(v) ((uint16_t) (v))\r
+#elif (USHRT_MAX == UINT16_MAX)\r
+  typedef unsigned short uint16_t;\r
+# define UINT16_C(v) ((uint16_t) (v))\r
+# ifndef PRINTF_INT16_MODIFIER\r
+#  define PRINTF_INT16_MODIFIER "h"\r
+# endif\r
+#else\r
+#error "Platform not supported"\r
+#endif\r
+#endif\r
+\r
+#ifndef INT16_MAX\r
+# define INT16_MAX 0x7fff\r
+#endif\r
+#ifndef INT16_MIN\r
+# define INT16_MIN INT16_C(0x8000)\r
+#endif\r
+#ifndef int16_t\r
+#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S)\r
+  typedef signed int int16_t;\r
+# define INT16_C(v) ((int16_t) (v))\r
+# ifndef PRINTF_INT16_MODIFIER\r
+#  define PRINTF_INT16_MODIFIER ""\r
+# endif\r
+#elif (SHRT_MAX == INT16_MAX)\r
+  typedef signed short int16_t;\r
+# define INT16_C(v) ((int16_t) (v))\r
+# ifndef PRINTF_INT16_MODIFIER\r
+#  define PRINTF_INT16_MODIFIER "h"\r
+# endif\r
+#else\r
+#error "Platform not supported"\r
+#endif\r
+#endif\r
+\r
+#ifndef UINT32_MAX\r
+# define UINT32_MAX (0xffffffffUL)\r
+#endif\r
+#ifndef uint32_t\r
+#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)\r
+  typedef unsigned long uint32_t;\r
+# define UINT32_C(v) v ## UL\r
+# ifndef PRINTF_INT32_MODIFIER\r
+#  define PRINTF_INT32_MODIFIER "l"\r
+# endif\r
+#elif (UINT_MAX == UINT32_MAX)\r
+  typedef unsigned int uint32_t;\r
+# ifndef PRINTF_INT32_MODIFIER\r
+#  define PRINTF_INT32_MODIFIER ""\r
+# endif\r
+# define UINT32_C(v) v ## U\r
+#elif (USHRT_MAX == UINT32_MAX)\r
+  typedef unsigned short uint32_t;\r
+# define UINT32_C(v) ((unsigned short) (v))\r
+# ifndef PRINTF_INT32_MODIFIER\r
+#  define PRINTF_INT32_MODIFIER ""\r
+# endif\r
+#else\r
+#error "Platform not supported"\r
+#endif\r
+#endif\r
+\r
+#ifndef INT32_MAX\r
+# define INT32_MAX (0x7fffffffL)\r
+#endif\r
+#ifndef INT32_MIN\r
+# define INT32_MIN INT32_C(0x80000000)\r
+#endif\r
+#ifndef int32_t\r
+#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)\r
+  typedef signed long int32_t;\r
+# define INT32_C(v) v ## L\r
+# ifndef PRINTF_INT32_MODIFIER\r
+#  define PRINTF_INT32_MODIFIER "l"\r
+# endif\r
+#elif (INT_MAX == INT32_MAX)\r
+  typedef signed int int32_t;\r
+# define INT32_C(v) v\r
+# ifndef PRINTF_INT32_MODIFIER\r
+#  define PRINTF_INT32_MODIFIER ""\r
+# endif\r
+#elif (SHRT_MAX == INT32_MAX)\r
+  typedef signed short int32_t;\r
+# define INT32_C(v) ((short) (v))\r
+# ifndef PRINTF_INT32_MODIFIER\r
+#  define PRINTF_INT32_MODIFIER ""\r
+# endif\r
+#else\r
+#error "Platform not supported"\r
+#endif\r
+#endif\r
+\r
+/*\r
+ *  The macro stdint_int64_defined is temporarily used to record\r
+ *  whether or not 64 integer support is available.  It must be\r
+ *  defined for any 64 integer extensions for new platforms that are\r
+ *  added.\r
+ */\r
+\r
+#undef stdint_int64_defined\r
+#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S)\r
+# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S)\r
+#  define stdint_int64_defined\r
+   typedef long long int64_t;\r
+   typedef unsigned long long uint64_t;\r
+#  define UINT64_C(v) v ## ULL\r
+#  define  INT64_C(v) v ## LL\r
+#  ifndef PRINTF_INT64_MODIFIER\r
+#   define PRINTF_INT64_MODIFIER "ll"\r
+#  endif\r
+# endif\r
+#endif\r
+\r
+#if !defined (stdint_int64_defined)\r
+# if defined(__GNUC__)\r
+#  define stdint_int64_defined\r
+   __extension__ typedef long long int64_t;\r
+   __extension__ typedef unsigned long long uint64_t;\r
+#  define UINT64_C(v) v ## ULL\r
+#  define  INT64_C(v) v ## LL\r
+#  ifndef PRINTF_INT64_MODIFIER\r
+#   define PRINTF_INT64_MODIFIER "ll"\r
+#  endif\r
+# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S)\r
+#  define stdint_int64_defined\r
+   typedef long long int64_t;\r
+   typedef unsigned long long uint64_t;\r
+#  define UINT64_C(v) v ## ULL\r
+#  define  INT64_C(v) v ## LL\r
+#  ifndef PRINTF_INT64_MODIFIER\r
+#   define PRINTF_INT64_MODIFIER "ll"\r
+#  endif\r
+# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC)\r
+#  define stdint_int64_defined\r
+   typedef __int64 int64_t;\r
+   typedef unsigned __int64 uint64_t;\r
+#  define UINT64_C(v) v ## UI64\r
+#  define  INT64_C(v) v ## I64\r
+#  ifndef PRINTF_INT64_MODIFIER\r
+#   define PRINTF_INT64_MODIFIER "I64"\r
+#  endif\r
+# endif\r
+#endif\r
+\r
+#if !defined (LONG_LONG_MAX) && defined (INT64_C)\r
+# define LONG_LONG_MAX INT64_C (9223372036854775807)\r
+#endif\r
+#ifndef ULONG_LONG_MAX\r
+# define ULONG_LONG_MAX UINT64_C (18446744073709551615)\r
+#endif\r
+\r
+#if !defined (INT64_MAX) && defined (INT64_C)\r
+# define INT64_MAX INT64_C (9223372036854775807)\r
+#endif\r
+#if !defined (INT64_MIN) && defined (INT64_C)\r
+# define INT64_MIN INT64_C (-9223372036854775808)\r
+#endif\r
+#if !defined (UINT64_MAX) && defined (INT64_C)\r
+# define UINT64_MAX UINT64_C (18446744073709551615)\r
+#endif\r
+\r
+/*\r
+ *  Width of hexadecimal for number field.\r
+ */\r
+\r
+#ifndef PRINTF_INT64_HEX_WIDTH\r
+# define PRINTF_INT64_HEX_WIDTH "16"\r
+#endif\r
+#ifndef PRINTF_INT32_HEX_WIDTH\r
+# define PRINTF_INT32_HEX_WIDTH "8"\r
+#endif\r
+#ifndef PRINTF_INT16_HEX_WIDTH\r
+# define PRINTF_INT16_HEX_WIDTH "4"\r
+#endif\r
+#ifndef PRINTF_INT8_HEX_WIDTH\r
+# define PRINTF_INT8_HEX_WIDTH "2"\r
+#endif\r
+\r
+#ifndef PRINTF_INT64_DEC_WIDTH\r
+# define PRINTF_INT64_DEC_WIDTH "20"\r
+#endif\r
+#ifndef PRINTF_INT32_DEC_WIDTH\r
+# define PRINTF_INT32_DEC_WIDTH "10"\r
+#endif\r
+#ifndef PRINTF_INT16_DEC_WIDTH\r
+# define PRINTF_INT16_DEC_WIDTH "5"\r
+#endif\r
+#ifndef PRINTF_INT8_DEC_WIDTH\r
+# define PRINTF_INT8_DEC_WIDTH "3"\r
+#endif\r
+\r
+/*\r
+ *  Ok, lets not worry about 128 bit integers for now.  Moore's law says\r
+ *  we don't need to worry about that until about 2040 at which point\r
+ *  we'll have bigger things to worry about.\r
+ */\r
+\r
+#ifdef stdint_int64_defined\r
+  typedef int64_t intmax_t;\r
+  typedef uint64_t uintmax_t;\r
+# define  INTMAX_MAX   INT64_MAX\r
+# define  INTMAX_MIN   INT64_MIN\r
+# define UINTMAX_MAX  UINT64_MAX\r
+# define UINTMAX_C(v) UINT64_C(v)\r
+# define  INTMAX_C(v)  INT64_C(v)\r
+# ifndef PRINTF_INTMAX_MODIFIER\r
+#   define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER\r
+# endif\r
+# ifndef PRINTF_INTMAX_HEX_WIDTH\r
+#  define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH\r
+# endif\r
+# ifndef PRINTF_INTMAX_DEC_WIDTH\r
+#  define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH\r
+# endif\r
+#else\r
+  typedef int32_t intmax_t;\r
+  typedef uint32_t uintmax_t;\r
+# define  INTMAX_MAX   INT32_MAX\r
+# define UINTMAX_MAX  UINT32_MAX\r
+# define UINTMAX_C(v) UINT32_C(v)\r
+# define  INTMAX_C(v)  INT32_C(v)\r
+# ifndef PRINTF_INTMAX_MODIFIER\r
+#   define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER\r
+# endif\r
+# ifndef PRINTF_INTMAX_HEX_WIDTH\r
+#  define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH\r
+# endif\r
+# ifndef PRINTF_INTMAX_DEC_WIDTH\r
+#  define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH\r
+# endif\r
+#endif\r
+\r
+/*\r
+ *  Because this file currently only supports platforms which have\r
+ *  precise powers of 2 as bit sizes for the default integers, the\r
+ *  least definitions are all trivial.  Its possible that a future\r
+ *  version of this file could have different definitions.\r
+ */\r
+\r
+#ifndef stdint_least_defined\r
+  typedef   int8_t   int_least8_t;\r
+  typedef  uint8_t  uint_least8_t;\r
+  typedef  int16_t  int_least16_t;\r
+  typedef uint16_t uint_least16_t;\r
+  typedef  int32_t  int_least32_t;\r
+  typedef uint32_t uint_least32_t;\r
+# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER\r
+# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER\r
+# define  UINT_LEAST8_MAX  UINT8_MAX\r
+# define   INT_LEAST8_MAX   INT8_MAX\r
+# define UINT_LEAST16_MAX UINT16_MAX\r
+# define  INT_LEAST16_MAX  INT16_MAX\r
+# define UINT_LEAST32_MAX UINT32_MAX\r
+# define  INT_LEAST32_MAX  INT32_MAX\r
+# define   INT_LEAST8_MIN   INT8_MIN\r
+# define  INT_LEAST16_MIN  INT16_MIN\r
+# define  INT_LEAST32_MIN  INT32_MIN\r
+# ifdef stdint_int64_defined\r
+    typedef  int64_t  int_least64_t;\r
+    typedef uint64_t uint_least64_t;\r
+#   define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER\r
+#   define UINT_LEAST64_MAX UINT64_MAX\r
+#   define  INT_LEAST64_MAX  INT64_MAX\r
+#   define  INT_LEAST64_MIN  INT64_MIN\r
+# endif\r
+#endif\r
+#undef stdint_least_defined\r
+\r
+/*\r
+ *  The ANSI C committee pretending to know or specify anything about\r
+ *  performance is the epitome of misguided arrogance.  The mandate of\r
+ *  this file is to *ONLY* ever support that absolute minimum\r
+ *  definition of the fast integer types, for compatibility purposes.\r
+ *  No extensions, and no attempt to suggest what may or may not be a\r
+ *  faster integer type will ever be made in this file.  Developers are\r
+ *  warned to stay away from these types when using this or any other\r
+ *  stdint.h.\r
+ */\r
+\r
+typedef   int_least8_t   int_fast8_t;\r
+typedef  uint_least8_t  uint_fast8_t;\r
+typedef  int_least16_t  int_fast16_t;\r
+typedef uint_least16_t uint_fast16_t;\r
+typedef  int_least32_t  int_fast32_t;\r
+typedef uint_least32_t uint_fast32_t;\r
+#define  UINT_FAST8_MAX  UINT_LEAST8_MAX\r
+#define   INT_FAST8_MAX   INT_LEAST8_MAX\r
+#define UINT_FAST16_MAX UINT_LEAST16_MAX\r
+#define  INT_FAST16_MAX  INT_LEAST16_MAX\r
+#define UINT_FAST32_MAX UINT_LEAST32_MAX\r
+#define  INT_FAST32_MAX  INT_LEAST32_MAX\r
+#define   INT_FAST8_MIN   IN_LEASTT8_MIN\r
+#define  INT_FAST16_MIN  INT_LEAST16_MIN\r
+#define  INT_FAST32_MIN  INT_LEAST32_MIN\r
+#ifdef stdint_int64_defined\r
+  typedef  int_least64_t  int_fast64_t;\r
+  typedef uint_least64_t uint_fast64_t;\r
+# define UINT_FAST64_MAX UINT_LEAST64_MAX\r
+# define  INT_FAST64_MAX  INT_LEAST64_MAX\r
+# define  INT_FAST64_MIN  INT_LEAST64_MIN\r
+#endif\r
+\r
+#undef stdint_int64_defined\r
+\r
+/*\r
+ *  Whatever piecemeal, per compiler thing we can do about the wchar_t\r
+ *  type limits.\r
+ */\r
+\r
+#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__)\r
+# include <wchar.h>\r
+# ifndef WCHAR_MIN\r
+#  define WCHAR_MIN 0\r
+# endif\r
+# ifndef WCHAR_MAX\r
+#  define WCHAR_MAX ((wchar_t)-1)\r
+# endif\r
+#endif\r
+\r
+/*\r
+ *  Whatever piecemeal, per compiler/platform thing we can do about the\r
+ *  (u)intptr_t types and limits.\r
+ */\r
+\r
+#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)\r
+# define STDINT_H_UINTPTR_T_DEFINED\r
+#endif\r
+\r
+#ifndef STDINT_H_UINTPTR_T_DEFINED\r
+# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64)\r
+#  define stdint_intptr_bits 64\r
+# elif defined (__WATCOMC__) || defined (__TURBOC__)\r
+#  if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)\r
+#    define stdint_intptr_bits 16\r
+#  else\r
+#    define stdint_intptr_bits 32\r
+#  endif\r
+# elif defined (__i386__) || defined (_WIN32) || defined (WIN32)\r
+#  define stdint_intptr_bits 32\r
+# elif defined (__INTEL_COMPILER)\r
+/* TODO -- what will Intel do about x86-64? */\r
+# endif\r
+\r
+# ifdef stdint_intptr_bits\r
+#  define stdint_intptr_glue3_i(a,b,c)  a##b##c\r
+#  define stdint_intptr_glue3(a,b,c)    stdint_intptr_glue3_i(a,b,c)\r
+#  ifndef PRINTF_INTPTR_MODIFIER\r
+#    define PRINTF_INTPTR_MODIFIER      stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER)\r
+#  endif\r
+#  ifndef PTRDIFF_MAX\r
+#    define PTRDIFF_MAX                 stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)\r
+#  endif\r
+#  ifndef PTRDIFF_MIN\r
+#    define PTRDIFF_MIN                 stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)\r
+#  endif\r
+#  ifndef UINTPTR_MAX\r
+#    define UINTPTR_MAX                 stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX)\r
+#  endif\r
+#  ifndef INTPTR_MAX\r
+#    define INTPTR_MAX                  stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)\r
+#  endif\r
+#  ifndef INTPTR_MIN\r
+#    define INTPTR_MIN                  stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)\r
+#  endif\r
+#  ifndef INTPTR_C\r
+#    define INTPTR_C(x)                 stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x)\r
+#  endif\r
+#  ifndef UINTPTR_C\r
+#    define UINTPTR_C(x)                stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x)\r
+#  endif\r
+  typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t;\r
+  typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t)  intptr_t;\r
+# else\r
+/* TODO -- This following is likely wrong for some platforms, and does\r
+   nothing for the definition of uintptr_t. */\r
+  typedef ptrdiff_t intptr_t;\r
+# endif\r
+# define STDINT_H_UINTPTR_T_DEFINED\r
+#endif\r
+\r
+/*\r
+ *  Assumes sig_atomic_t is signed and we have a 2s complement machine.\r
+ */\r
+\r
+#ifndef SIG_ATOMIC_MAX\r
+# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1)\r
+#endif\r
+\r
+#endif\r
diff --git a/include/socketdefines.h b/include/socketdefines.h
new file mode 100644 (file)
index 0000000..498d5b1
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _socket_defines_\r
+#define _socket_defines_\r
+\r
+#ifdef _WIN32\r
+       #include <winsock2.h>\r
+#endif\r
+\r
+#include <string>\r
+\r
+#ifndef SOCKET\r
+       typedef unsigned int SOCKET;\r
+#endif\r
+\r
+#ifndef INVALID_SOCKET\r
+       #define INVALID_SOCKET (SOCKET)(~0)\r
+#endif\r
+\r
+#ifndef SOCKET_ERROR\r
+       #define SOCKET_ERROR (-1)\r
+#endif\r
+\r
+std::string GetSocketErrorMessage();\r
+int GetSocketErrorNumber();\r
+\r
+#endif // _socket_defines_\r
diff --git a/include/stringfunctions.h b/include/stringfunctions.h
new file mode 100644 (file)
index 0000000..5222ca1
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef _string_functions_\r
+#define _string_functions_\r
+\r
+#include <string>\r
+#include <vector>\r
+#include <sstream>\r
+\r
+namespace StringFunctions\r
+{\r
+\r
+/**\r
+       \brief Converts a string into any other type\r
+       \param input[in] string to convert\r
+       \param output[out] output type\r
+       \return true if conversion was successful, false if it was not\r
+*/\r
+template <class T>\r
+inline const bool Convert(const std::string &input, T &output)\r
+{\r
+       std::istringstream i(input);\r
+       if(i >> output)\r
+       {\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+/**\r
+       \brief Converter from any type into a string\r
+       \param input[in] data to convert\r
+       \param output[out] string output\r
+       \return true if conversion was successful, false if it was not\r
+*/\r
+template <class T>\r
+inline const bool Convert(const T &input, std::string &output)\r
+{\r
+       std::ostringstream o;\r
+       o << input;\r
+       output=o.str();\r
+       return true;    \r
+}\r
+\r
+/**\r
+       \brief Replaces occurences of a string with another string\r
+\r
+       \param input string to search in\r
+       \param find string to find in input string\r
+       \param replace string to replace find string with\r
+*/\r
+std::string Replace(const std::string &input, const std::string &find, const std::string &replace);\r
+\r
+/**\r
+       \brief Splits a string into pieces separated by a delimeter\r
+       \r
+       If the delimiter is not found within the string, the output vector will contain 1 element with the entire input string\r
+       \param str string to split\r
+       \param delim delimeter to split at\r
+       \param[out] vector containing parts\r
+*/\r
+void Split(const std::string &str, const std::string &delim, std::vector<std::string> &output);\r
+\r
+/**\r
+       \brief Splits a string into pieces separated by one or more delimeters\r
+       \r
+       The delimiter string contains individual character delimieters\r
+       \param str string to split\r
+       \param delim string containing individual characters to split at\r
+       \param[out] vector containing parts\r
+*/\r
+void SplitMultiple(const std::string &str, const std::string &delim, std::vector<std::string> &output);\r
+\r
+/**\r
+       \brief Trims whitespace from beginning and end of string\r
+*/\r
+std::string TrimWhitespace(const std::string &str);\r
+\r
+/**\r
+       \brief Converts a string to upper case\r
+       \param str string to convert to upper case\r
+       \param[out] string converted to upper case\r
+*/\r
+void UpperCase(const std::string &str, std::string &output);\r
+\r
+/**\r
+       \brief Decodes a URI encoded string\r
+       \param aSrc string that is URI encoded\r
+       \return URI decoded input string\r
+*/\r
+std::string UriDecode(const std::string & sSrc);\r
+\r
+/**\r
+       \brief URI Encodes a string\r
+       \param aSrc string to encode\r
+       \return input string URI encoded\r
+*/\r
+std::string UriEncode(const std::string & sSrc);\r
+\r
+};\r
+\r
+#endif // _string_functions_\r
diff --git a/include/uuidgenerator.h b/include/uuidgenerator.h
new file mode 100644 (file)
index 0000000..0244716
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _uuidgenerator_\r
+#define _uuidgenerator_\r
+\r
+#include <string>\r
+\r
+/**\r
+       \brief UUID v4 (based on random numbers)\r
+\r
+       reference : http://lists.evolt.org/pipermail/javascript/2006-July/010716.html\r
+*/\r
+class UUIDGenerator\r
+{\r
+public:\r
+\r
+       const std::string Generate();\r
+\r
+private:\r
+\r
+       const std::string RandHex(const int len);\r
+\r
+};\r
+\r
+#endif // _uuidgenerator_\r
diff --git a/include/xyssl/config.h b/include/xyssl/config.h
new file mode 100644 (file)
index 0000000..5afc574
--- /dev/null
@@ -0,0 +1,278 @@
+/**\r
+ * \file config.h\r
+ *\r
+ * This set of compile-time options may be used to enable\r
+ * or disable features selectively, and reduce the global\r
+ * memory footprint.\r
+ */\r
+#ifndef XYSSL_CONFIG_H\r
+#define XYSSL_CONFIG_H\r
+\r
+#ifndef _CRT_SECURE_NO_DEPRECATE\r
+#define _CRT_SECURE_NO_DEPRECATE 1\r
+#endif\r
+\r
+/*\r
+ * Uncomment if native integers are 8-bit wide.\r
+ *\r
+#define XYSSL_HAVE_INT8\r
+ */\r
+\r
+/*\r
+ * Uncomment if native integers are 16-bit wide.\r
+ *\r
+#define XYSSL_HAVE_INT16\r
+ */\r
+\r
+/*\r
+ * Uncomment if the compiler supports long long.\r
+ *\r
+#define XYSSL_HAVE_LONGLONG\r
+ */\r
+\r
+/*\r
+ * Uncomment if the CPU supports SSE2 (IA-32 specific).\r
+ *\r
+#define XYSSL_HAVE_SSE2\r
+ */\r
+\r
+/*\r
+ * Enable all SSL/TLS debugging messages.\r
+ */\r
+#define XYSSL_DEBUG_MSG\r
+\r
+/*\r
+ * Enable the checkup functions (*_self_test).\r
+ *\r
+#define XYSSL_SELF_TEST\r
+ */\r
+\r
+/*\r
+ * Enable the prime-number generation code.\r
+ */\r
+#define XYSSL_GENPRIME\r
+\r
+/*\r
+ * Uncomment this macro to store the AES tables in ROM.\r
+ *\r
+#define XYSSL_AES_ROM_TABLES\r
+ */\r
+\r
+/*\r
+ * Module:  library/aes.c\r
+ * Caller:  library/ssl_tls.c\r
+ *\r
+ * This module enables the following ciphersuites:\r
+ *      SSL_RSA_AES_256_SHA\r
+ *      SSL_EDH_RSA_AES_256_SHA\r
+ */\r
+#define XYSSL_AES_C\r
+\r
+/*\r
+ * Module:  library/arc4.c\r
+ * Caller:  library/ssl_tls.c\r
+ *\r
+ * This module enables the following ciphersuites:\r
+ *      SSL_RSA_RC4_128_MD5\r
+ *      SSL_RSA_RC4_128_SHA\r
+ */\r
+#define XYSSL_ARC4_C\r
+\r
+/*\r
+ * Module:  library/base64.c\r
+ * Caller:  library/x509parse.c\r
+ *\r
+ * This module is required for X.509 support.\r
+ */\r
+#define XYSSL_BASE64_C\r
+\r
+/*\r
+ * Module:  library/bignum.c\r
+ * Caller:  library/dhm.c\r
+ *          library/rsa.c\r
+ *          library/ssl_tls.c\r
+ *          library/x509parse.c\r
+ *\r
+ * This module is required for RSA and DHM support.\r
+ */\r
+#define XYSSL_BIGNUM_C\r
+\r
+/*\r
+ * Module:  library/certs.c\r
+ * Caller:\r
+ *\r
+ * This module is used for testing (ssl_client/server).\r
+ */\r
+#define XYSSL_CERTS_C\r
+\r
+/*\r
+ * Module:  library/debug.c\r
+ * Caller:  library/ssl_cli.c\r
+ *          library/ssl_srv.c\r
+ *          library/ssl_tls.c\r
+ *\r
+ * This module provides debugging functions.\r
+ *\r
+#define XYSSL_DEBUG_C\r
+ */\r
+\r
+/*\r
+ * Module:  library/des.c\r
+ * Caller:  library/ssl_tls.c\r
+ *\r
+ * This module enables the following ciphersuites:\r
+ *      SSL_RSA_DES_168_SHA\r
+ *      SSL_EDH_RSA_DES_168_SHA\r
+ */\r
+#define XYSSL_DES_C\r
+\r
+/*\r
+ * Module:  library/dhm.c\r
+ * Caller:  library/ssl_cli.c\r
+ *          library/ssl_srv.c\r
+ *\r
+ * This module enables the following ciphersuites:\r
+ *      SSL_EDH_RSA_DES_168_SHA\r
+ *      SSL_EDH_RSA_AES_256_SHA\r
+ */\r
+#define XYSSL_DHM_C\r
+\r
+/*\r
+ * Module:  library/havege.c\r
+ * Caller:\r
+ *\r
+ * This module enables the HAVEGE random number generator.\r
+ */\r
+#define XYSSL_HAVEGE_C\r
+\r
+/*\r
+ * Module:  library/md2.c\r
+ * Caller:  library/x509parse.c\r
+ *\r
+ * This module enables support for MD2-signed X.509 certificates.\r
+ */\r
+#define XYSSL_MD2_C\r
+\r
+/*\r
+ * Module:  library/md4.c\r
+ * Caller:  library/x509parse.c\r
+ *\r
+ * This module enables support for MD4-signed X.509 certificates.\r
+ */\r
+#define XYSSL_MD4_C\r
+\r
+/*\r
+ * Module:  library/md5.c\r
+ * Caller:  library/ssl_tls.c\r
+ *          library/x509parse.c\r
+ *\r
+ * This module is required for SSL/TLS and X.509.\r
+ */\r
+#define XYSSL_MD5_C\r
+\r
+/*\r
+ * Module:  library/net.c\r
+ * Caller:\r
+ *\r
+ * This module provides TCP/IP networking routines.\r
+ */\r
+#define XYSSL_NET_C\r
+\r
+/*\r
+ * Module:  library/padlock.c\r
+ * Caller:  library/aes.c\r
+ *\r
+ * This modules adds support for the VIA PadLock on x86.\r
+ */\r
+#define XYSSL_PADLOCK_C\r
+\r
+/*\r
+ * Module:  library/rsa.c\r
+ * Caller:  library/ssl_cli.c\r
+ *          library/ssl_srv.c\r
+ *          library/ssl_tls.c\r
+ *          library/x509.c\r
+ *\r
+ * This module is required for SSL/TLS and X.509.\r
+ */\r
+#define XYSSL_RSA_C\r
+\r
+/*\r
+ * Module:  library/sha1.c\r
+ * Caller:  library/ssl_cli.c\r
+ *          library/ssl_srv.c\r
+ *          library/ssl_tls.c\r
+ *          library/x509parse.c\r
+ *\r
+ * This module is required for SSL/TLS and X.509.\r
+ */\r
+#define XYSSL_SHA1_C\r
+\r
+/*\r
+ * Module:  library/sha2.c\r
+ * Caller:\r
+ *\r
+ * This module adds support for SHA-224 and SHA-256.\r
+ */\r
+#define XYSSL_SHA2_C\r
+\r
+/*\r
+ * Module:  library/sha4.c\r
+ * Caller:\r
+ *\r
+ * This module adds support for SHA-384 and SHA-512.\r
+ */\r
+#define XYSSL_SHA4_C\r
+\r
+/*\r
+ * Module:  library/ssl_cli.c\r
+ * Caller:\r
+ *\r
+ * This module is required for SSL/TLS client support.\r
+ */\r
+#define XYSSL_SSL_CLI_C\r
+\r
+/*\r
+ * Module:  library/ssl_srv.c\r
+ * Caller:\r
+ *\r
+ * This module is required for SSL/TLS server support.\r
+ */\r
+#define XYSSL_SSL_SRV_C\r
+\r
+/*\r
+ * Module:  library/ssl_tls.c\r
+ * Caller:  library/ssl_cli.c\r
+ *          library/ssl_srv.c\r
+ *\r
+ * This module is required for SSL/TLS.\r
+ */\r
+#define XYSSL_SSL_TLS_C\r
+\r
+/*\r
+ * Module:  library/timing.c\r
+ * Caller:  library/havege.c\r
+ *\r
+ * This module is used by the HAVEGE random number generator.\r
+ */\r
+#define XYSSL_TIMING_C\r
+\r
+/*\r
+ * Module:  library/x509parse.c\r
+ * Caller:  library/ssl_cli.c\r
+ *          library/ssl_srv.c\r
+ *          library/ssl_tls.c\r
+ *\r
+ * This module is required for X.509 certificate parsing.\r
+ */\r
+#define XYSSL_X509_PARSE_C\r
+\r
+/*\r
+ * Module:  library/x509_write.c\r
+ * Caller:\r
+ *\r
+ * This module is required for X.509 certificate writing.\r
+ */\r
+#define XYSSL_X509_WRITE_C\r
+\r
+#endif /* config.h */\r
diff --git a/include/xyssl/sha1.h b/include/xyssl/sha1.h
new file mode 100644 (file)
index 0000000..0c6b03e
--- /dev/null
@@ -0,0 +1,119 @@
+/**\r
+ * \file sha1.h\r
+ */\r
+#ifndef XYSSL_SHA1_H\r
+#define XYSSL_SHA1_H\r
+\r
+/**\r
+ * \brief          SHA-1 context structure\r
+ */\r
+typedef struct\r
+{\r
+    unsigned long total[2];     /*!< number of bytes processed  */\r
+    unsigned long state[5];     /*!< intermediate digest state  */\r
+    unsigned char buffer[64];   /*!< data block being processed */\r
+\r
+    unsigned char ipad[64];     /*!< HMAC: inner padding        */\r
+    unsigned char opad[64];     /*!< HMAC: outer padding        */\r
+}\r
+sha1_context;\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/**\r
+ * \brief          SHA-1 context setup\r
+ *\r
+ * \param ctx      context to be initialized\r
+ */\r
+void sha1_starts( sha1_context *ctx );\r
+\r
+/**\r
+ * \brief          SHA-1 process buffer\r
+ *\r
+ * \param ctx      SHA-1 context\r
+ * \param input    buffer holding the  data\r
+ * \param ilen     length of the input data\r
+ */\r
+void sha1_update( sha1_context *ctx, unsigned char *input, int ilen );\r
+\r
+/**\r
+ * \brief          SHA-1 final digest\r
+ *\r
+ * \param ctx      SHA-1 context\r
+ * \param output   SHA-1 checksum result\r
+ */\r
+void sha1_finish( sha1_context *ctx, unsigned char output[20] );\r
+\r
+/**\r
+ * \brief          Output = SHA-1( input buffer )\r
+ *\r
+ * \param input    buffer holding the  data\r
+ * \param ilen     length of the input data\r
+ * \param output   SHA-1 checksum result\r
+ */\r
+void sha1( unsigned char *input, int ilen, unsigned char output[20] );\r
+\r
+/**\r
+ * \brief          Output = SHA-1( file contents )\r
+ *\r
+ * \param path     input file name\r
+ * \param output   SHA-1 checksum result\r
+ *\r
+ * \return         0 if successful, 1 if fopen failed,\r
+ *                 or 2 if fread failed\r
+ */\r
+int sha1_file( char *path, unsigned char output[20] );\r
+\r
+/**\r
+ * \brief          SHA-1 HMAC context setup\r
+ *\r
+ * \param ctx      HMAC context to be initialized\r
+ * \param key      HMAC secret key\r
+ * \param keylen   length of the HMAC key\r
+ */\r
+void sha1_hmac_starts( sha1_context *ctx, unsigned char *key, int keylen );\r
+\r
+/**\r
+ * \brief          SHA-1 HMAC process buffer\r
+ *\r
+ * \param ctx      HMAC context\r
+ * \param input    buffer holding the  data\r
+ * \param ilen     length of the input data\r
+ */\r
+void sha1_hmac_update( sha1_context *ctx, unsigned char *input, int ilen );\r
+\r
+/**\r
+ * \brief          SHA-1 HMAC final digest\r
+ *\r
+ * \param ctx      HMAC context\r
+ * \param output   SHA-1 HMAC checksum result\r
+ */\r
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] );\r
+\r
+/**\r
+ * \brief          Output = HMAC-SHA-1( hmac key, input buffer )\r
+ *\r
+ * \param key      HMAC secret key\r
+ * \param keylen   length of the HMAC key\r
+ * \param input    buffer holding the  data\r
+ * \param ilen     length of the input data\r
+ * \param output   HMAC-SHA-1 result\r
+ */\r
+void sha1_hmac( unsigned char *key, int keylen,\r
+                unsigned char *input, int ilen,\r
+                unsigned char output[20] );\r
+\r
+/**\r
+ * \brief          Checkup routine\r
+ *\r
+ * \return         0 if successful, or 1 if the test failed\r
+ */\r
+int sha1_self_test( int verbose );\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* sha1.h */
\ No newline at end of file
diff --git a/src/base64.cpp b/src/base64.cpp
new file mode 100644 (file)
index 0000000..06491fc
--- /dev/null
@@ -0,0 +1,97 @@
+#include "../include/base64.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+namespace Base64\r
+{\r
+\r
+static const std::string base64chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\r
+\r
+const bool Encode(const std::vector<unsigned char> &data, std::string &encoded)\r
+{\r
+       std::vector<unsigned char>::size_type currentdatapos=0;\r
+\r
+       while(currentdatapos<data.size())\r
+       {\r
+               encoded.push_back(base64chars[(data[currentdatapos]>>2 & 0x3F)]);\r
+               if(currentdatapos+1<data.size())\r
+               {\r
+                       encoded.push_back(base64chars[(data[currentdatapos]<<4 & 0x30) | (data[currentdatapos+1]>>4 & 0x0F)]);\r
+                       if(currentdatapos+2<data.size())\r
+                       {\r
+                               encoded.push_back(base64chars[(data[currentdatapos+1]<<2 & 0x3C) | (data[currentdatapos+2]>>6 & 0x03)]);\r
+                               encoded.push_back(base64chars[(data[currentdatapos+2] & 0x3F)]);\r
+                       }\r
+                       else\r
+                       {\r
+                               encoded.push_back(base64chars[(data[currentdatapos+1]<<2 & 0x3C)]);\r
+                               encoded.append("=");\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       encoded.push_back(base64chars[(data[currentdatapos]<<4 & 0x30)]);\r
+                       encoded.append("==");\r
+               }\r
+               currentdatapos+=3;\r
+       }\r
+       return true;\r
+}\r
+\r
+const bool Decode(const std::string &encoded, std::vector<unsigned char> &data)\r
+{\r
+       std::string::size_type charpos=0;\r
+       std::string::size_type encodedpos=0;\r
+       unsigned char currentbyte=0;\r
+\r
+       // loop while encoded pos fits in current size\r
+       while(encodedpos+3<encoded.size())\r
+       {\r
+               currentbyte=0;\r
+               charpos=base64chars.find(encoded[encodedpos]);\r
+               if(charpos==std::string::npos)\r
+               {\r
+                       return false;\r
+               }\r
+               currentbyte=(charpos<<2 & 0xFC);\r
+               charpos=base64chars.find(encoded[encodedpos+1]);\r
+               if(charpos==std::string::npos)\r
+               {\r
+                       return false;\r
+               }\r
+               currentbyte|=(charpos>>4 & 0x03);\r
+               data.push_back(currentbyte);\r
+               currentbyte=(charpos<<4 & 0xF0);\r
+\r
+               if(encoded[encodedpos+2]!='=')\r
+               {\r
+                       charpos=base64chars.find(encoded[encodedpos+2]);\r
+                       if(charpos==std::string::npos)\r
+                       {\r
+                               return false;\r
+                       }\r
+                       currentbyte|=(charpos>>2 & 0x0F);\r
+                       data.push_back(currentbyte);\r
+                       currentbyte=(charpos<<6 & 0xC0);\r
+               }\r
+               \r
+               if(encoded[encodedpos+2]!='=')\r
+               {\r
+                       charpos=base64chars.find(encoded[encodedpos+3]);\r
+                       if(charpos==std::string::npos)\r
+                       {\r
+                               return false;\r
+                       }\r
+                       currentbyte|=(charpos & 0x3F);\r
+                       data.push_back(currentbyte);\r
+               }\r
+\r
+               encodedpos+=4;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+}      // namespace\r
diff --git a/src/commandthread.cpp b/src/commandthread.cpp
new file mode 100644 (file)
index 0000000..7d872f0
--- /dev/null
@@ -0,0 +1,60 @@
+#include "../include/commandthread.h"\r
+#include "../include/stringfunctions.h"\r
+\r
+#include <iostream>\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+void CommandThread::HandleHelpCommand()\r
+{\r
+       std::cout << "Available Commands:" << std::endl;\r
+       std::cout << "QUIT              End program" << std::endl;\r
+}\r
+\r
+void CommandThread::HandleInput(const std::string &input)\r
+{\r
+       std::string command=input;\r
+       std::string argument="";\r
+       if(input.find(" ")!=std::string::npos)\r
+       {\r
+               command=input.substr(0,input.find(" "));\r
+               argument=input.substr(command.size()+1);\r
+       }\r
+       StringFunctions::UpperCase(command,command);\r
+       \r
+       if(command=="HELP")\r
+       {\r
+               HandleHelpCommand();\r
+       }\r
+       else if(command=="QUIT")\r
+       {\r
+               HandleQuit();\r
+       }\r
+       else\r
+       {\r
+               std::cout << "Unknown command.  Type HELP for a list of available commands." << std::endl;\r
+       }\r
+       \r
+}\r
+\r
+void CommandThread::HandleQuit()\r
+{\r
+       m_running=false;        \r
+}\r
+\r
+void CommandThread::run()\r
+{\r
+       std::string input;\r
+       m_running=true;\r
+       \r
+       do\r
+       {\r
+               std::cin >> input;\r
+               \r
+               HandleInput(input);\r
+               \r
+       }while(m_running==true);\r
+       \r
+}\r
diff --git a/src/datetime.cpp b/src/datetime.cpp
new file mode 100644 (file)
index 0000000..7d3d4af
--- /dev/null
@@ -0,0 +1,420 @@
+#include "../include/datetime.h"\r
+\r
+#include <vector>\r
+#include "../include/stringfunctions.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+DateTime::DateTime()\r
+{\r
+       Set();\r
+}\r
+\r
+DateTime::DateTime(const time_t &timet)\r
+{\r
+       Set(timet);\r
+}\r
+\r
+DateTime::DateTime(const struct tm *stm)\r
+{\r
+       Set(stm);\r
+}\r
+\r
+void DateTime::Add(const int seconds, const int minutes, const int hours, const int days, const int months, const int years)\r
+{\r
+       m_tm.tm_sec+=seconds;\r
+       m_tm.tm_min+=minutes;\r
+       m_tm.tm_hour+=hours;\r
+       m_tm.tm_mday+=days;\r
+       m_tm.tm_mon+=months;\r
+       m_tm.tm_year+=years;\r
+       \r
+       Normalize();\r
+}\r
+\r
+std::string DateTime::Format(const std::string &formatstring) const\r
+{\r
+       std::string returnval="";\r
+       char *str=new char[512];\r
+       memset(str,0,512);\r
+\r
+       strftime(str,511,formatstring.c_str(),&m_tm);\r
+\r
+       if(str)\r
+       {\r
+               returnval=str;\r
+               delete [] str;\r
+       }\r
+\r
+       return returnval;\r
+}\r
+\r
+void DateTime::Normalize()\r
+{\r
+       // check for tm_isdst in local time and take appropriate action when normalizing\r
+       // thanks to http://www.erack.de/download/timetest.c for example\r
+       int isdst;\r
+       struct tm temptm;\r
+       time_t temptimet;\r
+       temptimet=time(NULL);\r
+       temptm=*localtime(&temptimet);\r
+       isdst=temptm.tm_isdst;\r
+\r
+       temptm.tm_year=m_tm.tm_year;\r
+       temptm.tm_mon=m_tm.tm_mon;\r
+       temptm.tm_mday=m_tm.tm_mday;\r
+       temptm.tm_hour=m_tm.tm_hour;\r
+       temptm.tm_min=m_tm.tm_min;\r
+       temptm.tm_sec=m_tm.tm_sec;\r
+       temptm.tm_isdst=isdst;\r
+       temptimet=mktime(&temptm);\r
+\r
+       if(temptm.tm_isdst!=isdst)\r
+       {\r
+               // keep tm_isdst to whatever mktime returned and try again\r
+               temptm.tm_year=m_tm.tm_year;\r
+               temptm.tm_mon=m_tm.tm_mon;\r
+               temptm.tm_mday=m_tm.tm_mday;\r
+               temptm.tm_hour=m_tm.tm_hour;\r
+               temptm.tm_min=m_tm.tm_min;\r
+               temptm.tm_sec=m_tm.tm_sec;\r
+               temptimet=mktime(&temptm);\r
+       }\r
+       else if(isdst && temptimet==-1)\r
+       {\r
+               // isdst set, but TZ has no offset (e.g. GMT), try with isdst=0\r
+               temptm.tm_year=m_tm.tm_year;\r
+               temptm.tm_mon=m_tm.tm_mon;\r
+               temptm.tm_mday=m_tm.tm_mday;\r
+               temptm.tm_hour=m_tm.tm_hour;\r
+               temptm.tm_min=m_tm.tm_min;\r
+               temptm.tm_sec=m_tm.tm_sec;\r
+               temptm.tm_isdst=0;\r
+               temptimet=mktime(&temptm);\r
+       }\r
+\r
+       m_tm=temptm;\r
+       m_timet=temptimet;\r
+\r
+       // date is erroneous - set to default date\r
+       if(m_timet==-1 && (m_tm.tm_mon<0 || m_tm.tm_mon>11 || m_tm.tm_mday <1 || m_tm.tm_mday>31 || m_tm.tm_hour<0 || m_tm.tm_hour>23 || m_tm.tm_min<0 || m_tm.tm_min>59 || m_tm.tm_sec<0 || m_tm.tm_sec>59))\r
+       {\r
+               Set();\r
+       }\r
+\r
+}\r
+\r
+DateTime DateTime::operator+(const double &rhs)\r
+{\r
+       DateTime temp=*this;\r
+\r
+       double val=rhs;\r
+       int days=(int)val;\r
+       val-=days;\r
+       val*=24.0;\r
+       int hours=(int)val;\r
+       val-=hours;\r
+       val*=60.0;\r
+       int minutes=(int)val;\r
+       val-=minutes;\r
+       val*=60.0;\r
+       int seconds=(int)val;\r
+\r
+       temp.Add(seconds,minutes,hours,days);\r
+       return temp;\r
+}\r
+\r
+DateTime DateTime::operator+(const DateTime &rhs)\r
+{\r
+       DateTime temp=*this;\r
+\r
+       temp.Add(rhs.m_tm.tm_sec,rhs.m_tm.tm_min,rhs.m_tm.tm_hour,rhs.m_tm.tm_mday,rhs.m_tm.tm_mon+1,rhs.m_tm.tm_year+1900);\r
+       return temp;\r
+}\r
+\r
+DateTime &DateTime::operator+=(const double &rhs)\r
+{\r
+       *this=*this+rhs;\r
+\r
+       return *this;\r
+}\r
+\r
+DateTime &DateTime::operator+=(const DateTime &rhs)\r
+{\r
+       *this=*this+rhs;\r
+\r
+       return *this;\r
+}\r
+\r
+DateTime DateTime::operator-(const double &rhs)\r
+{\r
+       DateTime temp=*this;\r
+\r
+       double val=rhs;\r
+       int days=(int)val;\r
+       val-=days;\r
+       val*=24.0;\r
+       int hours=(int)val;\r
+       val-=hours;\r
+       val*=60.0;\r
+       int minutes=(int)val;\r
+       val-=minutes;\r
+       val*=60.0;\r
+       int seconds=(int)val;\r
+\r
+       temp.Add(-seconds,-minutes,-hours,-days);\r
+       return temp;\r
+}\r
+\r
+DateTime DateTime::operator-(const DateTime &rhs)\r
+{\r
+       DateTime temp=*this;\r
+\r
+       temp.Add(-rhs.m_tm.tm_sec,-rhs.m_tm.tm_min,-rhs.m_tm.tm_hour,-rhs.m_tm.tm_mday,-(rhs.m_tm.tm_mon+1),-(rhs.m_tm.tm_year+1900));\r
+       return temp;\r
+}\r
+\r
+DateTime &DateTime::operator-=(const double &rhs)\r
+{\r
+       *this=*this-rhs;\r
+\r
+       return *this;\r
+}\r
+\r
+DateTime &DateTime::operator-=(const DateTime &rhs)\r
+{\r
+       *this=*this-rhs;\r
+\r
+       return *this;\r
+}\r
+\r
+const bool DateTime::operator==(const struct tm &rhs) const\r
+{\r
+       return (m_tm.tm_year==rhs.tm_year && m_tm.tm_mon==rhs.tm_mon && m_tm.tm_mday==rhs.tm_mday && m_tm.tm_hour==rhs.tm_hour && m_tm.tm_min==rhs.tm_min && m_tm.tm_sec==rhs.tm_sec) ? true : false;\r
+}\r
+\r
+void DateTime::Set(const int year, const int month, const int day, const int hour, const int minute, const int second)\r
+{\r
+       m_tm.tm_year=year-1900;\r
+       m_tm.tm_mon=month-1;\r
+       m_tm.tm_mday=day;\r
+       m_tm.tm_hour=hour;\r
+       m_tm.tm_min=minute;\r
+       m_tm.tm_sec=second;\r
+\r
+       Normalize();\r
+}\r
+\r
+void DateTime::Set(const time_t &timet)\r
+{\r
+       m_timet=timet;\r
+\r
+       m_tm=*gmtime(&m_timet);\r
+       Normalize();\r
+}\r
+\r
+void DateTime::Set(const struct tm *stm)\r
+{\r
+       m_tm=*stm;\r
+       m_timet=mktime(&m_tm);\r
+       Normalize();\r
+}\r
+\r
+void DateTime::Set(const std::string &datestring)\r
+{\r
+       int year,month,day,hour,minute,second;\r
+       std::vector<std::string> tokens;\r
+       int vecpos;\r
+       int tempint;\r
+\r
+       year=month=day=hour=minute=second=-1;\r
+\r
+       // reset to 1900-01-01 00:00:00\r
+       Set();\r
+\r
+       StringFunctions::SplitMultiple(datestring,"-/\\., :",tokens);\r
+\r
+       // loop through 1st time to try to find 4 digit year and month (if it is a text month)\r
+       vecpos=0;\r
+       for(std::vector<std::string>::iterator i=tokens.begin(); i!=tokens.end(); i++,vecpos++)\r
+       {\r
+               StringFunctions::UpperCase((*i),(*i));\r
+\r
+               if((*i).find("JAN")==0)\r
+               {\r
+                       SetMonth(1);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("FEB")==0)\r
+               {\r
+                       SetMonth(2);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("MAR")==0)\r
+               {\r
+                       SetMonth(3);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("APR")==0)\r
+               {\r
+                       SetMonth(4);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("MAY")==0)\r
+               {\r
+                       SetMonth(5);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("JUN")==0)\r
+               {\r
+                       SetMonth(6);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("JUL")==0)\r
+               {\r
+                       SetMonth(7);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("AUG")==0)\r
+               {\r
+                       SetMonth(8);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("SEP")==0)\r
+               {\r
+                       SetMonth(9);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("OCT")==0)\r
+               {\r
+                       SetMonth(10);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("NOV")==0)\r
+               {\r
+                       SetMonth(11);\r
+                       month=vecpos;\r
+               }\r
+               if((*i).find("DEC")==0)\r
+               {\r
+                       SetMonth(12);\r
+                       month=vecpos;\r
+               }\r
+\r
+               // if we just got month - day is probaby in the next position\r
+               if(month==vecpos && vecpos+1<tokens.size() && tokens[vecpos+1].size()>0)\r
+               {\r
+                       tempint=-1;\r
+                       StringFunctions::Convert(tokens[vecpos+1],tempint);\r
+                       if(tempint>0 && tempint<32)\r
+                       {\r
+                               SetDay(tempint);\r
+                               day=vecpos+1;\r
+                       }\r
+               }\r
+\r
+               // if this is not month or day, and the size is 4 then it is probably the year\r
+               if(month!=vecpos && day!=vecpos && (*i).size()==4)\r
+               {\r
+                       tempint=-1;\r
+                       StringFunctions::Convert((*i),tempint);\r
+\r
+                       SetYear(tempint);\r
+                       year=vecpos;\r
+               }\r
+       }\r
+\r
+       // month is probably right after year\r
+       if(year!=-1 && month==-1 && year+1<tokens.size())\r
+       {\r
+               tempint=-1;\r
+               StringFunctions::Convert(tokens[year+1],tempint);\r
+               if(tempint>=1 && tempint<=12)\r
+               {\r
+                       SetMonth(tempint);\r
+                       month=year+1;\r
+               }\r
+       }\r
+\r
+       // otherwise it is probably 2 steps back (m/d/y)\r
+       if(year!=-1 && month==-1 && year-2>=0)\r
+       {\r
+               tempint=-1;\r
+               StringFunctions::Convert(tokens[year-2],tempint);\r
+               if(tempint>=1 && tempint<=12)\r
+               {\r
+                       SetMonth(tempint);\r
+                       month=year-2;\r
+               }\r
+       }\r
+\r
+       // day is probably right after month\r
+       if(month!=-1 && month+1<tokens.size())\r
+       {\r
+               tempint=-1;\r
+               StringFunctions::Convert(tokens[month+1],tempint);\r
+               if(tempint>=1 && tempint<32)\r
+               {\r
+                       SetDay(tempint);\r
+                       day=month+1;\r
+               }\r
+       }\r
+\r
+       // loop through another time to find hour\r
+       vecpos=0;\r
+       for(std::vector<std::string>::iterator i=tokens.begin(); i!=tokens.end(); i++,vecpos++)\r
+       {\r
+               if(vecpos!=year && vecpos!=month && vecpos!=day && hour==-1)\r
+               {\r
+                       tempint=-1;\r
+                       StringFunctions::Convert((*i),tempint);\r
+                       if(tempint>=0 && tempint<24)\r
+                       {\r
+                               SetHour(tempint);\r
+                               hour=vecpos;\r
+                       }\r
+               }\r
+       }\r
+\r
+       // minute right after hour\r
+       if(hour!=-1 && hour+1<tokens.size())\r
+       {\r
+               tempint=-1;\r
+               StringFunctions::Convert(tokens[hour+1],tempint);\r
+               if(tempint>=0 && tempint<60)\r
+               {\r
+                       SetMinute(tempint);\r
+                       minute=hour+1;\r
+               }\r
+       }\r
+\r
+       //second right after minute\r
+       if(minute!=-1 && minute+1<tokens.size())\r
+       {\r
+               tempint=-1;\r
+               StringFunctions::Convert(tokens[minute+1],tempint);\r
+               if(tempint>=0 && tempint<60)\r
+               {\r
+                       SetSecond(tempint);\r
+                       second=minute+1;\r
+               }\r
+       }\r
+\r
+}\r
+\r
+void DateTime::SetToGMTime()\r
+{\r
+       m_timet=time(NULL);\r
+\r
+       m_tm=*gmtime(&m_timet);\r
+       Normalize();\r
+}\r
+\r
+void DateTime::SetToLocalTime()\r
+{\r
+       m_timet=time(NULL);\r
+       m_tm=*localtime(&m_timet);\r
+       Normalize();\r
+}\r
diff --git a/src/db/sqlite3db.cpp b/src/db/sqlite3db.cpp
new file mode 100644 (file)
index 0000000..809fc68
--- /dev/null
@@ -0,0 +1,206 @@
+#include "../../include/db/sqlite3db.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+namespace SQLite3DB\r
+{\r
+\r
+DB::DB()\r
+{\r
+       Initialize();\r
+}\r
+\r
+DB::DB(std::string filename)\r
+{\r
+       Initialize();\r
+       Open(filename);\r
+}\r
+\r
+DB::~DB()\r
+{\r
+       if(IsOpen())\r
+       {\r
+               Close();        \r
+       }\r
+}\r
+\r
+const bool DB::Close()\r
+{\r
+       if(IsOpen())\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_mutex);\r
+               m_lastresult=sqlite3_close(m_db);\r
+               if(m_lastresult==SQLITE_OK)\r
+               {\r
+                       m_db=NULL;\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;   \r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;   \r
+       }\r
+}\r
+\r
+const bool DB::Execute(const std::string &sql)\r
+{\r
+       if(IsOpen())\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_mutex);\r
+               m_lastresult=sqlite3_exec(m_db,sql.c_str(),NULL,NULL,NULL);\r
+               if(m_lastresult==SQLITE_OK)\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;   \r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool DB::ExecuteInsert(const std::string &sql, long &insertid)\r
+{\r
+       if(IsOpen())\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_mutex);\r
+               m_lastresult=sqlite3_exec(m_db,sql.c_str(),NULL,NULL,NULL);\r
+               if(m_lastresult==SQLITE_OK)\r
+               {\r
+                       insertid=sqlite3_last_insert_rowid(m_db);\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;   \r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const int DB::GetLastError(std::string &errormessage)\r
+{\r
+       if(IsOpen())\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_mutex);\r
+               int errcode=sqlite3_errcode(m_db);\r
+               const char *errmsg=sqlite3_errmsg(m_db);\r
+               if(errmsg)\r
+               {\r
+                       errormessage=errmsg;\r
+               }\r
+               return errcode;\r
+       }\r
+       else\r
+       {\r
+               return SQLITE_OK;       \r
+       }\r
+}\r
+\r
+void DB::Initialize()\r
+{\r
+       m_db=NULL;\r
+       m_lastresult=SQLITE_OK;\r
+}\r
+\r
+const bool DB::IsOpen()\r
+{\r
+       ZThread::Guard<ZThread::Mutex> g(m_mutex);\r
+       return m_db ? true : false; \r
+}\r
+\r
+const bool DB::Open(const std::string &filename)\r
+{\r
+       if(IsOpen()==false)\r
+       {\r
+               Close();        \r
+       }\r
+       if(IsOpen()==false)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_mutex);\r
+               m_lastresult=sqlite3_open(filename.c_str(),&m_db);\r
+               if(m_lastresult==SQLITE_OK)\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;   \r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;   \r
+       }\r
+}\r
+\r
+Statement DB::Prepare(const std::string &sql)\r
+{\r
+       if(IsOpen())\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_mutex);\r
+               sqlite3_stmt *statement=NULL;\r
+               m_lastresult=sqlite3_prepare_v2(m_db,sql.c_str(),sql.size(),&statement,NULL);\r
+               if(m_lastresult==SQLITE_OK)\r
+               {\r
+                       return Statement(statement);\r
+               }\r
+               else\r
+               {\r
+                       return Statement();\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return Statement();\r
+       }\r
+}\r
+\r
+Recordset DB::Query(const std::string &sql)\r
+{\r
+       if(IsOpen())\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_mutex);\r
+               char **rs=NULL;\r
+               int rows,cols;\r
+               m_lastresult=sqlite3_get_table(m_db,sql.c_str(),&rs,&rows,&cols,NULL);\r
+               if(m_lastresult==SQLITE_OK)\r
+               {\r
+                       return Recordset(rs,rows,cols);\r
+               }\r
+               else\r
+               {\r
+                       sqlite3_free_table(rs);\r
+                       return Recordset();\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return Recordset();\r
+       }\r
+}\r
+\r
+const int DB::SetBusyTimeout(const int ms)\r
+{\r
+       if(IsOpen())\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_mutex);\r
+               m_lastresult=sqlite3_busy_timeout(m_db,ms);\r
+               return m_lastresult;\r
+       }\r
+}\r
+\r
+}      // namespace\r
diff --git a/src/db/sqlite3recordset.cpp b/src/db/sqlite3recordset.cpp
new file mode 100644 (file)
index 0000000..e9cdf5f
--- /dev/null
@@ -0,0 +1,85 @@
+#include "../../include/db/sqlite3db/sqlite3recordset.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+namespace SQLite3DB\r
+{\r
+\r
+Recordset::Recordset()\r
+{\r
+       m_rs=NULL;\r
+       m_rows=0;\r
+       m_cols=0;\r
+       m_currentrow=0;\r
+}\r
+\r
+Recordset::Recordset(char **rs, int rows, int cols)\r
+{\r
+       m_rs=rs;\r
+       m_rows=rows;\r
+       m_cols=cols;\r
+       m_currentrow=0;\r
+}\r
+\r
+Recordset::~Recordset()\r
+{\r
+       Free();\r
+}\r
+\r
+const char *Recordset::Get(const int row, const int field)\r
+{\r
+       if(row>=0 && row<m_rows && field>=0 && field<m_cols)\r
+       {\r
+               return m_rs[m_cols+(m_cols*row)+field];\r
+       }\r
+       else\r
+       {\r
+               return NULL;\r
+       }\r
+}\r
+\r
+const double Recordset::GetDouble(const int field)\r
+{\r
+       const char *result=GetField(field);\r
+       if(result)\r
+       {\r
+               return atof(result);\r
+       }\r
+       else\r
+       {\r
+               return 0;\r
+       }\r
+}\r
+\r
+const char *Recordset::GetField(const int field)\r
+{\r
+       return Get(m_currentrow,field);\r
+}\r
+\r
+const int Recordset::GetInt(const int field)\r
+{\r
+       const char *result=GetField(field);\r
+       if(result)\r
+       {\r
+               return atoi(result);\r
+       }\r
+       else\r
+       {\r
+               return 0;\r
+       }\r
+}\r
+\r
+void Recordset::Open(const std::string &sql, DB *db)\r
+{\r
+       Free();\r
+       m_currentrow=0;\r
+\r
+       ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+       if(sqlite3_get_table(db->GetDB(),sql.c_str(),&m_rs,&m_rows,&m_cols,NULL)==SQLITE_OK)\r
+       {\r
+       }\r
+}\r
+\r
+}      // namespace\r
diff --git a/src/db/sqlite3statement.cpp b/src/db/sqlite3statement.cpp
new file mode 100644 (file)
index 0000000..edb2f60
--- /dev/null
@@ -0,0 +1,337 @@
+#include "../../include/db/sqlite3db/sqlite3statement.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+namespace SQLite3DB\r
+{\r
+\r
+std::map<sqlite3_stmt *, long> Statement::m_statementcount;\r
+\r
+Statement::Statement()\r
+{\r
+       m_statement=NULL;\r
+       m_parametercount=0;\r
+       m_resultcolumncount=0;\r
+       m_rowreturned=false;\r
+}\r
+\r
+Statement::Statement(sqlite3_stmt *statement)\r
+{\r
+       m_statement=statement;\r
+       m_parametercount=sqlite3_bind_parameter_count(m_statement);\r
+       m_resultcolumncount=sqlite3_column_count(m_statement);\r
+       m_rowreturned=false;\r
+       \r
+       if(m_statement)\r
+       {\r
+               m_statementcount[m_statement]++;\r
+       }\r
+}\r
+\r
+Statement::Statement(Statement &rhs)\r
+{\r
+       m_statement=NULL;\r
+       m_parametercount=0;\r
+       m_resultcolumncount=0;\r
+       m_rowreturned=false;\r
+       *this=rhs;\r
+}\r
+\r
+Statement::~Statement()\r
+{\r
+       \r
+       Finalize();\r
+       \r
+       std::vector<char *>::iterator i;\r
+       for(i=textptrs.begin(); i!=textptrs.end(); i++)\r
+       {\r
+               if((*i))\r
+               {\r
+                       delete [] (*i);\r
+               }\r
+       }\r
+}\r
+\r
+const bool Statement::Bind(const int column)\r
+{\r
+       if(Valid() && column>=0 && column<m_parametercount)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               if(sqlite3_bind_null(m_statement,column+1)==SQLITE_OK)\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool Statement::Bind(const int column, const int value)\r
+{\r
+       if(Valid() && column>=0 && column<m_parametercount)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               if(sqlite3_bind_int(m_statement,column+1,value)==SQLITE_OK)\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool Statement::Bind(const int column, const double value)\r
+{\r
+       if(Valid() && column>=0 && column<m_parametercount)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               if(sqlite3_bind_double(m_statement,column+1,value)==SQLITE_OK)\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }       \r
+}\r
+\r
+const bool Statement::Bind(const int column, const std::string &value)\r
+{\r
+       if(Valid() && column>=0 && column<m_parametercount)\r
+       {\r
+               char *text=new char[value.size()+1];\r
+               strncpy(text,value.c_str(),value.size());\r
+               text[value.size()]=NULL;\r
+               textptrs.push_back(text);\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               if(sqlite3_bind_text(m_statement,column+1,text,value.size(),NULL)==SQLITE_OK)\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }       \r
+}\r
+\r
+const bool Statement::Bind(const int column, const void *data, const int length)\r
+{\r
+       if(Valid() && column>=0 && column<m_parametercount)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               if(sqlite3_bind_blob(m_statement,column+1,data,length,NULL)==SQLITE_OK)\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+void Statement::Finalize()\r
+{\r
+       if(m_statement)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               m_statementcount[m_statement]--;\r
+               if(m_statementcount[m_statement]<=0)\r
+               {\r
+                       m_statementcount.erase(m_statement);\r
+                       sqlite3_finalize(m_statement);\r
+               }\r
+               m_statement=NULL;\r
+       }\r
+}\r
+\r
+Statement &Statement::operator=(const Statement &rhs)\r
+{\r
+       if(&rhs!=this)\r
+       {\r
+               Finalize();\r
+\r
+               m_statement=rhs.m_statement;\r
+               m_parametercount=rhs.m_parametercount;\r
+               m_resultcolumncount=rhs.m_resultcolumncount;\r
+               m_rowreturned=rhs.m_rowreturned;\r
+\r
+               if(m_statement)\r
+               {\r
+                       ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+                       m_statementcount[m_statement]++;\r
+               }\r
+       }\r
+       return *this;\r
+}\r
+\r
+const bool Statement::Reset()\r
+{\r
+       if(Valid())\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               if(sqlite3_reset(m_statement)==SQLITE_OK)\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool Statement::ResultBlob(const int column, void *data, int &length)\r
+{\r
+       if(Valid() && column>=0 && column<m_resultcolumncount)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               data=(void *)sqlite3_column_blob(m_statement,column);\r
+               length=sqlite3_column_bytes(m_statement,column);\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool Statement::ResultDouble(const int column, double &result)\r
+{\r
+       if(Valid() && column>=0 && column<m_resultcolumncount)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               result=sqlite3_column_double(m_statement,column);\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool Statement::ResultInt(const int column, int &result)\r
+{\r
+       if(Valid() && column>=0 && column<m_resultcolumncount)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               result=sqlite3_column_int(m_statement,column);\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool Statement::ResultNull(const int column)\r
+{\r
+       if(Valid() && column>=0 && column<m_resultcolumncount)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               if(sqlite3_column_type(m_statement,column)==SQLITE_NULL)\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool Statement::ResultText(const int column, std::string &result)\r
+{\r
+       if(Valid() && column>=0 && column<m_resultcolumncount)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               const unsigned char *cresult=sqlite3_column_text(m_statement,column);\r
+               if(cresult)\r
+               {\r
+                       result=(char *)cresult;\r
+               }\r
+               else\r
+               {\r
+                       result="";\r
+               }\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool Statement::Step(const bool saveinsertrowid)\r
+{\r
+       m_rowreturned=false;\r
+       if(Valid())\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+               int result=sqlite3_step(m_statement);\r
+               if(result==SQLITE_OK || result==SQLITE_ROW || result==SQLITE_DONE)\r
+               {\r
+                       if(result==SQLITE_ROW)\r
+                       {\r
+                               m_rowreturned=true;\r
+                       }\r
+                       if(saveinsertrowid)\r
+                       {\r
+                               m_lastinsertrowid=sqlite3_last_insert_rowid(DB::instance()->GetDB());\r
+                       }\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool Statement::Valid()\r
+{\r
+       ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
+       return m_statement ? true : false ;\r
+}\r
+\r
+}      // namespace\r
diff --git a/src/freenet/captcha/easybmp/EasyBMP.cpp b/src/freenet/captcha/easybmp/EasyBMP.cpp
new file mode 100644 (file)
index 0000000..3bdd814
--- /dev/null
@@ -0,0 +1,1905 @@
+/*************************************************
+*                                                *
+*  EasyBMP Cross-Platform Windows Bitmap Library * 
+*                                                *
+*  Author: Paul Macklin                          *
+*   email: macklin01@users.sourceforge.net       *
+* support: http://easybmp.sourceforge.net        *
+*                                                *
+*          file: EasyBMP.cpp                     * 
+*    date added: 03-31-2006                      *
+* date modified: 12-01-2006                      *
+*       version: 1.06                            *
+*                                                *
+*   License: BSD (revised/modified)              *
+* Copyright: 2005-6 by the EasyBMP Project       * 
+*                                                *
+* description: Actual source file                *
+*                                                *
+*************************************************/\r
+\r
+#include "../../../../include/freenet/captcha/easybmp/EasyBMP.h"\r
+
+/* These functions are defined in EasyBMP.h */
+
+bool EasyBMPwarnings = true;
+
+void SetEasyBMPwarningsOff( void )
+{ EasyBMPwarnings = false; }
+void SetEasyBMPwarningsOn( void )
+{ EasyBMPwarnings = true; }
+bool GetEasyBMPwarningState( void )
+{ return EasyBMPwarnings; }
+
+/* These functions are defined in EasyBMP_DataStructures.h */\r
+\r
+int IntPow( int base, int exponent )
+{
+ int i;
+ int output = 1;
+ for( i=0 ; i < exponent ; i++ )
+ { output *= base; }
+ return output;
+}\r
+\r
+BMFH::BMFH()
+{
+ bfType = 19778;
+ bfReserved1 = 0;
+ bfReserved2 = 0;
+}\r
+\r
+void BMFH::SwitchEndianess( void )
+{
+ bfType = FlipWORD( bfType );
+ bfSize = FlipDWORD( bfSize );
+ bfReserved1 = FlipWORD( bfReserved1 );
+ bfReserved2 = FlipWORD( bfReserved2 );
+ bfOffBits = FlipDWORD( bfOffBits );
+ return;
+}
+\r
+BMIH::BMIH()
+{\r
+ biPlanes = 1;
+ biCompression = 0;
+ biXPelsPerMeter = DefaultXPelsPerMeter;  
+ biYPelsPerMeter = DefaultYPelsPerMeter;
+ biClrUsed = 0;
+ biClrImportant = 0;
+}
+
+void BMIH::SwitchEndianess( void )
+{
+ biSize = FlipDWORD( biSize );
+ biWidth = FlipDWORD( biWidth );
+ biHeight = FlipDWORD( biHeight );
+ biPlanes = FlipWORD( biPlanes );
+ biBitCount = FlipWORD( biBitCount );
+ biCompression = FlipDWORD( biCompression );
+ biSizeImage = FlipDWORD( biSizeImage );
+ biXPelsPerMeter = FlipDWORD( biXPelsPerMeter );
+ biYPelsPerMeter = FlipDWORD( biYPelsPerMeter );
+ biClrUsed = FlipDWORD( biClrUsed );
+ biClrImportant = FlipDWORD( biClrImportant );
+ return;
+}
+
+void BMIH::display( void )
+{
+ using namespace std;
+ cout << "biSize: " << (int) biSize << endl
+      << "biWidth: " << (int) biWidth << endl
+      << "biHeight: " << (int) biHeight << endl
+      << "biPlanes: " << (int) biPlanes << endl
+      << "biBitCount: " << (int) biBitCount << endl
+      << "biCompression: " << (int) biCompression << endl
+      << "biSizeImage: " << (int) biSizeImage << endl
+      << "biXPelsPerMeter: " << (int) biXPelsPerMeter << endl
+      << "biYPelsPerMeter: " << (int) biYPelsPerMeter << endl
+      << "biClrUsed: " << (int) biClrUsed << endl
+      << "biClrImportant: " << (int) biClrImportant << endl << endl;
+}
+
+void BMFH::display( void )
+{
+ using namespace std;
+ cout << "bfType: " << (int) bfType << endl
+      << "bfSize: " << (int) bfSize << endl
+      << "bfReserved1: " << (int) bfReserved1 << endl
+      << "bfReserved2: " << (int) bfReserved2 << endl
+      << "bfOffBits: " << (int) bfOffBits << endl << endl;
+}
+\r
+/* These functions are defined in EasyBMP_BMP.h */
+
+RGBApixel BMP::GetPixel( int i, int j ) const
+{
+ using namespace std;
+ bool Warn = false;
+ if( i >= Width )\r
+ { i = Width-1; Warn = true; }
+ if( i < 0 )\r
+ { i = 0; Warn = true; }
+ if( j >= Height )\r
+ { j = Height-1; Warn = true; }
+ if( j < 0 )\r
+ { j = 0; Warn = true; }
+ if( Warn && EasyBMPwarnings )
+ {
+  cout << "EasyBMP Warning: Attempted to access non-existent pixel;" << endl
+       << "                 Truncating request to fit in the range [0,"
+       << Width-1 << "] x [0," << Height-1 << "]." << endl;
+ }     
+ return Pixels[i][j];
+}
+
+bool BMP::SetPixel( int i, int j, RGBApixel NewPixel )
+{
+ Pixels[i][j] = NewPixel;
+ return true;
+}
+\r
+\r
+bool BMP::SetColor( int ColorNumber , RGBApixel NewColor )
+{
+ using namespace std;
+ if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: Attempted to change color table for a BMP object" << endl
+        << "                 that lacks a color table. Ignoring request." << endl;
+  }
+  return false;
+ }
+ if( !Colors )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: Attempted to set a color, but the color table" << endl
+        << "                 is not defined. Ignoring request." << endl; 
+  }
+  return false; 
+ }
+ if( ColorNumber >= TellNumberOfColors() )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: Requested color number " 
+        << ColorNumber << " is outside the allowed" << endl
+        << "                 range [0," << TellNumberOfColors()-1 
+           << "]. Ignoring request to set this color." << endl;
+  }
+  return false;
+ }
+ Colors[ColorNumber] = NewColor;
+ return true;
+}
+
+// RGBApixel BMP::GetColor( int ColorNumber ) const
+RGBApixel BMP::GetColor( int ColorNumber )
+{ 
+ RGBApixel Output;
+ Output.Red   = 255;
+ Output.Green = 255;
+ Output.Blue  = 255;
+ Output.Alpha = 0;
+ using namespace std;
+ if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: Attempted to access color table for a BMP object" << endl
+        << "                 that lacks a color table. Ignoring request." << endl;
+  }
+  return Output;
+ }
+ if( !Colors )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: Requested a color, but the color table" << endl
+        << "                 is not defined. Ignoring request." << endl;
+  }
+  return Output; 
+ }
+ if( ColorNumber >= TellNumberOfColors() )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: Requested color number " 
+        << ColorNumber << " is outside the allowed" << endl
+        << "                 range [0," << TellNumberOfColors()-1 
+           << "]. Ignoring request to get this color." << endl;
+  }
+  return Output;
+ }
+ Output = Colors[ColorNumber];
+ return Output;
+}
+
+BMP::BMP()
+{
+ Width = 1;
+ Height = 1;
+ BitDepth = 24;
+ Pixels = new RGBApixel* [Width];
+ Pixels[0] = new RGBApixel [Height];
+ Colors = NULL;\r
\r
+ XPelsPerMeter = 0;\r
+ YPelsPerMeter = 0;
+ MetaData1 = NULL;
+ SizeOfMetaData1 = 0;
+ MetaData2 = NULL;
+ SizeOfMetaData2 = 0;
+}
+
+// BMP::BMP( const BMP& Input )
+BMP::BMP( BMP& Input )
+{
+ // first, make the image empty.
+
+ Width = 1;
+ Height = 1;
+ BitDepth = 24;
+ Pixels = new RGBApixel* [Width];
+ Pixels[0] = new RGBApixel [Height];
+ Colors = NULL; 
+ XPelsPerMeter = 0;\r
+ YPelsPerMeter = 0;
+ MetaData1 = NULL;
+ SizeOfMetaData1 = 0;
+ MetaData2 = NULL;
+ SizeOfMetaData2 = 0;
+
+ // now, set the correct bit depth
+ SetBitDepth( Input.TellBitDepth() );
+ // set the correct pixel size 
+ SetSize( Input.TellWidth() , Input.TellHeight() );
+
+ // set the DPI information from Input
+ SetDPI( Input.TellHorizontalDPI() , Input.TellVerticalDPI() );
+ // if there is a color table, get all the colors
+
+ if( BitDepth == 1 || BitDepth == 4 ||  
+     BitDepth == 8 )
+ {
+  for( int k=0 ; k < TellNumberOfColors() ; k++ )
+  {
+   SetColor( k, Input.GetColor( k )); 
+  }
+ }
+ // get all the pixels 
+ for( int j=0; j < Height ; j++ )
+ {
+  for( int i=0; i < Width ; i++ )
+  {
+   Pixels[i][j] = *Input(i,j);
+//   Pixels[i][j] = Input.GetPixel(i,j); // *Input(i,j);
+  }
+ }
+}
+
+BMP::~BMP()
+{
+ int i;
+ for(i=0;i<Width;i++)
+ { delete [] Pixels[i]; }
+ delete [] Pixels;
+ if( Colors )
+ { delete [] Colors; }
+ if( MetaData1 )
+ { delete [] MetaData1; }
+ if( MetaData2 )
+ { delete [] MetaData2; }
+} 
+
+RGBApixel* BMP::operator()(int i, int j)
+{
+ using namespace std;
+ bool Warn = false;
+ if( i >= Width )\r
+ { i = Width-1; Warn = true; }
+ if( i < 0 )\r
+ { i = 0; Warn = true; }
+ if( j >= Height )\r
+ { j = Height-1; Warn = true; }
+ if( j < 0 )\r
+ { j = 0; Warn = true; }
+ if( Warn && EasyBMPwarnings )
+ {
+  cout << "EasyBMP Warning: Attempted to access non-existent pixel;" << endl
+       << "                 Truncating request to fit in the range [0,"
+       << Width-1 << "] x [0," << Height-1 << "]." << endl;
+ }     
+ return &(Pixels[i][j]);
+}
+
+// int BMP::TellBitDepth( void ) const
+int BMP::TellBitDepth( void )
+{ return BitDepth; }
+
+// int BMP::TellHeight( void ) const
+int BMP::TellHeight( void )
+{ return Height; }
+
+// int BMP::TellWidth( void ) const
+int BMP::TellWidth( void )
+{ return Width; }
+
+// int BMP::TellNumberOfColors( void ) const
+int BMP::TellNumberOfColors( void )
+{
+ int output = IntPow( 2, BitDepth );
+ if( BitDepth == 32 )
+ { output = IntPow( 2, 24 ); }
+ return output;
+}
+
+bool BMP::SetBitDepth( int NewDepth )
+{
+ using namespace std;
+ if( NewDepth != 1 && NewDepth != 4 && 
+     NewDepth != 8 && NewDepth != 16 && 
+     NewDepth != 24 && NewDepth != 32 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: User attempted to set unsupported bit depth " 
+        << NewDepth << "." << endl
+        << "                 Bit depth remains unchanged at " 
+           << BitDepth << "." << endl;
+  }
+  return false;
+ }
+ BitDepth = NewDepth;
+ if( Colors )
+ { delete [] Colors; }
+ int NumberOfColors = IntPow( 2, BitDepth );
+ if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
+ { Colors = new RGBApixel [NumberOfColors]; }
+ else
+ { Colors = NULL; } 
+ if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
+ { CreateStandardColorTable(); }
+ return true;
+}
+
+bool BMP::SetSize(int NewWidth , int NewHeight )
+{
+ using namespace std;
+ if( NewWidth <= 0 || NewHeight <= 0 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: User attempted to set a non-positive width or height." << endl
+        << "                 Size remains unchanged at " 
+        << Width << " x " << Height << "." << endl;
+  }
+  return false;
+ }
+
+ int i,j; 
+
+ for(i=0;i<Width;i++)
+ { delete [] Pixels[i]; }
+ delete [] Pixels;
+
+ Width = NewWidth;
+ Height = NewHeight;
+ Pixels = new RGBApixel* [ Width ]; 
+ for(i=0; i<Width; i++)
+ { Pixels[i] = new RGBApixel [ Height ]; }
+ for( i=0 ; i < Width ; i++)
+ {
+  for( j=0 ; j < Height ; j++ )
+  {
+   Pixels[i][j].Red = 255; 
+   Pixels[i][j].Green = 255; 
+   Pixels[i][j].Blue = 255; 
+   Pixels[i][j].Alpha = 0;    
+  }
+ }
+
+ return true; 
+}
+
+bool BMP::WriteToFile( const char* FileName )
+{
+ using namespace std;
+ if( !EasyBMPcheckDataSize() )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: Data types are wrong size!" << endl
+        << "               You may need to mess with EasyBMP_DataTypes.h" << endl
+           << "               to fix these errors, and then recompile." << endl
+           << "               All 32-bit and 64-bit machines should be" << endl
+           << "               supported, however." << endl << endl;
+  }
+  return false; 
+ }
+ FILE* fp = fopen( FileName, "wb" );
+ if( fp == NULL )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: Cannot open file " 
+        << FileName << " for output." << endl;
+  }
+  fclose( fp );
+  return false;
+ }
+  
+ // some preliminaries
+ double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
+ double dBytesPerRow = dBytesPerPixel * (Width+0.0);
+ dBytesPerRow = ceil(dBytesPerRow);
+  
+ int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
+ if( BytePaddingPerRow == 4 )
+ { BytePaddingPerRow = 0; } 
+ double dActualBytesPerRow = dBytesPerRow + BytePaddingPerRow;
+ double dTotalPixelBytes = Height * dActualBytesPerRow;
+ double dPaletteSize = 0;
+ if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
+ { dPaletteSize = IntPow(2,BitDepth)*4.0; }
+
+ // leave some room for 16-bit masks 
+ if( BitDepth == 16 )
+ { dPaletteSize = 3*4; }
+ double dTotalFileSize = 14 + 40 + dPaletteSize + dTotalPixelBytes;
+ // write the file header 
+ BMFH bmfh;
+ bmfh.bfSize = (ebmpDWORD) dTotalFileSize; 
+ bmfh.bfReserved1 = 0; 
+ bmfh.bfReserved2 = 0; 
+ bmfh.bfOffBits = (ebmpDWORD) (14+40+dPaletteSize);  
+ if( IsBigEndian() )
+ { bmfh.SwitchEndianess(); }
+ fwrite( (char*) &(bmfh.bfType) , sizeof(ebmpWORD) , 1 , fp );
+ fwrite( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1 , fp );
+ fwrite( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1 , fp );
+ fwrite( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1 , fp );
+ fwrite( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp );
+ // write the info header 
+ BMIH bmih;
+ bmih.biSize = 40;
+ bmih.biWidth = Width;
+ bmih.biHeight = Height;
+ bmih.biPlanes = 1;
+ bmih.biBitCount = BitDepth;
+ bmih.biCompression = 0;
+ bmih.biSizeImage = (ebmpDWORD) dTotalPixelBytes;
+ if( XPelsPerMeter )
+ { bmih.biXPelsPerMeter = XPelsPerMeter; }
+ else
+ { bmih.biXPelsPerMeter = DefaultXPelsPerMeter; }
+ if( YPelsPerMeter )
+ { bmih.biYPelsPerMeter = YPelsPerMeter; }
+ else
+ { bmih.biYPelsPerMeter = DefaultYPelsPerMeter; }
+
+ bmih.biClrUsed = 0;
+ bmih.biClrImportant = 0;
+
+ // indicates that we'll be using bit fields for 16-bit files
+ if( BitDepth == 16 )
+ { bmih.biCompression = 3; }
+ if( IsBigEndian() )
+ { bmih.SwitchEndianess(); }
+ fwrite( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp );
+ fwrite( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp );
+ fwrite( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp );
+ fwrite( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1 , fp );
+ fwrite( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1 , fp );
+ fwrite( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp );
+ fwrite( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp );
+ fwrite( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
+ fwrite( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp ); 
+ fwrite( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
+ fwrite( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
+ // write the palette 
+ if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
+ {
+  int NumberOfColors = IntPow(2,BitDepth);
+  
+  // if there is no palette, create one 
+  if( !Colors )
+  {
+   if( !Colors )
+   { Colors = new RGBApixel [NumberOfColors]; }
+   CreateStandardColorTable(); 
+  }
+   
+  int n;
+  for( n=0 ; n < NumberOfColors ; n++ )
+  { fwrite( (char*) &(Colors[n]) , 4 , 1 , fp ); }
+ }
+ // write the pixels 
+ int i,j;
+ if( BitDepth != 16 )
+ {  
+  ebmpBYTE* Buffer;
+  int BufferSize = (int) ( (Width*BitDepth)/8.0 );
+  while( 8*BufferSize < Width*BitDepth )
+  { BufferSize++; }
+  while( BufferSize % 4 )
+  { BufferSize++; }
+  
+  Buffer = new ebmpBYTE [BufferSize];
+  for( j=0 ; j < BufferSize; j++ )
+  { Buffer[j] = 0; }
+    
+  j=Height-1;
+  
+  while( j > -1 )
+  {
+   bool Success = false;
+   if( BitDepth == 32 )
+   { Success = Write32bitRow( Buffer, BufferSize, j ); }
+   if( BitDepth == 24 )
+   { Success = Write24bitRow( Buffer, BufferSize, j ); }
+   if( BitDepth == 8  )
+   { Success = Write8bitRow( Buffer, BufferSize, j ); }
+   if( BitDepth == 4  )
+   { Success = Write4bitRow( Buffer, BufferSize, j ); }
+   if( BitDepth == 1  )
+   { Success = Write1bitRow( Buffer, BufferSize, j ); }
+   if( Success )
+   {
+    int BytesWritten = (int) fwrite( (char*) Buffer, 1, BufferSize, fp );
+    if( BytesWritten != BufferSize )
+    { Success = false; }
+   }
+   if( !Success )
+   {
+    if( EasyBMPwarnings )
+    {
+     cout << "EasyBMP Error: Could not write proper amount of data." << endl;
+       }
+    j = -1; 
+   }
+   j--; 
+  }
+  
+  delete [] Buffer;
+ }
+ if( BitDepth == 16 )
+ {
+  // write the bit masks
+
+  ebmpWORD BlueMask = 31;    // bits 12-16
+  ebmpWORD GreenMask = 2016; // bits 6-11
+  ebmpWORD RedMask = 63488;  // bits 1-5
+  ebmpWORD ZeroWORD;
+  
+  if( IsBigEndian() )
+  { RedMask = FlipWORD( RedMask ); }
+  fwrite( (char*) &RedMask , 2 , 1 , fp );
+  fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
+
+  if( IsBigEndian() )
+  { GreenMask = FlipWORD( GreenMask ); }
+  fwrite( (char*) &GreenMask , 2 , 1 , fp );
+  fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
+
+  if( IsBigEndian() )
+  { BlueMask = FlipWORD( BlueMask ); }
+  fwrite( (char*) &BlueMask , 2 , 1 , fp );
+  fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
+
+  int DataBytes = Width*2;
+  int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;
+  
+  // write the actual pixels
+  
+  for( j=Height-1 ; j >= 0 ; j-- )
+  {
+   // write all row pixel data
+   i=0;
+   int WriteNumber = 0;
+   while( WriteNumber < DataBytes )
+   {
+    ebmpWORD TempWORD;
+       
+       ebmpWORD RedWORD = (ebmpWORD) ((Pixels[i][j]).Red / 8);
+       ebmpWORD GreenWORD = (ebmpWORD) ((Pixels[i][j]).Green / 4);
+       ebmpWORD BlueWORD = (ebmpWORD) ((Pixels[i][j]).Blue / 8);
+       
+    TempWORD = (RedWORD<<11) + (GreenWORD<<5) + BlueWORD;
+       if( IsBigEndian() )
+       { TempWORD = FlipWORD( TempWORD ); }
+       
+    fwrite( (char*) &TempWORD , 2, 1, fp);
+    WriteNumber += 2;
+       i++;\r
+   }
+   // write any necessary row padding
+   WriteNumber = 0;
+   while( WriteNumber < PaddingBytes )
+   {
+    ebmpBYTE TempBYTE;
+    fwrite( (char*) &TempBYTE , 1, 1, fp);
+    WriteNumber++;
+   }
+  }
+  
+ }
+
+ fclose(fp);
+ return true;
+}
+
+bool BMP::ReadFromFile( const char* FileName )
+{ 
+ using namespace std;
+ if( !EasyBMPcheckDataSize() )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: Data types are wrong size!" << endl
+        << "               You may need to mess with EasyBMP_DataTypes.h" << endl
+           << "               to fix these errors, and then recompile." << endl
+           << "               All 32-bit and 64-bit machines should be" << endl
+           << "               supported, however." << endl << endl;
+  }
+  return false; 
+ }
+
+ FILE* fp = fopen( FileName, "rb" );
+ if( fp == NULL )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: Cannot open file " 
+        << FileName << " for input." << endl;
+  }
+  SetBitDepth(1);
+  SetSize(1,1);
+  return false;
+ }
+ // read the file header 
+ BMFH bmfh;
+ bool NotCorrupted = true;
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD), 1, fp);
+ bool IsBitmap = false;
+ if( IsBigEndian() && bmfh.bfType == 16973 )
+ { IsBitmap = true; }
+ if( !IsBigEndian() && bmfh.bfType == 19778 )
+ { IsBitmap = true; }
+ if( !IsBitmap ) 
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: " << FileName 
+        << " is not a Windows BMP file!" << endl; 
+  }
+  fclose( fp ); 
+  return false;
+ }
+
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1, fp); 
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1, fp);
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1, fp);
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp);
+ if( IsBigEndian() ) 
+ { bmfh.SwitchEndianess(); }
+  
+ // read the info header
+
+ BMIH bmih; 
+ NotCorrupted &= SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp); 
+ NotCorrupted &= SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1, fp); 
+ NotCorrupted &= SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1, fp);
+
+ NotCorrupted &= SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
+ if( IsBigEndian() ) 
+ { bmih.SwitchEndianess(); }
+
+ // a safety catch: if any of the header information didn't read properly, abort
+ // future idea: check to see if at least most is self-consistent
+  
+ if( !NotCorrupted )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: " << FileName 
+        << " is obviously corrupted." << endl;
+  }
+  SetSize(1,1);
+  SetBitDepth(1);
+  fclose(fp);
+  return false;
+ } 
+ XPelsPerMeter = bmih.biXPelsPerMeter;
+ YPelsPerMeter = bmih.biYPelsPerMeter;
+ // if bmih.biCompression 1 or 2, then the file is RLE compressed
+ if( bmih.biCompression == 1 || bmih.biCompression == 2 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: " << FileName << " is (RLE) compressed." << endl
+        << "               EasyBMP does not support compression." << endl;
+  }
+  SetSize(1,1);
+  SetBitDepth(1);
+  fclose(fp);
+  return false; 
+ }
+ // if bmih.biCompression > 3, then something strange is going on 
+ // it's probably an OS2 bitmap file.
+ if( bmih.biCompression > 3 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: " << FileName << " is in an unsupported format." 
+        << endl
+        << "               (bmih.biCompression = " 
+           << bmih.biCompression << ")" << endl
+           << "               The file is probably an old OS2 bitmap or corrupted." 
+           << endl;
+  }            
+  SetSize(1,1);
+  SetBitDepth(1);
+  fclose(fp);
+  return false; 
+ }
+ if( bmih.biCompression == 3 && bmih.biBitCount != 16 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: " << FileName 
+        << " uses bit fields and is not a" << endl
+        << "               16-bit file. This is not supported." << endl;
+  }
+  SetSize(1,1);
+  SetBitDepth(1);
+  fclose(fp);
+  return false; 
+ }
+
+ // set the bit depth
+ int TempBitDepth = (int) bmih.biBitCount;
+ if(    TempBitDepth != 1  && TempBitDepth != 4 
+     && TempBitDepth != 8  && TempBitDepth != 16
+     && TempBitDepth != 24 && TempBitDepth != 32 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: " << FileName << " has unrecognized bit depth." << endl;
+  }
+  SetSize(1,1);
+  SetBitDepth(1);
+  fclose(fp);
+  return false;
+ }
+ SetBitDepth( (int) bmih.biBitCount ); 
+ // set the size
+
+ if( (int) bmih.biWidth <= 0 || (int) bmih.biHeight <= 0 ) 
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: " << FileName 
+        << " has a non-positive width or height." << endl;
+  }
+  SetSize(1,1);
+  SetBitDepth(1);
+  fclose(fp);
+  return false;
+ } 
+ SetSize( (int) bmih.biWidth , (int) bmih.biHeight );
+  
+ // some preliminaries
+ double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
+ double dBytesPerRow = dBytesPerPixel * (Width+0.0);
+ dBytesPerRow = ceil(dBytesPerRow);
+  
+ int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
+ if( BytePaddingPerRow == 4 )
+ { BytePaddingPerRow = 0; }  
+ // if < 16 bits, read the palette
+ if( BitDepth < 16 )
+ {
+  // determine the number of colors specified in the 
+  // color table
+  
+  int NumberOfColorsToRead = ((int) bmfh.bfOffBits - 54 )/4;  
+  if( NumberOfColorsToRead > IntPow(2,BitDepth) )
+  { NumberOfColorsToRead = IntPow(2,BitDepth); }
+  if( NumberOfColorsToRead < TellNumberOfColors() )
+  {
+   if( EasyBMPwarnings )
+   {
+    cout << "EasyBMP Warning: file " << FileName << " has an underspecified" << endl
+         << "                 color table. The table will be padded with extra" << endl
+                << "                 white (255,255,255,0) entries." << endl;
+   }
+  }
+  int n;
+  for( n=0; n < NumberOfColorsToRead ; n++ )
+  {
+   SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);     
+  }
+  for( n=NumberOfColorsToRead ; n < TellNumberOfColors() ; n++ )
+  {
+   RGBApixel WHITE; 
+   WHITE.Red = 255;
+   WHITE.Green = 255;
+   WHITE.Blue = 255;
+   WHITE.Alpha = 0;
+   SetColor( n , WHITE );
+  }
+  
+  
+ }
+ // skip blank data if bfOffBits so indicates
+ int BytesToSkip = bmfh.bfOffBits - 54;;
+ if( BitDepth < 16 )
+ { BytesToSkip -= 4*IntPow(2,BitDepth); }
+ if( BitDepth == 16 && bmih.biCompression == 3 )
+ { BytesToSkip -= 3*4; }
+ if( BytesToSkip < 0 )
+ { BytesToSkip = 0; }
+ if( BytesToSkip > 0 && BitDepth != 16 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: Extra meta data detected in file " << FileName << endl
+        << "                 Data will be skipped." << endl;
+  }
+  ebmpBYTE* TempSkipBYTE;
+  TempSkipBYTE = new ebmpBYTE [BytesToSkip];
+  SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);   \r
+  delete [] TempSkipBYTE;
+ } 
+  
+ // This code reads 1, 4, 8, 24, and 32-bpp files 
+ // with a more-efficient buffered technique.
+
+ int i,j;
+ if( BitDepth != 16 )
+ {
+  int BufferSize = (int) ( (Width*BitDepth) / 8.0 );
+  while( 8*BufferSize < Width*BitDepth )
+  { BufferSize++; }
+  while( BufferSize % 4 )
+  { BufferSize++; }
+  ebmpBYTE* Buffer;
+  Buffer = new ebmpBYTE [BufferSize];
+  j= Height-1;
+  while( j > -1 )
+  {
+   int BytesRead = (int) fread( (char*) Buffer, 1, BufferSize, fp );
+   if( BytesRead < BufferSize )
+   {
+    j = -1; 
+    if( EasyBMPwarnings )
+    {
+     cout << "EasyBMP Error: Could not read proper amount of data." << endl;
+       }
+   }
+   else
+   {
+    bool Success = false;
+    if( BitDepth == 1  )
+       { Success = Read1bitRow(  Buffer, BufferSize, j ); }
+    if( BitDepth == 4  )
+       { Success = Read4bitRow(  Buffer, BufferSize, j ); }
+    if( BitDepth == 8  )
+       { Success = Read8bitRow(  Buffer, BufferSize, j ); }
+    if( BitDepth == 24 )
+       { Success = Read24bitRow( Buffer, BufferSize, j ); }
+       if( BitDepth == 32 )
+       { Success = Read32bitRow( Buffer, BufferSize, j ); }
+    if( !Success )
+    {
+     if( EasyBMPwarnings )
+     {
+      cout << "EasyBMP Error: Could not read enough pixel data!" << endl;
+        }
+        j = -1;
+    }
+   }   
+   j--;
+  }
+  delete [] Buffer; 
+ }
+
+ if( BitDepth == 16 )
+ {
+  int DataBytes = Width*2;
+  int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;
+
+  // set the default mask
+  
+  ebmpWORD BlueMask = 31; // bits 12-16
+  ebmpWORD GreenMask = 992; // bits 7-11
+  ebmpWORD RedMask = 31744; // bits 2-6
+
+  // read the bit fields, if necessary, to 
+  // override the default 5-5-5 mask
+  
+  if( bmih.biCompression != 0 )
+  {
+   // read the three bit masks
+
+   ebmpWORD TempMaskWORD;
+   ebmpWORD ZeroWORD;
+  
+   SafeFread( (char*) &RedMask , 2 , 1 , fp );
+   if( IsBigEndian() )
+   { RedMask = FlipWORD(RedMask); }
+   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
+  
+   SafeFread( (char*) &GreenMask , 2 , 1 , fp );
+   if( IsBigEndian() )
+   { GreenMask = FlipWORD(GreenMask); }
+   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
+
+   SafeFread( (char*) &BlueMask , 2 , 1 , fp );
+   if( IsBigEndian() )
+   { BlueMask = FlipWORD(BlueMask); }
+   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
+  }
+  
+  // read and skip any meta data
+
+  if( BytesToSkip > 0 )
+  {
+   if( EasyBMPwarnings )
+   {
+    cout << "EasyBMP Warning: Extra meta data detected in file " 
+         << FileName << endl
+         << "                 Data will be skipped." << endl;
+   }
+   ebmpBYTE* TempSkipBYTE;
+   TempSkipBYTE = new ebmpBYTE [BytesToSkip];
+   SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);\r
+   delete [] TempSkipBYTE;   
+  } 
+  
+  // determine the red, green and blue shifts
+  
+  int GreenShift = 0; 
+  ebmpWORD TempShiftWORD = GreenMask;
+  while( TempShiftWORD > 31 )
+  { TempShiftWORD = TempShiftWORD>>1; GreenShift++; }  
+  int BlueShift = 0;
+  TempShiftWORD = BlueMask;
+  while( TempShiftWORD > 31 )
+  { TempShiftWORD = TempShiftWORD>>1; BlueShift++; }  
+  int RedShift = 0;  
+  TempShiftWORD = RedMask;
+  while( TempShiftWORD > 31 )
+  { TempShiftWORD = TempShiftWORD>>1; RedShift++; }  
+  
+  // read the actual pixels
+  
+  for( j=Height-1 ; j >= 0 ; j-- )
+  {
+   i=0;
+   int ReadNumber = 0;
+   while( ReadNumber < DataBytes )
+   {
+       ebmpWORD TempWORD;
+       SafeFread( (char*) &TempWORD , 2 , 1 , fp );
+       if( IsBigEndian() )
+       { TempWORD = FlipWORD(TempWORD); }
+    ReadNumber += 2;
+  
+    ebmpWORD Red = RedMask & TempWORD;
+    ebmpWORD Green = GreenMask & TempWORD;
+    ebmpWORD Blue = BlueMask & TempWORD;
+                               
+       ebmpBYTE BlueBYTE = (ebmpBYTE) 8*(Blue>>BlueShift);
+    ebmpBYTE GreenBYTE = (ebmpBYTE) 8*(Green>>GreenShift);
+    ebmpBYTE RedBYTE = (ebmpBYTE) 8*(Red>>RedShift);
+               
+       (Pixels[i][j]).Red = RedBYTE;
+       (Pixels[i][j]).Green = GreenBYTE;
+       (Pixels[i][j]).Blue = BlueBYTE;
+       
+       i++;
+   }
+   ReadNumber = 0;
+   while( ReadNumber < PaddingBytes )
+   {
+    ebmpBYTE TempBYTE;
+    SafeFread( (char*) &TempBYTE , 1, 1, fp);
+    ReadNumber++;
+   }
+  }
+
+ }
+ fclose(fp);
+ return true;
+}
+
+bool BMP::CreateStandardColorTable( void )
+{
+ using namespace std;
+ if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: Attempted to create color table at a bit" << endl
+        << "                 depth that does not require a color table." << endl
+       << "                 Ignoring request." << endl;
+  }
+  return false;
+ }
+
+ if( BitDepth == 1 )
+ {
+  int i;
+  for( i=0 ; i < 2 ; i++ )
+  {
+   Colors[i].Red = i*255;
+   Colors[i].Green = i*255;
+   Colors[i].Blue = i*255;
+   Colors[i].Alpha = 0;
+  } 
+  return true;
+ } 
+
+ if( BitDepth == 4 )
+ {
+  int i = 0;
+  int j,k,ell;
+  
+  // simplify the code for the first 8 colors
+  for( ell=0 ; ell < 2 ; ell++ )
+  {
+   for( k=0 ; k < 2 ; k++ )
+   {
+    for( j=0 ; j < 2 ; j++ )
+    {
+     Colors[i].Red = j*128; 
+        Colors[i].Green = k*128;
+        Colors[i].Blue = ell*128;
+        i++;
+    }
+   }
+  }
+  // simplify the code for the last 8 colors
+  for( ell=0 ; ell < 2 ; ell++ )
+  {
+   for( k=0 ; k < 2 ; k++ )
+   {
+    for( j=0 ; j < 2 ; j++ )
+    {
+     Colors[i].Red = j*255;
+     Colors[i].Green = k*255; 
+     Colors[i].Blue = ell*255;
+        i++;
+    }
+   }
+  }
+  // overwrite the duplicate color
+  i=8; 
+  Colors[i].Red = 192;
+  Colors[i].Green = 192;
+  Colors[i].Blue = 192;
+   
+  for( i=0 ; i < 16 ; i++ )
+  { Colors[i].Alpha = 0; }
+  return true;
+ }
+
+ if( BitDepth == 8 )
+ {
+  int i=0;
+  int j,k,ell;
+    
+  // do an easy loop, which works for all but colors 
+  // 0 to 9 and 246 to 255
+  for( ell=0 ; ell < 4 ; ell++ ) 
+  {
+   for( k=0 ; k < 8 ; k++ )
+   {
+    for( j=0; j < 8 ; j++ )
+    {
+     Colors[i].Red = j*32; 
+     Colors[i].Green = k*32;
+     Colors[i].Blue = ell*64;
+     Colors[i].Alpha = 0;
+     i++;
+    }
+   }
+  } 
+   
+  // now redo the first 8 colors  
+  i=0;
+  for( ell=0 ; ell < 2 ; ell++ ) 
+  {
+   for( k=0 ; k < 2 ; k++ )
+   {
+    for( j=0; j < 2 ; j++ )
+    {
+     Colors[i].Red = j*128;
+     Colors[i].Green = k*128;
+     Colors[i].Blue = ell*128;
+     i++;
+    }
+   }
+  } 
+  // overwrite colors 7, 8, 9
+  i=7;
+  Colors[i].Red = 192;
+  Colors[i].Green = 192;
+  Colors[i].Blue = 192;
+  i++; // 8
+  Colors[i].Red = 192;
+  Colors[i].Green = 220;
+  Colors[i].Blue = 192;
+  i++; // 9
+  Colors[i].Red = 166;
+  Colors[i].Green = 202;
+  Colors[i].Blue = 240;
+   
+  // overwrite colors 246 to 255 
+  i=246;
+  Colors[i].Red = 255;
+  Colors[i].Green = 251;
+  Colors[i].Blue = 240;
+  i++; // 247
+  Colors[i].Red = 160;
+  Colors[i].Green = 160;
+  Colors[i].Blue = 164;
+  i++; // 248
+  Colors[i].Red = 128;
+  Colors[i].Green = 128;
+  Colors[i].Blue = 128;
+  i++; // 249
+  Colors[i].Red = 255;
+  Colors[i].Green = 0;
+  Colors[i].Blue = 0;
+  i++; // 250
+  Colors[i].Red = 0;
+  Colors[i].Green = 255;
+  Colors[i].Blue = 0;
+  i++; // 251
+  Colors[i].Red = 255;
+  Colors[i].Green = 255;
+  Colors[i].Blue = 0;
+  i++; // 252
+  Colors[i].Red = 0;
+  Colors[i].Green = 0;
+  Colors[i].Blue = 255;
+  i++; // 253
+  Colors[i].Red = 255;
+  Colors[i].Green = 0;
+  Colors[i].Blue = 255;
+  i++; // 254
+  Colors[i].Red = 0;
+  Colors[i].Green = 255;
+  Colors[i].Blue = 255;
+  i++; // 255
+  Colors[i].Red = 255;
+  Colors[i].Green = 255;
+  Colors[i].Blue = 255;
+  
+  return true;
+ }
+ return true;
+}
+
+bool SafeFread( char* buffer, int size, int number, FILE* fp )
+{
+ using namespace std;
+ int ItemsRead;
+ if( feof(fp) )
+ { return false; }
+ ItemsRead = (int) fread( buffer , size , number , fp );
+ if( ItemsRead < number )
+ { return false; }
+ return true;
+}
+
+void BMP::SetDPI( int HorizontalDPI, int VerticalDPI )
+{
+ XPelsPerMeter = (int) ( HorizontalDPI * 39.37007874015748 );
+ YPelsPerMeter = (int) (   VerticalDPI * 39.37007874015748 );
+}\r
+\r
+// int BMP::TellVerticalDPI( void ) const\r
+int BMP::TellVerticalDPI( void )\r
+{\r
+ if( !YPelsPerMeter )\r
+ { YPelsPerMeter = DefaultYPelsPerMeter; }\r
+ return (int) ( YPelsPerMeter / (double) 39.37007874015748 ); \r
+}
+
+// int BMP::TellHorizontalDPI( void ) const\r
+int BMP::TellHorizontalDPI( void )\r
+{\r
+ if( !XPelsPerMeter )\r
+ { XPelsPerMeter = DefaultXPelsPerMeter; }\r
+ return (int) ( XPelsPerMeter / (double) 39.37007874015748 );\r
+}\r
+\r
+/* These functions are defined in EasyBMP_VariousBMPutilities.h */\r
+\r
+BMFH GetBMFH( const char* szFileNameIn )
+{
+ using namespace std;
+ BMFH bmfh;
+
+ FILE* fp;
+ fp = fopen( szFileNameIn,"rb");
+ if( !fp  )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: Cannot initialize from file " 
+        << szFileNameIn << "." << endl
+        << "               File cannot be opened or does not exist." 
+           << endl;
+  }
+  bmfh.bfType = 0;
+  return bmfh;
+ } 
+ SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD) , 1 , fp );
+ SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp ); 
+ fclose( fp );
+ if( IsBigEndian() )
+ { bmfh.SwitchEndianess(); }
+
+ return bmfh;
+}
+
+BMIH GetBMIH( const char* szFileNameIn )
+{
+ using namespace std;
+ BMFH bmfh;
+ BMIH bmih;
+
+ FILE* fp;
+ fp = fopen( szFileNameIn,"rb");
+
+ if( !fp  )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: Cannot initialize from file " 
+        << szFileNameIn << "." << endl
+        << "               File cannot be opened or does not exist." 
+           << endl;
+  }
+  return bmih;
+ } 
+ // read the bmfh, i.e., first 14 bytes (just to get it out of the way);
+ ebmpBYTE TempBYTE;
+ int i;
+ for( i = 14 ; i > 0 ; i-- )
+ { SafeFread( (char*) &TempBYTE , sizeof(ebmpBYTE) , 1, fp ); }
+
+ // read the bmih 
+
+ SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp );
+ SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1 , fp );
+ SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp ); 
+ SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp ); 
+ fclose( fp );
+ if( IsBigEndian() )
+ { bmih.SwitchEndianess(); }
+
+ return bmih;
+}
+
+void DisplayBitmapInfo( const char* szFileNameIn )
+{
+ using namespace std;
+ FILE* fp;
+ fp = fopen( szFileNameIn,"rb");
+ if( !fp  )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: Cannot initialize from file " 
+        << szFileNameIn << "." << endl
+        << "               File cannot be opened or does not exist." 
+           << endl;
+  }
+  return;
+ } 
+ fclose( fp );
+
+ // don't duplicate work! Just use the functions from above!
+ BMFH bmfh = GetBMFH(szFileNameIn);
+ BMIH bmih = GetBMIH(szFileNameIn);
+
+ cout << "File information for file " << szFileNameIn 
+      << ":" << endl << endl;
+
+ cout << "BITMAPFILEHEADER:" << endl
+      << "bfType: " << bmfh.bfType << endl
+      << "bfSize: " << bmfh.bfSize << endl
+      << "bfReserved1: " << bmfh.bfReserved1 << endl
+      << "bfReserved2: " << bmfh.bfReserved2 << endl    
+      << "bfOffBits: " << bmfh.bfOffBits << endl << endl;
+
+ cout << "BITMAPINFOHEADER:" << endl
+      << "biSize: " << bmih.biSize << endl
+      << "biWidth: " << bmih.biWidth << endl
+      << "biHeight: " << bmih.biHeight << endl
+      << "biPlanes: " << bmih.biPlanes << endl
+      << "biBitCount: " << bmih.biBitCount << endl
+      << "biCompression: " << bmih.biCompression << endl
+      << "biSizeImage: " << bmih.biSizeImage << endl
+      << "biXPelsPerMeter: " << bmih.biXPelsPerMeter << endl
+      << "biYPelsPerMeter: " << bmih.biYPelsPerMeter << endl
+      << "biClrUsed: " << bmih.biClrUsed << endl
+      << "biClrImportant: " << bmih.biClrImportant << endl << endl;  
+ return;
+}
+
+int GetBitmapColorDepth( const char* szFileNameIn )
+{
+ BMIH bmih = GetBMIH( szFileNameIn );
+ return (int) bmih.biBitCount;
+}
+
+void PixelToPixelCopy( BMP& From, int FromX, int FromY,  
+                       BMP& To, int ToX, int ToY)
+{
+ *To(ToX,ToY) = *From(FromX,FromY);
+ return;
+}
+
+void PixelToPixelCopyTransparent( BMP& From, int FromX, int FromY,  
+                                  BMP& To, int ToX, int ToY,
+                                  RGBApixel& Transparent )
+{
+ if( From(FromX,FromY)->Red != Transparent.Red ||
+     From(FromX,FromY)->Green != Transparent.Green ||
+     From(FromX,FromY)->Blue != Transparent.Blue )      
+ { *To(ToX,ToY) = *From(FromX,FromY); }
+ return;
+}
+
+void RangedPixelToPixelCopy( BMP& From, int FromL , int FromR, int FromB, int FromT, 
+                             BMP& To, int ToX, int ToY )
+{
+ // make sure the conventions are followed
+ if( FromB < FromT )
+ { int Temp = FromT; FromT = FromB; FromB = Temp; }
+
+ // make sure that the copied regions exist in both bitmaps
+ if( FromR >= From.TellWidth() )
+ { FromR = From.TellWidth()-1; }
+ if( FromL < 0 ){ FromL = 0; }
+
+ if( FromB >= From.TellHeight() )
+ { FromB = From.TellHeight()-1; }
+ if( FromT < 0 ){ FromT = 0; }
+ if( ToX+(FromR-FromL) >= To.TellWidth() )
+ { FromR = To.TellWidth()-1+FromL-ToX; }
+ if( ToY+(FromB-FromT) >= To.TellHeight() )
+ { FromB = To.TellHeight()-1+FromT-ToY; } 
+ int i,j;
+ for( j=FromT ; j <= FromB ; j++ )
+ { 
+  for( i=FromL ; i <= FromR ; i++ )
+  {
+   PixelToPixelCopy( From, i,j,  
+                     To, ToX+(i-FromL), ToY+(j-FromT) );
+  }
+ }
+
+ return;
+}
+
+void RangedPixelToPixelCopyTransparent( 
+     BMP& From, int FromL , int FromR, int FromB, int FromT, 
+     BMP& To, int ToX, int ToY ,
+     RGBApixel& Transparent )
+{
+ // make sure the conventions are followed
+ if( FromB < FromT )
+ { int Temp = FromT; FromT = FromB; FromB = Temp; }
+
+ // make sure that the copied regions exist in both bitmaps
+ if( FromR >= From.TellWidth() )
+ { FromR = From.TellWidth()-1; }
+ if( FromL < 0 ){ FromL = 0; }
+
+ if( FromB >= From.TellHeight() )
+ { FromB = From.TellHeight()-1; }
+ if( FromT < 0 ){ FromT = 0; }
+ if( ToX+(FromR-FromL) >= To.TellWidth() )
+ { FromR = To.TellWidth()-1+FromL-ToX; }
+ if( ToY+(FromB-FromT) >= To.TellHeight() )
+ { FromB = To.TellHeight()-1+FromT-ToY; } 
+ int i,j;
+ for( j=FromT ; j <= FromB ; j++ )
+ { 
+  for( i=FromL ; i <= FromR ; i++ )
+  {
+   PixelToPixelCopyTransparent( From, i,j,  
+                     To, ToX+(i-FromL), ToY+(j-FromT) , 
+                     Transparent);
+  }
+ }
+
+ return;
+}
+
+bool CreateGrayscaleColorTable( BMP& InputImage )
+{
+ using namespace std;
+ int BitDepth = InputImage.TellBitDepth();
+ if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Warning: Attempted to create color table at a bit" << endl
+        << "                 depth that does not require a color table." << endl
+           << "                 Ignoring request." << endl;
+  }
+  return false;
+ }
+ int i;
+ int NumberOfColors = InputImage.TellNumberOfColors();
+ ebmpBYTE StepSize;
+ if( BitDepth != 1 )
+ { StepSize = 255/(NumberOfColors-1); }
+ else
+ { StepSize = 255; }
+  
+ for( i=0 ; i < NumberOfColors ; i++ )
+ {
+  ebmpBYTE TempBYTE = i*StepSize;
+  RGBApixel TempColor;
+  TempColor.Red = TempBYTE;
+  TempColor.Green = TempBYTE;
+  TempColor.Blue = TempBYTE;
+  TempColor.Alpha = 0;
+  InputImage.SetColor( i , TempColor );  
+ }
+ return true;
+}
+
+bool BMP::Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
+{ 
+ int i;
+ if( Width*4 > BufferSize )
+ { return false; }
+ for( i=0 ; i < Width ; i++ )
+ { memcpy( (char*) &(Pixels[i][Row]), (char*) Buffer+4*i, 4 ); }
+ return true;
+}
+
+bool BMP::Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
+{ 
+ int i;
+ if( Width*3 > BufferSize )
+ { return false; }
+ for( i=0 ; i < Width ; i++ )
+ { memcpy( (char*) &(Pixels[i][Row]), Buffer+3*i, 3 ); }
+ return true;
+}
+
+bool BMP::Read8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
+{
+ int i;
+ if( Width > BufferSize )
+ { return false; }
+ for( i=0 ; i < Width ; i++ )
+ {
+  int Index = Buffer[i];
+  *( this->operator()(i,Row) )= GetColor(Index); 
+ }
+ return true;
+}
+
+bool BMP::Read4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
+{
+ int Shifts[2] = {4  ,0 };
+ int Masks[2]  = {240,15};
+ int i=0;
+ int j;
+ int k=0;
+ if( Width > 2*BufferSize )
+ { return false; }
+ while( i < Width )
+ {
+  j=0;
+  while( j < 2 && i < Width )
+  {
+   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
+   *( this->operator()(i,Row) )= GetColor(Index); 
+   i++; j++;   
+  }
+  k++;
+ }
+ return true;
+}
+bool BMP::Read1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
+{
+ int Shifts[8] = {7  ,6 ,5 ,4 ,3,2,1,0};
+ int Masks[8]  = {128,64,32,16,8,4,2,1};
+ int i=0;
+ int j;
+ int k=0;
+ if( Width > 8*BufferSize )
+ { return false; }
+ while( i < Width )
+ {
+  j=0;
+  while( j < 8 && i < Width )
+  {
+   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
+   *( this->operator()(i,Row) )= GetColor(Index); 
+   i++; j++;   
+  }
+  k++;
+ }
+ return true;
+}
+
+bool BMP::Write32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
+{ 
+ int i;
+ if( Width*4 > BufferSize )
+ { return false; }
+ for( i=0 ; i < Width ; i++ )
+ { memcpy( (char*) Buffer+4*i, (char*) &(Pixels[i][Row]), 4 ); }
+ return true;
+}
+
+bool BMP::Write24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
+{ 
+ int i;
+ if( Width*3 > BufferSize )
+ { return false; }
+ for( i=0 ; i < Width ; i++ )
+ { memcpy( (char*) Buffer+3*i,  (char*) &(Pixels[i][Row]), 3 ); }
+ return true;
+}
+
+bool BMP::Write8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
+{
+ int i;
+ if( Width > BufferSize )
+ { return false; }
+ for( i=0 ; i < Width ; i++ )
+ { Buffer[i] = FindClosestColor( Pixels[i][Row] ); }
+ return true;
+}
+
+bool BMP::Write4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
+{ 
+ int PositionWeights[2]  = {16,1};
+ int i=0;
+ int j;
+ int k=0;
+ if( Width > 2*BufferSize )
+ { return false; }
+ while( i < Width )
+ {
+  j=0;
+  int Index = 0;
+  while( j < 2 && i < Width )
+  {
+   Index += ( PositionWeights[j]* (int) FindClosestColor( Pixels[i][Row] ) ); 
+   i++; j++;   
+  }
+  Buffer[k] = (ebmpBYTE) Index;
+  k++;
+ }
+ return true;
+}
+
+bool BMP::Write1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row )
+{ 
+ int PositionWeights[8]  = {128,64,32,16,8,4,2,1};
+ int i=0;
+ int j;
+ int k=0;
+ if( Width > 8*BufferSize )
+ { return false; }
+ while( i < Width )
+ {
+  j=0;
+  int Index = 0;
+  while( j < 8 && i < Width )
+  {
+   Index += ( PositionWeights[j]* (int) FindClosestColor( Pixels[i][Row] ) ); 
+   i++; j++;   
+  }
+  Buffer[k] = (ebmpBYTE) Index;
+  k++;
+ }
+ return true;
+}
+
+ebmpBYTE BMP::FindClosestColor( RGBApixel& input )
+{
+ using namespace std;
+ int i=0;
+ int NumberOfColors = TellNumberOfColors();
+ ebmpBYTE BestI = 0;
+ int BestMatch = 999999;
+  
+ while( i < NumberOfColors )
+ {
+  RGBApixel Attempt = GetColor( i );
+  int TempMatch = IntSquare( (int) Attempt.Red - (int) input.Red )
+                + IntSquare( (int) Attempt.Green - (int) input.Green )
+                + IntSquare( (int) Attempt.Blue - (int) input.Blue );
+  if( TempMatch < BestMatch )
+  { BestI = (ebmpBYTE) i; BestMatch = TempMatch; }
+  if( BestMatch < 1 )
+  { i = NumberOfColors; }
+  i++;
+ }
+ return BestI;
+}
+
+bool EasyBMPcheckDataSize( void )
+{
+ using namespace std;
+ bool ReturnValue = true;
+ if( sizeof( ebmpBYTE ) != 1 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: ebmpBYTE has the wrong size (" 
+        << sizeof( ebmpBYTE ) << " bytes)," << endl
+           << "               Compared to the expected 1 byte value" << endl;
+  }
+  ReturnValue = false;
+ }
+ if( sizeof( ebmpWORD ) != 2 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: ebmpWORD has the wrong size (" 
+        << sizeof( ebmpWORD ) << " bytes)," << endl
+           << "               Compared to the expected 2 byte value" << endl;
+  }
+  ReturnValue = false;
+ }
+ if( sizeof( ebmpDWORD ) != 4 )
+ {
+  if( EasyBMPwarnings )
+  {
+   cout << "EasyBMP Error: ebmpDWORD has the wrong size (" 
+        << sizeof( ebmpDWORD ) << " bytes)," << endl
+           << "               Compared to the expected 4 byte value" << endl;
+  }
+  ReturnValue = false;
+ }
+ return ReturnValue;
+}
+
+bool Rescale( BMP& InputImage , char mode, int NewDimension )
+{
+ using namespace std;
+ int CapMode = toupper( mode );
+
+ BMP OldImage( InputImage );
+ if( CapMode != 'P' &&
+     CapMode != 'W' &&
+     CapMode != 'H' && 
+     CapMode != 'F' )
+ {
+  if( EasyBMPwarnings )
+  {
+   char ErrorMessage [1024];
+   sprintf( ErrorMessage, "EasyBMP Error: Unknown rescale mode %c requested\n" , mode );
+   cout << ErrorMessage; 
+  }
+  return false;
+ }
+
+ int NewWidth  =0;
+ int NewHeight =0;
+ int OldWidth = OldImage.TellWidth();
+ int OldHeight= OldImage.TellHeight();
+ if( CapMode == 'P' )
+ {
+  NewWidth = (int) floor( OldWidth * NewDimension / 100.0 );
+  NewHeight = (int) floor( OldHeight * NewDimension / 100.0 );
+ }
+ if( CapMode == 'F' )
+ {
+  if( OldWidth > OldHeight )
+  { CapMode = 'W'; }
+  else
+  { CapMode = 'H'; }
+ }
+
+ if( CapMode == 'W' )
+ {
+  double percent = (double) NewDimension / (double) OldWidth;
+  NewWidth = NewDimension;
+  NewHeight = (int) floor( OldHeight * percent );
+ }
+ if( CapMode == 'H' )
+ {
+  double percent = (double) NewDimension / (double) OldHeight;
+  NewHeight = NewDimension;
+  NewWidth = (int) floor( OldWidth * percent );
+ }
+ if( NewWidth < 1 )
+ { NewWidth = 1; }
+ if( NewHeight < 1 )
+ { NewHeight = 1; }
+ InputImage.SetSize( NewWidth, NewHeight );
+ InputImage.SetBitDepth( 24 );
+
+ int I,J;
+ double ThetaI,ThetaJ;
+ for( int j=0; j < NewHeight-1 ; j++ )
+ {
+  ThetaJ = (double)(j*(OldHeight-1.0))
+          /(double)(NewHeight-1.0);
+  J    = (int) floor( ThetaJ );
+  ThetaJ -= J;  
+  
+  for( int i=0; i < NewWidth-1 ; i++ )
+  {
+   ThetaI = (double)(i*(OldWidth-1.0))
+           /(double)(NewWidth-1.0);
+   I = (int) floor( ThetaI );
+   ThetaI -= I;  
+   
+   InputImage(i,j)->Red = (ebmpBYTE) 
+                          ( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*(OldImage(I,J)->Red)
+                           +(ThetaI-ThetaI*ThetaJ)*(OldImage(I+1,J)->Red)   
+                           +(ThetaJ-ThetaI*ThetaJ)*(OldImage(I,J+1)->Red)   
+                           +(ThetaI*ThetaJ)*(OldImage(I+1,J+1)->Red) );
+   InputImage(i,j)->Green = (ebmpBYTE) 
+                          ( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*OldImage(I,J)->Green
+                           +(ThetaI-ThetaI*ThetaJ)*OldImage(I+1,J)->Green   
+                           +(ThetaJ-ThetaI*ThetaJ)*OldImage(I,J+1)->Green   
+                           +(ThetaI*ThetaJ)*OldImage(I+1,J+1)->Green );  
+   InputImage(i,j)->Blue = (ebmpBYTE) 
+                          ( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*OldImage(I,J)->Blue
+                           +(ThetaI-ThetaI*ThetaJ)*OldImage(I+1,J)->Blue   
+                           +(ThetaJ-ThetaI*ThetaJ)*OldImage(I,J+1)->Blue   
+                           +(ThetaI*ThetaJ)*OldImage(I+1,J+1)->Blue ); 
+  }
+   InputImage(NewWidth-1,j)->Red = (ebmpBYTE) 
+                            ( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Red)
+                          + ThetaJ*(OldImage(OldWidth-1,J+1)->Red) ); 
+   InputImage(NewWidth-1,j)->Green = (ebmpBYTE) 
+                            ( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Green)
+                          + ThetaJ*(OldImage(OldWidth-1,J+1)->Green) ); 
+   InputImage(NewWidth-1,j)->Blue = (ebmpBYTE) 
+                            ( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Blue)
+                          + ThetaJ*(OldImage(OldWidth-1,J+1)->Blue) ); 
+ } 
+
+ for( int i=0 ; i < NewWidth-1 ; i++ )
+ {
+  ThetaI = (double)(i*(OldWidth-1.0))
+          /(double)(NewWidth-1.0);
+  I = (int) floor( ThetaI );
+  ThetaI -= I;  
+  InputImage(i,NewHeight-1)->Red = (ebmpBYTE) 
+                            ( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Red)
+                          + ThetaI*(OldImage(I,OldHeight-1)->Red) ); 
+  InputImage(i,NewHeight-1)->Green = (ebmpBYTE) 
+                            ( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Green)
+                          + ThetaI*(OldImage(I,OldHeight-1)->Green) ); 
+  InputImage(i,NewHeight-1)->Blue = (ebmpBYTE) 
+                            ( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Blue)
+                          + ThetaI*(OldImage(I,OldHeight-1)->Blue) ); 
+ }
+ *InputImage(NewWidth-1,NewHeight-1) = *OldImage(OldWidth-1,OldHeight-1);
+ return true;
+}
diff --git a/src/freenet/captcha/easybmp/EasyBMP_Font.cpp b/src/freenet/captcha/easybmp/EasyBMP_Font.cpp
new file mode 100644 (file)
index 0000000..02c1487
--- /dev/null
@@ -0,0 +1,2178 @@
+/*************************************************\r
+*                                                *\r
+*  EasyBMP Cross-Platform Windows Bitmap Library * \r
+*                                                *\r
+*  Author: Paul Macklin                          *\r
+*   email: pmacklin@math.uci.edu                 *\r
+*                                                *\r
+*    file: EasyBMP_Font.h                        *\r
+*    date: 2-21-2005                             *\r
+* version: 1.05.00                               *\r
+*                                                *\r
+*   License: BSD (revised)                       *\r
+* Copyright: 2005-2006 by the EasyBMP Project    * \r
+*                                                *\r
+* description: draw a simple font                *\r
+*                                                *\r
+*************************************************/\r
+\r
+#include "../../../../include/freenet/captcha/easybmp/EasyBMP_Geometry.h"\r
+#include "../../../../include/freenet/captcha/easybmp/EasyBMP_Font.h"\r
+                                 \r
+int PrintString( BMP& Image, char* String , int TopLeftX, int TopLeftY , int Height , \r
+                  RGBApixel Color )\r
+{\r
+ int CharNumber = 0;\r
+ int StartX = TopLeftX;\r
+ int Spacing = (int) ebmpRound( 0.2*Height );\r
+ if( Spacing < 3 )\r
+ { Spacing = 3; }\r
\r
+ for( CharNumber = 0 ; CharNumber < strlen( String ) ; CharNumber++ )\r
+ {\r
+  int ReturnPosition = PrintLetter( Image , String[CharNumber] , StartX , TopLeftY , Height , Color );\r
+  StartX = ReturnPosition;\r
+  StartX += Spacing;\r
+ }\r
+ return StartX;\r
+}\r
+\r
+int PrintLetter( BMP& Image, char Letter , int TopLeftX, int TopLeftY, int Height , \r
+                  RGBApixel Color )\r
+{\r
+ int Width = (int) floor( 0.6*Height);\r
+ if( Width % 2 != 0 ){ Width++; }\r
+ int Center = (Width)/2;\r
\r
+ RGBApixel TempColor;\r
+ TempColor.Red = 0;\r
+ TempColor.Green = 255;\r
+ TempColor.Blue = 0;\r
\r
+ double pi = 3.14159265358979;\r
+\r
+// if( isalpha(Letter) )\r
+// { Letter = toupper(Letter); }\r
+\r
+ if( Letter == COPYRIGHT_SYMBOL )\r
+ {\r
+  return PrintCopyright( Image, TopLeftX, TopLeftY, Height, Color );\r
+ }\r
+\r
+ if( Letter == 'a'  )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  int x2 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y2 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x3 = x2;\r
+  int y3 = TopLeftY+Height;\r
+  \r
+  DrawArc(Image,x1,y1,0.25*Height,0,2*pi,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
\r
+  return ebmpRound( TopLeftX + 0.5*Height );\r
+ }\r
\r
+ if( Letter == 'b' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  int x2 = TopLeftX; // ebmpRound(TopLeftX+0.5*Height);\r
+  int y2 = TopLeftY; // ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x3 = x2;\r
+  int y3 = TopLeftY+Height;\r
+  \r
+  DrawArc(Image,x1,y1,0.25*Height,0,2*pi,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
\r
+  return ebmpRound( TopLeftX + 0.5*Height );\r
+ } \r
\r
+ if( Letter == 'c' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+\r
+  DrawArc(Image,x1,y1,0.25*Height,0.25*pi,-0.25*pi,Color);\r
+  return ebmpRound( TopLeftX+0.5*Height);\r
+ }\r
+\r
+ if( Letter == 'd' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  int x2 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y2 = TopLeftY; // ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x3 = x2;\r
+  int y3 = TopLeftY+Height;\r
+  \r
+  DrawArc(Image,x1,y1,0.25*Height,0,2*pi,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
\r
+  return ebmpRound( TopLeftX + 0.5*Height );\r
+ }  \r
\r
+ if( Letter == 'e' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  int x2 = TopLeftX;\r
+  int y2 = ebmpRound(TopLeftY + 0.75*Height);\r
+  \r
+  int x3 = ebmpRound( TopLeftX+0.5*Height);\r
+  int y3 = y2;\r
+\r
+  DrawArc(Image,x1,y1,0.25*Height,0.25*pi,0,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
+  \r
+  return x3;\r
+ } \r
\r
+ if( Letter == 'f' )\r
+ {\r
+  int x1 = ebmpRound( TopLeftX + 0.25*Height);\r
+  int y1 = TopLeftY + Center;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height;\r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = ebmpRound( TopLeftY + 0.5*Height);\r
+  \r
+  int x4 = x1 + (x1-x3);\r
+  int y4 = y3;\r
+  \r
+  double x5 = TopLeftX+0.5*Height;\r
+  double y5 = TopLeftY+0.25*Height;\r
+  \r
+  if( Height % 4 == 3 )\r
+  { x5 -= 1; }\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  \r
+  DrawArc(Image,x5,y5,0.25*Height,7*pi/8    ,2*pi,Color);\r
+\r
+  return x4;  \r
+ }\r
\r
+ if( Letter == 'g' )\r
+ {\r
+  double x1 = TopLeftX+0.25*Height;\r
+  double y1 = TopLeftY+0.75*Height;\r
\r
+  int x2 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y2 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x3 = x2;\r
+  int y3 = ebmpRound(TopLeftY+1.25*Height);\r
+  \r
+  double x4 = x1; \r
+  double y4 = TopLeftY+1.25*Height;\r
\r
+  DrawArc(Image,x1,y1,0.25*Height,0,2*pi,Color);\r
+  DrawArc(Image,x4,y4,0.25*Height,0,pi,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
\r
+  return ebmpRound(TopLeftX+0.5*Height);\r
+ }\r
\r
+ if( Letter == 'h' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = TopLeftY; // ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x4 = x3;\r
+  int y4 = TopLeftY + Height;\r
+  \r
+  int x5 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y5 = ebmpRound(TopLeftY+0.75*Height);\r
+  \r
+  int x6 = x5;\r
+  int y6 = y4;\r
+  \r
+  DrawArc(Image,x1,y1,0.25*Height,pi,2*pi,Color);\r
+  \r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  DrawLine(Image,x5,y5,x6,y6,Color);\r
\r
+  return x5;\r
+ }  \r
\r
+ if( Letter == 'i' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = ebmpRound(TopLeftY+0.5*Height);\r
+   \r
+  int x2 = x1;\r
+  int y2 = TopLeftY+Height;\r
+  \r
+  double x3 = x1;\r
+  double y3 = y1 - 2.5;\r
\r
+  DrawArc( Image, x3, y3, 0.75 , 0 , 6.3 , Color );\r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  \r
+  return ebmpRound(x1+1.25);\r
+ }\r
\r
+ if( Letter == 'j' )\r
+ {\r
+  int x1 = ebmpRound(TopLeftX+0.25*Height);\r
+  int y1 = ebmpRound(TopLeftY+0.5*Height);\r
+   \r
+  int x2 = x1;\r
+  int y2 = ebmpRound(TopLeftY+1.25*Height);\r
+  \r
+  double x3 = x1;\r
+  double y3 = y1 - 2.5;\r
+  \r
+  double x4 = TopLeftX;\r
+  double y4 = TopLeftY+1.25*Height;\r
\r
+  DrawArc( Image, x3, y3, 0.75 , 0 , 6.3 , Color );\r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  \r
+  DrawArc(Image,x4,y4,0.25*Height,0,pi,Color);\r
+  \r
+  return x1;\r
+ } \r
\r
+ if( Letter == 'k' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY+Height;\r
+  \r
+  int x3 = x1;\r
+  int y3 = ebmpRound(TopLeftY+0.75*Height);\r
+  \r
+  int x4 = ebmpRound(TopLeftX+0.3*Height);\r
+  int y4 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x5 = x4;\r
+  int y5 = y2;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  DrawLine(Image,x3,y3,x5,y5,Color);\r
\r
+  return x5;\r
+ }\r
\r
+ if( Letter == 'm' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+\r
+  double x2 = TopLeftX + 0.75*Height;\r
+  double y2 = y1;  \r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x4 = x3;\r
+  int y4 = TopLeftY + Height;\r
+  \r
+  int x5 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y5 = ebmpRound(TopLeftY+0.75*Height);\r
+  \r
+  int x6 = x5;\r
+  int y6 = y4;\r
+  \r
+  int x7 = ebmpRound(TopLeftX+Height);\r
+  if( x7 - x5 > x5 - x3 )\r
+  { x7--; }\r
+  \r
+  int y7 = y5;\r
+  \r
+  int x8 = x7;\r
+  int y8 = y4;\r
+  \r
+  \r
+  DrawArc(Image,x1,y1,0.25*Height,pi,2*pi,Color);\r
+  DrawArc(Image,x2,y2,0.25*Height,pi,2*pi,Color);\r
+  \r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  DrawLine(Image,x5,y5,x6,y6,Color);\r
+  DrawLine(Image,x7,y7,x8,y8,Color);\r
\r
+  return x7;\r
+ }\r
\r
+ if( Letter == 'n' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x4 = x3;\r
+  int y4 = TopLeftY + Height;\r
+  \r
+  int x5 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y5 = ebmpRound(TopLeftY+0.75*Height);\r
+  \r
+  int x6 = x5;\r
+  int y6 = y4;\r
+  \r
+  DrawArc(Image,x1,y1,0.25*Height,pi,2*pi,Color);\r
+  \r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  DrawLine(Image,x5,y5,x6,y6,Color);\r
\r
+  return x5;\r
+ } \r
\r
+ if( Letter == 'o' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  DrawArc(Image,x1,y1,0.25*Height,0,2*pi,Color);\r
\r
+  return ebmpRound(TopLeftX + 0.5*Height);\r
+ }   \r
\r
+ if( Letter == 'p' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  int x2 = TopLeftX;\r
+  int y2 = ebmpRound(TopLeftY + 0.5*Height);\r
+  \r
+  int x3 = x2;\r
+  int y3 = ebmpRound(TopLeftY + 1.5*Height);\r
+\r
+  DrawArc(Image,x1,y1,0.25*Height,0,2*pi,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
+\r
+  return ebmpRound( TopLeftX + 0.5*Height );\r
+ }\r
\r
+ if( Letter == 'q' )\r
+ {\r
+  double x1 = TopLeftX+0.25*Height;\r
+  double y1 = TopLeftY+0.75*Height;\r
\r
+  int x2 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y2 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x3 = x2;\r
+  int y3 = ebmpRound(TopLeftY+1.5*Height);\r
+\r
+  int x4 = ebmpRound(x3+0.2*Height);\r
+  int y4 = ebmpRound(y3-0.2*Height);\r
\r
+  DrawArc(Image,x1,y1,0.25*Height,0,2*pi,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
\r
+  return ebmpRound(TopLeftX+0.5*Height);\r
+ }\r
\r
+ if( Letter == 'r' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x4 = x3;\r
+  int y4 = TopLeftY + Height;\r
+\r
+/*  \r
+  int x5 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y5 = ebmpRound(TopLeftY+0.75*Height);\r
+  \r
+  int x6 = x5;\r
+  int y6 = y4;\r
+*/  \r
+  \r
+  DrawArc(Image,x1,y1,0.25*Height,pi,2*pi,Color);\r
+  \r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+//  DrawLine(Image,x5,y5,x6,y6,Color);\r
\r
+  return ebmpRound(TopLeftX+0.5*Height);\r
+ }  \r
\r
+ if( Letter == 's' )\r
+ {\r
+  double x1 = TopLeftX+0.125*Height;\r
+  double y1 = TopLeftY+0.625*Height;\r
+\r
+  double x2 = x1;\r
+  double y2 = (TopLeftY+0.875*Height);\r
+  \r
+  double difference = (TopLeftY+Height)-y2;\r
+  double MaxAngle1 = 0;\r
+  double MaxAngle2 = pi;\r
+  if( difference < 1.5 )\r
+  { difference = 1.5; MaxAngle1 = 0; MaxAngle2 = 1.5; x1 = TopLeftX + difference; x2 = x1; }\r
+  \r
+  y1 = y2 - 2*difference;\r
+  \r
+  DrawArc(Image,x1,y1,difference,0.5*pi,MaxAngle1,Color);\r
+  DrawArc(Image,x2,y2,difference,-0.5*pi,pi,Color);\r
\r
+  return ebmpRound(TopLeftX+2*difference);\r
+ }\r
\r
+ if( Letter == 't' )\r
+ {\r
+  int x1 = ebmpRound( TopLeftX + 0.25*Height);\r
+  int y1 = TopLeftY + Center;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height;\r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = ebmpRound( TopLeftY + 0.5*Height);\r
+  \r
+  int x4 = x1 + (x1-x3);\r
+  int y4 = y3;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+\r
+  return x4; \r
+ }\r
\r
+ if( Letter == 'u' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.75*Height;\r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x4 = x3;\r
+  int y4 = ebmpRound(TopLeftY+0.75*Height);//  + Height;\r
+  \r
+  int x5 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y5 = TopLeftY + Height;// ebmpRound(TopLeftY+0.75*Height);\r
+  \r
+  int x6 = x5;\r
+  int y6 = y3;\r
+  \r
+  DrawArc(Image,x1,y1,0.25*Height,0,pi,Color);\r
+  \r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  DrawLine(Image,x5,y5,x6,y6,Color);\r
\r
+  return x5;\r
+ }  \r
\r
+ if( Letter == 'v' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x2 = ebmpRound( TopLeftX+0.2*Height);\r
+  int y2 = TopLeftY+Height;\r
+  \r
+  int x3 = ebmpRound( TopLeftX+0.4*Height);\r
+  int y3 = y1;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
\r
+  return x3;\r
+ }\r
+\r
+ if( Letter == 'w' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x2 = ebmpRound(TopLeftX+0.2*Height);\r
+  int y2 = TopLeftY+Height;\r
+  \r
+  int x3 = ebmpRound(TopLeftX+0.4*Height);\r
+  int y3 = y1;\r
+  \r
+  int x4 = ebmpRound(x3+0.2*Height);\r
+  int y4 = y2;\r
+  \r
+  int x5 = ebmpRound(x3+0.4*Height);\r
+  int y5 = y1;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  DrawLine(Image,x4,y4,x5,y5,Color);\r
+  \r
+  return x5;\r
+ }\r
\r
+ if( Letter == 'x' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x2 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y2 = y1;\r
+  \r
+  int x3 = x1;\r
+  int y3 = TopLeftY+Height;\r
+  \r
+  int x4 = x2;\r
+  int y4 = y3;\r
+  \r
+  DrawLine(Image,x1,y1,x4,y4,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
\r
+  return x4;\r
+ }\r
\r
+ if( Letter == 'y' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x2 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y2 = y1;\r
+  \r
+  int x3 = ebmpRound(x1+0.25*Height);\r
+  int y3 = TopLeftY+Height;\r
+  \r
+  int x4 = x1;\r
+  int y4 = ebmpRound(TopLeftY+1.25*Height)+1;\r
+  \r
+  DrawLine(Image,x1,y1,x3,y3,Color);\r
+  DrawLine(Image,x2,y2,x4,y4,Color);\r
\r
+  return x2;\r
+ } \r
\r
+ if( Letter == 'z' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x2 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y2 = y1;\r
+  \r
+  int x3 = x1;\r
+  int y3 = TopLeftY+Height;\r
+  \r
+  int x4 = x2;\r
+  int y4 = y3;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  \r
+  return x4;\r
+ }\r
\r
+ if( Letter == 'A' )\r
+ {\r
+  // define some control points\r
+  \r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY+Height;\r
+  \r
+  int x2 = TopLeftX + ebmpRound( 0.3*Height );\r
+  int y2 = TopLeftY;\r
+  \r
+  int x3 = TopLeftX + ebmpRound( 0.6*Height );\r
+  int y3 = y1;\r
+  \r
+  int x4 = TopLeftX + ebmpRound( 0.1*Height );\r
+  int y4 = ebmpRound( y1 - Height/3.0 );\r
+  \r
+  int x5 = ebmpRound( x3 - 0.1*Height ); \r
+  int y5 = y4;\r
\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+  DrawLine( Image , x4, y4, x5, y5, Color );\r
\r
+  return x3; \r
+ }\r
\r
+ if( Letter == 'B' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY+Height;\r
+  \r
+  int x2 = TopLeftX;\r
+  int y2 = TopLeftY;\r
+  \r
+  int x3 = TopLeftX + Center; // (int) ebmpRound( 0.3*Height );\r
+  int y3 = TopLeftY;\r
+  \r
+  int x4 = x1;\r
+  int y4 = (int) ebmpRound( TopLeftY + 0.5*Height );\r
+\r
+  int x5 = x3;\r
+  int y5 = y4;\r
+  \r
+  int x6 = x3;\r
+  int y6 = y1;\r
+\r
+  // centers of the circles\r
+  \r
+  double x7 = x3;\r
+  double y7 = ( TopLeftY + 0.25*Height );\r
+\r
+  double x8 = x3;\r
+  double y8 = ( TopLeftY + 0.75*Height );\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+  \r
+  DrawLine( Image , x2, y2, x3, y3, Color );  \r
+  DrawLine( Image , x4, y4, x5, y5, Color );  \r
+  DrawLine( Image , x1, y1, x6, y6, Color );\r
+  \r
+  DrawArc( Image, x7, y7 , 0.25*Height , -1.57079632679490 , 1.57079632679490 , Color ); \r
+  DrawArc( Image, x8, y8 , 0.25*Height , -1.57079632679490 , 1.57079632679490 , Color ); \r
+  \r
+  return ebmpRound( TopLeftX + Center + 0.25*Height); \r
+ }\r
\r
+ if( Letter == 'C' )\r
+ {\r
+  double x5 = TopLeftX + Center; \r
+  double y5 = TopLeftY + Center; \r
+\r
+  double x6 = x5;\r
+  double y6 = TopLeftY + Height - Center; \r
+  \r
+  int x7 = TopLeftX;\r
+  int y7 = (int) y5; \r
+  \r
+  int x8 = x7;\r
+  int y8 = (int) y6; \r
+\r
+  DrawArc( Image, x5, y5 , Center , -3.14159265358979 , 0 , Color ); \r
+  DrawArc( Image, x6, y6 , Center , 0 , 3.14159265358979, Color ); \r
+  \r
+  DrawLine( Image , x7, y7, x8, y8, Color );\r
\r
+  return TopLeftX + Width; //  ebmpRound(TopLeftX+0.6*Height);\r
+ } \r
\r
+ if( Letter == 'D' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = TopLeftX + Center; // ebmpRound( TopLeftX + 0.3*Height );\r
+  int y2 = y1;\r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = TopLeftY+Height;\r
+  \r
+  int x4 = x2;\r
+  int y4 = y3;\r
+  \r
+  double x5 = x2;\r
+  double y5 = TopLeftY + Center; // TopLeftY + 0.3*Height;\r
+\r
+  double x6 = x2;\r
+  double y6 = TopLeftY + Height - Center; // TopLeftY + 0.7*Height;\r
+  \r
+  int x7 = TopLeftX + Width; // ebmpRound(TopLeftX + 0.6*Height);\r
+  int y7 = (int) y5; // ebmpRound( y5 );\r
+  \r
+  int x8 = x7;\r
+  int y8 = (int) y6; //  ebmpRound( y6 );\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x1, y1, x3, y3, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+\r
+  DrawArc( Image, x5, y5 , Center , -1.57079632679490 , 0 , Color ); \r
+  DrawArc( Image, x6, y6 , Center , 0 , 1.57079632679490 , Color ); \r
+\r
+  DrawLine( Image , x7, y7, x8, y8, Color );\r
\r
+  return x7;\r
+ }\r
\r
+ if( Letter == 'E' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height;\r
+  \r
+  int x3 = TopLeftX + Width;\r
+  int y3 = TopLeftY;\r
+  \r
+  int x4 = TopLeftX;\r
+  int y4 = ebmpRound( TopLeftY + 0.5*Height);\r
+  \r
+  int x5 = ebmpRound( TopLeftX + 0.45*Height);\r
+  int y5 = y4;\r
+  \r
+  int x6 = TopLeftX + Width;\r
+  int y6 = y2;\r
+\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x1, y1, x3, y3, Color );\r
+  DrawLine( Image , x4, y4, x5, y5, Color );\r
+  DrawLine( Image , x2, y2, x6, y6, Color );\r
+  \r
+  return x6;\r
+ }\r
\r
+ if( Letter == 'F' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height;\r
+  \r
+  int x3 = TopLeftX + Width;\r
+  int y3 = TopLeftY;\r
+  \r
+  int x4 = TopLeftX;\r
+  int y4 = ebmpRound( TopLeftY + 0.5*Height);\r
+  \r
+  int x5 = ebmpRound( TopLeftX + 0.45*Height); // x3;\r
+  int y5 = y4;\r
+\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x1, y1, x3, y3, Color );\r
+  DrawLine( Image , x4, y4, x5, y5, Color );\r
+  \r
+  return x3;\r
+ } \r
\r
+ if( Letter == 'G' )\r
+ {\r
+  double x5 = TopLeftX + Center; \r
+  double y5 = TopLeftY + Center; \r
+\r
+  double x6 = x5;\r
+  double y6 = TopLeftY + Height - Center; \r
+  \r
+  int x7 = TopLeftX;\r
+  int y7 = (int) y5; \r
+  \r
+  int x8 = x7;\r
+  int y8 = (int) y6; \r
+  \r
+  int x9 = TopLeftX + Center; // ebmpRound( TopLeftX + 0.45*Height );\r
+  int y9 = ebmpRound( TopLeftY + 0.6*Height );\r
+  \r
+  int x10 = TopLeftX + Width; // ebmpRound( TopLeftX + 0.65*Height );\r
+  int y10 = y9;\r
+  \r
+  int x11 = x10;\r
+  int y11 = TopLeftY + Height;\r
+\r
+  DrawArc( Image, x5, y5 , Center , -3.14159265358979 , 0 , Color ); \r
+  DrawArc( Image, x6, y6 , Center , 0 , 3.14159265358979, Color ); \r
+  \r
+  DrawLine( Image , x7, y7, x8, y8, Color );\r
+  \r
+  DrawLine( Image , x9, y9, x10 ,y10 ,Color );\r
+  DrawLine( Image , x10, y10, x11 ,y11 ,Color );\r
\r
+  return x10; //  ebmpRound(TopLeftX+0.6*Height);\r
+ }  \r
\r
+ if( Letter == 'H' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height;\r
+  \r
+  int x3 = TopLeftX + Width;\r
+  int y3 = y1;\r
+  \r
+  int x4 = x3;\r
+  int y4 = y2;\r
+  \r
+  int x5 = x1;\r
+  int y5 = ebmpRound( TopLeftY + 0.5*Height );\r
+  \r
+  int x6 = x3;\r
+  int y6 = y5;\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+  DrawLine( Image , x5, y5, x6, y6, Color );\r
+\r
+  return x3;\r
+ }\r
\r
+ if( Letter == 'I' )\r
+ {\r
+  int x1 = ebmpRound( TopLeftX + Height*0.05);\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = ebmpRound(x1 + 0.4*Height);\r
+  int y2 = y1;\r
+  \r
+  int x3 = ebmpRound( x1 + 0.2*Height);\r
+  int y3 = y1;\r
+  \r
+  int x4 = x1;\r
+  int y4 = TopLeftY+Height;\r
+  \r
+  int x5 = x2;\r
+  int y5 = y4;\r
+  \r
+  int x6 = x3;\r
+  int y6 = y4;\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x3, y3, x6, y6, Color );\r
+  DrawLine( Image , x4, y4, x5, y5, Color );\r
+  \r
+  return x2;\r
+ }\r
\r
+ if( Letter == 'J' )\r
+ {\r
+  int x1 = TopLeftX + Width;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height - Center;\r
+  \r
+  double x3 = TopLeftX + Center;\r
+  double y3 = y2;\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawArc( Image, x3, y3, Center , 0 , 1.1*pi , Color );\r
+  return x1;\r
+ }\r
\r
+ if( Letter == 'K' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height;\r
+  \r
+  int x3 = x1;\r
+  int y3 = TopLeftY + Height - Center; // ebmpRound( TopLeftY + 0.6*Height );\r
+  \r
+  int x4 = TopLeftX + Width;\r
+  int y4 = y1;\r
+  \r
+  int x5 = TopLeftX + Center;\r
+  int y5 = ebmpRound( TopLeftY + 0.5*Height );\r
+  \r
+  int x6 = x4;\r
+  int y6 = y2;\r
+  \r
+  DrawLine( Image, x1, y1, x2, y2, Color );\r
+  DrawLine( Image, x3, y3, x4, y4, Color );\r
+  DrawLine( Image, x5, y5, x6, y6, Color );\r
\r
+  return x4;\r
+ }\r
\r
+ if( Letter == 'L' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height;\r
+  \r
+  int x3 = TopLeftX + Width;\r
+  int y3 = y2;\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+\r
+  return x3;\r
+ }\r
+  \r
+ if( Letter == 'M' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height;\r
+  \r
+  int x3 = TopLeftX + Width;\r
+  int y3 = y1;\r
+  \r
+  int x4 = x3;\r
+  int y4 = y2;\r
+  \r
+  int x5 = TopLeftX + Center;\r
+  int y5 = y4;\r
+\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+  DrawLine( Image , x1, y1, x5, y5, Color );\r
+  DrawLine( Image , x3, y3, x5, y5, Color );\r
\r
+  return x3;\r
+ } \r
\r
+ if( Letter == 'N' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Height;\r
+  \r
+  int x3 = TopLeftX + Width;\r
+  int y3 = y1;\r
+  \r
+  int x4 = x3;\r
+  int y4 = y2;\r
+\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+  DrawLine( Image , x1, y1, x4, y4, Color );\r
\r
+  return x3;\r
+ }\r
+\r
+ if( Letter == 'P' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY+Height;\r
+  \r
+  int x2 = TopLeftX;\r
+  int y2 = TopLeftY;\r
+  \r
+  int x3 = TopLeftX + Center; \r
+  int y3 = TopLeftY;\r
+  \r
+  int x4 = x1;\r
+  int y4 = ebmpRound( TopLeftY + 0.5*Height );\r
+\r
+  int x5 = x3;\r
+  int y5 = y4;\r
+  \r
+  int x6 = x3;\r
+  int y6 = y1;\r
+\r
+  // centers of the circles\r
+  \r
+  double x7 = x3;\r
+  double y7 = ( 0.5*(y3+y5) );\r
+\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+  \r
+  DrawLine( Image , x2, y2, x3, y3, Color );  \r
+  DrawLine( Image , x4, y4, x5, y5, Color );  \r
+  \r
+  DrawArc( Image, x7, y7 , 0.25*Height , -1.57079632679490 , 1.57079632679490 , Color ); \r
+  \r
+  return ebmpRound( TopLeftX + Center + 0.25*Height); \r
+ }\r
\r
+ if( Letter == 'Q' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY + Height - Center;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Center; \r
+  \r
+  int x3 = TopLeftX + Width;\r
+  int y3 = y2;\r
+  \r
+  int x4 = x3;\r
+  int y4 = y1;\r
+\r
+  // centers of the circles\r
+  \r
+  double x5 = TopLeftX + Center; \r
+  double y5 = TopLeftY + Center; \r
+\r
+  double x6 = x5;\r
+  double y6 = TopLeftY + Height - Center; \r
+  \r
+  // more points\r
+  \r
+  int x7 = TopLeftX + Width;\r
+  int y7 = TopLeftY + Height;\r
+  \r
+  int x8 = x7 - Center;\r
+  int y8 = y7 - Center;\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+  \r
+  DrawArc( Image, x5, y5 , Center , 3.14159265358979 , 6.28318530717959 , Color ); \r
+  DrawArc( Image, x6, y6 , Center , 0 ,  3.14159265358979 , Color ); \r
+  \r
+  DrawLine( Image , x7, y7 , x8, y8 , Color );\r
+  \r
+  return x3; \r
+ } \r
\r
+ if( Letter == 'R' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY+Height;\r
+  \r
+  int x2 = TopLeftX;\r
+  int y2 = TopLeftY;\r
+  \r
+  int x3 = TopLeftX + Center; \r
+  int y3 = TopLeftY;\r
+  \r
+  int x4 = x1;\r
+  int y4 = ebmpRound( TopLeftY + 0.5*Height );\r
+\r
+  int x5 = x3;\r
+  int y5 = y4;\r
+  \r
+  int x6 = x3;\r
+  int y6 = y1;\r
+  \r
+  // centers of the circles\r
+  \r
+  double x7 = x3;\r
+  double y7 = ( 0.5*(y3+y5) );\r
+  \r
+  // more\r
+  \r
+  int x8 = TopLeftX + Width;\r
+  int y8 = y1;\r
+  \r
+  int x9 = ebmpRound( TopLeftX + 0.25*Height);\r
+  int y9 = y4;  \r
+\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+  \r
+  DrawLine( Image , x2, y2, x3, y3, Color );  \r
+  DrawLine( Image , x4, y4, x5, y5, Color );  \r
+  \r
+  DrawArc( Image, x7, y7 , 0.25*Height , -1.57079632679490 , 1.57079632679490 , Color ); \r
+  \r
+  DrawLine( Image , x8, y8, x9, y9 , Color);\r
+  \r
+  return TopLeftX + Width; \r
+ } \r
\r
+ if( Letter == 'T' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+    \r
+  int x2 = TopLeftX + Width;\r
+  int y2 = y1; \r
+  \r
+  int x3 = TopLeftX + Center;\r
+  int y3 = y1;\r
+  \r
+  int x4 = x3;\r
+  int y4 = TopLeftY + Height;\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
\r
+  return x2;\r
+ }\r
\r
+ if( Letter == 'S' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.25*Height;\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + 0.75*Height;\r
+  \r
+  DrawArc( Image, x1, y1 , 0.25*Height, 1.5707963267948 , 6.28318530717 , Color );\r
+  DrawArc( Image, x2, y2 , 0.25*Height, -1.5707963267948 ,3.1415926535897 , Color );\r
+  \r
+  return ebmpRound( TopLeftX + 0.5*Height );\r
+ }\r
\r
+ if( Letter == 'U' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY + Height - Center;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY; \r
+  \r
+  int x3 = TopLeftX + Width;\r
+  int y3 = y2;\r
+  \r
+  int x4 = x3;\r
+  int y4 = y1;\r
+\r
+  // centers of the circle\r
+  \r
+  double x5 = TopLeftX + Center;\r
+  double y5 = TopLeftY + Height - Center; \r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+  \r
+  DrawArc( Image, x5, y5 , Center , 0 , 3.14159265358979 , Color ); \r
+\r
+  return x3; \r
+ }\r
+\r
+ if( Letter == 'V' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = TopLeftX + Width;\r
+  int y2 = y1;\r
+  \r
+  int x3 = TopLeftX + Center;\r
+  int y3 = TopLeftY + Height;\r
+  \r
+  DrawLine( Image , x1, y1, x3, y3, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+\r
+  return x2;\r
+ } \r
\r
+ if( Letter == 'W' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = ebmpRound(TopLeftX + 0.4*Height);\r
+  int y2 = y1;\r
+  \r
+  int x3 = ebmpRound( TopLeftX + 0.8*Height);\r
+  int y3 = y1;\r
+  \r
+  int x4 = ebmpRound( TopLeftX + 0.2*Height );\r
+  int y4 = TopLeftY + Height;\r
+  \r
+  int x5 = ebmpRound( TopLeftX + 0.6*Height );\r
+  int y5 = y4;\r
+  \r
+  DrawLine( Image , x1, y1, x4, y4, Color );\r
+  DrawLine( Image , x4, y4, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x5, y5, Color );\r
+  DrawLine( Image , x5, y5, x3, y3, Color );\r
+\r
+  return x3;\r
+ }  \r
\r
+ if( Letter == 'X' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = TopLeftX + Width;\r
+  int y2 = y1;\r
+  \r
+  int x3 = x1;\r
+  int y3 = TopLeftY + Height;\r
+  \r
+  int x4 = x2;\r
+  int y4 = y3;\r
+  \r
+  DrawLine( Image , x1 , y1, x4, y4 , Color );\r
+  DrawLine( Image , x2 , y2, x3, y3 , Color );\r
\r
+  return x2;\r
+ }\r
\r
+ if( Letter == 'Y' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = TopLeftX + Width;\r
+  int y2 = y1;\r
+  \r
+  int x3 = TopLeftX + Center;\r
+  int y3 = ebmpRound( TopLeftY + 0.5*Height);\r
+  \r
+  int x4 = x3;\r
+  int y4 = TopLeftY + Height;\r
+  \r
+  DrawLine( Image , x1, y1, x3, y3, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+\r
+  return x2;\r
+ }\r
\r
+ if( Letter == 'Z' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = TopLeftX + Width;\r
+  int y2 = y1;\r
+  \r
+  int x3 = x1;\r
+  int y3 = TopLeftY + Height;\r
+  \r
+  int x4 = x2;\r
+  int y4 = y3;\r
+\r
+  \r
+  DrawLine( Image , x1 , y1, x2, y2 , Color );\r
+  DrawLine( Image , x2 , y2, x3, y3 , Color );\r
+  DrawLine( Image , x3 , y3, x4, y4 , Color );\r
\r
+  return x2;\r
+ } \r
\r
+ // space \r
\r
+ if( Letter == ' ' || Letter == '\t' )\r
+ {\r
+  return ebmpRound( TopLeftX + 0.5*Height );\r
+ }\r
+\r
+ // numbers\r
+\r
+ if( Letter == '0' || Letter == 'O' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY + Height - Center;\r
+  \r
+  int x2 = x1;\r
+  int y2 = TopLeftY + Center; \r
+  \r
+  int x3 = TopLeftX + Width;\r
+  int y3 = y2;\r
+  \r
+  int x4 = x3;\r
+  int y4 = y1;\r
+\r
+  // centers of the circles\r
+  \r
+  double x5 = TopLeftX + Center; \r
+  double y5 = TopLeftY + Center; \r
+\r
+  double x6 = x5;\r
+  double y6 = TopLeftY + Height - Center; \r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+  \r
+  DrawArc( Image, x5, y5 , Center , 3.14159265358979 , 6.28318530717959 , Color ); \r
+  DrawArc( Image, x6, y6 , Center , 0 ,  3.14159265358979 , Color ); \r
+  \r
+  return x3; \r
+ }\r
\r
+ if( Letter == '1' )\r
+ {\r
+  int x1 = ebmpRound( TopLeftX + Height*0.05);\r
+  int y1 = TopLeftY+Height;\r
+  \r
+  int x2 = ebmpRound(x1 + 0.4*Height);\r
+  int y2 = y1;\r
+  \r
+  int x3 = ebmpRound( x1 + 0.2*Height);\r
+  int y3 = y1;\r
+  \r
+  int x4 = x3;\r
+  int y4 = TopLeftY;\r
+  \r
+  int x5 = ebmpRound(x1 + 0.05*Height);\r
+  int y5 = ebmpRound(TopLeftY+ 0.2*Height);\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+  DrawLine( Image , x4, y4, x5, y5, Color );\r
+  \r
+  return ebmpRound(x2 + Height*0.05);\r
+ } \r
\r
+ if( Letter == '2' )\r
+ {\r
+  int x1 = TopLeftX + Width; // ebmpRound( TopLeftX + 0.6*Height );\r
+  int y1 = TopLeftY+Height;\r
+  \r
+  int x2 = TopLeftX;\r
+  int y2 = y1;\r
+  \r
+  int x3 = x1;\r
+  int y3 = TopLeftY + Center; // ebmpRound( TopLeftY + 0.3*Height )+1;\r
+  \r
+  double x4 = TopLeftX + Center; // TopLeftX + (0.3*Height);\r
+  double y4 = TopLeftY + Center; // TopLeftY + (0.3*Height);\r
+  \r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+  \r
+  DrawArc( Image , x4 , y4 , Center , 2.74 , 6.3 , Color );\r
+  \r
+  return x1;\r
+ } \r
\r
+ if( Letter == '3' )\r
+ {\r
+  double x1 = TopLeftX + (0.25*Height);\r
+  double y1 = TopLeftY + (0.25*Height);\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + (0.75*Height);\r
+  \r
+  int x3 = ebmpRound( TopLeftX + 0.3*Height);\r
+  int y3 = ebmpRound( TopLeftY + 0.5*Height);\r
+  \r
+  int x4 = ebmpRound( TopLeftX + 0.2*Height);\r
+  int y4 = y3;\r
+  \r
+  DrawArc( Image , x1 , y1 , 0.25*Height , -3.14159265358979 , 1.57079632679490 , Color );\r
+  DrawArc( Image , x2 , y2 , 0.25*Height , -1.57079632679490 , 3.14159265358979 , Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+\r
+  return ebmpRound(TopLeftX + 0.5*Height); \r
+ }  \r
\r
+ if( Letter == '4' )\r
+ {\r
+  // define some control points\r
+  \r
+  int x1 = TopLeftX+Width;\r
+  int y1 = TopLeftY+ebmpRound(Height*2.0/3.0);\r
+  \r
+  int x2 = TopLeftX;\r
+  int y2 = y1;\r
+  \r
+  int x3 = ebmpRound( TopLeftX + 0.5*Height );\r
+  int y3 = TopLeftY;\r
+  \r
+  int x4 = x3;\r
+  int y4 = TopLeftY + Height;\r
+  \r
\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+  \r
+  return x1;\r
+ }\r
\r
+ if( Letter == '5' )\r
+ {\r
+  int x1 = TopLeftX + Width;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2;\r
+  int y2 = TopLeftY;\r
+  \r
+  int x3 = TopLeftX + ebmpRound( 0.2*Height )-1;\r
+  int y3 = TopLeftY + ebmpRound( 0.48786796564404*Height );\r
+  \r
+  x2 = x3+1;\r
+  \r
+  double x4 = TopLeftX + Center;\r
+  double y4 = TopLeftY + Height - Center;\r
+\r
+  DrawArc( Image , x4, y4, Center, -2.35619449019234 , 3 , Color );\r
\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
\r
+  return x1;\r
+ }\r
+\r
+ if( Letter == '6' )\r
+ {\r
+  double x1 = TopLeftX + (0.25*Height);\r
+  double y1 = TopLeftY + (0.25*Height);\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + (0.75*Height);\r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = ebmpRound( y1 );\r
+  \r
+  int x4 = x3;\r
+  int y4 = ebmpRound( y2 );\r
+\r
+  DrawArc( Image , x1 , y1 , 0.25*Height , 3.1 , 6.2 , Color );\r
+  DrawArc( Image , x2 , y2 , 0.25*Height , 0 , 6.29 , Color );\r
+  \r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+\r
+  return TopLeftX + (int) ebmpRound(.5*Height); \r
+ } \r
\r
+ if( Letter == '7' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = TopLeftX + Width;\r
+  int y2 = y1;\r
+  \r
+  int x3 = ebmpRound(TopLeftX + 0.1*Height);\r
+  int y3 = TopLeftY + Height;\r
\r
+  DrawLine( Image , x1, y1, x2, y2, Color );\r
+  DrawLine( Image , x2, y2, x3, y3, Color );\r
+  \r
+  return x2; \r
+ }\r
\r
+ if( Letter == '8' )\r
+ {\r
+  double x1 = TopLeftX + (0.25*Height);\r
+  double y1 = TopLeftY + (0.25*Height);\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + (0.75*Height);\r
+\r
+  DrawArc( Image , x1 , y1 , 0.25*Height , 0 , 6.28318530717959 , Color );\r
+  DrawArc( Image , x2 , y2 , 0.25*Height , 0 , 6.28318530717959 , Color );\r
+\r
+  return TopLeftX + (int) ebmpRound(.5*Height); \r
+ } \r
+\r
+ if( Letter == '9' )\r
+ {\r
+  double x1 = TopLeftX + (0.25*Height);\r
+  double y1 = TopLeftY + (0.25*Height);\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + (0.75*Height);\r
+  \r
+  int x3 = ebmpRound( TopLeftX + 0.5*Height );\r
+  int y3 = ebmpRound( y1 );\r
+  \r
+  int x4 = x3;\r
+  int y4 = ebmpRound( y2 );\r
+\r
+  DrawArc( Image , x1 , y1 , 0.25*Height , 0 , 6.28318530717959 , Color );\r
+  DrawArc( Image , x2 , y2 , 0.25*Height , 0 , 3 , Color );\r
+  \r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+\r
+  return TopLeftX + (int) ebmpRound(.5*Height); \r
+ } \r
\r
+ if( Letter == '.' )\r
+ {\r
+  double x1 = TopLeftX + 1.25;\r
+  double y1 = TopLeftY + Height  - 0.5;\r
\r
+  DrawArc( Image, x1, y1, 0.75 , 0 , 6.3 , Color );\r
+  \r
+  return ebmpRound( x1 + 1.25 );\r
+ }\r
\r
+ if( Letter == '!' )\r
+ {\r
+  double x1 = TopLeftX + 1.25;\r
+  double y1 = TopLeftY + Height  - 0.5;\r
+  \r
+  int x2 = ebmpRound( x1 );\r
+  int y2 = TopLeftY;\r
+  \r
+  int x3 = x2;\r
+  int y3 = ebmpRound( y1 - 2 );\r
+  \r
+  int y4 = ebmpRound( 0.05*(13*y3+7*y2) );\r
\r
+  DrawArc( Image, x1, y1, 0.75 , 0 , 6.3 , Color );\r
+  \r
+  DrawLine( Image, x2,y2, x3,y3 , Color);\r
+  DrawLine( Image, x2-1, y2, x3-1,y4 , Color);\r
+  \r
+  return ebmpRound( x1 + 1.25 );\r
+ } \r
\r
+ if( Letter == ',' )\r
+ {\r
+  double x1 = TopLeftX + 1.25;\r
+  double y1 = TopLeftY + Height  - 0.5;\r
+  \r
+  double x3 = x1;\r
+  double y3 = y1 + 1.75;\r
\r
+  DrawArc( Image, x1, y1, 0.75 , 0 , 6.3 , Color );\r
+  DrawArc( Image, x3, y3, 1.75 , -0.5*pi , 0.65*pi , Color );\r
+  \r
+  return ebmpRound( x1 + 1.25 );\r
+ }\r
\r
+ if( Letter == '\'' )\r
+ {\r
+  double x1 = TopLeftX + 1.25;\r
+  double y1 = TopLeftY + Center  - 0.5;\r
+  \r
+  double x3 = x1;\r
+  double y3 = y1 + 1.75;\r
\r
+  DrawArc( Image, x1, y1, 0.75 , 0 , 6.3 , Color );\r
+  DrawArc( Image, x3, y3, 1.75 , -0.5*pi , 0.65*pi , Color );\r
+  \r
+  return ebmpRound( x1 + 1.25 );\r
+ } \r
+\r
+ if( Letter == '`' )\r
+ {\r
+  double x1 = TopLeftX + 1.25;\r
+  double y1 = TopLeftY + Center  - 0.5;\r
+  \r
+  double x3 = x1;\r
+  double y3 = y1 + 1.75;\r
\r
+  DrawArc( Image, x1, y1, 0.75 , 0 , 6.3 , Color );\r
+  DrawArc( Image, x3, y3, 1.75 , 0.35*pi , 1.5*pi , Color );\r
+  \r
+  return ebmpRound( x1 + 1.25 );\r
+ } \r
\r
\r
+ if( Letter == '"' )\r
+ {\r
+  double x1 = TopLeftX + 1.25;\r
+  double y1 = TopLeftY + Center  - 0.5;\r
+  \r
+  double x3 = x1;\r
+  double y3 = y1 + 1.75;\r
\r
+  DrawArc( Image, x1, y1, 0.75 , 0 , 6.3 , Color );\r
+  DrawArc( Image, x3, y3, 1.75 , -0.5*pi , 0.65*pi , Color );\r
+  \r
+  DrawArc( Image, x1+3.5, y1, 0.75 , 0 , 6.3 , Color );\r
+  DrawArc( Image, x3+3.5, y3, 1.75 , -0.5*pi , 0.65*pi , Color );  \r
+  \r
+  return ebmpRound( x1 + 1.25 + 3.5);\r
+ }  \r
\r
+ if( Letter == '[' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = y1 + Height;\r
+  \r
+  int x3 = ebmpRound(TopLeftX + 0.15*Height)+1;\r
+  int y3 = y1;\r
+  \r
+  int x4 = x3;\r
+  int y4 = y2;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x1,y1,x3,y3,Color);\r
+  DrawLine(Image,x2,y2,x4,y4,Color);\r
+  \r
+  return x3;\r
+ }   \r
\r
+ if( Letter == ']' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = y1 + Height;\r
+  \r
+  int x3 = ebmpRound(TopLeftX + 0.15*Height)+1;\r
+  int y3 = y1;\r
+  \r
+  int x4 = x3;\r
+  int y4 = y2;\r
+  \r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  DrawLine(Image,x1,y1,x3,y3,Color);\r
+  DrawLine(Image,x2,y2,x4,y4,Color);\r
+  \r
+  return x3;\r
+ }   \r
\r
+ if( Letter == '|' || Letter == 'l' )\r
+ {\r
+  int x1 = TopLeftX+2;\r
+  int y1 = TopLeftY;\r
+  \r
+  int x2 = x1;\r
+  int y2 = y1 + Height;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  \r
+  return x1+2;\r
+ }    \r
\r
+ if( Letter == ':' )\r
+ {\r
+  double x1 = TopLeftX + 1.25;\r
+  double y1 = TopLeftY + Height  - 0.5;\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + 0.5*Height;\r
\r
+  DrawArc( Image, x1, y1, 0.75 , 0 , 6.3 , Color );\r
+  DrawArc( Image, x2, y2, 0.75 , 0 , 6.3 , Color );\r
+  \r
+  return ebmpRound( x1 + 1.25 );\r
+ } \r
+\r
+ if( Letter == ';' )\r
+ {\r
+  double x1 = TopLeftX + 1.25;\r
+  double y1 = TopLeftY + Height  - 0.5;\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + 0.5*Height;\r
+  \r
+  double x3 = x1;\r
+  double y3 = y1 + 1.75;\r
\r
+  DrawArc( Image, x1, y1, 0.75 , 0 , 6.3 , Color );\r
+  DrawArc( Image, x2, y2, 0.75 , 0 , 6.3 , Color );\r
+  DrawArc( Image, x3, y3, 1.75 , -0.5*pi , 0.65*pi , Color );\r
+  \r
+  return ebmpRound( x1 + 1.25 );\r
+ } \r
\r
+ if( Letter == '-' )\r
+ {\r
+  int TempWidth = ebmpRound(0.5*Height);\r
+  if( TempWidth % 2 != 0 )\r
+  { TempWidth++; }\r
+  int TempRad = (TempWidth-1)/2;\r
\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY + TempWidth;\r
+  \r
+  int x2 = TopLeftX + TempWidth;\r
+  int y2 = y1;\r
+  \r
+  DrawLine( Image, x1, y1, x2, y2 , Color );\r
+  \r
+  return x2;\r
+ } \r
\r
+ if( Letter == '=' )\r
+ {\r
+  int TempWidth = ebmpRound(0.5*Height);\r
+  if( TempWidth % 2 != 0 )\r
+  { TempWidth++; }\r
+  int TempRad = (TempWidth-1)/2;\r
\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY + TempWidth-1;\r
+  \r
+  int x2 = TopLeftX + TempWidth+1;\r
+  int y2 = y1;\r
+  \r
+  int x3 = x1;\r
+  int y3 = y1+3;\r
+  \r
+  int x4 = x2;\r
+  int y4 = y3;\r
+  \r
+  \r
+  DrawLine( Image, x1, y1, x2, y2 , Color );\r
+  DrawLine( Image, x3, y3, x4, y4 , Color );\r
+  \r
+  return x2;\r
+ }  \r
\r
+ if( Letter == '+' )\r
+ {\r
+  int TempWidth = ebmpRound(0.5*Height);\r
+  if( TempWidth % 2 != 0 )\r
+  { TempWidth++; }\r
+  int TempRad = (TempWidth-1)/2;\r
\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY + TempWidth;\r
+  \r
+  int x2 = TopLeftX + TempWidth;\r
+  int y2 = y1;\r
+  \r
+  int x3 = ( x1 + TempRad + 1);\r
+  int y3 = ( y1 + TempRad + 1);\r
+\r
+  int x4 = x3;\r
+  int y4 = ( y1 - TempRad - 1);\r
+  \r
+  DrawLine( Image, x1, y1, x2, y2 , Color );\r
+  DrawLine( Image, x3, y3, x4, y4 , Color );\r
+  \r
+  return x2;\r
+ }  \r
\r
+ if( Letter == '/' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY+Height;\r
\r
+  int x2 = TopLeftX+Width;\r
+  int y2 = TopLeftY;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
\r
+  return x2;\r
+ }\r
+ if( Letter == '\\' )\r
+ {\r
+  int x1 = TopLeftX+Width;\r
+  int y1 = TopLeftY+Height;\r
\r
+  int x2 = TopLeftX;\r
+  int y2 = TopLeftY;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
\r
+  return x1;\r
+ }\r
\r
+ if( Letter == '%' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = TopLeftY+Height;\r
\r
+  int x2 = TopLeftX+Width;\r
+  int y2 = TopLeftY;\r
+  \r
+  double x3 = TopLeftX + 0.15*Height;\r
+  double y3 = TopLeftY + 0.15*Height;\r
+  \r
+  double x4 = ceil( TopLeftX + 0.45*Height + 0.5);\r
+  double y4 = ceil( TopLeftY + 0.85*Height );\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+\r
+  DrawArc(Image,x3,y3,0.15*Height,0,2*pi,Color);\r
+  DrawArc(Image,x4,y4,0.15*Height,0,2*pi,Color);\r
+  \r
+  return x2;\r
+ } \r
\r
+ if( Letter == '_' )\r
+ {\r
+  DrawLine(Image,TopLeftX,TopLeftY+Height,TopLeftX+Width,TopLeftY+Height,Color);\r
\r
+  return TopLeftX + Width;\r
+ }\r
\r
+ if( Letter == '^' )\r
+ {\r
+  DrawLine(Image,TopLeftX,TopLeftY+Center,TopLeftX+Center,TopLeftY,Color);\r
+  DrawLine(Image,TopLeftX+Center,TopLeftY,TopLeftX+Width,TopLeftY+Center,Color);\r
\r
+  return TopLeftX + Width;\r
+ } \r
\r
+ if( Letter == '<' )\r
+ {\r
+  int x1 = TopLeftX;\r
+  int y1 = ebmpRound( TopLeftY + 0.5*Height );\r
+  \r
+  int x2 = TopLeftX+Width;\r
+  int y2 = TopLeftY;\r
+  \r
+  int x3 = x2;\r
+  int y3 = TopLeftY+Height;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x1,y1,x3,y3,Color);\r
+  \r
+  return x2;\r
+ }\r
\r
+ if( Letter == '>' )\r
+ {\r
+  int x1 = TopLeftX+Width;\r
+  int y1 = ebmpRound( TopLeftY + 0.5*Height );\r
+  \r
+  int x2 = TopLeftX;\r
+  int y2 = TopLeftY;\r
+  \r
+  int x3 = x2;\r
+  int y3 = TopLeftY+Height;\r
+  \r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x1,y1,x3,y3,Color);\r
+  \r
+  return x1;\r
+ } \r
\r
+ if( Letter == '#' )\r
+ {\r
+  int TempWidth = ebmpRound(0.5*Height);\r
+  if( TempWidth % 2 != 0 )\r
+  { TempWidth++; }\r
+  int TempRad = (TempWidth-1)/2;\r
\r
+  int x1 = TopLeftX;\r
+  int y1 = (int) floor(TopLeftY + 0.5*Height-1);\r
+  \r
+  int x2 = TopLeftX + Width;\r
+  int y2 = y1;\r
+  \r
+  int x3 = x1;\r
+  int y3 = y1+2;\r
+  \r
+  int x4 = x2;\r
+  int y4 = y3;\r
+  \r
+  int x5 = TopLeftX+Center-1;\r
+  int y5 = TopLeftY;\r
+\r
+  int x6 = x5;\r
+  int y6 = TopLeftY+Height;\r
+  \r
+  int x7 = TopLeftX+Center+1;\r
+  int y7 = TopLeftY;\r
+\r
+  int x8 = x7;\r
+  int y8 = TopLeftY+Height;\r
+  \r
+  DrawLine( Image, x1, y1, x2, y2 , Color );\r
+  DrawLine( Image, x3, y3, x4, y4 , Color );\r
+  DrawLine( Image, x5, y5, x6, y6, Color );\r
+  DrawLine( Image, x7,y7,x8,y8,Color);\r
+\r
+  return x2;\r
+ }\r
\r
+ if( Letter == '?' )\r
+ {\r
+  double x1 = TopLeftX+Center;\r
+  double y1 = TopLeftY+Center;\r
+  \r
+  int x2 = (int) x1;\r
+  int y2 = TopLeftY + Width;\r
+  \r
+  int x3 = x2;\r
+  int y3 = ebmpRound(TopLeftY+ 0.8*Height);\r
+  if( TopLeftY+Height-y3 <= 2 )\r
+  { y3--; }\r
+  \r
+  double x4 = x1;\r
+  double y4 = TopLeftY + Height  - 0.5;\r
+  \r
+  DrawArc(Image,x1,y1,Center,pi,pi/2,Color);\r
+  DrawLine(Image,x2,y2,x3,y3,Color);\r
+  DrawArc( Image, x4, y4, 0.75 , 0 , 6.3 , Color );\r
\r
+  return TopLeftX + Width;\r
+ }\r
\r
+ if( Letter == '*' )\r
+ {\r
+  int x1 = TopLeftX+Center;\r
+  int y1 = TopLeftY;\r
\r
+  int x2 = x1;\r
+  int y2 = TopLeftY+Height;\r
+  \r
+  int x3 = TopLeftX;\r
+  int y3 = ebmpRound(TopLeftY+0.5*Height);\r
+  \r
+  int x4 = TopLeftX+Width;\r
+  int y4 = y3;\r
+  \r
+  int x5 = TopLeftX+1; // ebmpRound(TopLeftX+0.15*Width);\r
+  int y5 = TopLeftY+1; // ebmpRound(TopLeftY+0.15*Height);\r
+  \r
+  int x6 = TopLeftX+Width-1; // ebmpRound(TopLeftX+0.45*Width);\r
+  int y6 = TopLeftY+Height-1; //  ebmpRound(TopLeftY+0.85*Height);\r
+  \r
+  int x7 = x6;\r
+  int y7 = y5;\r
+  \r
+  int x8 = x5;\r
+  int y8 = y6;\r
\r
+  DrawLine(Image,x1,y1,x2,y2,Color);\r
+  DrawLine(Image,x3,y3,x4,y4,Color);\r
+  DrawLine(Image,x5,y5,x6,y6,Color);\r
+  DrawLine(Image,x7,y7,x8,y8,Color);\r
+  \r
+  return x4;\r
+ }\r
\r
+ if( Letter == '@' )\r
+ {\r
+  double x1 = TopLeftX + 1.5*Center;\r
+  double y1 = TopLeftY + Height - 1.5*Center;\r
+  \r
+  double x2 = x1 + .35*Center + .6*Center;\r
+  double y2 = y1 + .35*Center;\r
+  \r
+  DrawArc(Image,x1,y1,Center*1.5,0,2*pi,Color);\r
+  DrawArc(Image,x1,y1,Center*0.5,0,2*pi,Color);\r
+  \r
+  DrawArc(Image,x2,y2,Center*0.45,0,pi,Color);\r
\r
+  return ebmpRound(TopLeftX + 3*Center);\r
+ }\r
\r
+ if( Letter == '~' )\r
+ {\r
+  double x1 = TopLeftX + 0.2*Height;\r
+  double y1 = TopLeftY + 0.4*Height;\r
+  \r
+  double x2 = TopLeftX + 0.6*Height;\r
+  double y2 = y1;\r
+  \r
+  DrawArc(Image,x1,y1,0.2*Height, 0.7*pi,2*pi, Color);\r
+  DrawArc(Image,x2,y2,0.2*Height, -0.3*pi,pi, Color);\r
\r
+  return ebmpRound(TopLeftX + 0.8*Height);\r
+ }\r
\r
+ if( Letter == '(' ) \r
+ {\r
+  double x5 = TopLeftX + Center; \r
+  double y5 = TopLeftY + 0.5*Height; \r
+\r
+  DrawArc( Image, x5, y5 , 0.7*Height , 0.5*pi , -0.5*pi , Color ); \r
\r
+  return TopLeftX;\r
+ }\r
\r
+ if( Letter == ')' ) \r
+ {\r
+  double x5 = TopLeftX - Center; \r
+  double y5 = TopLeftY + 0.5*Height; \r
+\r
+  DrawArc( Image, x5, y5 , 0.7*Height , -0.5*pi , 0.5*pi , Color ); \r
\r
+  return TopLeftX;\r
+ } \r
\r
+ if( Letter == '&' )\r
+ {\r
+  double x1 = TopLeftX + Center;\r
+  double y1 = TopLeftY + Height-Center;\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + 0.2*Height;\r
+  \r
+  int x3 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y3 = ebmpRound(y2);\r
+  \r
+  int x4 = TopLeftX;\r
+  int y4 = ebmpRound(y1);\r
+  \r
+  int x5 = ebmpRound(TopLeftX+0.25*Height);\r
+  int y5 = TopLeftY+Height-2*Center;\r
+  \r
+  int x6 = ebmpRound(TopLeftX+1.1*Width);\r
+  int y6 = TopLeftY+Height;  \r
+  \r
+  \r
+  DrawArc( Image, x1,y1, Center, -.1*pi, 1.5*pi, Color);\r
+  DrawArc( Image, x2,y2, 0.2*Height, 0,2*pi,Color); \r
+  \r
+//  DrawLine( Image, x3,y3, x4,y4, Color);\r
+  DrawLine( Image, x5,y5, x6,y6, Color);\r
\r
+  return x6;\r
+ }\r
+\r
+ if( Letter == '&' && 1 == 0 ) // alt ampersand &\r
+ {\r
+  double x1 = TopLeftX + Center;\r
+  double y1 = TopLeftY + Height-Center;\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + 0.2*Height;\r
+  \r
+  int x3 = ebmpRound(TopLeftX+0.5*Height);\r
+  int y3 = ebmpRound(y2);\r
+  \r
+  int x4 = TopLeftX;\r
+  int y4 = ebmpRound(y1);\r
+  \r
+  int x5 = ebmpRound(TopLeftX+0.1*Height);\r
+  int y5 = y3;\r
+  \r
+  int x6 = ebmpRound(TopLeftX+1.1*Width);\r
+  int y6 = TopLeftY+Height;  \r
+  \r
+  \r
+  DrawArc( Image, x1,y1, Center, -.25*pi, pi, Color);\r
+  DrawArc( Image, x2,y2, 0.2*Height, pi,2*pi,Color); \r
+  \r
+  DrawLine( Image, x3,y3, x4,y4, Color);\r
+  DrawLine( Image, x5,y5, x6,y6, Color);\r
\r
+  return x6;\r
+ } \r
\r
+ if( Letter == '$' )\r
+ {\r
+  double x1 = TopLeftX + 0.25*Height;\r
+  double y1 = TopLeftY + 0.25*Height;\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + 0.75*Height;\r
+  \r
+  int x3 = ebmpRound(x1);\r
+  int y3 = ebmpRound(TopLeftY-0.1*Height);\r
+  \r
+  int x4 = x3;\r
+  int y4 = ebmpRound(TopLeftY+1.1*Height);\r
+  \r
+  DrawArc( Image, x1, y1 , 0.25*Height, 1.5707963267948 , 6.28318530717 , Color );\r
+  DrawArc( Image, x2, y2 , 0.25*Height, -1.5707963267948 ,3.1415926535897 , Color );\r
+  DrawLine( Image, x3, y3, x4, y4, Color);\r
+  \r
+  return ebmpRound( TopLeftX + 0.5*Height );\r
+ }\r
\r
+ if( Letter ==  '}' )\r
+ {\r
+  double x1 = TopLeftX;\r
+  double y1 = TopLeftY + 0.15*Height;\r
+  \r
+  double x2 = x1+0.3*Height;\r
+  double y2 = TopLeftY + 0.4*Height;\r
+\r
+  double x3 = x2;\r
+  double y3 = TopLeftY + 0.6*Height;\r
+  \r
+  double x4 = x1;\r
+  double y4 = TopLeftY + 0.85*Height;\r
+  \r
+  DrawArc( Image, x1,y1, 0.2*Height, 1.5*pi, 2*pi, Color);\r
+  \r
+  DrawArc( Image, x2,y2, 0.1*Height, 0.5*pi,pi, Color);\r
+  DrawArc( Image, x3,y3, 0.1*Height, pi,1.5*pi, Color);\r
+  \r
+  DrawArc( Image, x4,y4, 0.2*Height, 0,0.5*pi, Color);\r
+  \r
+  int x5 = ebmpRound( TopLeftX+0.2*Height);\r
+  int y5 = ebmpRound( TopLeftY+0.15*Height);\r
+  \r
+  int x6 = x5;\r
+  int y6 = ebmpRound( TopLeftY+0.4*Height);\r
+  \r
+  DrawLine( Image, x5,y5, x6,y6, Color );\r
+\r
+  int x7 = x5;\r
+  int y7 = ebmpRound( TopLeftY+0.6*Height);\r
+  \r
+  int x8 = x7;\r
+  int y8 = ebmpRound( TopLeftY+0.85*Height);\r
+  \r
+  DrawLine( Image, x7,y7, x8,y8, Color );  \r
+\r
+  return ebmpRound(TopLeftX + 0.4*Height);\r
+ }\r
\r
+ if( Letter ==  '{' )\r
+ {\r
+  double x1 = TopLeftX + 0.3*Height;\r
+  double y1 = TopLeftY + 0.15*Height;\r
+  \r
+  double x2 = TopLeftX  ;\r
+  double y2 = TopLeftY + 0.4*Height;\r
+\r
+  double x3 = x2;\r
+  double y3 = TopLeftY + 0.6*Height;\r
+  \r
+  double x4 = x1;\r
+  double y4 = TopLeftY + 0.85*Height;\r
+  \r
+  DrawArc( Image, x1,y1, 0.2*Height, pi,1.5*pi, Color);\r
+  \r
+  DrawArc( Image, x2,y2, 0.1*Height, 0,0.5*pi, Color);\r
+  DrawArc( Image, x3,y3, 0.1*Height, 1.5*pi,2*pi, Color);\r
+  \r
+  DrawArc( Image, x4,y4, 0.2*Height, 0.5*pi,pi, Color);\r
+  \r
+  int x5 = ebmpRound( TopLeftX+0.1*Height);\r
+  int y5 = ebmpRound( TopLeftY+0.15*Height);\r
+  \r
+  int x6 = x5;\r
+  int y6 = ebmpRound( TopLeftY+0.4*Height);\r
+  \r
+  DrawLine( Image, x5,y5, x6,y6, Color );\r
+\r
+  int x7 = x5;\r
+  int y7 = ebmpRound( TopLeftY+0.6*Height);\r
+  \r
+  int x8 = x7;\r
+  int y8 = ebmpRound( TopLeftY+0.85*Height);\r
+  \r
+  DrawLine( Image, x7,y7, x8,y8, Color );  \r
+\r
+  return ebmpRound(TopLeftX + 0.4*Height);\r
+ }  \r
\r
+ if( Letter == '&' && 1 == 0 ) // old ampersand '&'\r
+ {\r
+  double x1 = TopLeftX + (0.25*Height);\r
+  double y1 = TopLeftY + (0.25*Height);\r
+  \r
+  double x2 = x1;\r
+  double y2 = TopLeftY + (0.75*Height);\r
+  \r
+  int x3 = ebmpRound( TopLeftX + 0.3*Height);\r
+  int y3 = ebmpRound( TopLeftY + 0.5*Height);\r
+  \r
+  int x4 = ebmpRound( TopLeftX + 0.2*Height);\r
+  int y4 = y3;\r
+  \r
+  int x5 = ebmpRound(TopLeftX + 0.35*Height);\r
+  int y5 = ebmpRound(TopLeftY + 0.75*Height);\r
+  \r
+  int x6 = ebmpRound(TopLeftX + 0.65*Height);\r
+  int y6 = y5;\r
+  \r
+  \r
+  DrawArc( Image , x1 , y1 , 0.25*Height , 1.57079632679490 , 2*pi , Color );\r
+  DrawArc( Image , x2 , y2 , 0.25*Height , 0, 1.5*pi , Color );\r
+  DrawLine( Image , x3, y3, x4, y4, Color );\r
+  DrawLine( Image , x5, y5, x6, y6, Color );\r
+\r
+  return x6;\r
+ }   \r
\r
\r
+ return TopLeftX;\r
+}\r
+\r
+int PrintCopyright( BMP& Image, int TopLeftX, int TopLeftY , int Height , \r
+                  RGBApixel Color )\r
+{\r
+ double pi = 3.14159265358979;\r
\r
+ int CharNumber = 0;\r
+ int StartX = ebmpRound(TopLeftX+0.25*Height);\r
+ int Spacing = (int) ebmpRound( 0.2*Height );\r
+ if( Spacing < 3 )\r
+ { Spacing = 3; }\r
+ int StartY = ebmpRound( TopLeftY-0.25*Height);\r
\r
+ double x1 = TopLeftX + 0.5*Height;\r
+ double y1 = TopLeftY + 0.5*Height;\r
\r
+ DrawArc(Image, x1, y1, 0.6*Height , 0, 2*pi , Color );\r
+ return PrintLetter( Image, 'c' , StartX, StartY , Height, Color ) + Spacing; \r
+}\r
diff --git a/src/freenet/captcha/easybmp/EasyBMP_Geometry.cpp b/src/freenet/captcha/easybmp/EasyBMP_Geometry.cpp
new file mode 100644 (file)
index 0000000..3b504de
--- /dev/null
@@ -0,0 +1,367 @@
+/*************************************************\r
+*                                                *\r
+*  EasyBMP Cross-Platform Windows Bitmap Library * \r
+*                                                *\r
+*  Author: Paul Macklin                          *\r
+*   email: pmacklin@math.uci.edu                 *\r
+*                                                *\r
+*    file: EasyBMP_Geometry.h                    *\r
+*    date: 2-21-2005                             *\r
+* version: 1.05.00                               *\r
+*                                                *\r
+*   License: BSD (revised)                       *\r
+* Copyright: 2005-2006 by the EasyBMP Project    * \r
+*                                                *\r
+* description: draw simple geometric objects     *\r
+*                                                *\r
+*************************************************/\r
+\r
+#include "../../../../include/freenet/captcha/easybmp/EasyBMP_Geometry.h"\r
+\r
+int ebmpRound( double input )\r
+{\r
+ double output = floor( input );\r
+ if( output - input >= 0.50 )\r
+ { return (int) ( output+1 ); }\r
+ return (int) output;\r
+}\r
+\r
+double InverseAngle( double Xdir, double Ydir )\r
+{\r
+ double pi = 3.14159265358979;\r
+ double Norm = sqrt( Xdir*Xdir + Ydir*Ydir );\r
+ if( Norm <= 0.25 )\r
+ { return 0.0; }\r
+ Xdir /= Norm; \r
+ Ydir /= Norm;\r
+\r
+ double Xabs = fabs( Xdir );\r
+ double Yabs = fabs( Ydir );\r
+ double theta = 0.5*( acos( Xabs ) + asin( Yabs ) );\r
+\r
+ if( Xdir >= 0.0 && Ydir >= 0.0 )\r
+ { return theta; }\r
+ if( Xdir < 0.0 && Ydir >= 0.0 )\r
+ { return pi - theta; }\r
+ if( Xdir < 0.0 && Ydir < 0.0 )\r
+ { return pi + theta; }\r
+ return 2*pi - theta; \r
+}\r
+\r
+double LineFunction( double SlopeX , double SlopeY, int StartX, int StartY, double TestX, double TestY )\r
+{\r
+ return fabs( SlopeX*(TestY-StartY) - SlopeY*(TestX-StartX) );\r
+}\r
+\r
+void DrawAALine( BMP &Image , int FromX, int FromY, int ToX, int ToY , RGBApixel Color )\r
+{\r
+ double SlopeX = ToX-FromX;\r
+ double SlopeY = ToY-FromY;\r
+\r
+ if( fabs( SlopeX ) <= 0.8 && fabs( SlopeY ) <= 0.8 ) // nothing to do; don't bother\r
+ {\r
+  return;\r
+ }\r
+ double Norm = sqrt( Square( SlopeX ) + Square( SlopeY ) );\r
+ SlopeX /= Norm; \r
+ SlopeY /= Norm;\r
+\r
+ // bounds checking\r
+\r
+ if( FromX >= Image.TellWidth() )\r
+ { FromX = Image.TellWidth()-1; }\r
+ if( FromX < 0 )\r
+ { FromX = 0; }\r
+ if( ToX >= Image.TellWidth() )\r
+ { ToX = Image.TellWidth()-1; }\r
+ if( ToX < 0 )\r
+ { ToX = 0; }\r
+\r
+ if( FromY >= Image.TellHeight() )\r
+ { FromY = Image.TellHeight()-1; }\r
+ if( FromY < 0 )\r
+ { FromY = 0; }\r
+ if( ToY >= Image.TellHeight() )\r
+ { ToY = Image.TellHeight()-1; }\r
+ if( ToY < 0 )\r
+ { ToY = 0; }\r
+\r
+ int LeftI = FromX;\r
+ int RightI = ToX;\r
+ if( RightI < LeftI ){ int temp = LeftI; LeftI = RightI; RightI = temp; }\r
+ int LeftJ = FromY;\r
+ int RightJ = ToY;\r
+ if( RightJ < LeftJ ){ int temp = LeftJ; LeftJ = RightJ; RightJ = temp; }\r
\r
+ int i,j;\r
+ for( i=LeftI ; i <= RightI ; i++ )\r
+ {\r
+  for( j=LeftJ ; j <= RightJ ; j++ )\r
+  {\r
+   double ii=0;\r
+   double jj=0;\r
+   double dx = 0.25;\r
+   double dy = 0.25;\r
+   double x = i-1.5*dx;\r
+   double y = j-1.5*dx;\r
+   \r
+   double Temp = 0.0;\r
+   \r
+   for( ii=-2; ii<=1 ; ii++)\r
+   {\r
+    for( jj=-2 ; jj<=1 ; jj++)\r
+    {\r
+     x = i+ii*dx+0.5*dx;\r
+     y = j+jj*dy+0.5*dy;\r
+     double Temp1 = LineFunction( SlopeX, SlopeY , FromX, FromY, x,y ); \r
+     if( Temp1 <= 0.5 ){ Temp1 = 1.0; }else{ Temp1 = 0.0; }\r
+     Temp+=Temp1;\r
+    }   \r
+   }\r
+   \r
+   Temp /= 16.0;\r
+   double MinValue = 0.03125; // 1.0/32.0\r
+   \r
+   if( Temp > MinValue )\r
+   {\r
+    Image(i,j)->Red = (ebmpBYTE) (unsigned int) (  (1.0-Temp)*( (double) Image(i,j)->Red )\r
+                                                        +Temp*( (double) Color.Red ) );\r
+    Image(i,j)->Green = (ebmpBYTE) (unsigned int) (  (1.0-Temp)*( (double) Image(i,j)->Green )\r
+                                                        +Temp*( (double) Color.Green ) );\r
+    Image(i,j)->Blue = (ebmpBYTE) (unsigned int) (  (1.0-Temp)*( (double) Image(i,j)->Blue )\r
+                                                          +Temp*( (double) Color.Blue ) );\r
+   }\r
+   \r
+  }\r
+ }\r
\r
+ return; \r
+}\r
+\r
+void DrawFastLine( BMP &Image , int FromX, int FromY, int ToX, int ToY , RGBApixel Color )\r
+{\r
+ // bounds checking\r
+\r
+ if( FromX >= Image.TellWidth() )\r
+ { FromX = Image.TellWidth()-1; }\r
+ if( FromX < 0 )\r
+ { FromX = 0; }\r
+ if( ToX >= Image.TellWidth() )\r
+ { ToX = Image.TellWidth()-1; }\r
+ if( ToX < 0 )\r
+ { ToX = 0; }\r
+\r
+ if( FromY >= Image.TellHeight() )\r
+ { FromY = Image.TellHeight()-1; }\r
+ if( FromY < 0 )\r
+ { FromY = 0; }\r
+ if( ToY >= Image.TellHeight() )\r
+ { ToY = Image.TellHeight()-1; }\r
+ if( ToY < 0 )\r
+ { ToY = 0; }\r
+\r
+ // source: http://www.gamedev.net/reference/articles/article1275.asp\r
+\r
+ int dX = ToX - FromX;\r
+ int dY = ToY - FromY;\r
\r
+ if( dX == 0 && dY == 0 ) // nothing to do; don't bother\r
+ {\r
+  return;\r
+ }\r
\r
+ int Xinc1 = 1;\r
+ if( dX < 0 )\r
+ { Xinc1 = -1; dX = -dX; } \r
+ int Yinc1 = 1;\r
+ if( dY < 0 )\r
+ { Yinc1 = -1; dY = -dY; }\r
\r
+ int x = FromX;               // Start x off at the first pixel\r
+ int y = FromY;               // Start y off at the first pixel\r
\r
+ int Xinc2 = Xinc1;\r
+ int Yinc2 = Yinc1;\r
\r
+ double Denominator;\r
+ double Numerator;\r
+ int NumberToAdd;\r
+ int NumberOfPixels;\r
+\r
+ if ( dX >= dY )         // There is at least one x-value for every y-value\r
+ {\r
+  Xinc1 = 0;                  // Don't change the x when numerator >= denominator\r
+  Yinc2 = 0;                  // Don't change the y for every iteration\r
+  Denominator = dX+0.0;\r
+  Numerator = 0.5*dX;\r
+  NumberToAdd = dY;\r
+  NumberOfPixels = dX;         // There are more x-values than y-values\r
+ }\r
+ else                          // There is at least one y-value for every x-value\r
+ {\r
+  Xinc2 = 0;                  // Don't change the x for every iteration\r
+  Yinc1 = 0;                  // Don't change the y when numerator >= denominator\r
+  Denominator = dY+0.0;\r
+  Numerator = 0.5*dY;\r
+  NumberToAdd = dX;\r
+  NumberOfPixels = dY;         // There are more y-values than x-values\r
+ }\r
\r
+ int CurrentPixel;\r
+\r
+ for (CurrentPixel = 0; CurrentPixel <= NumberOfPixels; CurrentPixel++ )\r
+ {\r
+  Image(x,y)->Red = Color.Red;\r
+  Image(x,y)->Green = Color.Green;\r
+  Image(x,y)->Blue = Color.Blue;\r
+  \r
+  Numerator += NumberToAdd;   // Increase the numerator by the top of the fraction\r
+  if( Numerator >= Denominator ) // Check if numerator >= denominator\r
+  {\r
+    Numerator -= Denominator; // Calculate the new numerator value\r
+    x += Xinc1;               // Change the x as appropriate\r
+    y += Yinc1;               // Change the y as appropriate\r
+  }\r
+  x += Xinc2;                 // Change the x as appropriate\r
+  y += Yinc2;                 // Change the y as appropriate\r
+ }\r
\r
+ return; \r
+}\r
+\r
+void DrawArc( BMP &Image , double CenterX, double CenterY , double Radius, \r
+              double FromTheta, double ToTheta , RGBApixel Color )\r
+{\r
+ double pi = 3.14159265358979;\r
+\r
+ while( ToTheta < FromTheta )\r
+ { ToTheta += 2*pi; }\r
+\r
+ double Arclength = (ToTheta-FromTheta)*Radius;\r
+ if( fabs( Arclength ) <= 1e-5 ) // if it's short, don't bother\r
+ { return; }\r
\r
+ // set up the final circle first\r
\r
+ BMP Downsampled;\r
+ int FinalWidth = (int) floor( 2.0*Radius + 1.0); // was ceil ,also tried Round\r
\r
+ // new for testing\r
+ Radius = 0.5*(FinalWidth-1.0);\r
+ // end new for testing \r
\r
+ int FinalHeight = FinalWidth;\r
+ Downsampled.SetSize( FinalWidth , FinalHeight );\r
\r
+ // make a temporary circle of double resolution\r
+\r
+ BMP Temp;\r
+ double TempRadius = 2.0*Radius; \r
\r
+ Temp.SetSize( 2*FinalWidth, 2*FinalHeight );\r
+ double dTheta = 1.0/TempRadius;\r
\r
+ double CenterXtemp = FinalWidth - 0.5; // was TempRadius + .5\r
+ double CenterYtemp = FinalHeight - 0.5; // was TempRadius + 0.5;\r
+\r
+ int x,y;\r
\r
+ double OuterRadiusSquared = TempRadius+1.0;\r
+ OuterRadiusSquared *= OuterRadiusSquared;\r
+ double InnerRadiusSquared = TempRadius-1.0;\r
+ InnerRadiusSquared *= InnerRadiusSquared;\r
\r
+ for( x=0 ; x < Temp.TellWidth() ;x++)\r
+ {\r
+  for( y=0 ; y < Temp.TellHeight() ; y++)\r
+  {\r
+   double X = x-CenterXtemp;\r
+   double Y = y-CenterYtemp;\r
+   double TempRadiusSquared = X*X + Y*Y;\r
+   \r
+   if( InnerRadiusSquared <= TempRadiusSquared && \r
+       TempRadiusSquared <= OuterRadiusSquared )\r
+   {\r
+    double Angle = InverseAngle( X, Y );\r
+    bool PlotIt = false;\r
+    if( FromTheta <= Angle && Angle <= ToTheta )\r
+    { PlotIt = true; }\r
+    Angle += 2*pi;\r
+    if( FromTheta <= Angle && Angle <= ToTheta )\r
+    { PlotIt = true; }\r
+    Angle -= 4*pi;\r
+    if( FromTheta <= Angle && Angle <= ToTheta )\r
+    { PlotIt = true; }\r
+    \r
+    if( PlotIt )\r
+    { Temp(x,y)->Red = 0; }\r
+   }\r
+  }\r
+ }\r
\r
+ // downsample to anti-alias\r
\r
+ int i,j;\r
+ for( i=0 ; i < Downsampled.TellWidth() ; i++ )\r
+ {\r
+  for( j=0 ; j < Downsampled.TellHeight() ; j++ )\r
+  {\r
+   double TempRed = 0.0;\r
+  \r
+   int k,ell;\r
+   for( k=0 ; k <= 1 ; k++ )\r
+   {\r
+    for( ell=0 ; ell <= 1 ; ell++ )\r
+    {\r
+     int I = 2*i+k;\r
+     int J = 2*j+ell;\r
+     TempRed += (double) Temp(I,J)->Red;\r
+    }\r
+   }\r
+   TempRed /= 4.0;\r
+   \r
+   Downsampled(i,j)->Red = (ebmpBYTE) TempRed;\r
+  }\r
+ }\r
\r
+ // paste with alpha blending \r
\r
+ int DestinationTopLeft = ebmpRound( CenterX - Radius );\r
+ int DestinationTopRight = ebmpRound( CenterY - Radius );\r
\r
+ for( i=0 ; i < Downsampled.TellWidth() ; i++) \r
+ {\r
+  for( j=0 ; j < Downsampled.TellHeight() ; j++)\r
+  {\r
+   int DestinationI = DestinationTopLeft+i;\r
+   int DestinationJ = DestinationTopRight+j;\r
+   if( DestinationI >= 0 && DestinationI < Image.TellWidth() &&\r
+       DestinationJ >= 0 && DestinationJ < Image.TellHeight() )\r
+   {\r
+    double alpha = (255.0 - Downsampled(i,j)->Red )/255.0;\r
+    Image(DestinationI,DestinationJ)->Red = (ebmpBYTE) ( \r
+      (1.0-alpha)*Image(DestinationI,DestinationJ)->Red \r
+    + (alpha)*Color.Red );\r
+    Image(DestinationI,DestinationJ)->Green = (ebmpBYTE) ( \r
+      (1.0-alpha)*Image(DestinationI,DestinationJ)->Green \r
+    + (alpha)*Color.Green );\r
+    Image(DestinationI,DestinationJ)->Blue = (ebmpBYTE) ( \r
+      (1.0-alpha)*Image(DestinationI,DestinationJ)->Blue \r
+    + (alpha)*Color.Blue );\r
+   }\r
+  \r
+  }\r
+ }\r
\r
+ return;\r
+}\r
+\r
+void DrawLine( BMP &Image , int FromX , int FromY, int ToX, int ToY, RGBApixel Color )\r
+{\r
+ if( FromX != ToX && FromY != ToY )\r
+ {\r
+  DrawAALine( Image, FromX, FromY, ToX, ToY, Color);\r
+ } \r
+ DrawFastLine( Image, FromX, FromY, ToX, ToY, Color); \r
+ return;\r
+}\r
diff --git a/src/freenet/captcha/simplecaptcha.cpp b/src/freenet/captcha/simplecaptcha.cpp
new file mode 100644 (file)
index 0000000..c030bca
--- /dev/null
@@ -0,0 +1,93 @@
+#include "../../../include/freenet/captcha/simplecaptcha.h"\r
+#include "../../../include/freenet/captcha/easybmp/EasyBMP.h"\r
+#include "../../../include/freenet/captcha/easybmp/EasyBMP_Font.h"\r
+#include "../../../include/freenet/captcha/easybmp/EasyBMP_Geometry.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+void SimpleCaptcha::Generate()\r
+{\r
+       BMP bmp;\r
+       int bmpwidth=100;\r
+       int bmpheight=50;\r
+       std::string puzzlestring;\r
+       std::string tempfilename=GenerateRandomString(10);\r
+       tempfilename+=".bmp";\r
+\r
+       puzzlestring=GenerateRandomString(5);\r
+       m_solution.clear();\r
+       m_solution.insert(m_solution.begin(),puzzlestring.begin(),puzzlestring.end());\r
+\r
+       bmp.SetSize(bmpwidth,bmpheight);\r
+\r
+       // first draw some random lines around the bitmap\r
+       int numlines=(rand()%20)+10;\r
+       for(int i=0; i<numlines; i++)\r
+       {\r
+               RGBApixel pixel;\r
+               int x1=rand()%bmpwidth;\r
+               int y1=rand()%bmpheight;\r
+               int x2=rand()%bmpwidth;\r
+               int y2=rand()%bmpwidth;\r
+               // keep the colors light\r
+               pixel.Red=100+(rand()%150);\r
+               pixel.Green=100+(rand()%150);\r
+               pixel.Blue=100+(rand()%150);\r
+               DrawAALine(bmp,x1,y1,x2,y2,pixel);\r
+       }\r
+\r
+       // print puzzle onto bitmap\r
+       for(int i=0; i<5; i++)\r
+       {\r
+               // keep the colors dark\r
+               RGBApixel pixel;\r
+               pixel.Red=(rand()%200);\r
+               pixel.Green=(rand()%200);\r
+               pixel.Blue=(rand()%200);\r
+               PrintLetter(bmp,puzzlestring[i],5+(i*20),10+(rand()%10),20,pixel);\r
+       }\r
+\r
+       bmp.WriteToFile(tempfilename.c_str());\r
+       ReadPuzzleData(tempfilename);\r
+       unlink(tempfilename.c_str());\r
+}\r
+\r
+const std::string SimpleCaptcha::GenerateRandomString(const int len)\r
+{\r
+       static std::string chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";\r
+       std::string temp="";\r
+       for(int i=0; i<len; i++)\r
+       {\r
+               temp+=chars[rand()%chars.size()];\r
+       }\r
+       return temp;\r
+}\r
+\r
+const bool SimpleCaptcha::GetPuzzle(std::vector<unsigned char> &puzzle)\r
+{\r
+       puzzle=m_puzzle;\r
+       return true;\r
+}\r
+\r
+const bool SimpleCaptcha::GetSolution(std::vector<unsigned char> &solution)\r
+{\r
+       solution=m_solution;\r
+       return true;\r
+}\r
+\r
+void SimpleCaptcha::ReadPuzzleData(const std::string &filename)\r
+{\r
+       long filelen;\r
+       FILE *infile=fopen(filename.c_str(),"rb");\r
+       if(infile)\r
+       {\r
+               fseek(infile,0,SEEK_END);\r
+               filelen=ftell(infile);\r
+               fseek(infile,0,SEEK_SET);\r
+               m_puzzle.resize(filelen);\r
+               fread(&m_puzzle[0],1,filelen,infile);\r
+               fclose(infile);\r
+       }\r
+}
\ No newline at end of file
diff --git a/src/freenet/fcpv2.cpp b/src/freenet/fcpv2.cpp
new file mode 100644 (file)
index 0000000..42995f4
--- /dev/null
@@ -0,0 +1,443 @@
+#include "../../include/freenet/fcpv2.h"\r
+#include <cstdio>\r
+#include <cstdarg>\r
+#include <sstream>\r
+\r
+#ifdef _WIN32\r
+       #include <ws2tcpip.h>\r
+#else\r
+       #include <netdb.h>\r
+       #include <netinet/in.h>\r
+#endif\r
+\r
+/* XMEM doesn't play nice with strtok - should replace strtok with something else anyway\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+*/\r
+\r
+#ifdef _WIN32\r
+       bool FCPv2::m_wsastartup=false;\r
+#endif\r
+\r
+\r
+\r
+FCPv2::FCPv2()\r
+{\r
+#ifdef _WIN32\r
+       if(m_wsastartup==false)\r
+       {\r
+               WSAData wsadata;\r
+               WSAStartup(MAKEWORD(2,2),&wsadata);\r
+               m_wsastartup=true;\r
+       }\r
+#endif\r
+\r
+       // initialize socket to server\r
+       m_serversocket=-1;\r
+\r
+       // initialize buffers\r
+       m_tempbuffer=new char[65535];\r
+\r
+}\r
+\r
+\r
+FCPv2::~FCPv2()\r
+{\r
+       Disconnect();\r
+#ifdef _WIN32\r
+       WSACleanup();\r
+#endif\r
+\r
+       delete [] m_tempbuffer;\r
+\r
+}\r
+\r
+\r
+const bool FCPv2::Connect(const char *host, const int port)\r
+{\r
+       // disconnect socket to server if it is currently open\r
+       if(Connected())\r
+       {\r
+               Disconnect();\r
+       }\r
+\r
+       int rval=-1;\r
+       struct sockaddr_storage m_serveraddr;\r
+\r
+       std::ostringstream portstring;\r
+       addrinfo hint,*result;\r
+       result=NULL;\r
+       portstring << port;\r
+\r
+       memset(&hint,0,sizeof(addrinfo));\r
+       hint.ai_socktype=SOCK_STREAM;\r
+       rval=getaddrinfo(host,portstring.str().c_str(),&hint,&result);\r
+\r
+       // erase any data in buffers\r
+       m_sendbuffer.clear();\r
+       m_receivebuffer.clear();\r
+\r
+       if(result)\r
+       {\r
+               memset(&m_serveraddr,0,sizeof(struct sockaddr_storage));\r
+\r
+               m_serversocket=socket(result->ai_family,result->ai_socktype,result->ai_protocol);\r
+\r
+               if(m_serversocket!=-1)\r
+               {\r
+                       rval=connect(m_serversocket,result->ai_addr,result->ai_addrlen);\r
+                       if(rval==-1)\r
+                       {\r
+                               Disconnect();\r
+                       }\r
+               }\r
+\r
+               freeaddrinfo(result);\r
+       }\r
+\r
+       if(rval==0)\r
+       {\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+\r
+}\r
+\r
+const bool FCPv2::Disconnect()\r
+{\r
+       if(Connected())\r
+       {\r
+       #ifdef _WIN32\r
+               closesocket(m_serversocket);\r
+       #else\r
+               close(m_serversocket);\r
+       #endif\r
+               m_serversocket=-1;\r
+       }\r
+       return true;\r
+}\r
+\r
+int FCPv2::FindOnReceiveBuffer(const char *text)\r
+{\r
+       bool found;\r
+       int i,j;\r
+       size_t tlen=strlen(text);\r
+\r
+       if(m_receivebuffer.size()>=tlen)\r
+       {\r
+               for(i=0; i<=m_receivebuffer.size()-tlen; i++)\r
+               {\r
+                       found=true;\r
+                       for(j=0; j<tlen; j++)\r
+                       {\r
+                               if(m_receivebuffer[i+j]!=text[j])\r
+                               {\r
+                                       found=false;\r
+                                       j=tlen;\r
+                               }\r
+                       }\r
+                       if(found==true)\r
+                       {\r
+                               return i;\r
+                       }\r
+               }\r
+       }\r
+\r
+       return -1;\r
+}\r
+\r
+FCPMessage FCPv2::ReceiveMessage()\r
+{\r
+       int field=0;\r
+       int len=0;\r
+       int endlen=0;\r
+       int endmessage=-1;\r
+       char *buffpos;\r
+       char *prevpos;\r
+       char *buffer;\r
+\r
+       FCPMessage message;\r
+\r
+       // there is data on the receive buffer\r
+       if(m_receivebuffer.size()>0)\r
+       {\r
+\r
+               // find Data on a line by itself following AllData\r
+               if(FindOnReceiveBuffer("AllData\n")==0)\r
+               {\r
+                       endmessage=FindOnReceiveBuffer("\nData\n");\r
+                       if(endmessage!=-1)\r
+                       {\r
+                               endmessage++;\r
+                               endlen=5;\r
+                       }\r
+               }\r
+               // otherwise this is a regular message - search for EndMessage\r
+               else\r
+               {\r
+                       endmessage=FindOnReceiveBuffer("EndMessage\n");\r
+                       endlen=11;\r
+               }\r
+\r
+               // continue if we found "EndMessage\n" or "Data\n"\r
+               if(endmessage!=-1)\r
+               {\r
+                       // total length of message (including ending \n)\r
+                       len=endmessage+endlen;\r
+\r
+                       // allocate space for message\r
+                       buffer=new char[len+1];\r
+\r
+                       // copy message from receive buffer to message buffer\r
+                       std::copy(m_receivebuffer.begin(),m_receivebuffer.begin()+len,buffer);\r
+                       buffer[len]='\0';\r
+\r
+                       // remove from receive buffer\r
+                       m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
+\r
+                       // set buffer position\r
+                       buffpos=buffer;\r
+\r
+                       // find message name\r
+                       buffpos=strtok(buffer,"\n");\r
+                       message.SetName(buffer);\r
+\r
+                       do\r
+                       {\r
+                               // find next field\r
+                               prevpos=buffpos;\r
+                               buffpos=strtok(NULL,"=");\r
+\r
+                               // continue if we aren't at the end of a regular message, or at Data for an AllData message\r
+                               if(strncmp(buffpos,"EndMessage\n",11)!=0 && strncmp(buffpos,"Data\n",5)!=0)     //!(strncmp(message->MessageName,"AllData",7)==0 && strncmp(buffpos,"Data\n",5)==0))\r
+                               {\r
+\r
+                                       // find next value\r
+                                       prevpos=buffpos;\r
+                                       buffpos=strtok(NULL,"\n");\r
+\r
+                                       if(prevpos && buffpos)\r
+                                       {\r
+                                               message[prevpos]=buffpos;\r
+                                       }\r
+\r
+                                       field++;\r
+                               }\r
+                               else\r
+                               {\r
+                                       buffpos=0;\r
+                               }\r
+\r
+                       }while(buffpos!=0);\r
+\r
+                       delete [] buffer;\r
+\r
+               }\r
+       }\r
+\r
+       return message;\r
+}\r
+\r
+const long FCPv2::ReceiveRaw(char *data, long &datalen)\r
+{\r
+       long len=0;\r
+       if(m_receivebuffer.size()>0 && datalen>0)\r
+       {\r
+               if(datalen>m_receivebuffer.size())\r
+               {\r
+                       len=m_receivebuffer.size();\r
+               }\r
+               else\r
+               {\r
+                       len=datalen;\r
+               }\r
+\r
+               std::copy(m_receivebuffer.begin(),m_receivebuffer.begin()+len,data);\r
+\r
+               // erase bytes from receive buffer\r
+               m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
+\r
+       }\r
+       datalen=len;\r
+       return datalen;\r
+}\r
+\r
+void FCPv2::SendBufferedText(const char *text)\r
+{\r
+       unsigned int i;\r
+       for(i=0; i<strlen(text); i++)\r
+       {\r
+               m_sendbuffer.push_back(text[i]);\r
+       }\r
+}\r
+\r
+void FCPv2::SendBufferedRaw(const char *data, const long len)\r
+{\r
+       int i;\r
+       for(i=0; i<len; i++)\r
+       {\r
+               m_sendbuffer.push_back(data[i]);\r
+       }\r
+}\r
+\r
+const int FCPv2::SendMessage(const char *messagename, const int fieldcount, ...)\r
+{\r
+       va_list args;\r
+       const char *field;\r
+       const char *val;\r
+       int bytecount=0;\r
+       int i;\r
+       int startlen;\r
+\r
+       startlen=m_sendbuffer.size();\r
+\r
+       SendBufferedText(messagename);\r
+       SendBufferedText("\n");\r
+\r
+       va_start(args,fieldcount);\r
+\r
+       for(i=0; i<fieldcount; i++)\r
+       {\r
+               field=va_arg(args,const char *);\r
+               val=va_arg(args,const char *);\r
+\r
+               SendBufferedText(field);\r
+               SendBufferedText("=");\r
+               SendBufferedText(val);\r
+               SendBufferedText("\n");\r
+       }\r
+\r
+       SendBufferedText("EndMessage\n");\r
+\r
+       bytecount=m_sendbuffer.size()-startlen;\r
+       \r
+       va_end(args);\r
+\r
+       return bytecount;\r
+}\r
+\r
+const int FCPv2::SendMessage(FCPMessage &message)\r
+{\r
+       int bytecount=0;\r
+       int startlen;\r
+       FCPMessage::iterator i;\r
+\r
+       startlen=m_sendbuffer.size();\r
+\r
+       if(message.GetName()!="")\r
+       {\r
+               SendBufferedText(message.GetName().c_str());\r
+               SendBufferedText("\n");\r
+\r
+               for(i=message.begin(); i!=message.end(); i++)\r
+               {\r
+                       SendBufferedText((*i).first.c_str());\r
+                       SendBufferedText("=");\r
+                       SendBufferedText((*i).second.c_str());\r
+                       SendBufferedText("\n");\r
+               }\r
+\r
+               SendBufferedText("EndMessage\n");\r
+       }\r
+\r
+       bytecount=m_sendbuffer.size()-startlen;\r
+\r
+       return bytecount;\r
+}\r
+\r
+\r
+const int FCPv2::SendRaw(const char *data, const int datalen)\r
+{\r
+       int bytecount=datalen;\r
+\r
+       if(bytecount>0)\r
+       {\r
+               SendBufferedRaw(data,datalen);\r
+       }\r
+\r
+       return bytecount;\r
+\r
+}\r
+\r
+void FCPv2::SocketReceive()\r
+{\r
+       int len=0;\r
+\r
+       len=recv(m_serversocket,m_tempbuffer,65535,0);\r
+\r
+       if(len>0)\r
+       {\r
+\r
+               m_receivebuffer.resize(m_receivebuffer.size()+len);\r
+               std::copy(m_tempbuffer,&m_tempbuffer[len],m_receivebuffer.end()-len);\r
+\r
+       }\r
+       // there was an error or server closed connection  - disconnect socket\r
+       else\r
+       {\r
+               Disconnect();\r
+       }\r
+}\r
+\r
+void FCPv2::SocketSend()\r
+{\r
+       int len=0;\r
+       if(m_sendbuffer.size()>0)\r
+       {\r
+               len=send(m_serversocket,&m_sendbuffer[0],m_sendbuffer.size(),0);\r
+               if(len>0)\r
+               {\r
+                       // move remaining data in buffer to beginning of buffer (erase the bytes we just sent)\r
+                       m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+len);\r
+               }\r
+               // there was an error with send - disconnect socket\r
+               else\r
+               {\r
+                       Disconnect();\r
+               }\r
+       }\r
+}\r
+\r
+\r
+const bool FCPv2::Update(const long waittime)\r
+{\r
+\r
+       if(Connected())\r
+       {\r
+               m_timeval.tv_sec=waittime;\r
+               m_timeval.tv_usec=0;\r
+\r
+               FD_ZERO(&m_readfs);\r
+               FD_ZERO(&m_writefs);\r
+\r
+               FD_SET(m_serversocket,&m_readfs);\r
+               \r
+               if(m_sendbuffer.size()>0)\r
+               {\r
+                       FD_SET(m_serversocket,&m_writefs);\r
+               }\r
+\r
+               select(m_serversocket+1,&m_readfs,&m_writefs,0,&m_timeval);\r
+\r
+               if(FD_ISSET(m_serversocket,&m_readfs))\r
+               {\r
+                       SocketReceive();\r
+               }\r
+               if(Connected() && FD_ISSET(m_serversocket,&m_writefs))\r
+               {\r
+                       SocketSend();\r
+               }\r
+\r
+               return true;\r
+\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+\r
+}\r
diff --git a/src/freenet/freenetmasterthread.cpp b/src/freenet/freenetmasterthread.cpp
new file mode 100644 (file)
index 0000000..01f03a0
--- /dev/null
@@ -0,0 +1,246 @@
+#include "../../include/freenet/freenetmasterthread.h"\r
+#include "../../include/option.h"\r
+#include "../../include/stringfunctions.h"\r
+#include "../../include/freenet/unkeyedidcreator.h"\r
+#include "../../include/freenet/identityinserter.h"\r
+#include "../../include/freenet/identityrequester.h"\r
+#include "../../include/freenet/introductionpuzzleinserter.h"\r
+#include "../../include/freenet/identityintroductionrequester.h"\r
+#include "../../include/freenet/introductionpuzzlerequester.h"\r
+#include "../../include/freenet/introductionpuzzleremover.h"\r
+#include "../../include/freenet/identityintroductioninserter.h"\r
+\r
+#include <zthread/Thread.h>\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+FreenetMasterThread::FreenetMasterThread()\r
+{\r
+       std::string fcpport;\r
+\r
+       if(Option::instance()->Get("FCPHost",m_fcphost)==false)\r
+       {\r
+               m_fcphost="localhost";\r
+               Option::instance()->Set("FCPHost",m_fcphost);\r
+       }\r
+       if(Option::instance()->Get("FCPPort",fcpport)==false)\r
+       {\r
+               fcpport="9481";\r
+               Option::instance()->Set("FCPPort",fcpport);\r
+       }\r
+\r
+       // convert fcp port to long, and make sure it's within the valid port range\r
+       if(StringFunctions::Convert(fcpport,m_fcpport)==false)\r
+       {\r
+               m_fcpport=9481;\r
+               Option::instance()->Set("FCPPort","9481");\r
+       }\r
+\r
+       m_receivednodehello=false;\r
+\r
+}\r
+\r
+FreenetMasterThread::~FreenetMasterThread()\r
+{\r
+\r
+}\r
+\r
+const bool FreenetMasterThread::FCPConnect()\r
+{\r
+       // we were previosly connected, send FCPDisconnect to objects\r
+       if(m_receivednodehello==true)\r
+       {\r
+               for(std::vector<IFCPConnected *>::iterator i=m_fcpconnected.begin(); i!=m_fcpconnected.end(); i++)\r
+               {\r
+                       (*i)->FCPDisconnected();\r
+               }\r
+               m_receivednodehello=false;\r
+       }\r
+\r
+       m_log->WriteLog(LogFile::LOGLEVEL_INFO,__FUNCTION__" trying to connect to node "+m_fcphost);\r
+\r
+       if(m_fcp.Connect(m_fcphost.c_str(),m_fcpport)==true)\r
+       {\r
+               // send ClientHello message to node\r
+               m_fcp.SendMessage("ClientHello",2,"Name","FMSClient","ExpectedVersion","2.0");\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_INFO,__FUNCTION__" connected to node");\r
+\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+\r
+}\r
+\r
+const bool FreenetMasterThread::HandleMessage(FCPMessage &message)\r
+{\r
+       if(message.GetName()=="NodeHello")\r
+       {\r
+               m_receivednodehello=true;\r
+\r
+               // send connected message to all objects, must do this AFTER we received the NodeHello message\r
+               for(std::vector<IFCPConnected *>::iterator i=m_fcpconnected.begin(); i!=m_fcpconnected.end(); i++)\r
+               {\r
+                       (*i)->FCPConnected();\r
+               }\r
+\r
+               return true;\r
+       }\r
+       if(m_receivednodehello==true)\r
+       {\r
+               bool handled=false;\r
+               std::vector<IFCPMessageHandler *>::iterator i=m_fcpmessagehandlers.begin();\r
+               while(handled==false && i!=m_fcpmessagehandlers.end())\r
+               {\r
+                       handled=(*i)->HandleMessage(message);\r
+                       i++;\r
+               }\r
+\r
+               if(handled==false)\r
+               {\r
+                       std::string info("");\r
+                       for(std::map<std::string,std::string>::iterator mi=message.begin(); mi!=message.end(); mi++)\r
+                       {\r
+                               info+="\t\t\t\t"+(*mi).first+"="+(*mi).second+"\r\n";\r
+                       }\r
+                       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" received unhandled "+message.GetName()+" message.  Message content :\r\n"+info);\r
+\r
+                       // if unhandled message was alldata - we must retrieve the data\r
+                       if(message.GetName()=="AllData")\r
+                       {\r
+                               long length;\r
+                               StringFunctions::Convert(message["DataLength"],length);\r
+                               while(m_fcp.Connected() && m_fcp.ReceiveBufferSize()<length)\r
+                               {\r
+                                       m_fcp.Update(1);\r
+                               }\r
+                               if(m_fcp.Connected())\r
+                               {\r
+                                       char *data=new char[length];\r
+                                       m_fcp.ReceiveRaw(data,length);\r
+                                       delete [] data;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return handled;\r
+\r
+       }\r
+       else\r
+       {\r
+               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" received "+message.GetName()+" message before NodeHello");\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+void FreenetMasterThread::RegisterFCPConnected(IFCPConnected *obj)\r
+{\r
+       m_fcpconnected.push_back(obj);\r
+}\r
+\r
+void FreenetMasterThread::RegisterFCPMessageHandler(IFCPMessageHandler *obj)\r
+{\r
+       m_fcpmessagehandlers.push_back(obj);\r
+}\r
+\r
+void FreenetMasterThread::RegisterPeriodicProcessor(IPeriodicProcessor *obj)\r
+{\r
+       m_processors.push_back(obj);\r
+}\r
+\r
+void FreenetMasterThread::run()\r
+{\r
+\r
+       FCPMessage message;\r
+       bool done=false;\r
+\r
+       Setup();\r
+\r
+       do\r
+       {\r
+               if(m_fcp.Connected()==false)\r
+               {\r
+                       if(FCPConnect()==false)\r
+                       {\r
+\r
+                               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" could not connect to node.  Waiting 60 seconds.");\r
+\r
+                               // wait 60 seconds - will then try to connect again\r
+                               try\r
+                               {\r
+                                       ZThread::Thread::sleep(60000);\r
+                               }\r
+                               catch(...)\r
+                               {\r
+                                       done=true;\r
+                               }\r
+                       }\r
+               }\r
+               // fcp is connected\r
+               else\r
+               {\r
+                       m_fcp.Update(1);\r
+\r
+                       // check for message on receive buffer and handle it\r
+                       if(m_fcp.ReceiveBufferSize()>0)\r
+                       {\r
+                               message.Reset();\r
+                               message=m_fcp.ReceiveMessage();\r
+\r
+                               if(message.GetName()!="")\r
+                               {\r
+                                       HandleMessage(message);\r
+                               }\r
+                       }\r
+\r
+                       // let objects do their processing\r
+                       for(std::vector<IPeriodicProcessor *>::iterator i=m_processors.begin(); i!=m_processors.end(); i++)\r
+                       {\r
+                               (*i)->Process();\r
+                       }\r
+\r
+               }\r
+       }while(!ZThread::Thread::interrupted() && done==false);\r
+\r
+       m_fcp.Disconnect();\r
+\r
+       Shutdown();\r
+\r
+}\r
+\r
+void FreenetMasterThread::Setup()\r
+{\r
+\r
+       // seed random number generator\r
+       srand(time(NULL));\r
+\r
+       m_registrables.push_back(new UnkeyedIDCreator(&m_fcp));\r
+       m_registrables.push_back(new IdentityInserter(&m_fcp));\r
+       m_registrables.push_back(new IdentityRequester(&m_fcp));\r
+       m_registrables.push_back(new IntroductionPuzzleInserter(&m_fcp));\r
+       m_registrables.push_back(new IdentityIntroductionRequester(&m_fcp));\r
+       m_registrables.push_back(new IntroductionPuzzleRequester(&m_fcp));\r
+       m_registrables.push_back(new IntroductionPuzzleRemover());\r
+       m_registrables.push_back(new IdentityIntroductionInserter(&m_fcp));\r
+\r
+       for(std::vector<IFreenetRegistrable *>::iterator i=m_registrables.begin(); i!=m_registrables.end(); i++)\r
+       {\r
+               (*i)->RegisterWithThread(this);\r
+       }\r
+\r
+}\r
+\r
+void FreenetMasterThread::Shutdown()\r
+{\r
+       // delete each registerable object\r
+       for(std::vector<IFreenetRegistrable *>::iterator i=m_registrables.begin(); i!=m_registrables.end(); i++)\r
+       {\r
+               delete (*i);\r
+       }\r
+}
\ No newline at end of file
diff --git a/src/freenet/freenetssk.cpp b/src/freenet/freenetssk.cpp
new file mode 100644 (file)
index 0000000..e48ddc6
--- /dev/null
@@ -0,0 +1,58 @@
+#include "../../include/freenet/freenetssk.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+const bool FreenetSSK::SetPrivateKey(const std::string &privatekey)\r
+{\r
+       if(ValidBaseKey(privatekey))\r
+       {\r
+               m_privatekey=privatekey;\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool FreenetSSK::SetPublicKey(const std::string &publickey)\r
+{\r
+       if(ValidBaseKey(publickey))\r
+       {\r
+               m_publickey=publickey;\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool FreenetSSK::ValidBaseKey(const std::string &key) const\r
+{\r
+       if(key.size()==0)\r
+       {\r
+               return false;\r
+       }\r
+       if(key.find("SSK@")!=0)\r
+       {\r
+               return false;\r
+       }\r
+       if(key.size()>0 && key.find("/")!=key.size()-1)\r
+       {\r
+               return false;\r
+       }\r
+       return true;\r
+}\r
+\r
+const bool FreenetSSK::ValidPrivateKey() const\r
+{\r
+       return ValidBaseKey(m_privatekey);\r
+}\r
+\r
+const bool FreenetSSK::ValidPublicKey() const\r
+{\r
+       return ValidBaseKey(m_publickey);\r
+}\r
diff --git a/src/freenet/identityinserter.cpp b/src/freenet/identityinserter.cpp
new file mode 100644 (file)
index 0000000..33a8085
--- /dev/null
@@ -0,0 +1,193 @@
+#include "../../include/freenet/identityinserter.h"\r
+#include "../../include/freenet/identityxml.h"\r
+#include "../../include/stringfunctions.h"\r
+#include "../../include/option.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IdentityInserter::IdentityInserter()\r
+{\r
+       Initialize();\r
+}\r
+\r
+IdentityInserter::IdentityInserter(FCPv2 *fcp):IFCPConnected(fcp)\r
+{\r
+       Initialize();\r
+}\r
+\r
+void IdentityInserter::FCPConnected()\r
+{\r
+       m_db->Execute("UPDATE tblLocalIdentity SET InsertingIdentity='false';");\r
+}\r
+\r
+void IdentityInserter::CheckForNeededInsert()\r
+{\r
+       DateTime date;\r
+       date.SetToGMTime();\r
+       // set date to 1 hour back\r
+       date.Add(0,0,-1);\r
+\r
+       SQLite3DB::Recordset rs=m_db->Query("SELECT LocalIdentityID FROM tblLocalIdentity WHERE PrivateKey IS NOT NULL AND PrivateKey <> '' AND InsertingIdentity='false' AND (LastInsertedIdentity<'"+date.Format("%Y-%m-%d %H:%M:%S")+"' OR LastInsertedIdentity IS NULL) ORDER BY LastInsertedIdentity;");\r
+       \r
+       if(rs.Empty()==false)\r
+       {\r
+               StartInsert(rs.GetInt(0));\r
+       }\r
+\r
+}\r
+\r
+void IdentityInserter::FCPDisconnected()\r
+{\r
+       \r
+}\r
+\r
+const bool IdentityInserter::HandleMessage(FCPMessage &message)\r
+{\r
+\r
+       if(message["Identifier"].find("IdentityInserter")==0)\r
+       {\r
+               DateTime now;\r
+               std::vector<std::string> idparts;\r
+\r
+               now.SetToGMTime();\r
+               StringFunctions::Split(message["Identifier"],"|",idparts);\r
+\r
+               // no action for URIGenerated\r
+               if(message.GetName()=="URIGenerated")\r
+               {\r
+                       return true;\r
+               }\r
+\r
+               // no action for IdentifierCollision\r
+               if(message.GetName()=="IdentifierCollision")\r
+               {\r
+                       return true;\r
+               }\r
+\r
+               if(message.GetName()=="PutSuccessful")\r
+               {\r
+                       m_db->Execute("UPDATE tblLocalIdentity SET InsertingIdentity='false', LastInsertedIdentity='"+now.Format("%Y-%m-%d %H:%M:%S")+"' WHERE LocalIdentityID="+idparts[1]+";");\r
+                       m_db->Execute("INSERT INTO tblLocalIdentityInserts(LocalIdentityID,Day,InsertIndex) VALUES("+idparts[1]+",'"+idparts[4]+"',"+idparts[2]+");");\r
+                       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" inserted identity xml");\r
+                       return true;\r
+               }\r
+\r
+               if(message.GetName()=="PutFailed")\r
+               {\r
+                       m_db->Execute("UPDATE tblLocalIdentity SET InsertingIdentity='false' WHERE LocalIdentityID="+idparts[1]+";");\r
+                       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" failure inserting identity xml.  Code="+message["Code"]+" Description="+message["CodeDescription"]);\r
+                       \r
+                       // if code 9 (collision), then insert index into inserted table\r
+                       if(message["Code"]=="9")\r
+                       {\r
+                               m_db->Execute("INSERT INTO tblLocalIdentityInserts(LocalIdentityID,Day,InsertIndex) VALUES("+idparts[1]+",'"+idparts[4]+"',"+idparts[2]+");");\r
+                       }\r
+                       \r
+                       return true;\r
+               }\r
+\r
+       }\r
+\r
+       return false;\r
+\r
+}\r
+\r
+void IdentityInserter::Initialize()\r
+{\r
+       m_lastchecked.SetToGMTime();\r
+}\r
+\r
+void IdentityInserter::Process()\r
+{\r
+       DateTime now;\r
+       now.SetToGMTime();\r
+\r
+       if(m_lastchecked<(now-(1.0/1440.0)))\r
+       {\r
+               CheckForNeededInsert();\r
+               m_lastchecked=now;\r
+       }\r
+\r
+}\r
+\r
+void IdentityInserter::RegisterWithThread(FreenetMasterThread *thread)\r
+{\r
+       thread->RegisterFCPConnected(this);\r
+       thread->RegisterFCPMessageHandler(this);\r
+       thread->RegisterPeriodicProcessor(this);\r
+}\r
+\r
+void IdentityInserter::StartInsert(const long localidentityid)\r
+{\r
+       DateTime date;\r
+       std::string idstring;\r
+\r
+       StringFunctions::Convert(localidentityid,idstring);\r
+       date.SetToGMTime();\r
+\r
+       SQLite3DB::Recordset rs=m_db->Query("SELECT Name,PrivateKey,SingleUse FROM tblLocalIdentity WHERE LocalIdentityID="+idstring+";");\r
+\r
+       if(rs.Empty()==false)\r
+       {\r
+               IdentityXML idxml;\r
+               FCPMessage mess;\r
+               DateTime now;\r
+               std::string messagebase;\r
+               std::string data;\r
+               std::string datasizestr;\r
+               std::string privatekey;\r
+               long index=0;\r
+               std::string indexstr;\r
+               std::string singleuse="false";\r
+\r
+               now.SetToGMTime();\r
+\r
+               SQLite3DB::Recordset rs2=m_db->Query("SELECT MAX(InsertIndex) FROM tblLocalIdentityInserts WHERE LocalIdentityID="+idstring+" AND Day='"+now.Format("%Y-%m-%d")+"';");\r
+               if(rs2.Empty()==false)\r
+               {\r
+                       if(rs2.GetField(0)==NULL)\r
+                       {\r
+                               index=0;\r
+                       }\r
+                       else\r
+                       {\r
+                               index=rs2.GetInt(0)+1;\r
+                       }\r
+               }\r
+               StringFunctions::Convert(index,indexstr);\r
+\r
+               Option::instance()->Get("MessageBase",messagebase);\r
+\r
+               if(rs.GetField(0))\r
+               {\r
+                       idxml.SetName(rs.GetField(0));\r
+               }\r
+\r
+               if(rs.GetField(1))\r
+               {\r
+                       privatekey=rs.GetField(1);\r
+               }\r
+\r
+               if(rs.GetField(2))\r
+               {\r
+                       singleuse=rs.GetField(2);\r
+               }\r
+               singleuse=="true" ? idxml.SetSingleUse(true) : idxml.SetSingleUse(false);\r
+\r
+               data=idxml.GetXML();\r
+               StringFunctions::Convert(data.size(),datasizestr);\r
+\r
+               mess.SetName("ClientPut");\r
+               mess["URI"]=privatekey+messagebase+"|"+now.Format("%Y-%m-%d")+"|Identity|"+indexstr+".xml";\r
+               mess["Identifier"]="IdentityInserter|"+idstring+"|"+indexstr+"|"+mess["URI"];\r
+               mess["UploadFrom"]="direct";\r
+               mess["DataLength"]=datasizestr;\r
+               m_fcp->SendMessage(mess);\r
+               m_fcp->SendRaw(data.c_str(),data.size());\r
+\r
+               m_db->Execute("UPDATE tblLocalIdentity SET InsertingIdentity='true' WHERE LocalIdentityID="+idstring+";");\r
+\r
+       }\r
+}\r
diff --git a/src/freenet/identityintroductioninserter.cpp b/src/freenet/identityintroductioninserter.cpp
new file mode 100644 (file)
index 0000000..dce7b78
--- /dev/null
@@ -0,0 +1,156 @@
+#include "../../include/freenet/identityintroductioninserter.h"\r
+#include "../../include/freenet/identityintroductionxml.h"\r
+#include "../../include/xyssl/sha1.h"\r
+#include "../../include/stringfunctions.h"\r
+#include "../../include/hex.h"\r
+#include "../../include/option.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IdentityIntroductionInserter::IdentityIntroductionInserter()\r
+{\r
+       Initialize();\r
+}\r
+\r
+IdentityIntroductionInserter::IdentityIntroductionInserter(FCPv2 *fcp):IFCPConnected(fcp)\r
+{\r
+       Initialize();\r
+}\r
+\r
+void IdentityIntroductionInserter::CheckForNewInserts()\r
+{\r
+       SQLite3DB::Recordset rs=m_db->Query("SELECT LocalIdentityID, Day, UUID, Solution FROM tblIdentityIntroductionInserts WHERE Inserted='false';");\r
+       if(!rs.Empty())\r
+       {\r
+               if(rs.GetField(0) && rs.GetField(1) && rs.GetField(2))\r
+               {\r
+                       StartInsert(rs.GetInt(0),rs.GetField(1),rs.GetField(2),rs.GetField(3));\r
+               }\r
+       }\r
+}\r
+\r
+void IdentityIntroductionInserter::FCPConnected()\r
+{\r
+       m_inserting=false;\r
+}\r
+\r
+void IdentityIntroductionInserter::FCPDisconnected()\r
+{\r
+\r
+}\r
+\r
+const bool IdentityIntroductionInserter::HandleMessage(FCPMessage &message)\r
+{\r
+\r
+       if(message["Identifier"].find("IdentityIntroductionInserter")==0)\r
+       {\r
+               std::vector<std::string> idparts;\r
+               StringFunctions::Split(message["Identifier"],"|",idparts);\r
+               \r
+               // no action for URIGenerated\r
+               if(message.GetName()=="URIGenerated")\r
+               {\r
+                       return true;\r
+               }\r
+\r
+               if(message.GetName()=="PutFailed")\r
+               {\r
+                       // if fatal error, or data is already there - remove insert from database\r
+                       if(message["Fatal"]=="true" || message["Code"]=="9")\r
+                       {\r
+                               m_db->Execute("DELETE FROM tblIdentityIntroductionInserts WHERE UUID='"+idparts[3]+"';");\r
+                               m_log->WriteLog(LogFile::LOGLEVEL_WARNING,__FUNCTION__" received fatal error trying to insert IdentityIntroduction "+idparts[3]);\r
+                       }\r
+                       m_inserting=false;\r
+                       return true;\r
+               }\r
+\r
+               if(message.GetName()=="PutSuccessful")\r
+               {\r
+                       m_db->Execute("UPDATE tblIdentityIntroductionInserts SET Inserted='true' WHERE UUID='"+idparts[3]+"';");\r
+                       m_inserting=false;\r
+                       m_log->WriteLog(LogFile::LOGLEVEL_INFO,__FUNCTION__" successfully inserted IdentityIntroduction "+idparts[3]);\r
+                       return true;\r
+               }\r
+\r
+               if(message.GetName()=="IdentifierCollision")\r
+               {\r
+                       m_inserting=false;\r
+                       return true;\r
+               }\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+void IdentityIntroductionInserter::Initialize()\r
+{\r
+       m_inserting=false;\r
+       Option::instance()->Get("MessageBase",m_messagebase);\r
+}\r
+\r
+void IdentityIntroductionInserter::Process()\r
+{\r
+       DateTime now;\r
+       now.SetToGMTime();\r
+\r
+       // only do 1 insert at a time\r
+       if(!m_inserting && m_lastchecked<(now-(1.0/1440.0)))\r
+       {\r
+               CheckForNewInserts();\r
+               m_lastchecked=now;\r
+       }\r
+}\r
+\r
+void IdentityIntroductionInserter::RegisterWithThread(FreenetMasterThread *thread)\r
+{\r
+       thread->RegisterFCPConnected(this);\r
+       thread->RegisterFCPMessageHandler(this);\r
+       thread->RegisterPeriodicProcessor(this);\r
+}\r
+\r
+void IdentityIntroductionInserter::StartInsert(const long localidentityid, const std::string &day, const std::string &UUID, const std::string &solution)\r
+{\r
+       FCPMessage message;\r
+       IdentityIntroductionXML xml;\r
+       std::string publickey;\r
+       std::string data;\r
+       std::string datasizestr;\r
+       std::vector<unsigned char> hash;\r
+       std::string encodedhash;\r
+       \r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey FROM tblLocalIdentity WHERE PublicKey IS NOT NULL AND PublicKey<>'' AND LocalIdentityID=?;");\r
+       st.Bind(0,localidentityid);\r
+       st.Step();\r
+\r
+       if(st.RowReturned())\r
+       {\r
+               st.ResultText(0,publickey);\r
+\r
+               xml.SetIdentity(publickey);\r
+               data=xml.GetXML();\r
+               StringFunctions::Convert(data.size(),datasizestr);\r
+\r
+               hash.resize(20);\r
+               sha1((unsigned char *)solution.c_str(),solution.size(),&hash[0]);\r
+               Hex::Encode(hash,encodedhash);\r
+\r
+               message.SetName("ClientPut");\r
+               message["URI"]="KSK@"+m_messagebase+"|"+day+"|"+UUID+"|"+encodedhash+".xml";\r
+               message["Identifier"]="IdentityIntroductionInserter|"+message["URI"];\r
+               message["UploadFrom"]="direct";\r
+               message["DataLength"]=datasizestr;\r
+\r
+               m_fcp->SendMessage(message);\r
+               m_fcp->SendRaw(data.c_str(),data.size());\r
+\r
+               m_inserting=true;\r
+       }\r
+       else\r
+       {\r
+               m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" could not find a public key for identity.  It is probably a new identity that doesn't have a key yet.");\r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/src/freenet/identityintroductionrequester.cpp b/src/freenet/identityintroductionrequester.cpp
new file mode 100644 (file)
index 0000000..a474c9c
--- /dev/null
@@ -0,0 +1,333 @@
+#include "../../include/freenet/identityintroductionrequester.h"\r
+#include "../../include/freenet/identityintroductionxml.h"\r
+#include "../../include/freenet/freenetssk.h"\r
+#include "../../include/option.h"\r
+#include "../../include/stringfunctions.h"\r
+#include "../../include/xyssl/sha1.h"\r
+#include "../../include/hex.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IdentityIntroductionRequester::IdentityIntroductionRequester()\r
+{\r
+       Initialize();\r
+}\r
+\r
+IdentityIntroductionRequester::IdentityIntroductionRequester(FCPv2 *fcp):IFCPConnected(fcp)\r
+{\r
+       Initialize();\r
+}\r
+\r
+void IdentityIntroductionRequester::FCPConnected()\r
+{\r
+       m_requesting.clear();\r
+       PopulateIDList();\r
+}\r
+\r
+void IdentityIntroductionRequester::FCPDisconnected()\r
+{\r
+       \r
+}\r
+\r
+const bool IdentityIntroductionRequester::HandleAllData(FCPMessage &message)\r
+{\r
+       FreenetSSK ssk;\r
+       DateTime date;\r
+       std::vector<std::string> idparts;\r
+       std::vector<char> data;\r
+       long datalength;\r
+       IdentityIntroductionXML xml;\r
+\r
+       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+       StringFunctions::Convert(message["DataLength"],datalength);\r
+\r
+       // wait for all data to be received from connection\r
+       while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)\r
+       {\r
+               m_fcp->Update(1);\r
+       }\r
+\r
+       // if we got disconnected- return immediately\r
+       if(m_fcp->Connected()==false)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // receive the file\r
+       data.resize(datalength);\r
+       m_fcp->ReceiveRaw(&data[0],datalength);\r
+\r
+       // parse file into xml and update the database\r
+       if(xml.ParseXML(std::string(data.begin(),data.end()))==true)\r
+       {\r
+\r
+               ssk.SetPublicKey(xml.GetIdentity());\r
+\r
+               // mark puzzle found\r
+               SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");\r
+               st.Bind(0,idparts[3]);\r
+               st.Step();\r
+               st.Finalize();\r
+\r
+               if(ssk.ValidPublicKey()==true)\r
+               {\r
+                       // try to find existing identity with this SSK\r
+                       st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");\r
+                       st.Bind(0,xml.GetIdentity());\r
+                       st.Step();\r
+                       if(st.RowReturned()==false)\r
+                       {\r
+                               // we don't already know about this id - add it\r
+                               st.Finalize();\r
+                               date.SetToGMTime();\r
+                               st=m_db->Prepare("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES(?,?);");\r
+                               st.Bind(0,xml.GetIdentity());\r
+                               st.Bind(1,date.Format("%Y-%m-%d %H:%M:%S"));\r
+                               st.Step();\r
+                       }\r
+                       st.Finalize();\r
+               }\r
+               else\r
+               {\r
+                       m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" parsed public SSK key was not valid.");\r
+               }\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" parsed IdentityIntroduction XML file : "+message["Identifier"]);\r
+       }\r
+       else\r
+       {\r
+\r
+               SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");\r
+               st.Bind(0,idparts[3]);\r
+               st.Step();\r
+               st.Finalize();          \r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" error parsing IdentityIntroduction XML file : "+message["Identifier"]);\r
+       }\r
+\r
+       // remove UUID from request list\r
+       RemoveFromRequestList(idparts[3]);\r
+\r
+       return true;\r
+}\r
+\r
+const bool IdentityIntroductionRequester::HandleGetFailed(FCPMessage &message)\r
+{\r
+       std::vector<std::string> idparts;\r
+\r
+       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+\r
+       // fatal error - don't try to download again\r
+       if(message["Fatal"]=="true")\r
+       {\r
+               SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");\r
+               st.Bind(0,idparts[3]);\r
+               st.Step();\r
+               st.Finalize();\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" Fatal GetFailed for "+message["Identifier"]);\r
+       }\r
+\r
+       // remove UUID from request list\r
+       RemoveFromRequestList(idparts[3]);\r
+\r
+       return true;\r
+}\r
+\r
+const bool IdentityIntroductionRequester::HandleMessage(FCPMessage &message)\r
+{\r
+\r
+       if(message["Identifier"].find("IdentityIntroductionRequester")==0)\r
+       {\r
+               \r
+               // ignore DataFound\r
+               if(message.GetName()=="DataFound")\r
+               {\r
+                       return true;\r
+               }\r
+\r
+               if(message.GetName()=="AllData")\r
+               {\r
+                       return HandleAllData(message);\r
+               }\r
+\r
+               if(message.GetName()=="GetFailed")\r
+               {\r
+                       return HandleGetFailed(message);\r
+               }\r
+\r
+               if(message.GetName()=="IdentifierCollision")\r
+               {\r
+                       // remove one of the ids from the requesting list\r
+                       std::vector<std::string> idparts;\r
+                       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+                       RemoveFromRequestList(idparts[3]);\r
+                       return true;\r
+               }\r
+\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+void IdentityIntroductionRequester::Initialize()\r
+{\r
+       std::string tempval="";\r
+       Option::instance()->Get("MaxIdentityIntroductionRequests",tempval);\r
+       StringFunctions::Convert(tempval,m_maxrequests);\r
+       if(m_maxrequests<1)\r
+       {\r
+               m_maxrequests=1;\r
+               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxIdentityIntroductionRequests is currently set at "+tempval+".  It must be 1 or greater.");\r
+       }\r
+       if(m_maxrequests>100)\r
+       {\r
+               m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxIdentityIntroductionRequests is currently set at "+tempval+".  This value might be incorrectly configured.");\r
+       }\r
+       Option::instance()->Get("MessageBase",m_messagebase);\r
+       m_tempdate.SetToGMTime();\r
+}\r
+\r
+void IdentityIntroductionRequester::PopulateIDList()\r
+{\r
+       DateTime date;\r
+       int id;\r
+\r
+       date.SetToGMTime();\r
+       date.Add(0,0,0,-1);\r
+\r
+       // get all identities that have unsolved puzzles from yesterday or today\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT LocalIdentityID FROM tblIntroductionPuzzleInserts WHERE Day>='"+date.Format("%Y-%m-%d")+"' AND FoundSolution='false' GROUP BY LocalIdentityID;");\r
+       st.Step();\r
+\r
+       m_ids.clear();\r
+\r
+       while(st.RowReturned())\r
+       {\r
+               st.ResultInt(0,id);\r
+               m_ids[id]=false;\r
+               st.Step();\r
+       }\r
+\r
+}\r
+\r
+void IdentityIntroductionRequester::Process()\r
+{\r
+       // max is the smaller of the config value or the total number of identities we will request from\r
+       long max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;\r
+\r
+               // try to keep up to max requests going\r
+       if(m_requesting.size()<max)\r
+       {\r
+               std::map<long,bool>::iterator i=m_ids.begin();\r
+               while(i!=m_ids.end() && (*i).second==true)\r
+               {\r
+                       i++;\r
+               }\r
+\r
+               if(i!=m_ids.end())\r
+               {\r
+                       StartRequests((*i).first);\r
+               }\r
+               else\r
+               {\r
+                       // we requested from all ids in the list, repopulate the list\r
+                       PopulateIDList();\r
+               }\r
+       }\r
+       // special case - if there were 0 identities on the list when we started then we will never get a chance to repopulate the list\r
+       // this will recheck for ids every minute\r
+       DateTime now;\r
+       now.SetToGMTime();\r
+       if(m_tempdate<(now-(1.0/1440.0)))\r
+       {\r
+               PopulateIDList();\r
+               m_tempdate=now;\r
+       }\r
+}\r
+\r
+void IdentityIntroductionRequester::RegisterWithThread(FreenetMasterThread *thread)\r
+{\r
+       thread->RegisterFCPConnected(this);\r
+       thread->RegisterFCPMessageHandler(this);\r
+       thread->RegisterPeriodicProcessor(this);\r
+}\r
+\r
+void IdentityIntroductionRequester::RemoveFromRequestList(const std::string &UUID)\r
+{\r
+       std::vector<std::string>::iterator i=m_requesting.begin();\r
+       while(i!=m_requesting.end() && (*i)!=UUID)\r
+       {\r
+               i++;\r
+       }\r
+       if(i!=m_requesting.end())\r
+       {\r
+               m_requesting.erase(i);\r
+       }\r
+}\r
+\r
+void IdentityIntroductionRequester::StartRequest(const std::string &UUID)\r
+{\r
+       std::string day;\r
+       std::string solution;\r
+       std::vector<unsigned char> solutionhash;\r
+       std::string encodedhash;\r
+       FCPMessage message;\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT Day, PuzzleSolution FROM tblIntroductionPuzzleInserts WHERE FoundSolution='false' AND UUID=?;");\r
+       st.Bind(0,UUID);\r
+       st.Step();\r
+\r
+       //TODO finish\r
+       if(st.RowReturned())\r
+       {\r
+               st.ResultText(0,day);\r
+               st.ResultText(1,solution);\r
+\r
+               // get the hash of the solution\r
+               solutionhash.resize(20);\r
+               sha1((unsigned char *)solution.c_str(),solution.size(),&solutionhash[0]);\r
+               Hex::Encode(solutionhash,encodedhash);\r
+\r
+               //start request for the solution\r
+               message.SetName("ClientGet");\r
+               message["URI"]="KSK@"+m_messagebase+"|"+day+"|"+UUID+"|"+encodedhash+".xml";\r
+               message["Identifier"]="IdentityIntroductionRequester|"+message["URI"];\r
+               message["ReturnType"]="direct";\r
+               message["MaxSize"]="10000";\r
+\r
+               m_fcp->SendMessage(message);\r
+\r
+               m_requesting.push_back(UUID);\r
+\r
+       }\r
+\r
+}\r
+\r
+void IdentityIntroductionRequester::StartRequests(const long localidentityid)\r
+{\r
+       DateTime date;\r
+       std::string localidentityidstr;\r
+       std::string uuid;\r
+\r
+       date.SetToGMTime();\r
+       date.Add(0,0,0,-1);\r
+       StringFunctions::Convert(localidentityid,localidentityidstr);\r
+\r
+       // get all non-solved puzzles from yesterday and today for this identity\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID="+localidentityidstr+" AND Day>='"+date.Format("%Y-%m-%d")+"' AND FoundSolution='false';");\r
+       st.Step();\r
+\r
+       // start requests for all non-solved puzzles\r
+       while(st.RowReturned())\r
+       {\r
+               uuid="";\r
+               st.ResultText(0,uuid);\r
+               StartRequest(uuid);\r
+               st.Step();\r
+       }\r
+\r
+       m_ids[localidentityid]=true;\r
+\r
+}\r
diff --git a/src/freenet/identityintroductionxml.cpp b/src/freenet/identityintroductionxml.cpp
new file mode 100644 (file)
index 0000000..e1a4eff
--- /dev/null
@@ -0,0 +1,68 @@
+#include "../../include/freenet/identityintroductionxml.h"\r
+#include "../../include/freenet/freenetssk.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IdentityIntroductionXML::IdentityIntroductionXML()\r
+{\r
+       Initialize();\r
+}\r
+\r
+std::string IdentityIntroductionXML::GetXML()\r
+{\r
+       TiXmlDocument td;\r
+       TiXmlDeclaration *tdec=new TiXmlDeclaration("1.0","UTF-8","");\r
+       TiXmlElement *tid;\r
+       TiXmlPrinter tp;\r
+\r
+       td.LinkEndChild(tdec);\r
+       tid=new TiXmlElement("IdentityIntroduction");\r
+       td.LinkEndChild(tid);\r
+\r
+       tid->LinkEndChild(XMLCreateCDATAElement("Identity",m_identity));\r
+\r
+       td.Accept(&tp);\r
+       return std::string(tp.CStr());\r
+}\r
+\r
+void IdentityIntroductionXML::Initialize()\r
+{\r
+       m_identity="";\r
+}\r
+\r
+const bool IdentityIntroductionXML::ParseXML(const std::string &xml)\r
+{\r
+       FreenetSSK ssk;\r
+       TiXmlDocument td;\r
+       td.Parse(xml.c_str());\r
+\r
+       if(!td.Error())\r
+       {\r
+               TiXmlElement *el;\r
+               TiXmlText *txt;\r
+               TiXmlHandle hnd(&td);\r
+\r
+               Initialize();\r
+\r
+               txt=hnd.FirstChild("IdentityIntroduction").FirstChild("Identity").FirstChild().ToText();\r
+               if(txt)\r
+               {\r
+                       m_identity=txt->ValueStr();\r
+               }\r
+               ssk.SetPublicKey(m_identity);\r
+               if(ssk.ValidPublicKey()==false)\r
+               {\r
+                       return false;\r
+               }\r
+\r
+               return true;\r
+\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/src/freenet/identityrequester.cpp b/src/freenet/identityrequester.cpp
new file mode 100644 (file)
index 0000000..056900d
--- /dev/null
@@ -0,0 +1,329 @@
+#include "../../include/freenet/identityrequester.h"\r
+#include "../../include/freenet/identityxml.h"\r
+#include "../../include/stringfunctions.h"\r
+#include "../../include/option.h"\r
+#include "../../include/datetime.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IdentityRequester::IdentityRequester()\r
+{\r
+       Initialize();\r
+}\r
+\r
+IdentityRequester::IdentityRequester(FCPv2 *fcp):IFCPConnected(fcp)\r
+{\r
+       Initialize();\r
+}\r
+\r
+void IdentityRequester::FCPConnected()\r
+{\r
+       m_requesting.clear();\r
+       PopulateIDList();\r
+}\r
+\r
+void IdentityRequester::FCPDisconnected()\r
+{\r
+       \r
+}\r
+\r
+const bool IdentityRequester::HandleAllData(FCPMessage &message)\r
+{\r
+       DateTime now;\r
+       SQLite3DB::Statement st;\r
+       std::vector<std::string> idparts;\r
+       long datalength;\r
+       std::vector<char> data;\r
+       IdentityXML xml;\r
+       long identityid;\r
+       long index;\r
+\r
+       now.SetToGMTime();\r
+       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+       StringFunctions::Convert(message["DataLength"],datalength);\r
+       StringFunctions::Convert(idparts[1],identityid);\r
+       StringFunctions::Convert(idparts[2],index);\r
+\r
+       // wait for all data to be received from connection\r
+       while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)\r
+       {\r
+               m_fcp->Update(1);\r
+       }\r
+\r
+       // if we got disconnected- return immediately\r
+       if(m_fcp->Connected()==false)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // receive the file\r
+       data.resize(datalength);\r
+       m_fcp->ReceiveRaw(&data[0],datalength);\r
+\r
+       // parse file into xml and update the database\r
+       if(xml.ParseXML(std::string(data.begin(),data.end()))==true)\r
+       {\r
+\r
+               st=m_db->Prepare("UPDATE tblIdentity SET Name=?, SingleUse=?, LastSeen=? WHERE IdentityID=?");\r
+               st.Bind(0,xml.GetName());\r
+               if(xml.GetSingleUse()==true)\r
+               {\r
+                       st.Bind(1,"true");\r
+               }\r
+               else\r
+               {\r
+                       st.Bind(1,"false");\r
+               }\r
+               st.Bind(2,now.Format("%Y-%m-%d %H:%M:%S"));\r
+               st.Bind(3,identityid);\r
+               st.Step();\r
+               st.Finalize();\r
+\r
+               st=m_db->Prepare("INSERT INTO tblIdentityRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'true');");\r
+               st.Bind(0,identityid);\r
+               st.Bind(1,idparts[4]);\r
+               st.Bind(2,index);\r
+               st.Step();\r
+               st.Finalize();\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" parsed Identity XML file : "+message["Identifier"]);\r
+       }\r
+       else\r
+       {\r
+               // bad data - mark index\r
+               st=m_db->Prepare("INSERT INTO tblIdentityRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
+               st.Bind(0,identityid);\r
+               st.Bind(1,idparts[4]);\r
+               st.Bind(2,index);\r
+               st.Step();\r
+               st.Finalize();\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" error parsing Identity XML file : "+message["Identifier"]);\r
+       }\r
+\r
+       // remove this identityid from request list\r
+       RemoveFromRequestList(identityid);\r
+\r
+       return true;\r
+\r
+}\r
+\r
+const bool IdentityRequester::HandleGetFailed(FCPMessage &message)\r
+{\r
+       DateTime now;\r
+       SQLite3DB::Statement st;\r
+       std::vector<std::string> idparts;\r
+       long identityid;\r
+       long index;\r
+\r
+       now.SetToGMTime();\r
+       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+       StringFunctions::Convert(idparts[1],identityid);\r
+       StringFunctions::Convert(idparts[2],index);     \r
+\r
+       // if this is a fatal error - insert index into database so we won't try to download this index again\r
+       if(message["Fatal"]=="true")\r
+       {\r
+               st=m_db->Prepare("INSERT INTO tblIdentityRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
+               st.Bind(0,identityid);\r
+               st.Bind(1,idparts[4]);\r
+               st.Bind(2,index);\r
+               st.Step();\r
+               st.Finalize();\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" fatal error requesting "+message["Identifier"]);\r
+       }\r
+\r
+       // remove this identityid from request list\r
+       RemoveFromRequestList(identityid);\r
+\r
+       return true;\r
+\r
+}\r
+\r
+const bool IdentityRequester::HandleMessage(FCPMessage &message)\r
+{\r
+\r
+       if(message["Identifier"].find("IdentityRequester")==0)\r
+       {\r
+               if(message.GetName()=="DataFound")\r
+               {\r
+                       return true;\r
+               }\r
+\r
+               if(message.GetName()=="AllData")\r
+               {\r
+                       return HandleAllData(message);\r
+               }\r
+\r
+               if(message.GetName()=="GetFailed")\r
+               {\r
+                       return HandleGetFailed(message);\r
+               }\r
+\r
+               if(message.GetName()=="IdentifierCollision")\r
+               {\r
+                       // remove one of the ids from the requesting list\r
+                       long identityid=0;\r
+                       std::vector<std::string> idparts;\r
+                       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+                       StringFunctions::Convert(idparts[1],identityid);\r
+                       RemoveFromRequestList(identityid);\r
+                       return true;\r
+               }\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+void IdentityRequester::Initialize()\r
+{\r
+       std::string tempval="";\r
+       Option::instance()->Get("MaxIdentityRequests",tempval);\r
+       StringFunctions::Convert(tempval,m_maxrequests);\r
+       if(m_maxrequests<1)\r
+       {\r
+               m_maxrequests=1;\r
+               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxIdentityRequests is currently set at "+tempval+".  It must be 1 or greater.");\r
+       }\r
+       if(m_maxrequests>100)\r
+       {\r
+               m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxIdentityRequests is currently set at "+tempval+".  This value might be incorrectly configured.");\r
+       }\r
+       Option::instance()->Get("MessageBase",m_messagebase);\r
+       m_tempdate.SetToGMTime();\r
+}\r
+\r
+void IdentityRequester::PopulateIDList()\r
+{\r
+       DateTime date;\r
+       int id;\r
+\r
+       date.SetToGMTime();\r
+       date.Add(0,0,-1);\r
+\r
+       // select identities we want to query (haven't seen in last hour) - sort by their trust level (descending) with secondary sort on how long ago we saw them (ascending)\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey IS NOT NULL AND PublicKey <> '' AND (LastSeen IS NULL OR LastSeen<='"+date.Format("%Y-%m-%d %H:%M:%S")+"') ORDER BY LocalMessageTrust+LocalTrustListTrust DESC, LastSeen;");\r
+       st.Step();\r
+\r
+       m_ids.clear();\r
+\r
+       while(st.RowReturned())\r
+       {\r
+               st.ResultInt(0,id);\r
+               m_ids[id]=false;\r
+               st.Step();\r
+       }\r
+}\r
+\r
+void IdentityRequester::Process()\r
+{\r
+       // max is the smaller of the config value or the total number of identities we will request from\r
+       long max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;\r
+\r
+       // try to keep up to max requests going\r
+       if(m_requesting.size()<max)\r
+       {\r
+               std::map<long,bool>::iterator i=m_ids.begin();\r
+               while(i!=m_ids.end() && (*i).second==true)\r
+               {\r
+                       i++;\r
+               }\r
+\r
+               if(i!=m_ids.end())\r
+               {\r
+                       StartRequest((*i).first);\r
+               }\r
+               else\r
+               {\r
+                       // we requested from all ids in the list, repopulate the list\r
+                       PopulateIDList();\r
+               }\r
+       }\r
+       // special case - if there were 0 identities on the list when we started then we will never get a chance to repopulate the list\r
+       // this will recheck for ids every minute\r
+       DateTime now;\r
+       now.SetToGMTime();\r
+       if(m_tempdate<(now-(1.0/1440.0)))\r
+       {\r
+               PopulateIDList();\r
+               m_tempdate=now;\r
+       }\r
+\r
+}\r
+\r
+void IdentityRequester::RemoveFromRequestList(const long identityid)\r
+{\r
+       std::vector<long>::iterator i=m_requesting.begin();\r
+       while(i!=m_requesting.end() && (*i)!=identityid)\r
+       {\r
+               i++;\r
+       }\r
+       if(i!=m_requesting.end())\r
+       {\r
+               m_requesting.erase(i);\r
+       }\r
+}\r
+\r
+void IdentityRequester::RegisterWithThread(FreenetMasterThread *thread)\r
+{\r
+       thread->RegisterFCPConnected(this);\r
+       thread->RegisterFCPMessageHandler(this);\r
+       thread->RegisterPeriodicProcessor(this);\r
+}\r
+\r
+void IdentityRequester::StartRequest(const long identityid)\r
+{\r
+       DateTime now;\r
+       FCPMessage message;\r
+       std::string publickey;\r
+       int index;\r
+       std::string indexstr;\r
+       std::string identityidstr;\r
+\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey FROM tblIdentity WHERE IdentityID=?;");\r
+       st.Bind(0,identityid);\r
+       st.Step();\r
+\r
+       if(st.RowReturned())\r
+       {\r
+               st.ResultText(0,publickey);\r
+\r
+               now.SetToGMTime();\r
+\r
+               SQLite3DB::Statement st2=m_db->Prepare("SELECT MAX(RequestIndex) FROM tblIdentityRequests WHERE Day=? AND IdentityID=?;");\r
+               st2.Bind(0,now.Format("%Y-%m-%d"));\r
+               st2.Bind(1,identityid);\r
+               st2.Step();\r
+\r
+               index=0;\r
+               if(st2.RowReturned())\r
+               {\r
+                       if(st2.ResultNull(0)==false)\r
+                       {\r
+                               st2.ResultInt(0,index);\r
+                               index++;\r
+                       }\r
+               }\r
+               st2.Finalize();\r
+\r
+               StringFunctions::Convert(index,indexstr);\r
+               StringFunctions::Convert(identityid,identityidstr);\r
+\r
+               message.SetName("ClientGet");\r
+               message["URI"]=publickey+m_messagebase+"|"+now.Format("%Y-%m-%d")+"|Identity|"+indexstr+".xml";\r
+               message["Identifier"]="IdentityRequester|"+identityidstr+"|"+indexstr+"|"+message["URI"];\r
+               message["ReturnType"]="direct";\r
+               message["MaxSize"]="10000";                     // 10 KB\r
+\r
+               m_fcp->SendMessage(message);\r
+\r
+               m_requesting.push_back(identityid);\r
+       }\r
+       st.Finalize();\r
+\r
+       m_ids[identityid]=true;\r
+\r
+}\r
diff --git a/src/freenet/identityxml.cpp b/src/freenet/identityxml.cpp
new file mode 100644 (file)
index 0000000..b2b33c7
--- /dev/null
@@ -0,0 +1,77 @@
+#include "../../include/freenet/identityxml.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IdentityXML::IdentityXML()\r
+{\r
+       Initialize();\r
+}\r
+\r
+std::string IdentityXML::GetXML()\r
+{\r
+       TiXmlDocument td;\r
+       TiXmlDeclaration *tdec=new TiXmlDeclaration("1.0","UTF-8","");\r
+       TiXmlElement *tid;\r
+       TiXmlPrinter tp;\r
+\r
+       td.LinkEndChild(tdec);\r
+       tid=new TiXmlElement("Identity");\r
+       td.LinkEndChild(tid);\r
+\r
+       tid->LinkEndChild(XMLCreateCDATAElement("Name",m_name));\r
+\r
+       tid->LinkEndChild(XMLCreateBooleanElement("SingleUse",m_singleuse));\r
+\r
+       tid->LinkEndChild(XMLCreateBooleanElement("PublishTrustList",m_publishtrustlist));\r
+\r
+       tid->LinkEndChild(XMLCreateBooleanElement("PublishBoardList",m_publishboardlist));\r
+\r
+       td.Accept(&tp);\r
+       return std::string(tp.CStr());\r
+\r
+}\r
+\r
+void IdentityXML::Initialize()\r
+{\r
+       m_name="";\r
+       m_publishtrustlist=false;\r
+       m_publishboardlist=false;\r
+       m_singleuse=false;\r
+}\r
+\r
+const bool IdentityXML::ParseXML(const std::string &xml)\r
+{\r
+       TiXmlDocument td;\r
+       td.Parse(xml.c_str());\r
+\r
+       if(!td.Error())\r
+       {\r
+               TiXmlElement *el;\r
+               TiXmlText *txt;\r
+               TiXmlHandle hnd(&td);\r
+\r
+               Initialize();\r
+\r
+               txt=hnd.FirstChild("Identity").FirstChild("Name").FirstChild().ToText();\r
+               if(txt)\r
+               {\r
+                       m_name=txt->ValueStr();\r
+               }\r
+\r
+               m_singleuse=XMLGetBooleanElement(hnd.FirstChild("Identity").ToElement(),"SingleUse");\r
+\r
+               m_publishtrustlist=XMLGetBooleanElement(hnd.FirstChild("Identity").ToElement(),"PublishTrustList");\r
+\r
+               m_publishboardlist=XMLGetBooleanElement(hnd.FirstChild("Identity").ToElement(),"PublishBoardList");\r
+\r
+               return true;\r
+\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+\r
+}\r
diff --git a/src/freenet/introductionpuzzleinserter.cpp b/src/freenet/introductionpuzzleinserter.cpp
new file mode 100644 (file)
index 0000000..f87e2bd
--- /dev/null
@@ -0,0 +1,239 @@
+#include "../../include/freenet/introductionpuzzleinserter.h"\r
+#include "../../include/freenet/introductionpuzzlexml.h"\r
+#include "../../include/stringfunctions.h"\r
+#include "../../include/option.h"\r
+#include "../../include/freenet/captcha/simplecaptcha.h"\r
+#include "../../include/uuidgenerator.h"\r
+#include "../../include/base64.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IntroductionPuzzleInserter::IntroductionPuzzleInserter()\r
+{\r
+       Initialize();\r
+}\r
+\r
+IntroductionPuzzleInserter::IntroductionPuzzleInserter(FCPv2 *fcp):IFCPConnected(fcp)\r
+{\r
+       Initialize();\r
+}\r
+\r
+void IntroductionPuzzleInserter::CheckForNeededInsert()\r
+{\r
+       // select all local ids that aren't single use and that aren't currently inserting a puzzle\r
+       SQLite3DB::Recordset rs=m_db->Query("SELECT LocalIdentityID FROM tblLocalIdentity WHERE SingleUse='false' AND InsertingPuzzle='false' AND PrivateKey IS NOT NULL AND PrivateKey <> '' ORDER BY LastInsertedPuzzle;");\r
+       \r
+       while(!rs.AtEnd())\r
+       {\r
+               DateTime now;\r
+               now.SetToGMTime();\r
+\r
+               // if this identity has any non-solved puzzles for today, we don't need to insert a new puzzle\r
+               SQLite3DB::Recordset rs2=m_db->Query("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE Day='"+now.Format("%Y-%m-%d")+"' AND FoundSolution='false';");\r
+\r
+               // identity doesn't have any non-solved puzzles for today - start a new insert\r
+               if(rs2.Empty()==true)\r
+               {\r
+                       StartInsert(rs.GetInt(0));\r
+               }\r
+\r
+               rs.Next();\r
+       }\r
+}\r
+\r
+void IntroductionPuzzleInserter::FCPConnected()\r
+{\r
+       m_db->Execute("UPDATE tblLocalIdentity SET InsertingPuzzle='false';");\r
+}\r
+\r
+void IntroductionPuzzleInserter::FCPDisconnected()\r
+{\r
+       \r
+}\r
+\r
+void IntroductionPuzzleInserter::GenerateCaptcha(std::string &encodeddata, std::string &solution)\r
+{\r
+       SimpleCaptcha captcha;\r
+       std::vector<unsigned char> puzzle;\r
+       std::vector<unsigned char> puzzlesolution;\r
+\r
+       captcha.Generate();\r
+       captcha.GetPuzzle(puzzle);\r
+       captcha.GetSolution(puzzlesolution);\r
+\r
+       encodeddata.clear();\r
+       solution.clear();\r
+\r
+       Base64::Encode(puzzle,encodeddata);\r
+       solution.insert(solution.begin(),puzzlesolution.begin(),puzzlesolution.end());\r
+\r
+}\r
+\r
+const bool IntroductionPuzzleInserter::HandleMessage(FCPMessage &message)\r
+{\r
+\r
+       if(message["Identifier"].find("IntroductionPuzzleInserter")==0)\r
+       {\r
+\r
+               // ignore URIGenerated message\r
+               if(message.GetName()=="URIGenerated")\r
+               {\r
+                       return true;\r
+               }\r
+\r
+               if(message.GetName()=="PutSuccessful")\r
+               {\r
+                       return HandlePutSuccessful(message);\r
+               }\r
+\r
+               if(message.GetName()=="PutFailed")\r
+               {\r
+                       return HandlePutFailed(message);\r
+               }\r
+\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+const bool IntroductionPuzzleInserter::HandlePutFailed(FCPMessage &message)\r
+{\r
+       SQLite3DB::Statement st;\r
+       std::vector<std::string> idparts;\r
+       long localidentityid;\r
+\r
+       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+       StringFunctions::Convert(idparts[1],localidentityid);\r
+\r
+       st=m_db->Prepare("UPDATE tblLocalIdentity SET InsertingPuzzle='false' WHERE LocalIdentityID=?;");\r
+       st.Bind(0,localidentityid);\r
+       st.Step();\r
+       st.Finalize();\r
+\r
+       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" failed to insert puzzle "+idparts[3]);\r
+\r
+       return true;\r
+}\r
+\r
+const bool IntroductionPuzzleInserter::HandlePutSuccessful(FCPMessage &message)\r
+{\r
+       DateTime now;\r
+       SQLite3DB::Statement st;\r
+       std::vector<std::string> idparts;\r
+       long localidentityid;\r
+       long insertindex;\r
+\r
+       now.SetToGMTime();\r
+       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+       StringFunctions::Convert(idparts[1],localidentityid);\r
+       StringFunctions::Convert(idparts[2],insertindex);\r
+\r
+       st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET Day=?, InsertIndex=? WHERE UUID=?;");\r
+       st.Bind(0,idparts[5]);\r
+       st.Bind(1,insertindex);\r
+       st.Bind(2,idparts[3]);\r
+       st.Step();\r
+       st.Finalize();\r
+\r
+       st=m_db->Prepare("UPDATE tblLocalIdentity SET InsertingPuzzle='false', LastInsertedPuzzle=? WHERE LocalIdentityID=?;");\r
+       st.Bind(0,now.Format("%Y-%m-%d %H:%M:%S"));\r
+       st.Bind(1,localidentityid);\r
+       st.Step();\r
+       st.Finalize();\r
+\r
+       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" inserted puzzle "+idparts[3]);\r
+\r
+       return true;\r
+}\r
+\r
+void IntroductionPuzzleInserter::Initialize()\r
+{\r
+       m_lastchecked.SetToGMTime();\r
+}\r
+\r
+void IntroductionPuzzleInserter::Process()\r
+{\r
+\r
+       DateTime now;\r
+\r
+       now.SetToGMTime();\r
+\r
+       if(m_lastchecked<(now-(1.0/1440.0)))\r
+       {\r
+               CheckForNeededInsert();\r
+               m_lastchecked=now;\r
+       }\r
+\r
+}\r
+\r
+void IntroductionPuzzleInserter::RegisterWithThread(FreenetMasterThread *thread)\r
+{\r
+       thread->RegisterFCPConnected(this);\r
+       thread->RegisterFCPMessageHandler(this);\r
+       thread->RegisterPeriodicProcessor(this);\r
+}\r
+\r
+void IntroductionPuzzleInserter::StartInsert(const long localidentityid)\r
+{\r
+       DateTime now;\r
+       std::string idstring;\r
+       long index=0;\r
+       std::string indexstr;\r
+       UUIDGenerator uuid;\r
+       std::string messagebase;\r
+       IntroductionPuzzleXML xml;\r
+       std::string encodedpuzzle;\r
+       std::string solutionstring;\r
+       FCPMessage message;\r
+       std::string xmldata;\r
+       std::string xmldatasizestr;\r
+       std::string privatekey;\r
+\r
+       StringFunctions::Convert(localidentityid,idstring);\r
+       now.SetToGMTime();\r
+       SQLite3DB::Recordset rs=m_db->Query("SELECT MAX(InsertIndex) FROM tblIntroductionPuzzleInserts WHERE Day='"+now.Format("%Y-%m-%d")+"' AND LocalIdentityID="+idstring+";");\r
+\r
+       if(rs.Empty() || rs.GetField(0)==NULL)\r
+       {\r
+               index=0;\r
+       }\r
+       else\r
+       {\r
+               index=rs.GetInt(0)+1;\r
+       }\r
+       StringFunctions::Convert(index,indexstr);\r
+\r
+       SQLite3DB::Recordset rs2=m_db->Query("SELECT PrivateKey FROM tblLocalIdentity WHERE LocalIdentityID="+idstring+";");\r
+       if(rs2.Empty()==false && rs2.GetField(0)!=NULL)\r
+       {\r
+               privatekey=rs2.GetField(0);\r
+       }\r
+\r
+       Option::instance()->Get("MessageBase",messagebase);\r
+\r
+       GenerateCaptcha(encodedpuzzle,solutionstring);\r
+\r
+       xml.SetType("captcha");\r
+       xml.SetUUID(uuid.Generate());\r
+       xml.SetPuzzleData(encodedpuzzle);\r
+       xml.SetMimeType("bitmap/image");\r
+\r
+       xmldata=xml.GetXML();\r
+       StringFunctions::Convert(xmldata.size(),xmldatasizestr);\r
+\r
+       message.SetName("ClientPut");\r
+       message["URI"]=privatekey+messagebase+"|"+now.Format("%Y-%m-%d")+"|IntroductionPuzzle|"+indexstr+".xml";\r
+       message["Identifier"]="IntroductionPuzzleInserter|"+idstring+"|"+indexstr+"|"+xml.GetUUID()+"|"+message["URI"];\r
+       message["UploadFrom"]="direct";\r
+       message["DataLength"]=xmldatasizestr;\r
+       m_fcp->SendMessage(message);\r
+       m_fcp->SendRaw(xmldata.c_str(),xmldata.size());\r
+\r
+       m_db->Execute("UPDATE tblLocalIdentity SET InsertingPuzzle='true' WHERE LocalIdentityID="+idstring+";");\r
+       m_db->Execute("INSERT INTO tblIntroductionPuzzleInserts(UUID,Type,MimeType,LocalIdentityID,PuzzleData,PuzzleSolution) VALUES('"+xml.GetUUID()+"','captcha','image/bmp',"+idstring+",'"+encodedpuzzle+"','"+solutionstring+"');");\r
+\r
+       m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" started insert for id "+idstring);\r
+\r
+}\r
diff --git a/src/freenet/introductionpuzzleremover.cpp b/src/freenet/introductionpuzzleremover.cpp
new file mode 100644 (file)
index 0000000..5650a6f
--- /dev/null
@@ -0,0 +1,36 @@
+#include "../../include/freenet/introductionpuzzleremover.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IntroductionPuzzleRemover::IntroductionPuzzleRemover()\r
+{\r
+       m_lastchecked.SetToGMTime();\r
+}\r
+\r
+void IntroductionPuzzleRemover::Process()\r
+{\r
+       DateTime now;\r
+       DateTime date;\r
+       now.SetToGMTime();\r
+       date.SetToGMTime();\r
+\r
+       // check once a day\r
+       if(m_lastchecked<(now-1.0))\r
+       {\r
+\r
+               date.Add(0,0,0,-2);\r
+\r
+               // delete all puzzles 2 or more days old\r
+               m_db->Execute("DELETE FROM tblIntroductionPuzzleInserts WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
+               m_db->Execute("DELETE FROM tblIntroductionPuzzleRequests WHERE Day<='"+date.Format("%Y-%m-%d")+"';");\r
+\r
+               m_lastchecked=now;\r
+       }\r
+}\r
+\r
+void IntroductionPuzzleRemover::RegisterWithThread(FreenetMasterThread *thread)\r
+{\r
+       thread->RegisterPeriodicProcessor(this);\r
+}\r
diff --git a/src/freenet/introductionpuzzlerequester.cpp b/src/freenet/introductionpuzzlerequester.cpp
new file mode 100644 (file)
index 0000000..70a2e8e
--- /dev/null
@@ -0,0 +1,313 @@
+#include "../../include/freenet/introductionpuzzlerequester.h"\r
+#include "../../include/freenet/introductionpuzzlexml.h"\r
+#include "../../include/option.h"\r
+#include "../../include/stringfunctions.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IntroductionPuzzleRequester::IntroductionPuzzleRequester()\r
+{\r
+       Initialize();\r
+}\r
+\r
+IntroductionPuzzleRequester::IntroductionPuzzleRequester(FCPv2 *fcp):IFCPConnected(fcp)\r
+{\r
+       Initialize();\r
+}\r
+\r
+void IntroductionPuzzleRequester::FCPConnected()\r
+{\r
+       m_requesting.clear();\r
+       PopulateIDList();\r
+}\r
+\r
+void IntroductionPuzzleRequester::FCPDisconnected()\r
+{\r
+       \r
+}\r
+\r
+const bool IntroductionPuzzleRequester::HandleAllData(FCPMessage &message)\r
+{\r
+       DateTime now;\r
+       SQLite3DB::Statement st;\r
+       std::vector<std::string> idparts;\r
+       long datalength;\r
+       std::vector<char> data;\r
+       IntroductionPuzzleXML xml;\r
+       long identityid;\r
+       long index;\r
+\r
+       now.SetToGMTime();\r
+       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+       StringFunctions::Convert(message["DataLength"],datalength);\r
+       StringFunctions::Convert(idparts[1],identityid);\r
+       StringFunctions::Convert(idparts[2],index);\r
+\r
+       // wait for all data to be received from connection\r
+       while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)\r
+       {\r
+               m_fcp->Update(1);\r
+       }\r
+\r
+       // if we got disconnected- return immediately\r
+       if(m_fcp->Connected()==false)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       // receive the file\r
+       data.resize(datalength);\r
+       m_fcp->ReceiveRaw(&data[0],datalength);\r
+\r
+       // parse file into xml and update the database\r
+       if(xml.ParseXML(std::string(data.begin(),data.end()))==true)\r
+       {\r
+               st=m_db->Prepare("INSERT INTO tblIntroductionPuzzleRequests(IdentityID,Day,RequestIndex,Found,UUID,Type,MimeType,PuzzleData) VALUES(?,?,?,?,?,?,?,?);");\r
+               st.Bind(0,identityid);\r
+               st.Bind(1,idparts[4]);\r
+               st.Bind(2,index);\r
+               st.Bind(3,"true");\r
+               st.Bind(4,xml.GetUUID());\r
+               st.Bind(5,xml.GetType());\r
+               st.Bind(6,xml.GetMimeType());\r
+               st.Bind(7,xml.GetPuzzleData());\r
+               st.Step();\r
+               st.Finalize();\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" parsed IntroductionPuzzle XML file : "+message["Identifier"]);\r
+       }\r
+       else\r
+       {\r
+               // bad data - mark index\r
+               st=m_db->Prepare("INSERT INTO tblIntroductionPuzzleRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
+               st.Bind(0,identityid);\r
+               st.Bind(1,idparts[4]);\r
+               st.Bind(2,index);\r
+               st.Step();\r
+               st.Finalize();\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" error parsing IntroductionPuzzle XML file : "+message["Identifier"]);\r
+       }\r
+\r
+       // remove this identityid from request list\r
+       RemoveFromRequestList(identityid);\r
+\r
+       return true;\r
+\r
+}\r
+\r
+const bool IntroductionPuzzleRequester::HandleGetFailed(FCPMessage &message)\r
+{\r
+       DateTime now;\r
+       SQLite3DB::Statement st;\r
+       std::vector<std::string> idparts;\r
+       long identityid;\r
+       long index;\r
+\r
+       now.SetToGMTime();\r
+       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+       StringFunctions::Convert(idparts[1],identityid);\r
+       StringFunctions::Convert(idparts[2],index);     \r
+\r
+       // if this is a fatal error - insert index into database so we won't try to download this index again\r
+       if(message["Fatal"]=="true")\r
+       {\r
+               st=m_db->Prepare("INSERT INTO tblIntroductionPuzzleRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
+               st.Bind(0,identityid);\r
+               st.Bind(1,idparts[4]);\r
+               st.Bind(2,index);\r
+               st.Step();\r
+               st.Finalize();\r
+\r
+               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" fatal error requesting "+message["Identifier"]);\r
+       }\r
+\r
+       // remove this identityid from request list\r
+       RemoveFromRequestList(identityid);\r
+\r
+       return true;\r
+\r
+}\r
+\r
+const bool IntroductionPuzzleRequester::HandleMessage(FCPMessage &message)\r
+{\r
+\r
+       if(message["Identifier"].find("IntroductionPuzzleRequester")==0)\r
+       {\r
+               if(message.GetName()=="DataFound")\r
+               {\r
+                       return true;\r
+               }\r
+\r
+               if(message.GetName()=="AllData")\r
+               {\r
+                       return HandleAllData(message);\r
+               }\r
+\r
+               if(message.GetName()=="GetFailed")\r
+               {\r
+                       return HandleGetFailed(message);\r
+               }\r
+               \r
+               if(message.GetName()=="IdentifierCollision")\r
+               {\r
+                       // remove one of the ids from the requesting list\r
+                       long identityid=0;\r
+                       std::vector<std::string> idparts;\r
+                       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+                       StringFunctions::Convert(idparts[1],identityid);\r
+                       RemoveFromRequestList(identityid);\r
+                       return true;\r
+               }\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+void IntroductionPuzzleRequester::Initialize()\r
+{\r
+       std::string tempval="";\r
+       Option::instance()->Get("MaxIntroductionPuzzleRequests",tempval);\r
+       StringFunctions::Convert(tempval,m_maxrequests);\r
+       if(m_maxrequests<1)\r
+       {\r
+               m_maxrequests=1;\r
+               m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxIntroductionPuzzleRequests is currently set at "+tempval+".  It must be 1 or greater.");\r
+       }\r
+       if(m_maxrequests>100)\r
+       {\r
+               m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxIntroductionPuzzleRequests is currently set at "+tempval+".  This value might be incorrectly configured.");\r
+       }\r
+       Option::instance()->Get("MessageBase",m_messagebase);\r
+       m_tempdate.SetToGMTime();\r
+}\r
+\r
+void IntroductionPuzzleRequester::PopulateIDList()\r
+{\r
+       DateTime now;\r
+       int id;\r
+\r
+       now.SetToGMTime();\r
+\r
+       // select identities that aren't single use and have been seen today\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey IS NOT NULL AND PublicKey <> '' AND SingleUse='false' AND LastSeen>='"+now.Format("%Y-%m-%d")+"';");\r
+       st.Step();\r
+\r
+       m_ids.clear();\r
+\r
+       while(st.RowReturned())\r
+       {\r
+               st.ResultInt(0,id);\r
+               m_ids[id]=false;\r
+               st.Step();\r
+       }\r
+}\r
+\r
+void IntroductionPuzzleRequester::Process()\r
+{\r
+       // max is the smaller of the config value or the total number of identities we will request from\r
+       long max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;\r
+\r
+       // try to keep up to max requests going\r
+       if(m_requesting.size()<max)\r
+       {\r
+               std::map<long,bool>::iterator i=m_ids.begin();\r
+               while(i!=m_ids.end() && (*i).second==true)\r
+               {\r
+                       i++;\r
+               }\r
+\r
+               if(i!=m_ids.end())\r
+               {\r
+                       StartRequest((*i).first);\r
+               }\r
+               else\r
+               {\r
+                       // we requested from all ids in the list, repopulate the list\r
+                       PopulateIDList();\r
+               }\r
+       }\r
+       // special case - if there were 0 identities on the list when we started then we will never get a chance to repopulate the list\r
+       // this will recheck for ids every minute\r
+       DateTime now;\r
+       now.SetToGMTime();\r
+       if(m_tempdate<(now-(1.0/1440.0)))\r
+       {\r
+               PopulateIDList();\r
+               m_tempdate=now;\r
+       }\r
+}\r
+\r
+void IntroductionPuzzleRequester::RegisterWithThread(FreenetMasterThread *thread)\r
+{\r
+       thread->RegisterFCPConnected(this);\r
+       thread->RegisterFCPMessageHandler(this);\r
+       thread->RegisterPeriodicProcessor(this);\r
+}\r
+\r
+void IntroductionPuzzleRequester::RemoveFromRequestList(const long identityid)\r
+{\r
+       std::vector<long>::iterator i=m_requesting.begin();\r
+       while(i!=m_requesting.end() && (*i)!=identityid)\r
+       {\r
+               i++;\r
+       }\r
+       if(i!=m_requesting.end())\r
+       {\r
+               m_requesting.erase(i);\r
+       }\r
+}\r
+\r
+void IntroductionPuzzleRequester::StartRequest(const long identityid)\r
+{\r
+       DateTime now;\r
+       FCPMessage message;\r
+       std::string publickey;\r
+       int index;\r
+       std::string indexstr;\r
+       std::string identityidstr;\r
+\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey FROM tblIdentity WHERE IdentityID=?;");\r
+       st.Bind(0,identityid);\r
+       st.Step();\r
+\r
+       if(st.RowReturned())\r
+       {\r
+               st.ResultText(0,publickey);\r
+\r
+               now.SetToGMTime();\r
+\r
+               SQLite3DB::Statement st2=m_db->Prepare("SELECT MAX(RequestIndex) FROM tblIntroductionPuzzleRequests WHERE Day=? AND IdentityID=?;");\r
+               st2.Bind(0,now.Format("%Y-%m-%d"));\r
+               st2.Bind(1,identityid);\r
+               st2.Step();\r
+\r
+               index=0;\r
+               if(st2.RowReturned())\r
+               {\r
+                       if(st2.ResultNull(0)==false)\r
+                       {\r
+                               st2.ResultInt(0,index);\r
+                               index++;\r
+                       }\r
+               }\r
+               st2.Finalize();\r
+\r
+               StringFunctions::Convert(index,indexstr);\r
+               StringFunctions::Convert(identityid,identityidstr);\r
+\r
+               message.SetName("ClientGet");\r
+               message["URI"]=publickey+m_messagebase+"|"+now.Format("%Y-%m-%d")+"|IntroductionPuzzle|"+indexstr+".xml";\r
+               message["Identifier"]="IntroductionPuzzleRequester|"+identityidstr+"|"+indexstr+"|"+message["URI"];\r
+               message["ReturnType"]="direct";\r
+               message["MaxSize"]="1000000";           // 1 MB\r
+\r
+               m_fcp->SendMessage(message);\r
+               \r
+               m_requesting.push_back(identityid);\r
+       }\r
+\r
+       m_ids[identityid]=true;\r
+}\r
diff --git a/src/freenet/introductionpuzzlexml.cpp b/src/freenet/introductionpuzzlexml.cpp
new file mode 100644 (file)
index 0000000..8eb8a1a
--- /dev/null
@@ -0,0 +1,87 @@
+#include "../../include/freenet/introductionpuzzlexml.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+IntroductionPuzzleXML::IntroductionPuzzleXML()\r
+{\r
+       Initialize();\r
+}\r
+\r
+std::string IntroductionPuzzleXML::GetXML()\r
+{\r
+       TiXmlDocument td;\r
+       TiXmlDeclaration *tdec=new TiXmlDeclaration("1.0","UTF-8","");\r
+       TiXmlElement *tid;\r
+       TiXmlPrinter tp;\r
+\r
+       td.LinkEndChild(tdec);\r
+       tid=new TiXmlElement("IntroductionPuzzle");\r
+       td.LinkEndChild(tid);\r
+\r
+       tid->LinkEndChild(XMLCreateTextElement("Type",m_type));\r
+\r
+       tid->LinkEndChild(XMLCreateTextElement("UUID",m_uuid));\r
+\r
+       tid->LinkEndChild(XMLCreateTextElement("MimeType",m_mimetype));\r
+\r
+       tid->LinkEndChild(XMLCreateTextElement("PuzzleData",m_puzzledata));\r
+\r
+       td.Accept(&tp);\r
+       return std::string(tp.CStr());\r
+}\r
+\r
+void IntroductionPuzzleXML::Initialize()\r
+{\r
+       m_type="";\r
+       m_uuid="";\r
+       m_puzzledata="";\r
+       m_mimetype="";\r
+}\r
+\r
+const bool IntroductionPuzzleXML::ParseXML(const std::string &xml)\r
+{\r
+       TiXmlDocument td;\r
+       td.Parse(xml.c_str());\r
+\r
+       if(!td.Error())\r
+       {\r
+               TiXmlElement *el;\r
+               TiXmlText *txt;\r
+               TiXmlHandle hnd(&td);\r
+\r
+               Initialize();\r
+\r
+               txt=hnd.FirstChild("IntroductionPuzzle").FirstChild("Type").FirstChild().ToText();\r
+               if(txt)\r
+               {\r
+                       m_type=txt->ValueStr();\r
+               }\r
+\r
+               txt=hnd.FirstChild("IntroductionPuzzle").FirstChild("UUID").FirstChild().ToText();\r
+               if(txt)\r
+               {\r
+                       m_uuid=txt->ValueStr();\r
+               }\r
+\r
+               txt=hnd.FirstChild("IntroductionPuzzle").FirstChild("MimeType").FirstChild().ToText();\r
+               if(txt)\r
+               {\r
+                       m_mimetype=txt->ValueStr();\r
+               }\r
+\r
+               txt=hnd.FirstChild("IntroductionPuzzle").FirstChild("PuzzleData").FirstChild().ToText();\r
+               if(txt)\r
+               {\r
+                       m_puzzledata=txt->ValueStr();\r
+               }\r
+\r
+               return true;\r
+\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}
\ No newline at end of file
diff --git a/src/freenet/unkeyedidcreator.cpp b/src/freenet/unkeyedidcreator.cpp
new file mode 100644 (file)
index 0000000..df46469
--- /dev/null
@@ -0,0 +1,122 @@
+#include "../../include/freenet/unkeyedidcreator.h"\r
+#include "../../include/stringfunctions.h"\r
+\r
+#include <sstream>\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+UnkeyedIDCreator::UnkeyedIDCreator()\r
+{\r
+       Initialize();\r
+}\r
+\r
+UnkeyedIDCreator::UnkeyedIDCreator(FCPv2 *fcp):IFCPConnected(fcp)\r
+{\r
+       Initialize();\r
+}\r
+\r
+void UnkeyedIDCreator::FCPConnected()\r
+{\r
+       m_waiting=false;\r
+}\r
+\r
+void UnkeyedIDCreator::FCPDisconnected()\r
+{\r
+       m_waiting=false;\r
+}\r
+\r
+void UnkeyedIDCreator::CheckForUnkeyedID()\r
+{\r
+       SQLite3DB::Recordset rs=m_db->Query("SELECT LocalIdentityID FROM tblLocalIdentity WHERE PublicKey IS NULL OR PrivateKey IS NULL OR PublicKey='' OR PrivateKey='';");\r
+\r
+       if(rs.Empty()==false)\r
+       {\r
+               std::string idstring;\r
+               StringFunctions::Convert(rs.GetInt(0),idstring);\r
+\r
+               std::ostringstream idstr;\r
+               long id=rs.GetInt(0);\r
+               idstr << id;\r
+\r
+               FCPMessage message;\r
+               message.SetName("GenerateSSK");\r
+               message["Identifier"]="UnkeyedIDRequest|"+idstr.str();\r
+               m_fcp->SendMessage(message);\r
+\r
+               m_waiting=true;\r
+\r
+       }\r
+\r
+       // set last checked time to now\r
+       m_lastchecked.SetToGMTime();\r
+\r
+}\r
+\r
+const bool UnkeyedIDCreator::HandleMessage(FCPMessage &message)\r
+{\r
+       if(message["Identifier"].find("UnkeyedIDRequest")==0)\r
+       {\r
+\r
+               if(message.GetName()=="SSKKeypair")\r
+               {\r
+\r
+                       long id;\r
+                       std::vector<std::string> idparts;\r
+                       StringFunctions::Split(message["Identifier"],"|",idparts);\r
+\r
+                       if(idparts.size()>1)\r
+                       {\r
+                               if(StringFunctions::Convert(idparts[1],id)==false)\r
+                               {\r
+                                       id=0;\r
+                               }\r
+                               SaveKeys(id,message["RequestURI"],message["InsertURI"]);\r
+                       }\r
+\r
+                       m_log->WriteLog(LogFile::LOGLEVEL_INFO,__FUNCTION__" received keypair");\r
+\r
+                       m_waiting=false;\r
+\r
+                       return true;\r
+               }\r
+\r
+       }\r
+\r
+       return false;\r
+}\r
+\r
+void UnkeyedIDCreator::Initialize()\r
+{\r
+       m_waiting=false;\r
+       m_lastchecked.SetToGMTime();\r
+}\r
+\r
+void UnkeyedIDCreator::Process()\r
+{\r
+       DateTime now;\r
+       now.SetToGMTime();\r
+\r
+       // only perform check every minute (1/1440 of 1 day)\r
+       if(m_waiting==false && m_lastchecked<(now-(1.0/1440.0)))\r
+       {\r
+               CheckForUnkeyedID();\r
+       }\r
+}\r
+\r
+void UnkeyedIDCreator::RegisterWithThread(FreenetMasterThread *thread)\r
+{\r
+       thread->RegisterFCPConnected(this);\r
+       thread->RegisterFCPMessageHandler(this);\r
+       thread->RegisterPeriodicProcessor(this);\r
+}\r
+\r
+void UnkeyedIDCreator::SaveKeys(const long localidentityid, const std::string &publickey, const std::string &privatekey)\r
+{\r
+       SQLite3DB::Statement st=m_db->Prepare("UPDATE tblLocalIdentity SET PublicKey=?, PrivateKey=? WHERE LocalIdentityID=?;");\r
+       st.Bind(0,publickey);\r
+       st.Bind(1,privatekey);\r
+       st.Bind(2,localidentityid);\r
+       st.Step();\r
+}\r
diff --git a/src/hex.cpp b/src/hex.cpp
new file mode 100644 (file)
index 0000000..249619b
--- /dev/null
@@ -0,0 +1,49 @@
+#include "../include/hex.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+namespace Hex\r
+{\r
+       \r
+static const std::string hexchars="0123456789ABCDEF";\r
+\r
+const bool Encode(const std::vector<unsigned char> &data, std::string &encoded)\r
+{\r
+       for(std::vector<unsigned char>::const_iterator i=data.begin(); i!=data.end(); i++)\r
+       {\r
+               encoded.push_back(hexchars[(((*i)>>4) & 0x0F)]);\r
+               encoded.push_back(hexchars[((*i) & 0x0F)]);\r
+       }\r
+       return true;\r
+}\r
+\r
+const bool Decode(const std::string &encoded, std::vector<unsigned char> &data)\r
+{\r
+\r
+       std::string::size_type pos=0;\r
+       unsigned char byte;\r
+       int bytepart=0;\r
+       \r
+       pos=encoded.find_first_of(hexchars);\r
+       \r
+       while(pos!=std::string::npos)\r
+       {\r
+               if(bytepart==0)\r
+               {\r
+                       byte=(hexchars.find(encoded[pos]) << 4) & 0xF0;\r
+                       bytepart=1;\r
+               }\r
+               else\r
+               {\r
+                       byte|=hexchars.find(encoded[pos]) & 0x0F;\r
+                       data.push_back(byte);\r
+                       bytepart=0;\r
+               }\r
+               pos=encoded.find_first_of(hexchars,pos+1);\r
+       }\r
+       return true;\r
+}\r
+\r
+}      // namespace\r
diff --git a/src/identitytestglobal.cpp b/src/identitytestglobal.cpp
new file mode 100644 (file)
index 0000000..2acca4d
--- /dev/null
@@ -0,0 +1,255 @@
+#include "../include/identitytestglobal.h"\r
+#include "../include/datetime.h"\r
+#include "../include/logfile.h"\r
+#include "../include/option.h"\r
+#include "../include/stringfunctions.h"\r
+#include "../include/db/sqlite3db.h"\r
+#include "../include/freenet/freenetmasterthread.h"\r
+\r
+#ifdef _WIN32\r
+       #include <winsock2.h>\r
+#endif\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+void SetupDB()\r
+{\r
+\r
+       SQLite3DB::DB *db=SQLite3DB::DB::instance();\r
+\r
+       db->Open("fms.db3");\r
+       db->SetBusyTimeout(10000);              // set timeout to 10 seconds\r
+       db->Execute("VACUUM;");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblOption(\\r
+                               Option                          TEXT UNIQUE,\\r
+                               OptionValue                     TEXT NOT NULL,\\r
+                               OptionDescription       TEXT\\r
+                               );");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentity(\\r
+                               LocalIdentityID                 INTEGER PRIMARY KEY,\\r
+                               Name                                    TEXT,\\r
+                               PublicKey                               TEXT,\\r
+                               PrivateKey                              TEXT,\\r
+                               SingleUse                               BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\\r
+                               InsertingIdentity               BOOL CHECK(InsertingIdentity IN('true','false')) DEFAULT 'false',\\r
+                               LastInsertedIdentity    DATETIME,\\r
+                               InsertingPuzzle                 BOOL CHECK(InsertingPuzzle IN('true','false')) DEFAULT 'false',\\r
+                               LastInsertedPuzzle              DATETIME,\\r
+                               InsertingTrustList              BOOL CHECK(InsertingTrustList IN('true','false')) DEFAULT 'false',\\r
+                               LastInsertedTrustList   DATETIME\\r
+                               );");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblLocalIdentityInserts(\\r
+                               LocalIdentityID         INTEGER,\\r
+                               Day                                     DATE,\\r
+                               InsertIndex                     INTEGER\\r
+                               );");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleInserts(\\r
+                               UUID                            TEXT UNIQUE,\\r
+                               LocalIdentityID         INTEGER,\\r
+                               Day                                     DATE,\\r
+                               InsertIndex                     INTEGER,\\r
+                               Type                            TEXT,\\r
+                               MimeType                        TEXT,\\r
+                               PuzzleData                      TEXT,\\r
+                               PuzzleSolution          TEXT,\\r
+                               FoundSolution           BOOL CHECK(FoundSolution IN('true','false')) DEFAULT 'false'\\r
+                               );");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblIdentity(\\r
+                               IdentityID                      INTEGER PRIMARY KEY,\\r
+                               PublicKey                       TEXT,\\r
+                               Name                            TEXT,\\r
+                               SingleUse                       BOOL CHECK(SingleUse IN('true','false')) DEFAULT 'false',\\r
+                               DateAdded                       DATETIME,\\r
+                               LastSeen                        DATETIME,\\r
+                               LocalMessageTrust       INTEGER CHECK(LocalMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\\r
+                               PeerMessageTrust        INTEGER CHECK(PeerMessageTrust BETWEEN 0 AND 100) DEFAULT 50,\\r
+                               LocalTrustListTrust     INTEGER CHECK(LocalTrustListTrust BETWEEN 0 AND 100) DEFAULT 50,\\r
+                               PeerTrustListTrust      INTEGER CHECK(PeerTrustListTrust BETWEEN 0 AND 100) DEFAULT 50\\r
+                               );");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityRequests(\\r
+                               IdentityID                      INTEGER PRIMARY KEY,\\r
+                               Day                                     DATE,\\r
+                               RequestIndex            INTEGER,\\r
+                               Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
+                               );");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblIntroductionPuzzleRequests(\\r
+                               IdentityID                      INTEGER,\\r
+                               Day                                     DATE,\\r
+                               RequestIndex            INTEGER,\\r
+                               Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false',\\r
+                               UUID                            TEXT UNIQUE,\\r
+                               Type                            TEXT,\\r
+                               MimeType                        TEXT,\\r
+                               PuzzleData                      TEXT\\r
+                               );");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblIdentityIntroductionInserts(\\r
+                               LocalIdentityID         INTEGER,\\r
+                               Day                                     DATE,\\r
+                               UUID                            TEXT UNIQUE,\\r
+                               Solution                        TEXT,\\r
+                               Inserted                        BOOL CHECK(Inserted IN('true','false')) DEFAULT 'false'\\r
+                               );");\r
+\r
+}\r
+\r
+void SetupDefaultOptions()\r
+{\r
+       // OptionValue should always be inserted as a string, even if the option really isn't a string - just to keep the field data type consistent\r
+\r
+       std::ostringstream tempstr;     // must set tempstr to "" between db inserts\r
+       SQLite3DB::DB *db=SQLite3DB::DB::instance();\r
+       SQLite3DB::Statement st=db->Prepare("INSERT INTO tblOption(Option,OptionValue,OptionDescription) VALUES(?,?,?);");\r
+\r
+       // LogLevel\r
+       tempstr.str("");\r
+       tempstr << LogFile::LOGLEVEL_DEBUG;\r
+       st.Bind(0,"LogLevel");\r
+       st.Bind(1,tempstr.str());\r
+       st.Bind(2,"The maximum logging level that will be written to file.  0=Fatal Errors, 1=Errors, 2=Warnings, 3=Informational Messages, 4=Debug Messages.  Higher levels will include all messages from the previous levels.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       // StartFreenetUpdater\r
+       st.Bind(0,"StartFreenetUpdater");\r
+       st.Bind(1,"true");\r
+       st.Bind(2,"Start Freenet Updater.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       // FCPHost\r
+       st.Bind(0,"FCPHost");\r
+       st.Bind(1,"localhost");\r
+       st.Bind(2,"Host name or address of Freenet node.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       // FCPPort\r
+       st.Bind(0,"FCPPort");\r
+       st.Bind(1,"9481");\r
+       st.Bind(2,"The port that Freenet is listening for FCP connections on.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       st.Bind(0,"MessageBase");\r
+       st.Bind(1,"fms");\r
+       st.Bind(2,"A unique string shared by all clients who want to communicate with each other.  This should not be changed unless you want to create your own separate communications network.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       st.Bind(0,"MaxIdentityRequests");\r
+       st.Bind(1,"5");\r
+       st.Bind(2,"Maximum number of concurrent requests for new Identity xml files");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       st.Bind(0,"MaxIdentityIntroductionRequests");\r
+       st.Bind(1,"5");\r
+       st.Bind(2,"Maximum number of concurrent identities requesting IdentityIntroduction xml files.  Each identity may have multiple requests pending.");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+       st.Bind(0,"MaxIntroductionPuzzleRequests");\r
+       st.Bind(1,"5");\r
+       st.Bind(2,"Maximum number of concurrent requests for new IntroductionPuzzle xml files");\r
+       st.Step();\r
+       st.Reset();\r
+\r
+}\r
+\r
+void SetupLogFile()\r
+{\r
+       DateTime date;\r
+       std::string configval;\r
+       int loglevel;\r
+\r
+       date.SetToGMTime();\r
+\r
+       LogFile::instance()->SetFileName("fms-"+date.Format("%Y-%m-%d")+".log");\r
+       LogFile::instance()->OpenFile();\r
+       LogFile::instance()->SetWriteNewLine(true);\r
+       LogFile::instance()->SetWriteDate(true);\r
+       LogFile::instance()->SetWriteLogLevel(true);\r
+\r
+       if(Option::instance()->Get("LogLevel",configval)==false)\r
+       {\r
+               configval="4";\r
+               Option::instance()->Set("LogLevel",configval);\r
+       }\r
+       if(StringFunctions::Convert(configval,loglevel)==false)\r
+       {\r
+               loglevel=LogFile::LOGLEVEL_DEBUG;\r
+               Option::instance()->Set("LogLevel",loglevel);\r
+       }\r
+       LogFile::instance()->SetLogLevel((LogFile::LogLevel)loglevel);\r
+}\r
+\r
+void SetupNetwork()\r
+{\r
+#ifdef _WIN32\r
+       WSAData wsadata;\r
+       WSAStartup(MAKEWORD(2,2),&wsadata);\r
+#endif\r
+}\r
+\r
+void ShutdownNetwork()\r
+{\r
+#ifdef _WIN32\r
+       WSACleanup();\r
+#endif\r
+}\r
+\r
+void ShutdownThreads(std::vector<ZThread::Thread *> &threads)\r
+{\r
+       std::vector<ZThread::Thread *>::iterator i;\r
+       for(i=threads.begin(); i!=threads.end(); i++)\r
+       {\r
+               if((*i)->wait(1)==false)\r
+               {\r
+                       try\r
+                       {\r
+                               (*i)->interrupt();\r
+                       }\r
+                       catch(...)\r
+                       {\r
+                       }\r
+               }\r
+       }\r
+\r
+       for(i=threads.begin(); i!=threads.end(); i++)\r
+       {\r
+               (*i)->wait();\r
+               delete (*i);\r
+       }\r
+\r
+       threads.clear();\r
+\r
+}\r
+\r
+void StartThreads(std::vector<ZThread::Thread *> &threads)\r
+{\r
+       std::string startfreenet;\r
+       std::string startnntp;\r
+\r
+       if(Option::instance()->Get("StartFreenetUpdater",startfreenet)==false)\r
+       {\r
+               startfreenet="true";\r
+               Option::instance()->Set("StartFreenetUpdater","true");\r
+       }\r
+\r
+       if(startfreenet=="true")\r
+       {\r
+               ZThread::Thread *t=new ZThread::Thread(new FreenetMasterThread());\r
+               threads.push_back(t);\r
+       }\r
+\r
+}\r
diff --git a/src/identitytestmain.cpp b/src/identitytestmain.cpp
new file mode 100644 (file)
index 0000000..4776e36
--- /dev/null
@@ -0,0 +1,47 @@
+#include "../include/identitytestglobal.h"\r
+#include "../include/commandthread.h"\r
+\r
+#include <ctime>\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+int main()\r
+{\r
+\r
+       #ifdef XMEM\r
+               xmem_disable_print();\r
+       #endif\r
+\r
+       std::vector<ZThread::Thread *> threads;\r
+\r
+       srand(time(NULL));\r
+\r
+       SetupDB();\r
+       SetupDefaultOptions();\r
+\r
+\r
+       SetupLogFile();\r
+\r
+       SetupNetwork();\r
+\r
+       LogFile::instance()->WriteLog(LogFile::LOGLEVEL_INFO,"FMS startup v"FMS_VERSION);\r
+\r
+       \r
+       StartThreads(threads);\r
+\r
+\r
+       ZThread::Thread commandthread(new CommandThread());\r
+       commandthread.wait();\r
+\r
+\r
+       ShutdownThreads(threads);\r
+\r
+       ShutdownNetwork();\r
+\r
+       LogFile::instance()->WriteLog(LogFile::LOGLEVEL_INFO,"FMS shutdown");\r
+       LogFile::instance()->WriteNewLine();\r
+\r
+       return 0;\r
+}\r
diff --git a/src/logfile.cpp b/src/logfile.cpp
new file mode 100644 (file)
index 0000000..ab5b86f
--- /dev/null
@@ -0,0 +1,238 @@
+#include "../include/logfile.h"\r
+\r
+#include <ctime>\r
+#include <cstdarg>\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+LogFile::LogFile()\r
+{\r
+       m_fileptr=NULL;\r
+       m_loglevel=LOGLEVEL_DEBUG;\r
+       m_writedate=false;\r
+       m_writeloglevel=false;\r
+       m_writenewline=true;\r
+       m_datebuffer=new char[100];\r
+}\r
+\r
+LogFile::LogFile(const std::string &filename)\r
+{\r
+       m_fileptr=NULL; \r
+       m_loglevel=LOGLEVEL_DEBUG;\r
+       m_writedate=false;\r
+       m_writeloglevel=false;\r
+       m_filename=filename;\r
+       m_writenewline=true;\r
+       m_datebuffer=new char[100];\r
+}\r
+\r
+LogFile::~LogFile()\r
+{\r
+       CloseFile();\r
+       delete [] m_datebuffer;\r
+}\r
+\r
+bool LogFile::CloseFile()\r
+{\r
+       ZThread::Guard<ZThread::Mutex> g(m_logmutex);\r
+\r
+       if(m_fileptr)\r
+       {\r
+               fclose(m_fileptr);\r
+               m_fileptr=NULL;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+bool LogFile::OpenFile()\r
+{\r
+       CloseFile();\r
+\r
+       ZThread::Guard<ZThread::Mutex> g(m_logmutex);\r
+\r
+       m_fileptr=fopen(m_filename.c_str(),"a+b");\r
+\r
+       if(m_fileptr)\r
+       {\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;   \r
+       }\r
+}\r
+\r
+void LogFile::WriteDate()\r
+{\r
+       if(m_fileptr)\r
+       {\r
+               time_t rawtime=time(NULL);\r
+               struct tm *timeinfo=gmtime(&rawtime);\r
+               \r
+               strftime(m_datebuffer,99,"%Y-%m-%d %H:%M:%S : ",timeinfo);\r
+               m_datebuffer[99]=NULL;\r
+               \r
+               fputs(m_datebuffer,m_fileptr);\r
+       }\r
+}\r
+\r
+void LogFile::WriteLog(const char *format, ...)\r
+{\r
+       va_list va;\r
+       va_start(va,format);\r
+       \r
+       if(!m_fileptr)\r
+       {\r
+               OpenFile();\r
+       }\r
+       \r
+       if(m_fileptr)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_logmutex);\r
+               if(m_writedate)\r
+               {\r
+                       WriteDate();\r
+               }\r
+               vfprintf(m_fileptr,format,va);\r
+               if(m_writenewline==true)\r
+               {\r
+                       fputs("\r\n",m_fileptr);\r
+               }\r
+               fflush(m_fileptr);\r
+       }\r
+       \r
+       va_end(va);\r
+\r
+}\r
+\r
+void LogFile::WriteLog(const std::string &text)\r
+{\r
+       if(!m_fileptr)\r
+       {\r
+               OpenFile();     \r
+       }\r
+       \r
+       if(m_fileptr)\r
+       {\r
+               ZThread::Guard<ZThread::Mutex> g(m_logmutex);\r
+               if(m_writedate)\r
+               {\r
+                       WriteDate();    \r
+               }\r
+               fputs(text.c_str(),m_fileptr);\r
+               if(m_writenewline==true)\r
+               {\r
+                       fputs("\r\n",m_fileptr);\r
+               }\r
+               fflush(m_fileptr);\r
+       }\r
+}\r
+\r
+void LogFile::WriteLog(const LogLevel level, const char *format, ...)\r
+{\r
+       if(level<=m_loglevel)\r
+       {\r
+               \r
+               va_list va;\r
+               va_start(va,format);\r
+               \r
+               if(!m_fileptr)\r
+               {\r
+                       OpenFile();     \r
+               }\r
+               \r
+               if(m_fileptr)\r
+               {\r
+                       ZThread::Guard<ZThread::Mutex> g(m_logmutex);\r
+                       if(m_writedate)\r
+                       {\r
+                               WriteDate();    \r
+                       }\r
+                       if(m_writeloglevel)\r
+                       {\r
+                               WriteLogLevel(level);   \r
+                       }\r
+                       vfprintf(m_fileptr,format,va);\r
+                       if(m_writenewline==true)\r
+                       {\r
+                               fputs("\r\n",m_fileptr);\r
+                       }\r
+                       fflush(m_fileptr);\r
+               }\r
+               \r
+               va_end(va);\r
+       }\r
+}\r
+\r
+void LogFile::WriteLog(const LogLevel level, const std::string &text)\r
+{\r
+       if(level<=m_loglevel)\r
+       {\r
+               if(!m_fileptr)\r
+               {\r
+                       OpenFile();     \r
+               }\r
+               \r
+               if(m_fileptr)\r
+               {\r
+                       ZThread::Guard<ZThread::Mutex> g(m_logmutex);\r
+                       if(m_writedate)\r
+                       {\r
+                               WriteDate();    \r
+                       }\r
+                       if(m_writeloglevel)\r
+                       {\r
+                               WriteLogLevel(level);\r
+                       }\r
+                       fputs(text.c_str(),m_fileptr);\r
+                       if(m_writenewline==true)\r
+                       {\r
+                               fputs("\r\n",m_fileptr);\r
+                       }\r
+                       fflush(m_fileptr);\r
+               }\r
+       }       \r
+}\r
+\r
+void LogFile::WriteLogLevel(LogLevel level)\r
+{\r
+       if(m_fileptr)\r
+       {\r
+               switch(level)\r
+               {\r
+               case LOGLEVEL_FATAL:\r
+                       fputs("FATAL : ",m_fileptr);\r
+                       break;  \r
+               case LOGLEVEL_ERROR:\r
+                       fputs("ERROR : ",m_fileptr);\r
+                       break;\r
+               case LOGLEVEL_WARNING:\r
+                       fputs("WARN  : ",m_fileptr);\r
+                       break;\r
+               case LOGLEVEL_INFO:\r
+                       fputs("INFO  : ",m_fileptr);\r
+                       break;\r
+               case LOGLEVEL_DEBUG:\r
+                       fputs("DEBUG : ",m_fileptr);\r
+                       break;\r
+               default:\r
+                       fputs("????  : ",m_fileptr);\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+void LogFile::WriteNewLine()\r
+{\r
+       ZThread::Guard<ZThread::Mutex> g(m_logmutex);\r
+\r
+       if(m_fileptr)\r
+       {\r
+               fputs("\r\n",m_fileptr);\r
+               fflush(m_fileptr);\r
+       }\r
+}\r
+\r
diff --git a/src/option.cpp b/src/option.cpp
new file mode 100644 (file)
index 0000000..ae8d8ba
--- /dev/null
@@ -0,0 +1,22 @@
+#include "../include/option.h"\r
+#include "../include/db/sqlite3db.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+const bool Option::Get(const std::string &option, std::string &value)\r
+{\r
+       SQLite3DB::Statement st=SQLite3DB::DB::instance()->Prepare("SELECT OptionValue FROM tblOption WHERE Option=?;");\r
+       st.Bind(0,option);\r
+       st.Step();\r
+       if(st.RowReturned())\r
+       {\r
+               st.ResultText(0,value);\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}
\ No newline at end of file
diff --git a/src/socketdefines.cpp b/src/socketdefines.cpp
new file mode 100644 (file)
index 0000000..caf6fa6
--- /dev/null
@@ -0,0 +1,26 @@
+#include "../include/socketdefines.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+std::string GetSocketErrorMessage()\r
+{\r
+       if(strerror(GetSocketErrorNumber()))\r
+       {\r
+               return std::string(strerror(GetSocketErrorNumber()));\r
+       }\r
+       else\r
+       {\r
+               return std::string(""); \r
+       }\r
+}\r
+\r
+int GetSocketErrorNumber()\r
+{\r
+#ifdef _WIN32\r
+       return WSAGetLastError();\r
+#else\r
+       return errno;\r
+#endif\r
+}\r
diff --git a/src/stringfunctions.cpp b/src/stringfunctions.cpp
new file mode 100644 (file)
index 0000000..36a3707
--- /dev/null
@@ -0,0 +1,201 @@
+#include "../include/stringfunctions.h"\r
+\r
+#include <algorithm>\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+namespace StringFunctions\r
+{\r
+\r
+std::string Replace(const std::string &input, const std::string &find, const std::string &replace)\r
+{\r
+       std::string returnstr=input;\r
+       std::string::size_type pos=returnstr.find(find);\r
+\r
+       while(pos!=std::string::npos)\r
+       {\r
+               returnstr.replace(pos,find.size(),replace);\r
+               pos=returnstr.find(find,pos+replace.size());\r
+       }\r
+\r
+       return returnstr;\r
+\r
+}\r
+\r
+void Split(const std::string &str, const std::string &delim, std::vector<std::string> &output)\r
+{\r
+    unsigned int offset = 0;\r
+    unsigned int delimIndex = 0;\r
+    \r
+    delimIndex = str.find(delim, offset);\r
+\r
+    while (delimIndex != std::string::npos)\r
+    {\r
+        output.push_back(str.substr(offset, delimIndex - offset));\r
+        offset += delimIndex - offset + delim.length();\r
+        delimIndex = str.find(delim, offset);\r
+    }\r
+\r
+    output.push_back(str.substr(offset));\r
+}\r
+\r
+void SplitMultiple(const std::string &str, const std::string &delim, std::vector<std::string> &output)\r
+{\r
+    unsigned int offset = 0;\r
+    unsigned int delimIndex = 0;\r
+    \r
+    delimIndex = str.find_first_of(delim, offset);\r
+\r
+    while (delimIndex != std::string::npos)\r
+    {\r
+        output.push_back(str.substr(offset, delimIndex - offset));\r
+        offset += delimIndex - offset + 1;\r
+        delimIndex = str.find_first_of(delim, offset);\r
+    }\r
+\r
+    output.push_back(str.substr(offset));\r
+}\r
+\r
+std::string TrimWhitespace(const std::string &str)\r
+{\r
+       std::string returnstring=str;\r
+\r
+       while(returnstring.size()>0 && returnstring.find_first_of(" \t\r\n")==0)\r
+       {\r
+               returnstring.erase(0,1);\r
+       }\r
+       while(returnstring.size()>0 && returnstring.find_last_of(" \t\r\n")==returnstring.size()-1)\r
+       {\r
+               returnstring.erase(returnstring.size()-1,1);\r
+       }\r
+\r
+       return returnstring;\r
+}\r
+\r
+void UpperCase(const std::string &str, std::string &output)\r
+{\r
+       output=str;\r
+       std::transform(str.begin(),str.end(),output.begin(),toupper);\r
+}\r
+\r
+std::string UriDecode(const std::string & sSrc)\r
+{\r
+   // Note from RFC1630: "Sequences which start with a percent\r
+   // sign but are not followed by two hexadecimal characters\r
+   // (0-9, A-F) are reserved for future extension"\r
+   \r
+static const char HEX2DEC[256] = \r
+{\r
+    /*       0  1  2  3   4  5  6  7   8  9  A  B   C  D  E  F */\r
+    /* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* 3 */  0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,\r
+    \r
+    /* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    \r
+    /* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    \r
+    /* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,\r
+    /* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1\r
+};\r
+\r
+   const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();\r
+   const int SRC_LEN = sSrc.length();\r
+   const unsigned char * const SRC_END = pSrc + SRC_LEN;\r
+   // last decodable '%'\r
+   const unsigned char * const SRC_LAST_DEC = SRC_END - 2;\r
+\r
+   char * const pStart = new char[SRC_LEN];\r
+   char * pEnd = pStart;\r
+\r
+   while (pSrc < SRC_LAST_DEC)\r
+   {\r
+      if (*pSrc == '%')\r
+      {\r
+         char dec1, dec2;\r
+         if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)])\r
+            && -1 != (dec2 = HEX2DEC[*(pSrc + 2)]))\r
+         {\r
+            *pEnd++ = (dec1 << 4) + dec2;\r
+            pSrc += 3;\r
+            continue;\r
+         }\r
+      }\r
+\r
+      *pEnd++ = *pSrc++;\r
+   }\r
+\r
+   // the last 2- chars\r
+   while (pSrc < SRC_END)\r
+      *pEnd++ = *pSrc++;\r
+\r
+   std::string sResult(pStart, pEnd);\r
+   delete [] pStart;\r
+   return sResult;\r
+}\r
+\r
+std::string UriEncode(const std::string & sSrc)\r
+{\r
+       \r
+// Only alphanum is safe.\r
+static const char SAFE[256] =\r
+{\r
+    /*      0 1 2 3  4 5 6 7  8 9 A B  C D E F */\r
+    /* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    /* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    /* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    /* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,\r
+    \r
+    /* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,\r
+    /* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,\r
+    /* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,\r
+    /* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,\r
+    \r
+    /* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    /* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    /* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    /* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    \r
+    /* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    /* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    /* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,\r
+    /* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0\r
+};\r
+       \r
+   const char DEC2HEX[16 + 1] = "0123456789ABCDEF";\r
+   const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();\r
+   const int SRC_LEN = sSrc.length();\r
+   unsigned char * const pStart = new unsigned char[SRC_LEN * 3];\r
+   unsigned char * pEnd = pStart;\r
+   const unsigned char * const SRC_END = pSrc + SRC_LEN;\r
+\r
+   for (; pSrc < SRC_END; ++pSrc)\r
+   {\r
+      if (SAFE[*pSrc])\r
+         *pEnd++ = *pSrc;\r
+      else\r
+      {\r
+         // escape this char\r
+         *pEnd++ = '%';\r
+         *pEnd++ = DEC2HEX[*pSrc >> 4];\r
+         *pEnd++ = DEC2HEX[*pSrc & 0x0F];\r
+      }\r
+   }\r
+\r
+   std::string sResult((char *)pStart, (char *)pEnd);\r
+   delete [] pStart;\r
+   return sResult;\r
+}\r
+\r
+}      // namespace\r
diff --git a/src/uuidgenerator.cpp b/src/uuidgenerator.cpp
new file mode 100644 (file)
index 0000000..a2da3b6
--- /dev/null
@@ -0,0 +1,23 @@
+#include "../include/uuidgenerator.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+const std::string UUIDGenerator::Generate()\r
+{\r
+\r
+       return RandHex(8)+"-"+RandHex(4)+"-4"+RandHex(3)+"-"+RandHex(4)+"-"+RandHex(12);\r
+\r
+}\r
+\r
+const std::string UUIDGenerator::RandHex(const int len)\r
+{\r
+       static std::string hexchars="0123456789ABCDEF";\r
+       std::string rval="";\r
+       for(int i=0; i<len; i++)\r
+       {\r
+               rval+=hexchars[rand()%hexchars.size()];\r
+       }\r
+       return rval;\r
+}
\ No newline at end of file
diff --git a/src/xyssl/sha1.c b/src/xyssl/sha1.c
new file mode 100644 (file)
index 0000000..901b06f
--- /dev/null
@@ -0,0 +1,496 @@
+/*\r
+ *  FIPS-180-1 compliant SHA-1 implementation\r
+ *\r
+ *  Copyright (C) 2006-2007  Christophe Devine\r
+ *\r
+ *  This library is free software; you can redistribute it and/or\r
+ *  modify it under the terms of the GNU Lesser General Public\r
+ *  License, version 2.1 as published by the Free Software Foundation.\r
+ *\r
+ *  This library is distributed in the hope that it will be useful,\r
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ *  Lesser General Public License for more details.\r
+ *\r
+ *  You should have received a copy of the GNU Lesser General Public\r
+ *  License along with this library; if not, write to the Free Software\r
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\r
+ *  MA  02110-1301  USA\r
+ */\r
+/*\r
+ *  The SHA-1 standard was published by NIST in 1993.\r
+ *\r
+ *  http://www.itl.nist.gov/fipspubs/fip180-1.htm\r
+ */\r
+\r
+#include "../../include/xyssl/config.h"\r
+\r
+#if defined(XYSSL_SHA1_C)\r
+\r
+#include "../../include/xyssl/sha1.h"\r
+\r
+#include <string.h>\r
+#include <stdio.h>\r
+\r
+/*\r
+ * 32-bit integer manipulation macros (big endian)\r
+ */\r
+#ifndef GET_ULONG_BE\r
+#define GET_ULONG_BE(n,b,i)                             \\r
+{                                                       \\r
+    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \\r
+        | ( (unsigned long) (b)[(i) + 1] << 16 )        \\r
+        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \\r
+        | ( (unsigned long) (b)[(i) + 3]       );       \\r
+}\r
+#endif\r
+\r
+#ifndef PUT_ULONG_BE\r
+#define PUT_ULONG_BE(n,b,i)                             \\r
+{                                                       \\r
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \\r
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \\r
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \\r
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \\r
+}\r
+#endif\r
+\r
+/*\r
+ * SHA-1 context setup\r
+ */\r
+void sha1_starts( sha1_context *ctx )\r
+{\r
+    ctx->total[0] = 0;\r
+    ctx->total[1] = 0;\r
+\r
+    ctx->state[0] = 0x67452301;\r
+    ctx->state[1] = 0xEFCDAB89;\r
+    ctx->state[2] = 0x98BADCFE;\r
+    ctx->state[3] = 0x10325476;\r
+    ctx->state[4] = 0xC3D2E1F0;\r
+}\r
+\r
+static void sha1_process( sha1_context *ctx, unsigned char data[64] )\r
+{\r
+    unsigned long temp, W[16], A, B, C, D, E;\r
+\r
+    GET_ULONG_BE( W[ 0], data,  0 );\r
+    GET_ULONG_BE( W[ 1], data,  4 );\r
+    GET_ULONG_BE( W[ 2], data,  8 );\r
+    GET_ULONG_BE( W[ 3], data, 12 );\r
+    GET_ULONG_BE( W[ 4], data, 16 );\r
+    GET_ULONG_BE( W[ 5], data, 20 );\r
+    GET_ULONG_BE( W[ 6], data, 24 );\r
+    GET_ULONG_BE( W[ 7], data, 28 );\r
+    GET_ULONG_BE( W[ 8], data, 32 );\r
+    GET_ULONG_BE( W[ 9], data, 36 );\r
+    GET_ULONG_BE( W[10], data, 40 );\r
+    GET_ULONG_BE( W[11], data, 44 );\r
+    GET_ULONG_BE( W[12], data, 48 );\r
+    GET_ULONG_BE( W[13], data, 52 );\r
+    GET_ULONG_BE( W[14], data, 56 );\r
+    GET_ULONG_BE( W[15], data, 60 );\r
+\r
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))\r
+\r
+#define R(t)                                            \\r
+(                                                       \\r
+    temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^     \\r
+           W[(t - 14) & 0x0F] ^ W[ t      & 0x0F],      \\r
+    ( W[t & 0x0F] = S(temp,1) )                         \\r
+)\r
+\r
+#define P(a,b,c,d,e,x)                                  \\r
+{                                                       \\r
+    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \\r
+}\r
+\r
+    A = ctx->state[0];\r
+    B = ctx->state[1];\r
+    C = ctx->state[2];\r
+    D = ctx->state[3];\r
+    E = ctx->state[4];\r
+\r
+#define F(x,y,z) (z ^ (x & (y ^ z)))\r
+#define K 0x5A827999\r
+\r
+    P( A, B, C, D, E, W[0]  );\r
+    P( E, A, B, C, D, W[1]  );\r
+    P( D, E, A, B, C, W[2]  );\r
+    P( C, D, E, A, B, W[3]  );\r
+    P( B, C, D, E, A, W[4]  );\r
+    P( A, B, C, D, E, W[5]  );\r
+    P( E, A, B, C, D, W[6]  );\r
+    P( D, E, A, B, C, W[7]  );\r
+    P( C, D, E, A, B, W[8]  );\r
+    P( B, C, D, E, A, W[9]  );\r
+    P( A, B, C, D, E, W[10] );\r
+    P( E, A, B, C, D, W[11] );\r
+    P( D, E, A, B, C, W[12] );\r
+    P( C, D, E, A, B, W[13] );\r
+    P( B, C, D, E, A, W[14] );\r
+    P( A, B, C, D, E, W[15] );\r
+    P( E, A, B, C, D, R(16) );\r
+    P( D, E, A, B, C, R(17) );\r
+    P( C, D, E, A, B, R(18) );\r
+    P( B, C, D, E, A, R(19) );\r
+\r
+#undef K\r
+#undef F\r
+\r
+#define F(x,y,z) (x ^ y ^ z)\r
+#define K 0x6ED9EBA1\r
+\r
+    P( A, B, C, D, E, R(20) );\r
+    P( E, A, B, C, D, R(21) );\r
+    P( D, E, A, B, C, R(22) );\r
+    P( C, D, E, A, B, R(23) );\r
+    P( B, C, D, E, A, R(24) );\r
+    P( A, B, C, D, E, R(25) );\r
+    P( E, A, B, C, D, R(26) );\r
+    P( D, E, A, B, C, R(27) );\r
+    P( C, D, E, A, B, R(28) );\r
+    P( B, C, D, E, A, R(29) );\r
+    P( A, B, C, D, E, R(30) );\r
+    P( E, A, B, C, D, R(31) );\r
+    P( D, E, A, B, C, R(32) );\r
+    P( C, D, E, A, B, R(33) );\r
+    P( B, C, D, E, A, R(34) );\r
+    P( A, B, C, D, E, R(35) );\r
+    P( E, A, B, C, D, R(36) );\r
+    P( D, E, A, B, C, R(37) );\r
+    P( C, D, E, A, B, R(38) );\r
+    P( B, C, D, E, A, R(39) );\r
+\r
+#undef K\r
+#undef F\r
+\r
+#define F(x,y,z) ((x & y) | (z & (x | y)))\r
+#define K 0x8F1BBCDC\r
+\r
+    P( A, B, C, D, E, R(40) );\r
+    P( E, A, B, C, D, R(41) );\r
+    P( D, E, A, B, C, R(42) );\r
+    P( C, D, E, A, B, R(43) );\r
+    P( B, C, D, E, A, R(44) );\r
+    P( A, B, C, D, E, R(45) );\r
+    P( E, A, B, C, D, R(46) );\r
+    P( D, E, A, B, C, R(47) );\r
+    P( C, D, E, A, B, R(48) );\r
+    P( B, C, D, E, A, R(49) );\r
+    P( A, B, C, D, E, R(50) );\r
+    P( E, A, B, C, D, R(51) );\r
+    P( D, E, A, B, C, R(52) );\r
+    P( C, D, E, A, B, R(53) );\r
+    P( B, C, D, E, A, R(54) );\r
+    P( A, B, C, D, E, R(55) );\r
+    P( E, A, B, C, D, R(56) );\r
+    P( D, E, A, B, C, R(57) );\r
+    P( C, D, E, A, B, R(58) );\r
+    P( B, C, D, E, A, R(59) );\r
+\r
+#undef K\r
+#undef F\r
+\r
+#define F(x,y,z) (x ^ y ^ z)\r
+#define K 0xCA62C1D6\r
+\r
+    P( A, B, C, D, E, R(60) );\r
+    P( E, A, B, C, D, R(61) );\r
+    P( D, E, A, B, C, R(62) );\r
+    P( C, D, E, A, B, R(63) );\r
+    P( B, C, D, E, A, R(64) );\r
+    P( A, B, C, D, E, R(65) );\r
+    P( E, A, B, C, D, R(66) );\r
+    P( D, E, A, B, C, R(67) );\r
+    P( C, D, E, A, B, R(68) );\r
+    P( B, C, D, E, A, R(69) );\r
+    P( A, B, C, D, E, R(70) );\r
+    P( E, A, B, C, D, R(71) );\r
+    P( D, E, A, B, C, R(72) );\r
+    P( C, D, E, A, B, R(73) );\r
+    P( B, C, D, E, A, R(74) );\r
+    P( A, B, C, D, E, R(75) );\r
+    P( E, A, B, C, D, R(76) );\r
+    P( D, E, A, B, C, R(77) );\r
+    P( C, D, E, A, B, R(78) );\r
+    P( B, C, D, E, A, R(79) );\r
+\r
+#undef K\r
+#undef F\r
+\r
+    ctx->state[0] += A;\r
+    ctx->state[1] += B;\r
+    ctx->state[2] += C;\r
+    ctx->state[3] += D;\r
+    ctx->state[4] += E;\r
+}\r
+\r
+/*\r
+ * SHA-1 process buffer\r
+ */\r
+void sha1_update( sha1_context *ctx, unsigned char *input, int ilen )\r
+{\r
+    int fill;\r
+    unsigned long left;\r
+\r
+    if( ilen <= 0 )\r
+        return;\r
+\r
+    left = ctx->total[0] & 0x3F;\r
+    fill = 64 - left;\r
+\r
+    ctx->total[0] += ilen;\r
+    ctx->total[0] &= 0xFFFFFFFF;\r
+\r
+    if( ctx->total[0] < (unsigned long) ilen )\r
+        ctx->total[1]++;\r
+\r
+    if( left && ilen >= fill )\r
+    {\r
+        memcpy( (void *) (ctx->buffer + left),\r
+                (void *) input, fill );\r
+        sha1_process( ctx, ctx->buffer );\r
+        input += fill;\r
+        ilen  -= fill;\r
+        left = 0;\r
+    }\r
+\r
+    while( ilen >= 64 )\r
+    {\r
+        sha1_process( ctx, input );\r
+        input += 64;\r
+        ilen  -= 64;\r
+    }\r
+\r
+    if( ilen > 0 )\r
+    {\r
+        memcpy( (void *) (ctx->buffer + left),\r
+                (void *) input, ilen );\r
+    }\r
+}\r
+\r
+static const unsigned char sha1_padding[64] =\r
+{\r
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
+};\r
+\r
+/*\r
+ * SHA-1 final digest\r
+ */\r
+void sha1_finish( sha1_context *ctx, unsigned char output[20] )\r
+{\r
+    unsigned long last, padn;\r
+    unsigned long high, low;\r
+    unsigned char msglen[8];\r
+\r
+    high = ( ctx->total[0] >> 29 )\r
+         | ( ctx->total[1] <<  3 );\r
+    low  = ( ctx->total[0] <<  3 );\r
+\r
+    PUT_ULONG_BE( high, msglen, 0 );\r
+    PUT_ULONG_BE( low,  msglen, 4 );\r
+\r
+    last = ctx->total[0] & 0x3F;\r
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );\r
+\r
+    sha1_update( ctx, (unsigned char *) sha1_padding, padn );\r
+    sha1_update( ctx, msglen, 8 );\r
+\r
+    PUT_ULONG_BE( ctx->state[0], output,  0 );\r
+    PUT_ULONG_BE( ctx->state[1], output,  4 );\r
+    PUT_ULONG_BE( ctx->state[2], output,  8 );\r
+    PUT_ULONG_BE( ctx->state[3], output, 12 );\r
+    PUT_ULONG_BE( ctx->state[4], output, 16 );\r
+}\r
+\r
+/*\r
+ * output = SHA-1( input buffer )\r
+ */\r
+void sha1( unsigned char *input, int ilen, unsigned char output[20] )\r
+{\r
+    sha1_context ctx;\r
+\r
+    sha1_starts( &ctx );\r
+    sha1_update( &ctx, input, ilen );\r
+    sha1_finish( &ctx, output );\r
+\r
+    memset( &ctx, 0, sizeof( sha1_context ) );\r
+}\r
+\r
+/*\r
+ * output = SHA-1( file contents )\r
+ */\r
+int sha1_file( char *path, unsigned char output[20] )\r
+{\r
+    FILE *f;\r
+    size_t n;\r
+    sha1_context ctx;\r
+    unsigned char buf[1024];\r
+\r
+    if( ( f = fopen( path, "rb" ) ) == NULL )\r
+        return( 1 );\r
+\r
+    sha1_starts( &ctx );\r
+\r
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )\r
+        sha1_update( &ctx, buf, (int) n );\r
+\r
+    sha1_finish( &ctx, output );\r
+\r
+    memset( &ctx, 0, sizeof( sha1_context ) );\r
+\r
+    if( ferror( f ) != 0 )\r
+    {\r
+        fclose( f );\r
+        return( 2 );\r
+    }\r
+\r
+    fclose( f );\r
+    return( 0 );\r
+}\r
+\r
+/*\r
+ * SHA-1 HMAC context setup\r
+ */\r
+void sha1_hmac_starts( sha1_context *ctx, unsigned char *key, int keylen )\r
+{\r
+    int i;\r
+    unsigned char sum[20];\r
+\r
+    if( keylen > 64 )\r
+    {\r
+        sha1( key, keylen, sum );\r
+        keylen = 20;\r
+        key = sum;\r
+    }\r
+\r
+    memset( ctx->ipad, 0x36, 64 );\r
+    memset( ctx->opad, 0x5C, 64 );\r
+\r
+    for( i = 0; i < keylen; i++ )\r
+    {\r
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );\r
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );\r
+    }\r
+\r
+    sha1_starts( ctx );\r
+    sha1_update( ctx, ctx->ipad, 64 );\r
+\r
+    memset( sum, 0, sizeof( sum ) );\r
+}\r
+\r
+/*\r
+ * SHA-1 HMAC process buffer\r
+ */\r
+void sha1_hmac_update( sha1_context *ctx, unsigned char *input, int ilen )\r
+{\r
+    sha1_update( ctx, input, ilen );\r
+}\r
+\r
+/*\r
+ * SHA-1 HMAC final digest\r
+ */\r
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] )\r
+{\r
+    unsigned char tmpbuf[20];\r
+\r
+    sha1_finish( ctx, tmpbuf );\r
+    sha1_starts( ctx );\r
+    sha1_update( ctx, ctx->opad, 64 );\r
+    sha1_update( ctx, tmpbuf, 20 );\r
+    sha1_finish( ctx, output );\r
+\r
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );\r
+}\r
+\r
+/*\r
+ * output = HMAC-SHA-1( hmac key, input buffer )\r
+ */\r
+void sha1_hmac( unsigned char *key, int keylen, unsigned char *input, int ilen,\r
+                unsigned char output[20] )\r
+{\r
+    sha1_context ctx;\r
+\r
+    sha1_hmac_starts( &ctx, key, keylen );\r
+    sha1_hmac_update( &ctx, input, ilen );\r
+    sha1_hmac_finish( &ctx, output );\r
+\r
+    memset( &ctx, 0, sizeof( sha1_context ) );\r
+}\r
+\r
+#if defined(XYSSL_SELF_TEST)\r
+\r
+/*\r
+ * FIPS-180-1 test vectors\r
+ */\r
+static const char sha1_test_str[3][57] = \r
+{\r
+    { "abc" },\r
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },\r
+    { "" }\r
+};\r
+\r
+static const unsigned char sha1_test_sum[3][20] =\r
+{\r
+    { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,\r
+      0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },\r
+    { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,\r
+      0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },\r
+    { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,\r
+      0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }\r
+};\r
+\r
+/*\r
+ * Checkup routine\r
+ */\r
+int sha1_self_test( int verbose )\r
+{\r
+    int i, j;\r
+    unsigned char buf[1000];\r
+    unsigned char sha1sum[20];\r
+    sha1_context ctx;\r
+\r
+    for( i = 0; i < 3; i++ )\r
+    {\r
+        if( verbose != 0 )\r
+            printf( "  SHA-1 test #%d: ", i + 1 );\r
+\r
+        sha1_starts( &ctx );\r
+\r
+        if( i < 2 )\r
+            sha1_update( &ctx, (unsigned char *) sha1_test_str[i],\r
+                         strlen( sha1_test_str[i] ) );\r
+        else\r
+        {\r
+            memset( buf, 'a', 1000 );\r
+            for( j = 0; j < 1000; j++ )\r
+                sha1_update( &ctx, buf, 1000 );\r
+        }\r
+\r
+        sha1_finish( &ctx, sha1sum );\r
+\r
+        if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )\r
+        {\r
+            if( verbose != 0 )\r
+                printf( "failed\n" );\r
+\r
+            return( 1 );\r
+        }\r
+\r
+        if( verbose != 0 )\r
+            printf( "passed\n" );\r
+    }\r
+\r
+    if( verbose != 0 )\r
+        printf( "\n" );\r
+\r
+    return( 0 );\r
+}\r
+\r
+#endif\r
+\r
+#endif
\ No newline at end of file