1 //-< CLIDB.CPP >-----------------------------------------------------*--------*
2 // FastDB                    Version 1.0         (c) 1999  GARRET    *     ?  *
3 // (Main Memory Database Management System)                          *   /\|  *
4 //                                                                   *  /  \  *
5 //                          Created:      7-Nov-99    K.A. Knizhnik  * / [] \ *
6 //                          Last update:  7-Nov-99    K.A. Knizhnik  * GARRET *
7 //-------------------------------------------------------------------*--------*
8 // Example of Web database publishing: Clients Database
9 //-------------------------------------------------------------------*--------*
10 
11 #include "clidb.h"
12 
13 dbDatabase db;
14 
15 //- Client ------------------------------------------------
16 
print(WWWconnection & con) const17 void Client::print(WWWconnection& con) const
18 {
19     con << TAG << "<OPTION VALUE=" << clientId << ">" << organization
20         << "</OPTION>";
21 }
22 
23 REGISTER(Client);
24 
25 
26 //- Manager ------------------------------------------------
27 
28 bool Manager::loginFromAnyHost;
29 
print(WWWconnection & con) const30 void Manager::print(WWWconnection& con) const
31 {
32     con << TAG << "<OPTION VALUE=\"" << name << "\">" << name
33         << "</OPTION>";
34 }
35 
36 REGISTER(Manager);
37 
38 //- Segment ------------------------------------------------
39 
print(WWWconnection & con) const40 void Segment::print(WWWconnection& con) const
41 {
42     con << TAG << "<OPTION VALUE=\"" << name << "\">" << name
43         << "</OPTION>";
44 }
45 
46 REGISTER(Segment);
47 
48 //- History ------------------------------------------------
49 
print(WWWconnection & con) const50 void History::print(WWWconnection& con) const
51 {
52     ThreadContext& the = ThreadContext::of(con);
53     char buf[64];
54 
55     con << TAG << "<OPTION VALUE=" << messageId << ">"
56         << date.asString(buf, sizeof buf)
57         << " " << (the.managerForm
58                    ? the.clients.at(client)->organization
59                    : manager != null ? the.managers.at(manager)->name : "")
60         << "</OPTION>";
61 }
62 
63 REGISTER(History);
64 
65 //---- ClientSequencer -------------------------------------
66 
67 REGISTER(Sequencer);
68 
69 
70 template<class T>
print(WWWconnection & con,dbCursor<T> & cursor)71 void print(WWWconnection& con, dbCursor<T>& cursor) {
72     do {
73         cursor->print(con);
74     } while(cursor.next());
75 }
76 
77 template<class T>
print(WWWconnection & con,dbArray<dbReference<T>> const & arr)78 void print(WWWconnection& con, dbArray<dbReference<T> > const& arr) {
79     dbCursor<T> cursor;
80     for (int i = 0, n = (int)arr.length(); i < n; i++) {
81         cursor.at(arr[i])->print(con);
82     }
83 }
84 
85 //---- Thread Context --------------------------------------------------
86 
of(WWWconnection & con)87 ThreadContext& ThreadContext::of(WWWconnection& con)
88 {
89     if (con.userData == NULL) {
90         con.userData = new ThreadContext;
91     }
92     return *(ThreadContext*)con.userData;
93 }
94 
ThreadContext()95 ThreadContext::ThreadContext()
96 {
97     qClient = "clientId=",clientId;
98     qManager = "name=",&name;
99     qClients = "start from",clientsArray,"order by organization";
100     qManagers = "start from",managersArray,"order by name";
101     qSegment = "name=",&name;
102     qMessage = "messageId=",messageId;
103     qMessages = "start from",messagesArray,
104                 "order by",dbDateTime::descent("date");
105 }
106 
107 //--- HTML specific part -------------------------------------------
108 
109 #define HTML_HEAD "Content-type: text/html\r\n\r\n\
110 <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\"><HTML><HEAD>"
111 
112 #define BODY "<BODY BGCOLOR=\"#c0c0c0\">"
113 
114 #define EMPTY_LIST "<OPTION>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</OPTION></SELECT><BR>"
115 
mainMenuReference(WWWconnection & con)116 void mainMenuReference(WWWconnection& con)
117 {
118     char* manager = con.get("manager");
119     if (manager != NULL) {
120         con << TAG
121             << "<P><HR><CENTER><A HREF=\"" << con.getStub() << "?socket="
122             << con.getAddress() << "&page=managerForm&manager="
123             << URL << manager << "\">Back to main menu</A></CENTER>";
124     }
125     con << TAG << "</BODY></HTML>";
126 }
127 
error(WWWconnection & con,char const * msg)128 bool error(WWWconnection& con, char const* msg)
129 {
130     con << TAG <<
131         HTML_HEAD "<TITLE>ClientDB error</TITLE></HEAD><BODY>"
132         "<H1><FONT COLOR=\"#FF0000\">"
133         << msg << "</FONT></H1></BODY></HTML>";
134     mainMenuReference(con);
135     return true;
136 }
137 
138 
139 
addManagerForm(WWWconnection & con)140 bool addManagerForm(WWWconnection& con)
141 {
142     con << TAG <<
143         HTML_HEAD "<TITLE>Add new manager</TITLE></HEAD>"
144         BODY
145         "<H2>Add manager</H2>"
146         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
147         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
148         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"addManager\">"
149         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << con.get("manager") <<
150         "\">"
151         "<INPUT TYPE=hidden NAME=\"segment\" VALUE=\"" << con.get("segment") <<
152         "\"><TABLE>"
153         "<TR><TH ALIGN=LEFT>Manager name</TH>"
154         "<TD><INPUT TYPE=text NAME=\"name\" SIZE=30></TD></TR>"
155         "<TR><TH ALIGN=LEFT>Host IP address</TH>"
156         "<TD><INPUT TYPE=text NAME=\"ipaddr\" SIZE=16 VALUE=\"*\"></TD></TR>"
157         "<TR><TH ALIGN=LEFT>Administrator rights</TH>"
158         "<TD><INPUT TYPE=CHECKBOX NAME=\"miniadmin\" VALUE=\"on\"></TD></TR>"
159         "</TABLE>"
160         "<INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
161         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
162     mainMenuReference(con);
163     return true;
164 }
165 
addClientForm(WWWconnection & con)166 bool addClientForm(WWWconnection& con)
167 {
168     con << TAG <<
169         HTML_HEAD "<TITLE>Add new client</TITLE></HEAD>"
170         BODY
171         "<H2>Add client</H2>"
172         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
173         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
174         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"addClient\">"
175         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << con.get("manager") <<
176         "\">"
177         "<INPUT TYPE=hidden NAME=\"segment\" VALUE=\"" << con.get("segment") <<
178         "\"><TABLE>"
179         "<TR><TH ALIGN=LEFT>Organization</TH>"
180         "<TD><INPUT TYPE=text NAME=\"organization\" SIZE=40></TD></TR>"
181         "<TR><TH ALIGN=LEFT>Phone</TH>"
182         "<TD><INPUT TYPE=text NAME=\"phone\" SIZE=20></TD></TR>"
183         "<TR><TH ALIGN=LEFT>Phone2</TH>"
184         "<TD><INPUT TYPE=text NAME=\"phone2\" SIZE=20></TD></TR>"
185         "<TR><TH ALIGN=LEFT>Fax</TH>"
186         "<TD><INPUT TYPE=text NAME=\"fax\" SIZE=20></TD></TR>"
187         "<TR><TH ALIGN=LEFT>E-Mail</TH>"
188         "<TD><INPUT TYPE=text NAME=\"email\" SIZE=30></TD></TR>"
189         "<TR><TH ALIGN=LEFT>WWW address</TH>"
190         "<TD><INPUT TYPE=text NAME=\"www\" SIZE=30></TD></TR>"
191         "<TR><TH ALIGN=LEFT>Person</TH>"
192         "<TD><INPUT TYPE=text NAME=\"person\" SIZE=40></TD></TR>"
193         "<TR><TH ALIGN=LEFT>Person2</TH>"
194         "<TD><INPUT TYPE=text NAME=\"person2\" SIZE=40></TD></TR>"
195         "<TR><TH ALIGN=LEFT>CEO</TH>"
196         "<TD><INPUT TYPE=text NAME=\"lpr\" SIZE=40></TD></TR>"
197         "<TR><TH ALIGN=LEFT>Address</TH>"
198         "<TD><INPUT TYPE=text NAME=\"addr\" SIZE=40></TD></TR>"
199         "<TR><TH ALIGN=LEFT>Information</TH>"
200         "<TD><INPUT TYPE=text NAME=\"info\" SIZE=40></TD></TR>"
201         "<TR><TH ALIGN=LEFT>Status</TH>"
202         "<TD><INPUT TYPE=text NAME=\"status\" SIZE=40></TD></TR>"
203         "</TABLE><INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
204         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
205     mainMenuReference(con);
206     return true;
207 }
208 
209 
addSegmentForm(WWWconnection & con)210 bool addSegmentForm(WWWconnection& con)
211 {
212     con << TAG <<
213         HTML_HEAD "<TITLE>Add new segment</TITLE></HEAD>"
214         BODY
215         "<H2>Add segment</H2>"
216         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
217         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
218         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"addSegment\">"
219         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << con.get("manager") <<
220         "\"><TABLE>"
221         "<TR><TH ALIGN=LEFT>Segment name </TH>"
222         "<TD><INPUT TYPE=text NAME=\"name\" SIZE=30></TD></TR>"
223         "</TD></TR></TABLE><P>"
224         "<INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
225         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
226     mainMenuReference(con);
227     return true;
228 }
229 
addHistoryForm(WWWconnection & con)230 bool addHistoryForm(WWWconnection& con)
231 {
232     con << TAG <<
233         HTML_HEAD "<TITLE>Add message</TITLE></HEAD>"
234         BODY
235         "<H2>Add message</H2>"
236         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
237         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
238         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"addHistory\">"
239         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << con.get("manager") <<
240         "\"><INPUT TYPE=hidden NAME=\"client\" VALUE=" << con.get("client") <<
241         "\"><TEXTAREA NAME=\"message\" ROWS=10 COLS=60></TEXTAREA><P>"
242         "<INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
243         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
244     mainMenuReference(con);
245     return true;
246 }
247 
248 
editManagerForm(WWWconnection & con)249 bool editManagerForm(WWWconnection& con)
250 {
251     if (con.get("new")) {
252         return addManagerForm(con);
253     }
254     ThreadContext& the = ThreadContext::of(con);
255     the.name = con.get("name");
256     if (the.name == NULL) {
257         return error(con, "No manager was selected");
258     }
259     if (the.managers.select(the.qManager) == 0) {
260         return error(con, "No such manager");
261     }
262 
263     con << TAG <<
264         HTML_HEAD "<TITLE>Edit manager form</TITLE></HEAD>"
265         BODY
266         "<H2>Update manager</H2>"
267         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
268         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
269         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editManager\">"
270         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << con.get("manager") <<
271         "\"><INPUT TYPE=hidden NAME=\"oldName\" VALUE=\"" << the.name << "\">"
272         "<TABLE><TR><TH ALIGN=LEFT>Manager name</TH>"
273         "<TD><INPUT TYPE=text NAME=\"name\" SIZE=30 VALUE=\""
274         << the.managers->name << "\"></TD></TR>"
275         "<TR><TH ALIGN=LEFT>Host IP address</TH>"
276         "<TD><INPUT TYPE=text NAME=\"ipaddr\" SIZE=16 VALUE=\""
277         << the.managers->IPaddr << "\"</TD></TR>"
278         "<TR><TH ALIGN=LEFT>Administrator rights</TH>"
279         "<TD><INPUT TYPE=CHECKBOX NAME=\"miniadmin\" VALUE=\"on\""
280         << ((the.managers->flags & Manager::isMinAdmin)
281             ? "CHECKED" : "") << "></TD></TR></TABLE>"
282         "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Update\">&nbsp;"
283         "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\"></FORM><P>"
284         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
285         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
286         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editHistoryForm\">"
287         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << con.get("manager") <<
288         "\"><SELECT NAME=\"messageId\" SIZE=15>";
289     the.managerForm = true;
290     if (the.managers->messages.length() != 0) {
291         print(con, the.managers->messages);
292         con << TAG <<
293             "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\"></FORM>";
294     } else {
295         con << TAG << EMPTY_LIST "</FORM>";
296     }
297     mainMenuReference(con);
298     return true;
299 }
300 
editClientForm(WWWconnection & con)301 bool editClientForm(WWWconnection& con)
302 {
303     if (con.get("new")) {
304         return addClientForm(con);
305     }
306     ThreadContext& the = ThreadContext::of(con);
307     char* client = con.get("client");
308     if (client == NULL) {
309         return error(con, "No client was selected");
310     }
311     the.clientId = atoi(client);
312     if (the.clients.select(the.qClient) == 0) {
313         return error(con, "No such client");
314     }
315     the.name = con.get("manager");
316     if (the.managers.select(the.qManager) == 0) {
317         return error(con, "No such manager");
318     }
319     con << TAG <<
320         HTML_HEAD "<TITLE>Edit client form</TITLE></HEAD>"
321         BODY
322         "<H2>Update client</H2>"
323         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
324         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
325         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editClient\">"
326         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << the.name << "\">"
327         "<INPUT TYPE=hidden NAME=\"client\" VALUE=" << client << "\">"
328         "<TABLE>"
329         "<TR><TH ALIGN=LEFT>Organization</TH>"
330         "<TD><INPUT TYPE=text NAME=\"organization\" SIZE=40 VALUE=\""
331         << the.clients->organization << "\"></TD></TR>"
332         "<TR><TH ALIGN=LEFT>Phone</TH>"
333         "<TD><INPUT TYPE=text NAME=\"phone\" SIZE=20 VALUE=\""
334         << the.clients->phone << "\"></TD></TR>"
335         "<TR><TH ALIGN=LEFT>Phone2</TH>"
336         "<TD><INPUT TYPE=text NAME=\"phone2\" SIZE=20 VALUE=\""
337         << the.clients->phone2 << "\"></TD></TR>"
338         "<TR><TH ALIGN=LEFT>Fax</TH>"
339         "<TD><INPUT TYPE=text NAME=\"fax\" SIZE=20 VALUE=\""
340         << the.clients->fax << "\"></TD></TR>"
341         "<TR><TH ALIGN=LEFT>E-Mail</TH>"
342         "<TD><INPUT TYPE=text NAME=\"email\" SIZE=30 VALUE=\""
343         << the.clients->email << "\"></TD></TR>"
344         "<TR><TH ALIGN=LEFT>WWW address</TH>"
345         "<TD><INPUT TYPE=text NAME=\"www\" SIZE=30 VALUE=\""
346         << the.clients->www << "\"></TD></TR>"
347         "<TR><TH ALIGN=LEFT>Person</TH>"
348         "<TD><INPUT TYPE=text NAME=\"person\" SIZE=40 VALUE=\""
349         << the.clients->person << "\"></TD></TR>"
350         "<TR><TH ALIGN=LEFT>Person2</TH>"
351         "<TD><INPUT TYPE=text NAME=\"person2\" SIZE=40 VALUE=\""
352         << the.clients->person2 << "\"></TD></TR>"
353         "<TR><TH ALIGN=LEFT>CEO</TH>"
354         "<TD><INPUT TYPE=text NAME=\"lpr\" SIZE=40 VALUE=\""
355         << the.clients->lpr << "\"></TD></TR>"
356         "<TR><TH ALIGN=LEFT>Address</TH>"
357         "<TD><INPUT TYPE=text NAME=\"addr\" SIZE=40 VALUE=\""
358         << the.clients->addr << "\"></TD></TR>"
359         "<TR><TH ALIGN=LEFT>Information</TH>"
360         "<TD><INPUT TYPE=text NAME=\"info\" SIZE=40 VALUE=\""
361         << the.clients->info << "\"></TD></TR>"
362         "<TR><TH ALIGN=LEFT>Status</TH>"
363         "<TD><INPUT TYPE=text NAME=\"status\" SIZE=40 VALUE=\""
364         << the.clients->status << "\"></TD></TR></TABLE><P>";
365     if (the.managers->flags & (Manager::isAdministrator|Manager::isMinAdmin)) {
366         con << TAG
367             << "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Update\">&nbsp;";
368     }
369     if (the.managers->flags & Manager::isAdministrator) {
370         con << TAG << "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
371     }
372     con << TAG << "</FORM><P>"
373         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
374         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
375         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editHistoryForm\">"
376         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << the.name << "\">"
377         "<INPUT TYPE=hidden NAME=\"client\" VALUE=" << client << "\">"
378         "<SELECT SIZE=10 NAME=\"messageId\">";
379     the.managerForm = false;
380     the.messagesArray = &the.clients->history;
381     if (the.messages.select(the.qMessages) != 0) {
382         print(con, the.messages);
383         con << TAG <<
384             "</SELECT><BR><INPUT TYPE=submit VALUE=\"Select\">&nbsp;";
385     } else {
386         con << TAG << EMPTY_LIST;
387     }
388     con << TAG <<
389         "<INPUT TYPE=submit NAME=\"new\" VALUE=\"New message\"></FORM>";
390     mainMenuReference(con);
391     return true;
392 }
393 
394 
editSegmentForm(WWWconnection & con)395 bool editSegmentForm(WWWconnection& con)
396 {
397     if (con.get("new")) {
398         return addSegmentForm(con);
399     }
400     ThreadContext& the = ThreadContext::of(con);
401     the.name = con.get("name");
402     if (the.name == NULL) {
403         return error(con, "No segment was selected");
404     }
405     if (the.segments.select(the.qSegment) == 0) {
406         return error(con, "No such segment");
407     }
408     char* manager = con.get("manager");
409 
410     con << TAG <<
411         HTML_HEAD "<TITLE>Edit segment</TITLE></HEAD>"
412         BODY
413         "<H2>Update segment</H2>"
414         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
415         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
416         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editSegment\">"
417         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << manager << "\">"
418         "<INPUT TYPE=hidden NAME=\"oldName\" VALUE=\"" << the.name << "\">"
419         "<TABLE><TR><TH ALIGN=LEFT>Segment name </TH>"
420         "<TD><INPUT TYPE=text NAME=\"name\" SIZE=30 VALUE=\""
421         << the.segments->name << "\"></TD></TR>"
422         "</TD></TR></TABLE><P>"
423         "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Update\">&nbsp;"
424         "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\"></FORM><P>"
425 
426         "<H2>Select manager</H2>"
427         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
428         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
429         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editManagerForm\">"
430         "<INPUT TYPE=hidden NAME=\"segment\" VALUE=\"" << the.name << "\">"
431         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << manager << "\">"
432         "<SELECT NAME=\"name\" SIZE=10>";
433     the.managersArray = &the.segments->managers;
434     if (the.managers.select(the.qManagers) != 0) {
435         print(con, the.managers);
436         con << TAG <<
437             "</SELECT><BR><INPUT TYPE=submit VALUE=\"Select\">&nbsp;";
438     } else {
439         con << TAG << EMPTY_LIST;
440     }
441     con << TAG << "<INPUT TYPE=submit NAME=\"new\" VALUE=\"New\"></FORM><P>"
442         "<H2>Select client</H2>"
443         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
444         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
445         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editClientForm\">"
446         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << manager << "\">"
447         "<INPUT TYPE=hidden NAME=\"segment\" VALUE=\"" << the.name << "\">"
448         "<SELECT NAME=\"client\" SIZE=10>";
449     the.clientsArray = &the.segments->clients;
450     if (the.clients.select(the.qClients) != 0) {
451         print(con, the.clients);
452         con << TAG <<
453             "</SELECT><BR><INPUT TYPE=submit VALUE=\"Select\">&nbsp;";
454     } else {
455         con << TAG << EMPTY_LIST;
456     }
457     con << TAG << "<INPUT TYPE=submit NAME=\"new\" VALUE=\"New\"></FORM>";
458 
459     mainMenuReference(con);
460     return true;
461 }
462 
463 
editHistoryForm(WWWconnection & con)464 bool editHistoryForm(WWWconnection& con)
465 {
466     if (con.get("new")) {
467         return addHistoryForm(con);
468     }
469     ThreadContext& the = ThreadContext::of(con);
470     char buf[64];
471     char* messageId = con.get("messageId");
472     if (messageId == NULL) {
473         return error(con, "No message was selected");
474     }
475     the.messageId = atoi(messageId);
476     if (the.messages.select(the.qMessage) == 0) {
477         return error(con, "No such message");
478     }
479     the.name = con.get("manager");
480     the.clients.at(the.messages->client);
481     if (the.messages->manager != null) {
482         the.managers.at(the.messages->manager);
483     }
484     con << TAG <<
485         HTML_HEAD "<TITLE>Edit message</TITLE></HEAD>"
486         BODY
487         "<H2>Edit message</H2>"
488         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
489         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
490         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editHistory\">"
491         "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << the.name << "\">"
492         "<INPUT TYPE=hidden NAME=\"messageId\" VALUE=" << messageId << "\">"
493         "<TABLE><TR><TH ALIGN=LEFT>Client</TH>"
494         "<TD><A HREF=\"" << con.getStub() << "?socket=" << con.getAddress()
495         << "&page=editClientForm&manager=" << URL << the.name
496         << "&client=" << the.clients->clientId << "\">"
497         << the.clients->organization << "</A></TD></TR>";
498     if (the.messages->manager != null) {
499         con << TAG <<
500             "<TR><TH ALIGN=LEFT>Manager</TH><TD><A HREF=\""
501             << con.getStub() << "?socket=" << con.getAddress()
502             << "&page=editManagerForm&manager=" << URL << the.name
503             << "&name=" << URL << the.managers->name << "\">"
504             << the.managers->name << "</A></TD></TR>";
505     }
506     con << TAG <<
507         "<TR><TH ALIGN=LEFT>Date</TH>"
508         "<TD><INPUT TYPE=text SIZE=30 VALUE=\""
509         << the.messages->date.asString(buf, sizeof buf) << "\"></TD></TR>"
510         "</TABLE><P>"
511         "<TEXTAREA NAME=\"message\" ROWS=10 COLS=60>"
512         << the.messages->message << "</TEXTAREA><P>";
513     if (the.managers.select(the.qManager) == 0) {
514         return error(con, "No such manager");
515     }
516     if ((the.managers->flags & (Manager::isAdministrator|Manager::isMinAdmin))
517         || the.managers.currentId() == the.messages->manager)
518     {
519         con << TAG
520             << "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Update\">&nbsp;"
521                "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
522     }
523     con << TAG << "</FORM>";
524     mainMenuReference(con);
525     return true;
526 }
527 
528 
managerForm(WWWconnection & con)529 bool managerForm(WWWconnection& con)
530 {
531     ThreadContext& the = ThreadContext::of(con);
532     the.name = con.get("manager");
533     if (the.managers.select(the.qManager) == 0) {
534         return error(con, "No such manager");
535     }
536     if (the.managers->flags & Manager::isAdministrator) {
537         con << TAG <<
538             HTML_HEAD "<TITLE>Administrator menu</TITLE></HEAD>"
539             BODY
540             "<H2>Administrator menu</H2>"
541             "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
542             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""<< con.getAddress() <<
543             "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editManager\">"
544             "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << the.name << "\">"
545             "<INPUT TYPE=hidden NAME=\"oldName\" VALUE=\"" << the.name << "\">"
546             "<TABLE><TR><TH ALIGN=LEFT>Manager name</TH>"
547             "<TD><INPUT TYPE=text NAME=\"name\" SIZE=30 VALUE=\""
548             << the.managers->name << "\"></TD></TR>"
549             "<TR><TH ALIGN=LEFT>Manager host IP address</TH>"
550             "<TD><INPUT TYPE=text NAME=\"ipaddr\" SIZE=16 VALUE=\""
551             << the.managers->IPaddr << "\"</TD></TR></TABLE>"
552             "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Change\"></FORM><P>"
553             "<H2>Select segment</H2>"
554             "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
555             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""<< con.getAddress() <<
556             "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editSegmentForm\">"
557             "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << the.name << "\">"
558             "<SELECT SIZE=15 NAME=\"name\">";
559         if (the.segments.select() != 0) {
560             print(con, the.segments);
561             con << TAG <<
562                 "</SELECT><BR><INPUT TYPE=submit VALUE=\"Select\">&nbsp;";
563         } else {
564             con << TAG << EMPTY_LIST;
565         }
566         con << TAG <<
567             "<INPUT TYPE=submit NAME=\"new\" VALUE=\"New segment\"></FORM>"
568             "<P><HR>"
569             "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
570             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""<< con.getAddress() <<
571             "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"shutdown\">"
572             "<CENTER><INPUT TYPE=submit VALUE=\"Shutdown server\"></CENTER>"
573             "</FORM>";
574     } else {
575         con << TAG <<
576             HTML_HEAD "<TITLE>Manager menu</TITLE></HEAD>"
577             BODY
578             "<H2>Manager menu</H2>"
579             "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
580             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""<< con.getAddress() <<
581             "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editManager\">"
582             "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << the.name << "\">"
583             "<INPUT TYPE=hidden NAME=\"oldName\" VALUE=\"" << the.name << "\">";
584         if (the.managers->flags & Manager::isMinAdmin) {
585             con << TAG <<"<INPUT TYPE=hidden NAME=\"miniadmin\" VALUE=\"on\">";
586         }
587         the.segments.at(the.managers->segment);
588         con << TAG <<
589             "<TABLE><TR><TH ALIGN=LEFT>Manager name</TH>"
590             "<TD><INPUT TYPE=text NAME=\"name\" SIZE=30 VALUE=\""
591             << the.managers->name << "\"></TD></TR>"
592             "<TR><TH ALIGN=LEFT>Manager host IP address</TH>"
593             "<TD><INPUT TYPE=text NAME=\"ipaddr\" SIZE=16 VALUE=\""
594             << the.managers->IPaddr << "\"</TD></TR></TABLE>"
595             "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Change\"></FORM><P>"
596             "<H2>Select client</H2>"
597             "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
598             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""<< con.getAddress() <<
599             "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"editClientForm\">"
600             "<INPUT TYPE=hidden NAME=\"manager\" VALUE=\"" << the.name << "\">"
601             "<INPUT TYPE=hidden NAME=\"segment\" VALUE=\""
602             << the.segments->name << "\">"
603             "<SELECT SIZE=15 NAME=\"client\">";
604         the.clientsArray = &the.segments->clients;
605         if (the.clients.select(the.qClients) != 0) {
606             print(con, the.clients);
607             con << TAG <<
608                 "</SELECT><BR><INPUT TYPE=submit VALUE=\"Select\">&nbsp;";
609         } else {
610             con << TAG << EMPTY_LIST;
611         }
612         con << TAG << "<INPUT TYPE=submit NAME=\"new\" VALUE=\"New\"></FORM>";
613     }
614     con << TAG << "</BODY></HTML>";
615     return true;
616 }
617 
618 
login(WWWconnection & con)619 bool login(WWWconnection& con)
620 {
621     ThreadContext& the = ThreadContext::of(con);
622     the.name = con.get("name");
623     if (the.managers.select(the.qManager) == 0) {
624         return error(con, "No such manager");
625     }
626     if (!Manager::loginFromAnyHost
627         && strcmp(the.managers->IPaddr, "*") != 0
628         && strcmp(the.managers->IPaddr, con.getPeer()) != 0)
629     {
630         return error(con, "You can not login from this host");
631     }
632     con.addPair("manager", the.name);
633     return managerForm(con);
634 }
635 
shutdown(WWWconnection & con)636 bool shutdown(WWWconnection& con)
637 {
638     con << TAG <<
639         HTML_HEAD "<TITLE>ClientDB message</TITLE></HEAD><BODY>"
640         "<H1>ClientDB server is terminated</H1></BODY></HTML>";
641     return false;
642 }
643 
addManager(WWWconnection & con)644 bool addManager(WWWconnection& con)
645 {
646     ThreadContext& the = ThreadContext::of(con);
647     Manager manager;
648     the.name = con.get("segment");
649     if (the.segments.select(the.qSegment, dbCursorForUpdate) == 0) {
650         return error(con, "No such segment");
651     }
652     the.name = con.get("name");
653     if (the.managers.select(the.qManager) != 0) {
654         return error(con, "Manager with such name already exists");
655     }
656     manager.name = con.get("name");
657     manager.IPaddr = con.get("ipaddr");
658     manager.flags = con.get("miniadmin") ? Manager::isMinAdmin : 0;
659     manager.segment = the.segments.currentId();
660     insert(manager);
661     return managerForm(con);
662 }
663 
addClient(WWWconnection & con)664 bool addClient(WWWconnection& con)
665 {
666     ThreadContext& the = ThreadContext::of(con);
667     Client client;
668     the.sequencer.select(dbCursorForUpdate);
669     the.name = con.get("segment");
670     if (the.segments.select(the.qSegment) == 0) {
671         return error(con, "No such segment");
672     }
673     client.organization = con.get("organization");
674     client.phone = con.get("phone");
675     client.phone2 = con.get("phone2");
676     client.fax = con.get("fax");
677     client.email = con.get("email");
678     client.www = con.get("www");
679     client.person = con.get("person");
680     client.person2 = con.get("person2");
681     client.lpr = con.get("lpr");
682     client.addr = con.get("addr");
683     client.info = con.get("info");
684     client.status = con.get("status");
685     client.clientId = ++the.sequencer->lastClientId;
686     client.segment = the.segments.currentId();
687     the.sequencer.update();
688     insert(client);
689     return managerForm(con);
690 }
691 
addSegment(WWWconnection & con)692 bool addSegment(WWWconnection& con)
693 {
694     ThreadContext& the = ThreadContext::of(con);
695     Segment segment;
696     segment.name = the.name = con.get("name");
697     if (the.segments.select(the.qSegment, dbCursorForUpdate) != 0) {
698         return error(con, "Segment with such name already exists");
699     }
700     insert(segment);
701     return managerForm(con);
702 }
703 
addHistory(WWWconnection & con)704 bool addHistory(WWWconnection& con)
705 {
706     ThreadContext& the = ThreadContext::of(con);
707     the.sequencer.select(dbCursorForUpdate);
708     the.clientId = atoi(con.get("client"));
709     if (the.clients.select(the.qClient) == 0) {
710         error(con, "No such client");
711         return true;
712     }
713     History his;
714     his.messageId = ++the.sequencer->lastMessageId;
715     his.message = con.get("message");
716     his.client = the.clients.currentId();
717     the.name = con.get("manager");
718     if (the.managers.select(the.qManager) == 0) {
719         error(con, "No such manger");
720         return true;
721     }
722     his.manager = the.managers.currentId();
723     his.date = dbDateTime::current();
724     insert(his);
725     the.sequencer.update();
726     return managerForm(con);
727 }
728 
editManager(WWWconnection & con)729 bool editManager(WWWconnection& con)
730 {
731     ThreadContext& the = ThreadContext::of(con);
732     the.name = con.get("oldName");
733     if (the.managers.select(the.qManager, dbCursorForUpdate) == 0) {
734         error(con, "No such manager");
735         return true;
736     }
737     if (strcmp(con.get("action"), "Remove") == 0) {
738         the.managers.remove();
739         return managerForm(con);
740     }
741     the.managers->name = con.get("name");
742     the.managers->IPaddr = con.get("ipaddr");
743     if (con.get("miniadmin")) {
744         the.managers->flags |= Manager::isMinAdmin;
745     } else {
746         the.managers->flags &= ~Manager::isMinAdmin;
747     }
748     the.managers.update();
749     return managerForm(con);
750 }
751 
editClient(WWWconnection & con)752 bool editClient(WWWconnection& con)
753 {
754     ThreadContext& the = ThreadContext::of(con);
755     the.clientId = atoi(con.get("client"));
756     if (the.clients.select(the.qClient, dbCursorForUpdate) == 0) {
757         error(con, "No such client");
758         return true;
759     }
760     if (strcmp(con.get("action"), "Remove") == 0) {
761         the.clients.remove();
762     } else {
763         the.clients->organization = con.get("organization");
764         the.clients->phone = con.get("phone");
765         the.clients->phone2 = con.get("phone2");
766         the.clients->fax = con.get("fax");
767         the.clients->email = con.get("email");
768         the.clients->www = con.get("www");
769         the.clients->person = con.get("person");
770         the.clients->person2 = con.get("person2");
771         the.clients->lpr = con.get("lpr");
772         the.clients->addr = con.get("addr");
773         the.clients->info = con.get("info");
774         the.clients->status = con.get("status");
775         the.clients.update();
776     }
777     return managerForm(con);
778 }
779 
editSegment(WWWconnection & con)780 bool editSegment(WWWconnection& con)
781 {
782     ThreadContext& the = ThreadContext::of(con);
783     the.name = con.get("oldName");
784     if (the.segments.select(the.qSegment, dbCursorForUpdate) == 0) {
785         error(con, "No such segment");
786         return true;
787     }
788     if (strcmp(con.get("action"), "Remove") == 0) {
789         the.segments.remove();
790     } else {
791         the.segments->name = con.get("name");
792         the.segments.update();
793     }
794     return managerForm(con);
795 }
796 
editHistory(WWWconnection & con)797 bool editHistory(WWWconnection& con)
798 {
799     ThreadContext& the = ThreadContext::of(con);
800     the.messageId = atoi(con.get("messageId"));
801     if (the.messages.select(the.qMessage, dbCursorForUpdate) == 0) {
802         error(con, "No such message");
803         return true;
804     }
805     if (strcmp(con.get("action"), "Remove") == 0) {
806         the.messages.remove();
807     } else {
808         the.messages->message = con.get("message");
809         the.messages.update();
810     }
811     return managerForm(con);
812 }
813 
814 
815 WWWapi::dispatcher dispatchTable[] = {
816     {"addManagerForm", addManagerForm},
817     {"addClientForm", addClientForm},
818     {"addSegmentForm", addSegmentForm},
819     {"addHistoryForm", addHistoryForm},
820     {"editManagerForm", editManagerForm},
821     {"editClientForm", editClientForm},
822     {"editSegmentForm", editSegmentForm},
823     {"editHistoryForm", editHistoryForm},
824     {"managerForm", managerForm},
825     {"login", login},
826     {"shutdown", shutdown},
827     {"addManager", addManager},
828     {"addClient", addClient},
829     {"addSegment", addSegment},
830     {"addHistory", addHistory},
831     {"editManager", editManager},
832     {"editClient", editClient},
833     {"editSegment", editSegment},
834     {"editHistory", editHistory}
835 };
836 
837 #ifdef USE_EXTERNAL_HTTP_SERVER
838 CGIapi wwwServer(db, itemsof(dispatchTable), dispatchTable);
839 char* defaultAddress = "localhost:6101";
840 socket_t::socket_domain domain = socket_t::sock_local_domain;
841 #else
842 #ifdef USE_QUEUE_MANAGER
843 HTTPapi wwwServer(db, itemsof(dispatchTable), dispatchTable, true);
844 #else
845 HTTPapi wwwServer(db, itemsof(dispatchTable), dispatchTable, false);
846 #endif
847 char* defaultAddress = "localhost:80";
848 socket_t::socket_domain domain = socket_t::sock_global_domain;
849 #endif
850 
main(int argc,char * argv[])851 int main(int argc, char* argv[])
852 {
853     char* address = (argc > 1) ? argv[1] : defaultAddress;
854     if (!wwwServer.open(address, domain)) {
855         fprintf(stderr, "Failed to open WWW session\n");
856         return EXIT_FAILURE;
857     }
858     if (!db.open(_T("clidb"))) {
859         fprintf(stderr, "Failed to open database\n");
860         return EXIT_FAILURE;
861     }
862     dbCursor<Sequencer> sequencer;
863     if (sequencer.select() == 0) {
864         Sequencer seq;
865         seq.lastClientId = 0;
866         seq.lastMessageId = 0;
867         insert(seq);
868 
869         Manager administrator;
870         administrator.name = "administrator";
871         administrator.IPaddr = "*";
872         administrator.flags = Manager::isAdministrator;
873         insert(administrator);
874     }
875     db.commit();
876     if (argc > 2 && strcmp(argv[2], "login_from_any_host") == 0) {
877         Manager::loginFromAnyHost = true;
878     }
879 #ifdef USE_QUEUE_MANAGER
880     QueueManager qmgr(wwwServer, db);
881     qmgr.start();
882 #else
883     WWWconnection con;
884     while (wwwServer.connect(con) && wwwServer.serve(con));
885 #endif
886     db.close();
887     printf("End of session\n");
888     return EXIT_SUCCESS;
889 }
890