f87e2bd334afafd45c39aa47aabd7f0207d381b5
[fms.git] / src / freenet / introductionpuzzleinserter.cpp
1 #include "../../include/freenet/introductionpuzzleinserter.h"\r
2 #include "../../include/freenet/introductionpuzzlexml.h"\r
3 #include "../../include/stringfunctions.h"\r
4 #include "../../include/option.h"\r
5 #include "../../include/freenet/captcha/simplecaptcha.h"\r
6 #include "../../include/uuidgenerator.h"\r
7 #include "../../include/base64.h"\r
8 \r
9 #ifdef XMEM\r
10         #include <xmem.h>\r
11 #endif\r
12 \r
13 IntroductionPuzzleInserter::IntroductionPuzzleInserter()\r
14 {\r
15         Initialize();\r
16 }\r
17 \r
18 IntroductionPuzzleInserter::IntroductionPuzzleInserter(FCPv2 *fcp):IFCPConnected(fcp)\r
19 {\r
20         Initialize();\r
21 }\r
22 \r
23 void IntroductionPuzzleInserter::CheckForNeededInsert()\r
24 {\r
25         // select all local ids that aren't single use and that aren't currently inserting a puzzle\r
26         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
27         \r
28         while(!rs.AtEnd())\r
29         {\r
30                 DateTime now;\r
31                 now.SetToGMTime();\r
32 \r
33                 // if this identity has any non-solved puzzles for today, we don't need to insert a new puzzle\r
34                 SQLite3DB::Recordset rs2=m_db->Query("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE Day='"+now.Format("%Y-%m-%d")+"' AND FoundSolution='false';");\r
35 \r
36                 // identity doesn't have any non-solved puzzles for today - start a new insert\r
37                 if(rs2.Empty()==true)\r
38                 {\r
39                         StartInsert(rs.GetInt(0));\r
40                 }\r
41 \r
42                 rs.Next();\r
43         }\r
44 }\r
45 \r
46 void IntroductionPuzzleInserter::FCPConnected()\r
47 {\r
48         m_db->Execute("UPDATE tblLocalIdentity SET InsertingPuzzle='false';");\r
49 }\r
50 \r
51 void IntroductionPuzzleInserter::FCPDisconnected()\r
52 {\r
53         \r
54 }\r
55 \r
56 void IntroductionPuzzleInserter::GenerateCaptcha(std::string &encodeddata, std::string &solution)\r
57 {\r
58         SimpleCaptcha captcha;\r
59         std::vector<unsigned char> puzzle;\r
60         std::vector<unsigned char> puzzlesolution;\r
61 \r
62         captcha.Generate();\r
63         captcha.GetPuzzle(puzzle);\r
64         captcha.GetSolution(puzzlesolution);\r
65 \r
66         encodeddata.clear();\r
67         solution.clear();\r
68 \r
69         Base64::Encode(puzzle,encodeddata);\r
70         solution.insert(solution.begin(),puzzlesolution.begin(),puzzlesolution.end());\r
71 \r
72 }\r
73 \r
74 const bool IntroductionPuzzleInserter::HandleMessage(FCPMessage &message)\r
75 {\r
76 \r
77         if(message["Identifier"].find("IntroductionPuzzleInserter")==0)\r
78         {\r
79 \r
80                 // ignore URIGenerated message\r
81                 if(message.GetName()=="URIGenerated")\r
82                 {\r
83                         return true;\r
84                 }\r
85 \r
86                 if(message.GetName()=="PutSuccessful")\r
87                 {\r
88                         return HandlePutSuccessful(message);\r
89                 }\r
90 \r
91                 if(message.GetName()=="PutFailed")\r
92                 {\r
93                         return HandlePutFailed(message);\r
94                 }\r
95 \r
96         }\r
97 \r
98         return false;\r
99 }\r
100 \r
101 const bool IntroductionPuzzleInserter::HandlePutFailed(FCPMessage &message)\r
102 {\r
103         SQLite3DB::Statement st;\r
104         std::vector<std::string> idparts;\r
105         long localidentityid;\r
106 \r
107         StringFunctions::Split(message["Identifier"],"|",idparts);\r
108         StringFunctions::Convert(idparts[1],localidentityid);\r
109 \r
110         st=m_db->Prepare("UPDATE tblLocalIdentity SET InsertingPuzzle='false' WHERE LocalIdentityID=?;");\r
111         st.Bind(0,localidentityid);\r
112         st.Step();\r
113         st.Finalize();\r
114 \r
115         m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" failed to insert puzzle "+idparts[3]);\r
116 \r
117         return true;\r
118 }\r
119 \r
120 const bool IntroductionPuzzleInserter::HandlePutSuccessful(FCPMessage &message)\r
121 {\r
122         DateTime now;\r
123         SQLite3DB::Statement st;\r
124         std::vector<std::string> idparts;\r
125         long localidentityid;\r
126         long insertindex;\r
127 \r
128         now.SetToGMTime();\r
129         StringFunctions::Split(message["Identifier"],"|",idparts);\r
130         StringFunctions::Convert(idparts[1],localidentityid);\r
131         StringFunctions::Convert(idparts[2],insertindex);\r
132 \r
133         st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET Day=?, InsertIndex=? WHERE UUID=?;");\r
134         st.Bind(0,idparts[5]);\r
135         st.Bind(1,insertindex);\r
136         st.Bind(2,idparts[3]);\r
137         st.Step();\r
138         st.Finalize();\r
139 \r
140         st=m_db->Prepare("UPDATE tblLocalIdentity SET InsertingPuzzle='false', LastInsertedPuzzle=? WHERE LocalIdentityID=?;");\r
141         st.Bind(0,now.Format("%Y-%m-%d %H:%M:%S"));\r
142         st.Bind(1,localidentityid);\r
143         st.Step();\r
144         st.Finalize();\r
145 \r
146         m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" inserted puzzle "+idparts[3]);\r
147 \r
148         return true;\r
149 }\r
150 \r
151 void IntroductionPuzzleInserter::Initialize()\r
152 {\r
153         m_lastchecked.SetToGMTime();\r
154 }\r
155 \r
156 void IntroductionPuzzleInserter::Process()\r
157 {\r
158 \r
159         DateTime now;\r
160 \r
161         now.SetToGMTime();\r
162 \r
163         if(m_lastchecked<(now-(1.0/1440.0)))\r
164         {\r
165                 CheckForNeededInsert();\r
166                 m_lastchecked=now;\r
167         }\r
168 \r
169 }\r
170 \r
171 void IntroductionPuzzleInserter::RegisterWithThread(FreenetMasterThread *thread)\r
172 {\r
173         thread->RegisterFCPConnected(this);\r
174         thread->RegisterFCPMessageHandler(this);\r
175         thread->RegisterPeriodicProcessor(this);\r
176 }\r
177 \r
178 void IntroductionPuzzleInserter::StartInsert(const long localidentityid)\r
179 {\r
180         DateTime now;\r
181         std::string idstring;\r
182         long index=0;\r
183         std::string indexstr;\r
184         UUIDGenerator uuid;\r
185         std::string messagebase;\r
186         IntroductionPuzzleXML xml;\r
187         std::string encodedpuzzle;\r
188         std::string solutionstring;\r
189         FCPMessage message;\r
190         std::string xmldata;\r
191         std::string xmldatasizestr;\r
192         std::string privatekey;\r
193 \r
194         StringFunctions::Convert(localidentityid,idstring);\r
195         now.SetToGMTime();\r
196         SQLite3DB::Recordset rs=m_db->Query("SELECT MAX(InsertIndex) FROM tblIntroductionPuzzleInserts WHERE Day='"+now.Format("%Y-%m-%d")+"' AND LocalIdentityID="+idstring+";");\r
197 \r
198         if(rs.Empty() || rs.GetField(0)==NULL)\r
199         {\r
200                 index=0;\r
201         }\r
202         else\r
203         {\r
204                 index=rs.GetInt(0)+1;\r
205         }\r
206         StringFunctions::Convert(index,indexstr);\r
207 \r
208         SQLite3DB::Recordset rs2=m_db->Query("SELECT PrivateKey FROM tblLocalIdentity WHERE LocalIdentityID="+idstring+";");\r
209         if(rs2.Empty()==false && rs2.GetField(0)!=NULL)\r
210         {\r
211                 privatekey=rs2.GetField(0);\r
212         }\r
213 \r
214         Option::instance()->Get("MessageBase",messagebase);\r
215 \r
216         GenerateCaptcha(encodedpuzzle,solutionstring);\r
217 \r
218         xml.SetType("captcha");\r
219         xml.SetUUID(uuid.Generate());\r
220         xml.SetPuzzleData(encodedpuzzle);\r
221         xml.SetMimeType("bitmap/image");\r
222 \r
223         xmldata=xml.GetXML();\r
224         StringFunctions::Convert(xmldata.size(),xmldatasizestr);\r
225 \r
226         message.SetName("ClientPut");\r
227         message["URI"]=privatekey+messagebase+"|"+now.Format("%Y-%m-%d")+"|IntroductionPuzzle|"+indexstr+".xml";\r
228         message["Identifier"]="IntroductionPuzzleInserter|"+idstring+"|"+indexstr+"|"+xml.GetUUID()+"|"+message["URI"];\r
229         message["UploadFrom"]="direct";\r
230         message["DataLength"]=xmldatasizestr;\r
231         m_fcp->SendMessage(message);\r
232         m_fcp->SendRaw(xmldata.c_str(),xmldata.size());\r
233 \r
234         m_db->Execute("UPDATE tblLocalIdentity SET InsertingPuzzle='true' WHERE LocalIdentityID="+idstring+";");\r
235         m_db->Execute("INSERT INTO tblIntroductionPuzzleInserts(UUID,Type,MimeType,LocalIdentityID,PuzzleData,PuzzleSolution) VALUES('"+xml.GetUUID()+"','captcha','image/bmp',"+idstring+",'"+encodedpuzzle+"','"+solutionstring+"');");\r
236 \r
237         m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" started insert for id "+idstring);\r
238 \r
239 }\r