1 //-< BUGDB.CPP  >----------------------------------------------------*--------*
2 // FastDB                    Version 1.0         (c) 1999  GARRET    *     ?  *
3 // (Main Memory Database Management System)                          *   /\|  *
4 //                                                                   *  /  \  *
5 //                          Created:     27-Mar-99    K.A. Knizhnik  * / [] \ *
6 //                          Last update: 30-Jun-99    K.A. Knizhnik  * GARRET *
7 //-------------------------------------------------------------------*--------*
8 // Example of database Web publishing: Bug Tracking Database
9 //-------------------------------------------------------------------*--------*
10 
11 #include "bugdb.h"
12 
13 //#define USE_EXTERNAL_HTTP_SERVER 1
14 
15 char const* const eCATEGORY_STRING[] =
16 {
17     "",
18     "CRASH",
19     "PROGRAM_HANGS",
20     "UI_DISPLAY",
21     "UI_BEHAVIOR",
22     "CALCULATION",
23     "ERROR_HANDLING",
24     "PERFORMANCE",
25     "LICENSING",
26     "INSTALLATION",
27     "DOCUMENTATION",
28     "ENHANCEMENT",
29     "HOW_TO_QUESTION",
30     NULL
31 };
32 
33 char const* const eSTATUS_STRING[] = {
34     "",
35     "OPENED",
36     "FIXED",
37     "CLOSED",
38     "PENDING_ENGINEER",
39     "PENDING_USER",
40     "POSTPONED",
41     "IRREPRODUCIBLE",
42     "WITHDRAWN",
43     "AS_DESIGNED",
44     NULL
45 };
46 
47 char const* const eSEVERITY_STRING[] = {
48     "",
49     "FATAL",
50     "SERIOUS",
51     "MINOR",
52     NULL
53 };
54 
55 char const* const eFIXING_PRIORITY_STRING[] = {
56     "",
57     "FIX_IMMEDIATELY",
58     "FIX_BEFORE_NEXT_BUILD_RELEASE",
59     "FIX_BEFORE_NEXT_MINOR_RELEASE",
60     "FIX_BEFORE_NEXT_MAJOR_RELEASE",
61     "FIX_IF_POSSIBLE",
62     "OPTIONAL",
63     NULL
64 };
65 
66 dbDatabase db;
67 
68 dbCursor<Bug>          allBugs;
69 dbCursor<Bug>          bugs(dbCursorForUpdate);
70 dbCursor<Report>       reports(dbCursorForUpdate);
71 dbCursor<Person>       persons(dbCursorForUpdate);
72 dbCursor<Software>     products(dbCursorForUpdate);
73 dbCursor<Version>      versions(dbCursorForUpdate);
74 dbCursor<BugSequencer> sequencer(dbCursorForUpdate);
75 
76 dbQuery qBug;
77 dbQuery qReport;
78 dbQuery qAllReports;
79 dbQuery qVersion;
80 dbQuery qAllVersions;
81 dbQuery qPerson;
82 dbQuery qSoftware;
83 
84 //
85 // Query paramters
86 //
87 char* key;
88 int   bugId;
89 int   reportId;
90 dbReference<Report>  firstReport;
91 dbReference<Version> initialVersion;
92 int   majorVersion;
93 int   minorVersion;
94 
95 
96 //- Person ------------------------------------------------
97 
print(WWWconnection & con) const98 void Person::print(WWWconnection& con) const
99 {
100     con << TAG << "<OPTION VALUE=\"" << sName << "\">" << sName << "</OPTION>";
101 }
102 
103 REGISTER(Person);
104 
105 //------- Version ---------------------------------------
106 
print(WWWconnection & con) const107 void Version::print(WWWconnection& con) const
108 {
109     char buf[64];
110     con << TAG << "<OPTION VALUE=\"" << getVersionString() <<
111         "\">Version " << getVersionString() << " " << sLabel <<
112         " " << released.asString(buf, sizeof buf) << "</OPTION>";
113 }
114 
getVersion() const115 int Version::getVersion() const
116 {
117     return majorVersionNumber*100 + minorVersionNumber;
118 }
119 
getVersionString() const120 char* Version::getVersionString() const
121 {
122     static char buf[16];
123     sprintf(buf, "%d.%02d", majorVersionNumber, minorVersionNumber);
124     return buf;
125 }
126 
127 REGISTER(Version);
128 
129 //----- Software -------------------------------------
130 
getLastVersion() const131 int Software::getLastVersion() const
132 {
133     if (pVersions == null) {
134         return 0;
135     }
136     versions.at(pVersions);
137     return versions->getVersion();
138 }
139 
getLastVersionString() const140 char* Software::getLastVersionString() const
141 {
142     if (pVersions == null) {
143         return "";
144     }
145     versions.at(pVersions);
146     return versions->getVersionString();
147 }
148 
print(WWWconnection & con) const149 void Software::print(WWWconnection& con) const
150 {
151     con << TAG << "<OPTION VALUE=\"" << sName << "\">" << sName << "</OPTION>";
152 }
153 
154 REGISTER(Software);
155 
156 //----- Report -------------------------------------------
157 
print(WWWconnection & con) const158 void Report::print(WWWconnection& con) const
159 {
160     char buf[64];
161     if (pAuthor != null) {
162         persons.at(pAuthor);
163         con << TAG << "<OPTION VALUE=" << index << ">" << persons->sName << " "
164             << creationDate.asString(buf, sizeof buf) << "</OPTION>";
165     } else {
166         con << TAG << "<OPTION VALUE=" << index << ">" << "Report from "
167             << creationDate.asString(buf, sizeof buf) << "</OPTION>";
168     }
169 }
170 
171 REGISTER(Report);
172 
173 //--- Bug -----------------------------------------
174 
print(WWWconnection & con) const175 void Bug::print(WWWconnection& con) const
176 {
177     con << TAG << "<OPTION VALUE=" << bugId << ">" << sOneLineSummary
178         << "</OPTION>";
179 }
180 
181 REGISTER(Bug);
182 
183 //---- BugSequencer -------------------------------------
184 
185 REGISTER(BugSequencer);
186 
187 template<class T>
print(WWWconnection & con,dbCursor<T> & cursor)188 void print(WWWconnection& con, dbCursor<T>& cursor) {
189     do {
190         cursor->print(con);
191     } while(cursor.next());
192 }
193 
194 template<class T>
print(WWWconnection & con,dbArray<dbReference<T>> const & arr)195 void print(WWWconnection& con, dbArray<dbReference<T> > const& arr) {
196     dbCursor<T> cursor;
197     for (int i = 0, n = (int)arr.length(); i < n; i++) {
198         cursor.at(arr[i])->print(con);
199     }
200 }
201 
202 //--- HTML specific part -------------------------------------------
203 
204 #define HTML_HEAD "Content-type: text/html\r\n\r\n\
205 <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\"><HTML><HEAD>"
206 
207 #define BODY "<BODY BGCOLOR=\"#c0c0c0\">"
208 
209 #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>"
210 
mainMenuReference(WWWconnection & con)211 void mainMenuReference(WWWconnection& con)
212 {
213     char* myself = con.get("myself");
214     if (myself != NULL) {
215         con << TAG
216             << "<P><HR><CENTER><A HREF=\"" << con.getStub() << "?socket="
217             << con.getAddress() << "&page=userForm&myself="
218             << URL << myself <<  "&name=" << URL << myself
219             << "\">Back to main menu</A></CENTER>";
220     }
221     con << TAG << "</BODY></HTML>";
222 }
223 
error(WWWconnection & con,char const * msg)224 void error(WWWconnection& con, char const* msg)
225 {
226     con << TAG <<
227         HTML_HEAD "<TITLE>BUGDB error</TITLE></HEAD><BODY>"
228         "<H1><FONT COLOR=\"#FF0000\">"
229         << msg << "</FONT></H1></BODY></HTML>";
230     mainMenuReference(con);
231 }
232 
233 
message(WWWconnection & con,char const * msg)234 void message(WWWconnection& con, char const* msg)
235 {
236     con << TAG <<
237         HTML_HEAD "<TITLE>BUGDB message</TITLE></HEAD><BODY>"
238         "<H1><FONT COLOR=\"#004000\">"
239         << msg << "</FONT></H1></BODY></HTML>";
240     mainMenuReference(con);
241 }
242 
243 
addUserForm(WWWconnection & con)244 bool addUserForm(WWWconnection& con)
245 {
246     con << TAG <<
247         HTML_HEAD "<TITLE>Enter new user</TITLE></HEAD>"
248         BODY
249         "<H2>Add user</H2>"
250         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
251         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
252         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"addUser\">"
253         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
254         "\"><TABLE>"
255         "<TR><TH ALIGN=LEFT>User name:</TH>"
256         "<TD><INPUT TYPE=text NAME=\"name\" SIZE=30</TD></TR>"
257         "<TR><TH ALIGN=LEFT>E-mail:</TH>"
258         "<TD><INPUT TYPE=text NAME=\"email\" SIZE=30 </TD></TR></TABLE><P>"
259         "<INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
260         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
261     mainMenuReference(con);
262     return true;
263 }
264 
addEngineerForm(WWWconnection & con)265 bool addEngineerForm(WWWconnection& con)
266 {
267     con << TAG <<
268         HTML_HEAD "<TITLE>Enter new engineer</TITLE></HEAD>"
269         BODY
270         "<H2>Add engineer</H2>"
271         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
272         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
273         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"addEngineer\">"
274         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
275         "\"><TABLE>"
276         "<TR><TH ALIGN=LEFT>Engineer name:</TH>"
277         "<TD><INPUT TYPE=text NAME=\"name\" SIZE=30</TD></TR>"
278         "<TR><TH ALIGN=LEFT>E-mail:</TH>"
279         "<TD><INPUT TYPE=text NAME=\"email\" SIZE=30 </TD></TR></TABLE><P>"
280         "<INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
281         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
282     mainMenuReference(con);
283     return true;
284 }
285 
addSoftwareForm(WWWconnection & con)286 bool addSoftwareForm(WWWconnection& con)
287 {
288     con << TAG <<
289         HTML_HEAD "<TITLE>Enter new software product</TITLE></HEAD>"
290         BODY
291         "<H2>Add software product</H2>"
292         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
293         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
294         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"addSoftware\">"
295         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
296         "\"><TABLE>"
297         "<TR><TH ALIGN=LEFT>Software name:</TH>"
298         "<TD><INPUT TYPE=text NAME=\"software\" SIZE=40</TD></TR>"
299         "<TR><TH ALIGN=LEFT>Version number:</TH>"
300         "<TD><INPUT TYPE=text NAME=\"version\" SIZE=8</TD></TR>"
301         "<TR><TH ALIGN=LEFT>Version label:</TH>"
302         "<TD><INPUT TYPE=text NAME=\"label\" SIZE=20</TD></TR>"
303         "<TR><TH ALIGN=LEFT>Version comment:</TH>"
304         "<TD><INPUT TYPE=text NAME=\"comment\" SIZE=40</TD></TR>"
305         "</TABLE><P><INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
306         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
307     mainMenuReference(con);
308     return true;
309 }
310 
selectSoftwareForm(WWWconnection & con)311 bool selectSoftwareForm(WWWconnection& con)
312 {
313     con << TAG <<
314         HTML_HEAD "<TITLE>Select software product</TITLE></HEAD>"
315         BODY
316         "<H2>Select software product</H2>"
317         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
318         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
319         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"softwareForm\">"
320         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
321         "\"><SELECT SIZE=15 NAME=\"software\">";
322     if (products.select() > 0) {
323         print(con, products);
324         con << TAG <<
325            "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
326     } else {
327         con << TAG << EMPTY_LIST;
328     }
329     con << TAG << "</FORM>";
330     mainMenuReference(con);
331     return true;
332 }
333 
removeSoftwareForm(WWWconnection & con)334 bool removeSoftwareForm(WWWconnection& con)
335 {
336     con << TAG <<
337         HTML_HEAD "<TITLE>Remove software product</TITLE></HEAD>"
338         BODY
339         "<H2>Remove software product</H2>"
340         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
341         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
342         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"removeSoftware\">"
343         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
344         "\"><SELECT SIZE=15 NAME=\"software\">";
345     if (products.select() != 0) {
346         print(con, products);
347         con << TAG << "</SELECT><BR><INPUT TYPE=\"submit\" VALUE=\"Remove\">";
348     } else {
349         con << TAG << EMPTY_LIST;
350     }
351     con << TAG << "</FORM>";
352     mainMenuReference(con);
353     return true;
354 }
355 
selectPersonForm(WWWconnection & con)356 bool selectPersonForm(WWWconnection& con)
357 {
358     con << TAG <<
359         HTML_HEAD "<TITLE>Select a person</TITLE></HEAD>"
360         BODY
361         "<H2>Select a person</H2>"
362         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
363         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
364         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"userForm\">"
365         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
366         "\"><SELECT SIZE=20 NAME=\"name\">";
367     if (persons.select() != 0) {
368         print(con, persons);
369         con << TAG << "</SELECT><BR><INPUT TYPE=submit VALUE=\"Select\">";
370     } else {
371         con << TAG << EMPTY_LIST;
372     }
373     con << TAG << "</FORM>";
374     mainMenuReference(con);
375     return true;
376 }
377 
removePersonForm(WWWconnection & con)378 bool removePersonForm(WWWconnection& con)
379 {
380     con << TAG <<
381         HTML_HEAD "<TITLE>Remove a person</TITLE></HEAD>"
382         BODY
383         "<H2>Remove a person</H2>"
384         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
385         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
386         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"removePerson\">"
387         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
388         "\"><SELECT SIZE=20 NAME=\"name\">";
389     if (persons.select() != 0) {
390         print(con, persons);
391         con << TAG << "</SELECT><BR><INPUT TYPE=submit VALUE=\"Remove\">";
392     } else {
393         con << TAG << EMPTY_LIST;
394     }
395     con << TAG << "</FORM>";
396     mainMenuReference(con);
397     return true;
398 }
399 
selectBugForm(WWWconnection & con)400 bool selectBugForm(WWWconnection& con)
401 {
402     con << TAG <<
403         HTML_HEAD "<TITLE>Select a bug</TITLE></HEAD>"
404         BODY
405         "<H2>Select a bug</H2>"
406         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
407         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
408         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"bugForm\">"
409         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
410         "\"><SELECT SIZE=15 NAME=\"bug\">";
411     if (bugs.select() != 0) {
412         print(con, bugs);
413         con << TAG <<
414            "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
415     } else {
416         con << TAG << EMPTY_LIST;
417     }
418     con << TAG << "</FORM>";
419     mainMenuReference(con);
420     return true;
421 }
422 
removeBugForm(WWWconnection & con)423 bool removeBugForm(WWWconnection& con)
424 {
425     con << TAG <<
426         HTML_HEAD "<TITLE>Remove a bug</TITLE></HEAD>"
427         BODY
428         "<H2>Remove a bug</H2>"
429         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
430         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
431         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"removeBug\">"
432         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
433         "\"><SELECT SIZE=15 NAME=\"bug\">";
434     if (bugs.select() != 0) {
435         print(con, bugs);
436         con << TAG << "</SELECT><BR><INPUT TYPE=submit VALUE=\"Remove\">";
437     } else {
438         con << TAG << EMPTY_LIST;
439     }
440     con << TAG << "</FORM>";
441     mainMenuReference(con);
442     return true;
443 }
444 
changePasswordForm(WWWconnection & con)445 bool changePasswordForm(WWWconnection& con)
446 {
447     con << TAG <<
448         HTML_HEAD "<TITLE>Change password</TITLE></HEAD>"
449         BODY
450         "<H2>Change password</H2>"
451         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
452         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
453         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"changePassword\">"
454         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
455         "\"><INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << con.get("name") <<
456         "\"><TABLE>"
457         "<TR><TH ALIGN=LEFT>New password:</TH>"
458         "<TD><INPUT TYPE=password NAME=\"password\" SIZE=20</TD></TR>"
459         "<TR><TH ALIGN=LEFT>Re-type password:</TH>"
460         "<TD><INPUT TYPE=password NAME=\"password2\" SIZE=20</TD></TR>"
461         "</TABLE><P>"
462         "<INPUT TYPE=submit VALUE=\"Change\">&nbsp;"
463         "<INPUT TYPE=reset VALUE=\"Reset\">"
464         "</FORM>";
465     con << TAG << "</FORM>";
466     mainMenuReference(con);
467     return true;
468 }
469 
shutdown(WWWconnection & con)470 bool shutdown(WWWconnection& con)
471 {
472     con << TAG <<
473         HTML_HEAD "<TITLE>BUGDB message</TITLE></HEAD><BODY>"
474         "<H1>BUGDB server is terminated</H1></BODY></HTML>";
475     return false;
476 }
477 
478 bool userForm(WWWconnection& con);
479 bool userGroupForm(WWWconnection& con);
480 bool softwareForm(WWWconnection& con);
481 
addUser(WWWconnection & con)482 bool addUser(WWWconnection& con)
483 {
484     Person person;
485     person.sName = key = con.get("name");
486     person.sEmailAddress = con.get("email");
487     person.sPassword = "";
488     person.status = Person::isUser;
489     person.nReports = 0;
490     if (persons.select(qPerson) != 0) {
491         error(con, "Person already exists");
492         return true;
493     }
494     insert(person);
495     return userForm(con);
496 }
497 
addEngineer(WWWconnection & con)498 bool addEngineer(WWWconnection& con)
499 {
500     Person person;
501     person.sName = key = con.get("name");
502     person.sEmailAddress = con.get("email");
503     person.sPassword = "";
504     person.status = Person::isEngineer;
505     person.nReports = 0;
506     if (persons.select(qPerson) != 0) {
507         error(con, "Person already exists");
508         return true;
509     }
510     insert(person);
511     return userForm(con);
512 }
513 
removePerson(WWWconnection & con)514 bool removePerson(WWWconnection& con)
515 {
516     key = con.get("name");
517     if (key == NULL) {
518         error(con, "No person was selected");
519         return true;
520     }
521     if (persons.select(qPerson) == 0) {
522         error(con, "No such person");
523     } else if (persons->nReports > 0
524                || persons->setReportedBugs.length() > 0)
525     {
526         error(con, "It is not possible to delete person who is author "
527               "of existed bug reports");
528     } else {
529         persons.remove();
530         message(con, "Person is removed");
531     }
532     return true;
533 }
534 
addSoftware(WWWconnection & con)535 bool addSoftware(WWWconnection& con)
536 {
537     Software software;
538     Version  version;
539     software.sName = key = con.get("software");
540     if (products.select(qSoftware) != 0) {
541         error(con, "Software product already exists");
542         return true;
543     }
544     char* versionStr = con.get("version");
545     if (sscanf(versionStr, "%d.%d", &version.majorVersionNumber,
546                &version.minorVersionNumber) != 2)
547     {
548         error(con, "Bad version number (MAJOR.MINOR expected)");
549         return true;
550     }
551     version.sComment = con.get("comment");
552     version.sLabel = con.get("label");
553     version.released = dbDateTime::current();
554     software.pVersions = insert(version);
555     insert(software);
556     con.addPair("action", "Select");
557     return softwareForm(con);
558 }
559 
removeSoftware(WWWconnection & con)560 bool removeSoftware(WWWconnection& con)
561 {
562     key = con.get("software");
563     if (products.select(qSoftware) == 0) {
564         error(con, "No such software product");
565         return true;
566     }
567     if (products->setBugs.length() != 0) {
568         error(con, "Can not remove software with non-empty reported bug list");
569         return true;
570     }
571     products.remove();
572     message(con, "Software product is removed");
573     return true;
574 }
575 
removeBug(WWWconnection & con)576 bool removeBug(WWWconnection& con)
577 {
578     char* bug = con.get("bug");
579     if (bug == NULL) {
580         error(con, "No bug was selected");
581     } else {
582         bugId = atoi(bug);
583         if (bugs.select(qBug) == 0) {
584             error(con, "No such bug");
585         } else {
586             if (bugs->pReportHistory != null ||
587                 bugs->pWorkArounds != null)
588             {
589                 error(con, "Can not remove bug with existed reports");
590                 return true;
591             }
592             bugs.remove();
593             message(con, "Bug is removed");
594         }
595     }
596     return true;
597 }
598 
changePassword(WWWconnection & con)599 bool changePassword(WWWconnection& con)
600 {
601     char* password = con.get("password");
602     char* password2 = con.get("password2");
603     if (strcmp(password, password2) != 0) {
604         error(con, "Passwords are not equal");
605     } else {
606         key = con.get("name");
607         if (persons.select(qPerson) == 0) {
608             error(con, "No such person");
609         } else {
610             persons->sPassword = password;
611             persons.update();
612             message(con, "Password changed");
613         }
614     }
615     return true;
616 }
617 
updatePerson(WWWconnection & con)618 bool updatePerson(WWWconnection& con)
619 {
620     char* name = con.get("name");
621     key = name;
622     if (persons.select(qPerson) == 0) {
623         error(con, "No such person");
624         return true;
625     } else {
626         char* newName = con.get("newname");
627         char* eMail = con.get("email");
628         if (eMail != NULL) {
629             persons->sEmailAddress = eMail;
630         }
631         if (newName != NULL) {
632             persons->sName = newName;
633             con.addPair("name", newName);
634             if (strcmp(name, con.get("myself")) == 0) {
635                 con.addPair("myself", newName);
636             }
637         }
638         persons.update();
639     }
640     return userForm(con);
641 }
642 
login(WWWconnection & con)643 bool login(WWWconnection& con)
644 {
645     char* name = con.get("name");
646     key = con.get("name");
647     if (persons.select(qPerson) == 0) {
648         error(con, "No such person");
649         return true;
650     }
651     if (!persons->checkPassword(con.get("password"))) {
652         error(con, "Incorrect password");
653         return true;
654     }
655     con.addPair("myself", name);
656     return userForm(con);
657 }
658 
bugQueryForm(WWWconnection & con)659 bool bugQueryForm(WWWconnection& con)
660 {
661     int i;
662     con << TAG <<
663         HTML_HEAD "<TITLE>Query to locate bug</TITLE></HEAD>"
664         BODY
665         "<H2>Bug query</H2>"
666         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
667         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
668         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"bugQuery\">"
669         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
670         "\"><TABLE>"
671         "<TR><TH ALIGN=LEFT>Description substring:</TH>"
672         "<TD><INPUT TYPE=text NAME=\"summary\" SIZE=30</TD></TR>"
673         "<TR><TH ALIGN=LEFT>Category:</TH>"
674         "<TD><SELECT NAME=\"category\" SIZE=1>"
675         "<OPTION VALUE=0 SELECTED></OPTION>";
676     for (i = 1; eCATEGORY_STRING[i] != NULL; i++) {
677         con << TAG << "<OPTION VALUE=" << i << ">"
678             << eCATEGORY_STRING[i] << "</OPTION>";
679     }
680     con << TAG << "</SELECT></TD></TR>"
681         "<TR><TH ALIGN=LEFT>Severity:</TH>"
682         "<TD><SELECT NAME=\"severity\" SIZE=1>"
683         "<OPTION VALUE=0 SELECTED></OPTION>";
684     for (i = 1; eSEVERITY_STRING[i] != NULL; i++) {
685         con << TAG << "<OPTION VALUE=" << i << ">"
686             << eSEVERITY_STRING[i] << "</OPTION>";
687     }
688     con << TAG << "</SELECT></TD></TR>"
689         "<TR><TH ALIGN=LEFT>Fixing priority:</TH>"
690         "<TD><SELECT NAME=\"priority\" SIZE=1>"
691         "<OPTION VALUE=0 SELECTED></OPTION>";
692     for (i = 1; eFIXING_PRIORITY_STRING[i] != NULL; i++) {
693         con << TAG << "<OPTION VALUE=" << i << ">"
694             << eFIXING_PRIORITY_STRING[i] << "</OPTION>";
695     }
696     con << TAG <<
697         "</SELECT></TD></TR>"
698         "<TR><TH ALIGN=LEFT>Platform:</TH>"
699         "<TD><INPUT TYPE=text NAME=\"platform\"</TD></TR>"
700         "<TR><TH ALIGN=LEFT>OS</TH>"
701         "<TD><INPUT TYPE=text NAME=\"os\"</TD></TR>"
702         "<TR><TH ALIGN=LEFT>Software:</TH>"
703         "<TD><INPUT TYPE=text NAME=\"software\"</TD></TR>"
704         "<TR><TH ALIGN=LEFT>Assigned to:</TH>"
705         "<TD><INPUT TYPE=text NAME=\"engineer\"</TD></TR>"
706         "<TR><TH ALIGN=LEFT>Reported by:</TH>"
707         "<TD><INPUT TYPE=text NAME=\"user\"</TD></TR>"
708         "<TR><TH ALIGN=LEFT>Major version number:</TH>"
709         "<TD>from <INPUT TYPE=text NAME=\"minmajor\" SIZE=4>"
710         " to <INPUT TYPE=text NAME=\"maxmajor\" SIZE=4</TD></TR>"
711         "<TR><TH ALIGN=LEFT>Minor version number:</TH>"
712         "<TD>from <INPUT TYPE=text NAME=\"minminor\" SIZE=4</TD>"
713         " to <INPUT TYPE=text NAME=\"maxminor\" SIZE=4</TD></TR></TABLE><P>"
714         "<INPUT TYPE=submit VALUE=\"Search\">&nbsp;"
715         "<INPUT TYPE=reset VALUE=\"Reset\">"
716         "</FORM></BODY></HTML>";
717     return true;
718 }
719 
720 
bugQuery(WWWconnection & con)721 bool bugQuery(WWWconnection& con)
722 {
723     char* p;
724     dbQuery query;
725     query.reset();
726     p = con.get("software");
727     if (*p != '\0') {
728         query.add("pSoftware.sName like").add(p);
729     }
730     int4 category = atoi(con.get("category"));
731     if (category != 0) {
732         query.And("eCategory=").add(category);
733    }
734     int4 severity = atoi(con.get("severity"));
735     if (severity != 0) {
736         query.And("eSeverity=").add(severity);
737     }
738     int4 priority = atoi(con.get("priority"));
739     if (priority != 0) {
740         query.And("eFixingPriority=").add(priority);
741     }
742     p = con.get("os");
743     if (*p != '\0') {
744         query.And("sOperatingSystem like").add(p);
745     }
746     p = con.get("platform");
747     if (*p != '\0') {
748         query.And("sHardwarePlatform like").add(p);
749     }
750     p = con.get("engineer");
751     if (*p != '\0') {
752         query.And("pAssignedTo is not null and pAssignedTo.sName like").add(p);
753     }
754     p = con.get("user");
755     if (*p != '\0') {
756         query.And("pReportedBy.sName like").add(p);
757     }
758     p = con.get("summary");
759     if (*p != '\0') {
760         query.And("sOneLineSummary like").add(p);
761     }
762     p = con.get("minmajor");
763     int minMajorVersionNumber = (*p == '\0') ? 0 : atoi(p);
764     p = con.get("maxmajor");
765     int maxMajorVersionNumber = (*p == '\0') ? INT_MAX : atoi(p);
766     p = con.get("minminor");
767     int minMinorVersionNumber = (*p == '\0') ? 0 : atoi(p);
768     p = con.get("maxminor");
769     int maxMinorVersionNumber = (*p == '\0') ? INT_MAX : atoi(p);
770     if (minMajorVersionNumber != 0) {
771         if (maxMajorVersionNumber != INT_MAX) {
772             query.And("pVersion.majorVersionNumber between")
773                 .add(minMajorVersionNumber)
774                 .add("and").add(maxMajorVersionNumber);
775         } else {
776             query.And("pVersion.majorVersionNumber>=")
777                 .add(minMajorVersionNumber);
778         }
779     } else if (maxMajorVersionNumber != INT_MAX) {
780         query.And("pVersion.majorVersionNumber<=").add(maxMajorVersionNumber);
781     }
782     if (minMinorVersionNumber != 0) {
783         if (maxMinorVersionNumber != INT_MAX) {
784             query.And("pVersion.minorVersionNumber between")
785                 .add(minMinorVersionNumber)
786                 .add("and").add(maxMinorVersionNumber);
787         } else {
788             query.And("pVersion.minorVersionNumber>=")
789                 .add(minMinorVersionNumber);
790         }
791     } else if (maxMinorVersionNumber != INT_MAX) {
792         query.And("pVersion.minorVersionNumber<=").add(maxMinorVersionNumber);
793     }
794     con << TAG <<
795         HTML_HEAD "<TITLE>List of selected bugs</TITLE></HEAD>"
796         BODY
797         "<H2>Selected bugs</H2>"
798         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
799         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress() <<
800         "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"bugForm\">"
801         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself") <<
802         "\"><SELECT NAME=\"bug\" SIZE=20>";
803     if (bugs.select(query) != 0) {
804         print(con, bugs);
805         con << TAG <<
806            "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
807     } else {
808         con << TAG << EMPTY_LIST;
809     }
810     con << TAG << "</FORM>";
811     mainMenuReference(con);
812     return true;
813 }
814 
815 
userForm(WWWconnection & con)816 bool userForm(WWWconnection& con)
817 {
818     char* name = con.get("name");
819     if (name == NULL) {
820         error(con, "No person was selected");
821         return true;
822     }
823     char* myself = con.get("myself");
824     key = myself;
825     if (persons.select(qPerson) == 0) {
826         error(con, "Person authorization failed");
827         return true;
828     }
829     int selfStatus = persons->status;
830     key = name;
831     if (persons.select(qPerson) == 0) {
832         error(con, "Person not found");
833         return true;
834     }
835     if (persons->status == Person::isAdministrator) {
836         con << TAG <<
837             HTML_HEAD "<TITLE>BUGDB Administrator</TITLE></HEAD>"
838             BODY
839             "<H2>Administrator menu</H2><FONT SIZE=\"+1\">"
840             "<UL><LI><A HREF=\"" << con.getStub() << "?socket="
841             << con.getAddress()
842             << "&page=addUserForm&myself=" << URL << myself
843             << "\">Add user</A>"
844             "<LI><A HREF=\"" << con.getStub() << "?socket=" << con.getAddress()
845             << "&page=addEngineerForm&myself=" << URL << myself
846             << "\">Add engineer</A>"
847             "<LI><A HREF=\"" << con.getStub() << "?socket=" << con.getAddress()
848             << "&page=selectPersonForm&myself=" << URL << myself
849             << "\">Select person"
850             "</A>"
851             "<LI><A HREF=\"" << con.getStub() << "?socket=" << con.getAddress()
852             << "&page=removePersonForm&myself=" << URL << myself
853             << "\">Remove person</A></UL>"
854 
855             "<UL><LI><A HREF=\"" << con.getStub() << "?socket="
856             << con.getAddress()
857             << "&page=addSoftwareForm&myself=" << URL << myself
858             << "\">Add software product</A>"
859             "<LI><A HREF=\"" << con.getStub() << "?socket=" << con.getAddress()
860             << "&page=selectSoftwareForm&myself=" << URL << myself
861             << "\">Select software product</A>"
862             "<LI><A HREF=\"" << con.getStub() << "?socket=" << con.getAddress()
863             << "&page=removeSoftwareForm&myself=" << URL << myself
864             << "\">Remove software product</A></UL>"
865 
866             "<UL><LI><A HREF=\"" << con.getStub() << "?socket="
867             << con.getAddress()
868             << "&page=selectBugForm&myself=" << URL << myself
869             << "\">Select bug</A>"
870             "<LI><A HREF=\"" << con.getStub() << "?socket="
871             << con.getAddress()
872             << "&page=removeBugForm&myself=" << URL << myself
873             << "\">Remove bug</A></UL>";
874         if (selfStatus == Person::isAdministrator) {
875             con << TAG <<
876                 "<UL><LI><A HREF=\"" << con.getStub() << "?socket="
877                 << con.getAddress() << "&page=changePasswordForm"
878                 "&myself=administrator&name=" << URL << myself
879                 << "\">Change password</A>"
880                 "<LI><A HREF=\"" << con.getStub() << "?socket="
881                 << con.getAddress()
882                 << "&page=shutdown\">Shutdown server</A></UL>";
883         }
884         con << TAG << "</FONT></BODY></HTML>";
885         return true;
886     }
887     con <<
888         HTML_HEAD "<TITLE>" << name << "</TITLE></HEAD>"
889         BODY
890         "<H2>" << name << "</H2><FONT SIZE=\"+1\">"
891         "<UL><LI><A HREF=\"" << con.getStub() << "?socket="
892         << con.getAddress() << "&page=createBugReportForm&myself="
893         << URL << myself << "\">Create bug report</A>";
894     if (persons->sEmailAddress[0] != '\0') {
895         con << TAG <<
896             "<LI><A HREF=\"mailto:" << persons->sEmailAddress
897             << "\">Send e-mail</A>"
898             "<LI><A HREF=\"" << con.getStub() << "?socket=" << con.getAddress()
899             << "&page=bugQueryForm&myself=" << URL << myself
900             << "\">Find a bug</A>";
901     }
902     if (strcmp(myself, name) == 0 || selfStatus == Person::isAdministrator) {
903         con << TAG << "<LI><A HREF=\"" << con.getStub() << "?socket="
904             << con.getAddress() << "&page=changePasswordForm&myself="
905             << URL << myself << "&name=" << URL << name <<
906             "\">Change password</A>";
907     }
908     con << TAG <<
909         "</UL></FONT><P><TABLE><TR><TH ALIGN=LEFT>Person name:</TH>"
910         "<TD><FORM METHOD=POST ACTION=\""
911         << con.getStub() << "\"><INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
912         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\""
913         "updatePerson\"><INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself
914         << "\"><INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
915         "<INPUT TYPE=text NAME=\"newname\" SIZE=30 VALUE=\""
916         << name << "\"><INPUT TYPE=submit VALUE=\"Change\"></FORM></TD></TR>"
917         "<TR><TH ALIGN=LEFT>E-Mail:</TH>"
918         "<TD><FORM METHOD=POST ACTION=\""
919         << con.getStub() << "\"><INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
920         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\""
921         "updatePerson\"><INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself
922         << "\"><INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
923         "<INPUT TYPE=text NAME=\"email\" SIZE=30 VALUE=\""
924         << persons->sEmailAddress << "\">"
925         "<INPUT TYPE=submit VALUE=\"Change\"></FORM></TD></TR>";
926     if (persons->status != Person::isUser) {
927         con << TAG << "<TR><TH ALIGN=LEFT>Projects:</TH>"
928             "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
929             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
930             << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
931             "VALUE=\"softwareForm\">"
932             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
933             "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
934             "<SELECT NAME=\"software\" SIZE=1>";
935         if (persons->setProjects.length() != 0) {
936             print(con, persons->setProjects);
937             con << TAG <<
938                 "</SELECT><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">"
939                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Detach\">";
940         } else {
941             con << TAG << EMPTY_LIST;
942         }
943         if (products.select() != 0) {
944             con << TAG <<
945                 "</FORM></TD></TR>"
946                 "<TR><TH ALIGN=LEFT>Attach to project:</TH>"
947                 "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
948                 "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
949                 << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
950                 "VALUE=\"attachToProject\">"
951                 "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<"\">"
952                 "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
953                 "<SELECT NAME=\"software\" SIZE=1>";
954             print(con, products);
955             con << TAG << "</SELECT><INPUT TYPE=submit VALUE=\"Attach\">";
956         }
957         con << TAG <<
958             "</FORM></TD></TR>"
959             "<TR><TH ALIGN=LEFT>Find a person:</TH>"
960             "<TD><FORM METHOD=POST ACTION=\""
961             << con.getStub() << "\">"
962             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
963             << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
964             "VALUE=\"userForm\">"
965             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
966             "<INPUT TYPE=text NAME=\"name\" SIZE=30>"
967             "<INPUT TYPE=submit VALUE=\"Find\"></FORM></TD></TR>";
968     }
969     con << TAG << "<TR><TH ALIGN=LEFT>Used software:</TH>"
970         "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
971         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
972         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
973         "VALUE=\"softwareForm\">"
974         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
975         "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
976         "<SELECT NAME=\"software\" SIZE=1>";
977     if (persons->setUsedSoftware.length() != 0) {
978         print(con, persons->setUsedSoftware);
979         con << TAG <<
980             "</SELECT><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">"
981             "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Unregister\">";
982     } else {
983         con << TAG << EMPTY_LIST;
984     }
985     if (products.select() != 0) {
986         con << TAG <<
987             "</FORM></TD></TR>"
988             "<TR><TH ALIGN=LEFT>Register as software user:</TH>"
989             "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
990             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
991             << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
992             "VALUE=\"registerSoftware\">"
993             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
994             "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
995             "<SELECT NAME=\"software\" SIZE=1>";
996         print(con, products);
997         con << TAG << "</SELECT><INPUT TYPE=submit VALUE=\"Register\">";
998     }
999     con << TAG << "</FORM></TD></TR></TABLE><P>"
1000         "<B>Reported bugs:</B><BR>"
1001         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1002         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1003         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
1004         "VALUE=\"bugForm\">"
1005         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1006         "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
1007         "<SELECT NAME=\"bug\" SIZE=5>";
1008     if (persons->setReportedBugs.length() != 0) {
1009         print(con, persons->setReportedBugs);
1010         con << TAG <<
1011            "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
1012     } else {
1013         con << TAG << EMPTY_LIST;
1014     }
1015     con << TAG << "</FORM><P>";
1016     if (persons->status != Person::isUser) {
1017         con << TAG <<
1018             "<P><B>Assigned bugs:</B><BR>"
1019             "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1020             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1021             << con.getAddress() << "\"><INPUT TYPE=hidden "
1022             "NAME=\"page\" VALUE=\"bugForm\">"
1023             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1024             "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
1025             "<SELECT NAME=\"bug\" SIZE=5>";
1026         if (persons->setAssignedBugs.length() != 0) {
1027             print(con, persons->setAssignedBugs);
1028             con << TAG <<
1029                 "</SELECT><BR>"
1030                 "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">&nbsp;"
1031                 "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Deassign\">";
1032         } else {
1033             con << TAG << EMPTY_LIST;
1034         }
1035         con << TAG << "</FORM>";
1036     }
1037     if (strcmp(name, myself) == 0) {
1038         con << TAG << "</BODY></HTML>";
1039     } else {
1040         mainMenuReference(con);
1041     }
1042     return true;
1043 }
1044 
1045 
createBugReportForm(WWWconnection & con)1046 bool createBugReportForm(WWWconnection& con)
1047 {
1048     int i;
1049     sequencer.select();
1050     con << TAG <<
1051         HTML_HEAD "<TITLE>Bug</TITLE></HEAD>"
1052         BODY
1053         "<H2>Bug</H2>"
1054         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1055         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1056         << con.getAddress() << "\"><INPUT TYPE=hidden "
1057         "NAME=\"page\" VALUE=\"createBugReport\">"
1058         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\""<<con.get("myself")<<"\">"
1059         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << ++sequencer->nBugs << ">"
1060         "<TABLE><TH ALIGN=LEFT>Summary:</TH>"
1061         "<TD><INPUT TYPE=text NAME=\"summary\" SIZE=40></TD></TR>"
1062         "<TR><TH ALIGN=LEFT>Category:</TH>"
1063         "<TD><SELECT NAME=\"category\" SIZE=1>";
1064     for (i = 1; eCATEGORY_STRING[i] != NULL; i++) {
1065         con << TAG << "<OPTION SELECTED VALUE=" << i << ">"
1066             << eCATEGORY_STRING[i] << "</OPTION>";
1067     }
1068     con << TAG << "</SELECT></TD></TR>"
1069         "<TR><TH ALIGN=LEFT>Severity:</TH>"
1070         "<TD><SELECT NAME=\"severity\" SIZE=1>";
1071     for (i = 1; eSEVERITY_STRING[i] != NULL; i++) {
1072         con << TAG << "<OPTION SELECTED VALUE=" << i << ">"
1073             << eSEVERITY_STRING[i] << "</OPTION>";
1074     }
1075     con << TAG <<
1076         "</SELECT></TD></TR>"
1077         "<TR><TH ALIGN=LEFT>Priority:</TH>"
1078         "<TD><SELECT NAME=\"priority\" SIZE=1>";
1079     for (i = 1; eFIXING_PRIORITY_STRING[i] != NULL; i++) {
1080         con << TAG << "<OPTION SELECTED VALUE=" << i << ">"
1081             << eFIXING_PRIORITY_STRING[i] << "</OPTION>";
1082     }
1083     con << TAG <<
1084         "</SELECT></TD></TR>"
1085         "<TR><TH ALIGN=LEFT>Software:</TH>"
1086         "<TD><SELECT NAME=\"software\" SIZE=1>";
1087     if (products.select() != 0) {
1088         print(con, products);
1089     }
1090     con << TAG <<
1091             "</SELECT></TD></TR>"
1092             "<TR><TH ALIGN=LEFT>Version:</TH>"
1093             "<TD><INPUT TYPE=text NAME=\"version\"></TD></TR>"
1094             "<TR><TH ALIGN=LEFT>Platform:</TH>"
1095             "<TD><INPUT TYPE=text NAME=\"platform\"</TD></TR>"
1096             "<TR><TH ALIGN=LEFT>OS:</TH>"
1097             "<TD><INPUT TYPE=text NAME=\"os\"></TD></TR></TABLE><P>"
1098             "<INPUT TYPE=submit VALUE=\"Submit\">&nbsp;"
1099             "<INPUT TYPE=reset></FORM>";
1100     mainMenuReference(con);
1101     sequencer.update();
1102     return true;
1103 }
1104 
1105 bool bugForm(WWWconnection& con);
1106 
createBugReport(WWWconnection & con)1107 bool createBugReport(WWWconnection& con)
1108 {
1109     key = con.get("myself");
1110     if (persons.select(qPerson) == 0) {
1111         error(con, "Author unknown");
1112         return true;
1113     }
1114     key = con.get("software");
1115     if (products.select(qSoftware) == 0) {
1116         error(con, "No such software product");
1117         return true;
1118     }
1119     if (sscanf(con.get("version"), "%d.%d", &majorVersion, &minorVersion) != 2)
1120     {
1121         error(con, "Bad version format");
1122         return true;
1123     }
1124     initialVersion = products->pVersions;
1125     if (versions.select(qVersion) == 0) {
1126         error(con, "No such software product version");
1127         return true;
1128     }
1129 
1130     Bug bug;
1131     bug.bugId = atoi(con.get("bug"));
1132     bug.sOneLineSummary = con.get("summary");
1133     bug.eCategory = atoi(con.get("category"));
1134     bug.eFixingPriority = atoi(con.get("priority"));
1135     bug.eSeverity = atoi(con.get("severity"));
1136     bug.sOperatingSystem = con.get("os");
1137     bug.sHardwarePlatform = con.get("platform");
1138     bug.pReportedBy = persons.currentId();
1139     bug.pAssignedTo = null;
1140     bug.pSoftware = products.currentId();
1141     bug.pVersion = versions.currentId();
1142     bug.nReports = 0;
1143     insert(bug);
1144     con.addPair("action", "Select");
1145     return bugForm(con);
1146 }
1147 
bugForm(WWWconnection & con)1148 bool bugForm(WWWconnection& con)
1149 {
1150     int i;
1151     char* bugStr = con.get("bug");
1152     bugId = atoi(bugStr);
1153     if (bugs.select(qBug) == 0) {
1154         error(con, "No bug was selected");
1155         return true;
1156     }
1157     char* myself = con.get("myself");
1158     if (strcmp(con.get("action"), "Remove") == 0) {
1159         dbReference<Bug> pBug = bugs.currentId();
1160         bugId = atoi(con.get("relatedbug"));
1161         if (bugs.select(qBug) == 0) {
1162             error(con, "No such bug");
1163             return true;
1164         }
1165         int i = rindex(bugs->setSimilarBugs, pBug);
1166         if (i < 0) {
1167             error(con, "No such related bug");
1168             return true;
1169         }
1170         bugs->setSimilarBugs.remove(i);
1171         bugs.update();
1172         return bugForm(con);
1173     }
1174     key = myself;
1175     if (persons.select(qPerson) == 0) {
1176         error(con, "No such user");
1177         return true;
1178     }
1179     if (strcmp(con.get("action"), "Deassign") == 0) {
1180         int i = rindex(persons->setAssignedBugs, bugs.currentId());
1181         if (i < 0) {
1182             error(con, "Bug was not assigned");
1183             return true;
1184         }
1185         persons->setAssignedBugs.remove(i);
1186         persons.update();
1187         con.addPair("name", myself);
1188         return userForm(con);
1189     }
1190 
1191     int personStatus = persons->status;
1192     products.at(bugs->pSoftware);
1193     versions.at(bugs->pVersion);
1194     con << TAG <<
1195         HTML_HEAD "<TITLE>Bug in " << products->sName << " v. " <<
1196         versions->getVersionString() << "</TITLE></HEAD>"
1197         BODY
1198         "<H2>Bug in " << products->sName << " v. "
1199         << versions->getVersionString() << "</H2>"
1200         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1201         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1202         << con.getAddress() << "\"><INPUT TYPE=hidden "
1203         "NAME=\"page\" VALUE=\"updateBug\">"
1204         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1205         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1206         "<TABLE><TH ALIGN=LEFT>Summary:</TH>"
1207         "<TD><INPUT TYPE=text NAME=\"summary\" SIZE=40 VALUE=\""
1208         << bugs->sOneLineSummary << "\"></TD></TR>"
1209         "<TR><TH ALIGN=LEFT>Category:</TH>"
1210         "<TD><SELECT NAME=\"category\" SIZE=1>"
1211         "<OPTION SELECTED VALUE=" << bugs->eCategory << ">"
1212         << eCATEGORY_STRING[bugs->eCategory] << "</OPTION>";
1213     for (i = 1; eCATEGORY_STRING[i] != NULL; i++) {
1214         con << TAG << "<OPTION VALUE=" << i << ">"
1215             << eCATEGORY_STRING[i] << "</OPTION>";
1216     }
1217     con << TAG <<
1218         "</SELECT></TD></TR>"
1219         "<TR><TH ALIGN=LEFT>Severity:</TH>"
1220         "<TD><SELECT NAME=\"severity\" SIZE=1>"
1221         "<OPTION SELECTED VALUE=" << bugs->eSeverity << ">"
1222         << eSEVERITY_STRING[bugs->eSeverity] << "</OPTION>";
1223     for (i = 1; eSEVERITY_STRING[i] != NULL; i++) {
1224         con << TAG << "<OPTION  VALUE=" << i << ">"
1225             << eSEVERITY_STRING[i] << "</OPTION>";
1226     }
1227     con << TAG <<
1228         "</SELECT></TD></TR>"
1229         "<TR><TH ALIGN=LEFT>Priority:</TH>"
1230         "<TD><SELECT NAME=\"priority\" SIZE=1>"
1231         "<OPTION SELECTED VALUE=" << bugs->eFixingPriority << ">"
1232         << eFIXING_PRIORITY_STRING[bugs->eFixingPriority] << "</OPTION>";
1233     for (i = 1; eFIXING_PRIORITY_STRING[i] != NULL; i++) {
1234         con << TAG << "<OPTION VALUE=" << i << ">"
1235             << eFIXING_PRIORITY_STRING[i] << "</OPTION>";
1236     }
1237     con << TAG <<
1238         "</SELECT></TD></TR>"
1239         "<TR><TH ALIGN=LEFT>Platform:</TH>"
1240         "<TD><INPUT TYPE=text NAME=\"platform\" VALUE=\""
1241         << bugs->sHardwarePlatform << "\"></TD></TR>"
1242         "<TR><TH ALIGN=LEFT>OS:</TH>"
1243         "<TD><INPUT TYPE=text NAME=\"os\"VALUE=\""
1244         << bugs->sOperatingSystem << "\"></TD></TR>"
1245         "<TR><TH ALIGN=LEFT>Assigned to:</TH>"
1246         "<TD><SELECT SIZE=1 NAME=\"name\">";
1247     if (bugs->pAssignedTo != null) {
1248         persons.at(bugs->pAssignedTo);
1249         con << TAG << "<OPTION SELECTED VALUE=\"" << persons->sName
1250             << "\">" <<  persons->sName << "</OPTION>";
1251     } else {
1252         con << TAG << "<OPTION SELECTED VALUE=\"\"></OPTION>";
1253     }
1254     print(con, products->setEngineers);
1255     con << TAG << "</SELECT></TD></TR>"
1256         "<TR><TH ALIGN=LEFT>Similar with:</TH>"
1257         "<TD><SELECT NAME=\"similar\" SIZE=1>"
1258         "<OPTION SELECTED VALUE=\"\"></OPTION>";
1259     allBugs.select();
1260     print(con, allBugs);
1261     con << TAG << "</SELECT></TD></TR></TABLE><BR>";
1262 
1263     if (personStatus != Person::isUser) {
1264         con << TAG <<
1265             "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Update\">&nbsp;"
1266             "<INPUT TYPE=reset VALUE=\"Reset\">";
1267     }
1268     con << TAG << "</FORM><P><FORM METHOD=POST ACTION=\"" << con.getStub()
1269         << "\"><INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1270         << con.getAddress() << "\">"
1271         "<INPUT TYPE=hidden NAME=\"page\" VALUE=\"updateReportForm\">"
1272         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1273         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1274         "<B>Report history:</B><BR><SELECT NAME=\"report\" SIZE=5>";
1275     firstReport = bugs->pReportHistory;
1276     if (reports.select(qAllReports) != 0) {
1277         print(con, reports);
1278         con << TAG <<
1279             "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">"
1280             "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Add\">";
1281         if (personStatus == Person::isAdministrator) {
1282             con << TAG <<
1283                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
1284         }
1285     } else {
1286         con << TAG << EMPTY_LIST
1287             "<BR><INPUT TYPE=submit  NAME=\"action\" VALUE=\"Add\">";
1288     }
1289     con << TAG << "</FORM><P>";
1290 
1291     con << TAG <<
1292         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1293         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1294         << con.getAddress() << "\"><INPUT TYPE=hidden "
1295         "NAME=\"page\" VALUE=\"updateWorkAroundForm\">"
1296         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1297         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1298         "<B>Work arounds:</B><BR><SELECT NAME=\"workaround\" SIZE=5>";
1299     firstReport = bugs->pWorkArounds;
1300     if (reports.select(qAllReports) != 0) {
1301         print(con, reports);
1302         con << TAG <<
1303             "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">"
1304             "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Add\">";
1305         if (personStatus == Person::isAdministrator) {
1306             con << TAG <<
1307                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
1308         }
1309     } else {
1310         con << TAG << EMPTY_LIST
1311             "<BR><INPUT TYPE=submit  NAME=\"action\" VALUE=\"Add\">";
1312     }
1313     con << TAG << "</FORM><P>";
1314 
1315     if (bugs->setSimilarBugs.length() != 0) {
1316         con << TAG <<
1317             "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1318             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1319             << con.getAddress() << "\"><INPUT TYPE=hidden "
1320             "NAME=\"page\" VALUE=\"bugForm\">"
1321             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1322             "<INPUT TYPE=hidden NAME=\"relatedbug\" VALUE=" << bugStr << ">"
1323             "<B>Similar bugs:</B><BR><SELECT NAME=\"bug\" SIZE=1>";
1324         print(con, bugs->setSimilarBugs);
1325         con << TAG <<
1326             "</SELECT><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
1327         if (personStatus == Person::isAdministrator) {
1328             con << TAG <<
1329                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
1330         }
1331         con << TAG << "</FORM><P>";
1332     }
1333     con << TAG <<
1334         "</FORM><P>"
1335         "<FONT SIZE=\"+1\"><UL>";
1336     if (personStatus == Person::isUser) {
1337         if (bugs->pAssignedTo != null) {
1338             persons.at(bugs->pAssignedTo);
1339             con << TAG << "<LI>Assigned to <A HREF=\"mailto:"
1340                 << persons->sEmailAddress << "\">"
1341                 << persons->sName << "</A>";
1342         }
1343         persons.at(bugs->pReportedBy);
1344         con << TAG << "<LI>Reported by <A HREF=\"mailto:"
1345             << persons->sEmailAddress << "\">"
1346             << persons->sName << "</A></OL></FONT>";
1347     } else {
1348         if (bugs->pAssignedTo != null) {
1349             persons.at(bugs->pAssignedTo);
1350             con << TAG << "<LI>Assigned to <A HREF=\"" << con.getStub()
1351                 << "?socket=" << con.getAddress()
1352                 << "&page=userForm&myself=" << URL << myself
1353                 << "&name=" << URL << persons->sName << "\">"
1354                 << persons->sName << "</A>";
1355         }
1356         persons.at(bugs->pReportedBy);
1357         con << TAG
1358             << "<LI>Reported by <A HREF=\"" << con.getStub() << "?socket="
1359             << con.getAddress()
1360             << "&page=userForm&myself=" << URL << myself
1361             << "&name=" << URL << persons->sName << "\">"
1362             << persons->sName << "</A></OL></FONT>";
1363     }
1364     mainMenuReference(con);
1365     return true;
1366 }
1367 
updateBug(WWWconnection & con)1368 bool updateBug(WWWconnection& con)
1369 {
1370     char* bugStr = con.get("bug");
1371     bugId = atoi(bugStr);
1372     if (bugs.select(qBug) == 0) {
1373         error(con, "No such bug");
1374         return true;
1375     }
1376     char* similar = con.get("similar");
1377     if (*similar != '\0') {
1378         int id = atoi(similar);
1379         if (id != bugId) {
1380             bugId = id;
1381             if (allBugs.select(qBug) != 0) {
1382                 if (rindex(bugs->setSimilarBugs, allBugs.currentId()) < 0) {
1383                     bugs->setSimilarBugs.append(allBugs.currentId());
1384                 }
1385             }
1386         }
1387     }
1388     key = con.get("name");
1389     if (*key != '\0') {
1390         if (persons.select(qPerson) == 0 ||
1391             persons->status == Person::isUser)
1392         {
1393             error(con, "No such engineer");
1394             return true;
1395         }
1396         bugs->pAssignedTo = persons.currentId();
1397     }
1398     bugs.update();
1399     return bugForm(con);
1400 }
1401 
1402 
addReportForm(WWWconnection & con)1403 bool addReportForm(WWWconnection& con)
1404 {
1405     char* bugStr = con.get("bug");
1406     bugId = atoi(bugStr);
1407     if (bugs.select(qBug) == 0) {
1408         error(con, "No such bug");
1409         return true;
1410     }
1411     con << TAG <<
1412         HTML_HEAD "<TITLE>Bug report</TITLE></HEAD>"
1413         BODY
1414         "<H2>Bug report</H2>"
1415         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1416         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1417         << con.getAddress() << "\"><INPUT TYPE=hidden "
1418         "NAME=\"page\" VALUE=\"addReport\">"
1419         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1420         "<INPUT TYPE=hidden NAME=\"index\" VALUE=" << ++bugs->nReports
1421         << "><INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself")
1422         << "\"><B>Status: &nbsp;</B><SELECT SIZE=1 NAME=\"status\">";
1423     for (int i = 1; eSTATUS_STRING[i] != NULL; i++) {
1424         con << TAG << "<OPTION VALUE=" << i << ">" << eSTATUS_STRING[i]
1425             << "</OPTION>";
1426     }
1427     con << TAG <<
1428         "</SELECT><P>"
1429         "<B>Bug description:</B><P>"
1430         "<TEXTAREA COLS=40 ROWS=5 NAME=\"description\"></TEXTAREA><P>"
1431         "<INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
1432         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
1433     bugs.update();
1434     mainMenuReference(con);
1435     return true;
1436 }
1437 
addReport(WWWconnection & con)1438 bool addReport(WWWconnection& con)
1439 {
1440     bugId = atoi(con.get("bug"));
1441     if (bugs.select(qBug) == 0) {
1442         error(con, "No such bug");
1443         return true;
1444     }
1445     key = con.get("myself");
1446     if (persons.select(qPerson) == 0) {
1447         error(con, "No such person");
1448         return true;
1449     }
1450     reportId = atoi(con.get("index"));
1451     firstReport = bugs->pReportHistory;
1452     if (reports.select(qReport) == 0) {
1453         Report report;
1454         report.pAuthor = persons.currentId();
1455         persons->nReports += 1;
1456         report.sDescription = con.get("description");
1457         report.index = reportId;
1458         report.pNext = bugs->pReportHistory;
1459         report.status = atoi(con.get("status"));
1460         report.creationDate = dbDateTime::current();
1461         bugs->pReportHistory = insert(report);
1462         persons.update();
1463         bugs.update();
1464     }
1465     con.addPair("action", "Select");
1466     return bugForm(con);
1467 }
1468 
addWorkAroundForm(WWWconnection & con)1469 bool addWorkAroundForm(WWWconnection& con)
1470 {
1471     char* bugStr = con.get("bug");
1472     bugId = atoi(bugStr);
1473     if (bugs.select(qBug) == 0) {
1474         error(con, "No such bug");
1475         return true;
1476     }
1477     con << TAG <<
1478         HTML_HEAD "<TITLE>Work around</TITLE></HEAD>"
1479         BODY
1480         "<H2>Work around</H2>"
1481         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1482         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1483         << con.getAddress() << "\"><INPUT TYPE=hidden "
1484         "NAME=\"page\" VALUE=\"addWorkAround\">"
1485         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1486         "<INPUT TYPE=hidden NAME=\"index\" VALUE=" << ++bugs->nReports
1487         << "><INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself")
1488         << "\"><B>Status: &nbsp;</B><SELECT SIZE=1 NAME=\"status\">";
1489     for (int i = 1; eSTATUS_STRING[i] != NULL; i++) {
1490         con << TAG << "<OPTION VALUE=" << i << ">" << eSTATUS_STRING[i]
1491             << "</OPTION>";
1492     }
1493     con << TAG <<
1494         "</SELECT><P>"
1495         "<B>Description:</B><P>"
1496         "<TEXTAREA COLS=40 ROWS=5 NAME=\"description\"></TEXTAREA><P>"
1497         "<INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
1498         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
1499     bugs.update();
1500     mainMenuReference(con);
1501     return true;
1502 }
1503 
addWorkAround(WWWconnection & con)1504 bool addWorkAround(WWWconnection& con)
1505 {
1506     bugId = atoi(con.get("bug"));
1507     if (bugs.select(qBug) == 0) {
1508         error(con, "No such bug");
1509         return true;
1510     }
1511     key = con.get("myself");
1512     if (persons.select(qPerson) == 0) {
1513         error(con, "No such person");
1514         return true;
1515     }
1516     reportId = atoi(con.get("index"));
1517     firstReport = bugs->pWorkArounds;
1518     if (reports.select(qReport) == 0) {
1519         Report report;
1520         report.pAuthor = persons.currentId();
1521         persons->nReports += 1;
1522         report.sDescription = con.get("description");
1523         report.index = reportId;
1524         report.pNext = bugs->pWorkArounds;
1525         report.status = atoi(con.get("status"));
1526         report.creationDate = dbDateTime::current();
1527         bugs->pWorkArounds = insert(report);
1528         persons.update();
1529         bugs.update();
1530     }
1531     con.addPair("action", "Select");
1532     return bugForm(con);
1533 }
1534 
updateReportForm(WWWconnection & con)1535 bool updateReportForm(WWWconnection& con)
1536 {
1537     if (strcmp(con.get("action"), "Add") == 0) {
1538         return addReportForm(con);
1539     }
1540     char* bugStr = con.get("bug");
1541     bugId = atoi(bugStr);
1542     if (bugs.select(qBug) == 0) {
1543         error(con, "No such bug");
1544         return true;
1545     }
1546     char* report = con.get("report");
1547     if (report == NULL) {
1548         error(con, "No report was selected");
1549         return true;
1550     }
1551     int index = atoi(report);
1552     dbReference<Report> prev, curr = null, next = bugs->pReportHistory;
1553     do  {
1554         prev = curr;
1555         if (next == null) {
1556             error(con, "No such report");
1557             return true;
1558         }
1559         reports.at(next);
1560         curr = next;
1561         next = reports->pNext;
1562     } while (reports->index != index);
1563 
1564     if (strcmp(con.get("action"), "Remove") == 0) {
1565         reports.remove();
1566         bugs->nReports -= 1;
1567         if (prev == null) {
1568             bugs->pReportHistory = next;
1569         } else {
1570             reports.at(prev);
1571             reports->pNext = next;
1572             reports.update();
1573         }
1574         bugs.update();
1575         con.addPair("action", "Select");
1576         return bugForm(con);
1577     }
1578     char date[64];
1579     reports->creationDate.asString(date, sizeof date);
1580     char* myself = con.get("myself");
1581     key = myself;
1582     if (persons.select(qPerson) == 0) {
1583         error(con, "No such person");
1584         return true;
1585     }
1586     int personStatus = persons->status;
1587     persons.at(reports->pAuthor);
1588     con << TAG <<
1589         HTML_HEAD "<TITLE>Bug report from " << date << "</TITLE></HEAD>"
1590         BODY
1591         "<H2>Bug report from " << date << "</H2>"
1592         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1593         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1594         << con.getAddress() << "\"><INPUT TYPE=hidden "
1595         "NAME=\"page\" VALUE=\"updateReport\">"
1596         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1597         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1598         "\"><INPUT TYPE=hidden NAME=\"report\" VALUE=" << index << ">"
1599         "<B>Created by ";
1600     if (personStatus == Person::isUser) {
1601         con << TAG << "<A HREF=\"mailto:"
1602             << persons->sEmailAddress << "\">"
1603             << persons->sName << "</A>";
1604     } else {
1605         con << TAG <<
1606             "<A HREF=\"" << con.getStub() << "?socket="
1607             << con.getAddress()
1608             << "&page=userForm&myself=" << URL << myself
1609             << "&name=" << URL << persons->sName << "\">"
1610             << persons->sName << "</A>";
1611     }
1612     con << TAG << "<P>Status: </B><SELECT SIZE=1 NAME=\"status\">"
1613         "<OPTION SELECTED VALUE=" << reports->status << ">"
1614         << eSTATUS_STRING[reports->status] << "</OPTION>";
1615     for (int i = 1; eSTATUS_STRING[i] != NULL; i++) {
1616         con << TAG << "<OPTION VALUE=" << i << ">" << eSTATUS_STRING[i]
1617             << "</OPTION>";
1618     }
1619     con << TAG <<
1620         "</SELECT><P>"
1621         "<B>Bug description:</B><BR>"
1622         "<TEXTAREA COLS=40 ROWS=5 NAME=\"description\">"
1623         << reports->sDescription << "</TEXTAREA><P>";
1624     if (personStatus != Person::isUser) {
1625         con << TAG <<
1626             "<INPUT TYPE=submit VALUE=\"Update\">&nbsp;"
1627             "<INPUT TYPE=reset VALUE=\"Reset\">";
1628     }
1629     con << TAG << "</FORM>";
1630     mainMenuReference(con);
1631     return true;
1632 }
1633 
updateWorkAroundForm(WWWconnection & con)1634 bool updateWorkAroundForm(WWWconnection& con)
1635 {
1636     if (strcmp(con.get("action"), "Add") == 0) {
1637         return addWorkAroundForm(con);
1638     }
1639     char* bugStr = con.get("bug");
1640     bugId = atoi(bugStr);
1641     if (bugs.select(qBug) == 0) {
1642         error(con, "No such bug");
1643         return true;
1644     }
1645     char* workaround = con.get("workaround");
1646     int index = atoi(workaround);
1647     dbReference<Report> prev, curr = null, next = bugs->pWorkArounds;
1648     do  {
1649         prev = curr;
1650         if (next == null) {
1651             error(con, "No such report");
1652             return true;
1653         }
1654         reports.at(next);
1655         curr = next;
1656         next = reports->pNext;
1657     } while (reports->index != index);
1658 
1659     if (strcmp(con.get("action"), "Remove") == 0) {
1660         reports.remove();
1661         bugs->nReports -= 1;
1662         if (prev == null) {
1663             bugs->pWorkArounds = next;
1664         } else {
1665             reports.at(prev);
1666             reports->pNext = next;
1667             reports.update();
1668         }
1669         bugs.update();
1670         con.addPair("action", "Select");
1671         return bugForm(con);
1672     }
1673     char date[64];
1674     reports->creationDate.asString(date, sizeof date);
1675     char* myself = con.get("myself");
1676     key = myself;
1677     if (persons.select(qPerson) == 0) {
1678         error(con, "No such person");
1679         return true;
1680     }
1681     int personStatus = persons->status;
1682     persons.at(reports->pAuthor);
1683     con << TAG <<
1684         HTML_HEAD "<TITLE>Work around " << date << "</TITLE></HEAD>"
1685         BODY
1686         "<H2>Work around " << date << "</H2>"
1687         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1688         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1689         << con.getAddress() << "\"><INPUT TYPE=hidden "
1690         "NAME=\"page\" VALUE=\"updateWorkAround\">"
1691         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1692         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1693         "\"><INPUT TYPE=hidden NAME=\"workaround\" VALUE=" << index <<
1694         "><B>Created by ";
1695     if (personStatus == Person::isUser) {
1696         con << TAG << "<A HREF=\"mailto:"
1697             << persons->sEmailAddress << "\">"
1698             << persons->sName << "</A>";
1699     } else {
1700         con << TAG <<
1701             "<A HREF=\"" << con.getStub() << "?socket="
1702             << con.getAddress()
1703             << "&page=userForm&myself=" << URL << myself
1704             << "&name=" << URL << persons->sName << "\">"
1705             << persons->sName << "</A>";
1706     }
1707     con << TAG << "<P>Status: </B><SELECT SIZE=1 NAME=\"status\">"
1708         "<OPTION SELECTED VALUE=" << reports->status << ">"
1709         << eSTATUS_STRING[reports->status] << "</OPTION>";
1710     for (int i = 1; eSTATUS_STRING[i] != NULL; i++) {
1711         con << TAG << "<OPTION VALUE=" << i << ">" << eSTATUS_STRING[i]
1712             << "</OPTION>";
1713     }
1714     con << TAG <<
1715         "</SELECT><P>"
1716         "<B>Bug description:</B><BR>"
1717         "<TEXTAREA COLS=40 ROWS=5 NAME=\"description\">"
1718         << reports->sDescription << "</TEXTAREA><P>";
1719     if (personStatus != Person::isUser) {
1720         con << TAG <<
1721             "<INPUT TYPE=submit VALUE=\"Update\">&nbsp;"
1722             "<INPUT TYPE=reset VALUE=\"Reset\">";
1723     }
1724     con << TAG << "</FORM>";
1725     mainMenuReference(con);
1726     return true;
1727 }
1728 
updateReport(WWWconnection & con)1729 bool updateReport(WWWconnection& con)
1730 {
1731     bugId = atoi(con.get("bug"));
1732     if (bugs.select(qBug) == 0) {
1733         error(con, "No such bug");
1734         return true;
1735     }
1736     reportId = atoi(con.get("report"));
1737     firstReport = bugs->pReportHistory;
1738     if (reports.select(qReport) == 0) {
1739         error(con, "No report was selected");
1740         return true;
1741     }
1742     reports->sDescription = con.get("description");
1743     reports->status = atoi(con.get("status"));
1744     reports.update();
1745     con.addPair("action", "Select");
1746     return bugForm(con);
1747 }
1748 
updateWorkAround(WWWconnection & con)1749 bool updateWorkAround(WWWconnection& con)
1750 {
1751     bugId = atoi(con.get("bug"));
1752     if (bugs.select(qBug) == 0) {
1753         error(con, "No such bug");
1754         return true;
1755     }
1756     reportId = atoi(con.get("workaround"));
1757     firstReport = bugs->pWorkArounds;
1758     if (reports.select(qReport) == 0) {
1759         error(con, "No report was selected");
1760         return true;
1761     }
1762     reports->sDescription = con.get("description");
1763     reports->status = atoi(con.get("status"));
1764     reports.update();
1765     con.addPair("action", "Select");
1766     return bugForm(con);
1767 }
1768 
1769 
attachToProject(WWWconnection & con)1770 bool attachToProject(WWWconnection& con)
1771 {
1772     key = con.get("name");
1773     if (persons.select(qPerson) == 0 || persons->status == Person::isUser) {
1774         error(con, "No such engineer");
1775     } else {
1776         key = con.get("software");
1777         if (products.select(qSoftware) == 0) {
1778             error(con, "No such software product");
1779         } else {
1780             if (rindex(products->setEngineers, persons.currentId()) >= 0) {
1781                 error(con, "Engineer already attached to the project");
1782             } else {
1783                 products->setEngineers.append(persons.currentId());
1784                 products.update();
1785                 return userForm(con);
1786             }
1787         }
1788     }
1789     return true;
1790 }
1791 
1792 
registerSoftware(WWWconnection & con)1793 bool registerSoftware(WWWconnection& con)
1794 {
1795     key = con.get("name");
1796     if (persons.select(qPerson) == 0) {
1797         error(con, "No such person");
1798     } else {
1799         key = con.get("software");
1800         if (products.select(qSoftware) == 0) {
1801             error(con, "No such software product");
1802         } else {
1803             if (rindex(products->setUsers, persons.currentId()) >= 0) {
1804                 error(con, "User already registered this software");
1805             } else {
1806                 products->setUsers.append(persons.currentId());
1807                 products.update();
1808                 return userForm(con);
1809             }
1810         }
1811     }
1812     return true;
1813 }
1814 
1815 
softwareForm(WWWconnection & con)1816 bool softwareForm(WWWconnection& con)
1817 {
1818     char* software = con.get("software");
1819     if (software == NULL) {
1820         error(con, "No software product was selected");
1821         return true;
1822     }
1823     key = software;
1824     if (products.select(qSoftware) == 0) {
1825         error(con, "No such software product");
1826         return true;
1827     }
1828     if (strcmp(con.get("action"), "Detach") == 0) {
1829         key = con.get("name");
1830         if (persons.select(qPerson) == 0) {
1831             error(con, "No such person");
1832             return true;
1833         }
1834         int i = rindex(persons->setProjects, products.currentId());
1835         if (i < 0) {
1836             error(con, "Person was not attached to the project");
1837             return true;
1838         }
1839         persons->setProjects.remove(i);
1840         persons.update();
1841         return userForm(con);
1842     }
1843     if (strcmp(con.get("action"), "Unregister") == 0) {
1844         key = con.get("name");
1845         if (persons.select(qPerson) == 0) {
1846             error(con, "No such person");
1847             return true;
1848         }
1849         int i = rindex(persons->setUsedSoftware, products.currentId());
1850         if (i < 0) {
1851             error(con, "Person was not registered");
1852             return true;
1853         }
1854         persons->setProjects.remove(i);
1855         persons.update();
1856         return userForm(con);
1857     }
1858     char* myself = con.get("myself");
1859     key = myself;
1860     if (persons.select(qPerson) == 0) {
1861         error(con, "No such person");
1862         return true;
1863     }
1864     int personStatus = persons->status;
1865     con << TAG <<
1866         HTML_HEAD "<TITLE>" << software << "</TITLE></HEAD>"
1867         BODY
1868         "<H2>" << software << "</H2>"
1869         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1870         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1871         << con.getAddress() << "\"><INPUT TYPE=hidden "
1872         "NAME=\"page\" VALUE=\"updateSoftware\">"
1873         "<INPUT TYPE=hidden NAME=\"software\" VALUE=\"" << software << "\">"
1874         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1875         "<TABLE><TR><TH ALIGN=LEFT>Product name:</TH>"
1876         "<TD><INPUT TYPE=text NAME=\"newname\" VALUE=\"" << software << "\">"
1877         "</TD></TR>";
1878     if (products->pVersions != null) {
1879         versions.at(products->pVersions);
1880         con << TAG <<
1881             "<TR><TH ALIGN=LEFT>Current version:</TH>"
1882             "<TD><INPUT TYPE=text NAME=\"version\" SIZE=8 VALUE=\""
1883             << versions->getVersionString() << "\"></TD></TR>"
1884             "<TR><TH ALIGN=LEFT>Current version label:</TH>"
1885             "<TD><INPUT TYPE=text NAME=\"label\" SIZE=20 VALUE=\""
1886             << versions->sLabel << "\"></TD></TR>"
1887             "<TR><TH ALIGN=LEFT>Current version comment:</TH>"
1888             "<TD><INPUT TYPE=text NAME=\"comment\" SIZE=40 VALUE=\""
1889             << versions->sComment << "\"></TD></TR>";
1890     } else {
1891         con << TAG <<
1892             "<TR><TH ALIGN=LEFT>Current version:</TH>"
1893             "<TD><INPUT TYPE=text NAME=\"version\" SIZE=8></TD></TR>"
1894             "<TR><TH ALIGN=LEFT>Current version label:</TH>"
1895             "<TD><INPUT TYPE=text NAME=\"label\" SIZE=20></TD></TR>"
1896             "<TR><TH ALIGN=LEFT>Current version comment:</TH>"
1897             "<TD><INPUT TYPE=text NAME=\"comment\" SIZE=40></TD></TR>";
1898     }
1899     con << TAG << "</TABLE><BR>";
1900     if (personStatus != Person::isUser) {
1901         con << TAG <<
1902             "<INPUT TYPE=submit VALUE=\"Update\">&nbsp;<INPUT TYPE=reset>";
1903     }
1904     con << TAG << "</FORM><P>"
1905         "<TABLE><TR><TH ALIGN=LEFT>Engineers:</TH>"
1906         "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1907         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress()
1908         << "\"><INPUT TYPE=HIDDEN NAME=\"page\" VALUE=\"userForm\">"
1909         "<INPUT TYPE=HIDDEN NAME=\"myself\" VALUE=\"" << myself <<
1910         "\"><SELECT NAME=\"name\" SIZE=1>";
1911     if (products->setEngineers.length() != 0) {
1912         print(con, products->setEngineers);
1913         con << TAG << "</SELECT>";
1914         if (personStatus != Person::isUser) {
1915             con << TAG << "<INPUT TYPE=submit VALUE=\"Select\">";
1916         }
1917     } else {
1918         con << TAG << EMPTY_LIST;
1919     }
1920     con << TAG <<
1921         "</FORM></TD></TR>"
1922         "<TR><TH ALIGN=LEFT>Users:</TH>"
1923         "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1924         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress()
1925         << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"userForm\">"
1926         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1927         "\"><SELECT NAME=\"name\" SIZE=1>";
1928     if (products->setUsers.length() != 0) {
1929         print(con, products->setUsers);
1930         con << TAG << "</SELECT>";
1931         if (personStatus != Person::isUser) {
1932             con << TAG << "<INPUT TYPE=submit VALUE=\"Select\">";
1933         }
1934     } else {
1935         con << TAG << EMPTY_LIST;
1936     }
1937     con << TAG <<
1938         "</FORM></TD></TR>"
1939         "<TR><TH ALIGN=LEFT>Bugs:</TH>"
1940         "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1941         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress()
1942         << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"bugForm\">"
1943         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1944         "\"><SELECT NAME=\"bug\" SIZE=1>";
1945     if (products->setBugs.length() != 0) {
1946         print(con, products->setBugs);
1947         con << TAG <<
1948             "</SELECT><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
1949     } else {
1950         con << TAG << EMPTY_LIST;
1951     }
1952     con << TAG <<
1953         "</FORM></TD></TR>"
1954         "<TR><TH ALIGN=LEFT>Versions:</TH><TD>"
1955         "<FORM METHOD=POST ACTION=\""<<con.getStub() << "\">"
1956         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress()
1957         << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"versionForm\">"
1958         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1959         "\"><INPUT TYPE=HIDDEN NAME=\"software\" VALUE=\"" << software <<
1960         "\"><SELECT NAME=\"version\" SIZE=1>";
1961     initialVersion = products->pVersions;
1962     if (versions.select(qAllVersions) != 0) {
1963         print(con, versions);
1964         con << TAG << "</SELECT><INPUT TYPE=submit VALUE=\"Select\">";
1965     } else {
1966         con << TAG << EMPTY_LIST;
1967     }
1968     con << TAG << "</FORM></TD></TR></TABLE>";
1969     mainMenuReference(con);
1970     return true;
1971 }
1972 
1973 
updateSoftware(WWWconnection & con)1974 bool updateSoftware(WWWconnection& con)
1975 {
1976     char* software = con.get("software");
1977     key = software;
1978     if (products.select(qSoftware) == 0) {
1979         error(con, "No such software product");
1980         return true;
1981     }
1982     Version version;
1983     char* currentVersion = con.get("version");
1984     version.sLabel = con.get("label");
1985     version.sComment = con.get("comment");
1986     if (sscanf(currentVersion, "%d.%d", &majorVersion, &minorVersion) != 2)
1987     {
1988         error(con, "Bad version number (MAJOR.MINOR expected)");
1989         return true;
1990     }
1991     products->sName = con.get("newname");
1992     version.majorVersionNumber = majorVersion;
1993     version.minorVersionNumber = minorVersion;
1994     version.released = dbDateTime::current();
1995     if (products->pVersions != null) {
1996         initialVersion = products->pVersions;
1997         if (versions.select(qVersion) != 0) {
1998             versions->sComment = version.sComment;
1999             versions->sLabel = version.sLabel;
2000         } else {
2001             versions.at(products->pVersions);
2002             if (versions->majorVersionNumber > majorVersion ||
2003                 (versions->majorVersionNumber == majorVersion &&
2004                  versions->minorVersionNumber > minorVersion))
2005             {
2006                 error(con, "Version number less than of current version");
2007                 return true;
2008             }
2009             version.pNext = products->pVersions;
2010             products->pVersions = insert(version);
2011         }
2012     } else {
2013         version.pNext = null;
2014         products->pVersions = insert(version);
2015     }
2016     products.update();
2017     con.addPair("name", con.get("myself"));
2018     return userForm(con);
2019 }
2020 
2021 
versionForm(WWWconnection & con)2022 bool versionForm(WWWconnection& con)
2023 {
2024     char* software = con.get("software");
2025     char* myself = con.get("myself");
2026     char  buf[64];
2027     key = software;
2028     if (products.select(qSoftware) == 0) {
2029         error(con, "No such software product");
2030         return true;
2031     }
2032     char* versionString = con.get("version");
2033     if (sscanf(versionString, "%d.%d", &majorVersion, &minorVersion) != 2) {
2034         error(con, "Bad version format");
2035         return true;
2036     }
2037     initialVersion = products->pVersions;
2038     if (versions.select(qVersion) == 0) {
2039         error(con, "No such version");
2040         return true;
2041     }
2042     key = myself;
2043     if (persons.select(qPerson) == 0) {
2044         error(con, "No such person");
2045         return true;
2046     }
2047     con << TAG <<
2048         HTML_HEAD "<TITLE>" << software << " v. " << versionString <<
2049         "</TITLE></HEAD>"
2050         BODY
2051         "<H2>"  << software << " v. " << versionString << "</H2>"
2052         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
2053         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
2054         << con.getAddress() << "\"><INPUT TYPE=hidden "
2055         "NAME=\"page\" VALUE=\"updateVersion\">"
2056         "<INPUT TYPE=hidden NAME=\"software\" VALUE=\"" << software << "\">"
2057         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
2058         "<INPUT TYPE=hidden NAME=\"version\" VALUE=\"" << versionString <<"\">"
2059         "<TABLE><TR><TH ALIGN=LEFT>Released:</TH>"
2060         "<TD>" << versions->released.asString(buf, sizeof buf) << "</TD></TR>"
2061         "<TR><TH ALIGN=LEFT>Label:</TH>"
2062         "<TD><INPUT TYPE=text NAME=\"label\" SIZE=20 VALUE=\""
2063         << versions->sLabel << "\"></TD></TR>"
2064         "<TR><TH ALIGN=LEFT>Comment:</TH>"
2065         "<TD><INPUT TYPE=text NAME=\"comment\" SIZE=40 VALUE=\""
2066         << versions->sComment << "\"></TD></TR></TABLE>";
2067     if (persons->status != Person::isUser) {
2068         con << TAG <<
2069             "<P><INPUT TYPE=submit NAME=\"action\" VALUE=\"Update\">";
2070         if (persons->status == Person::isAdministrator) {
2071             con << TAG <<
2072                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
2073         }
2074         con << TAG << "&nbsp;<INPUT TYPE=reset>";
2075     }
2076     con << TAG << "<P></FORM>"
2077         "<B>Bugs:</B><BR>"
2078         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
2079         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
2080         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
2081         "VALUE=\"bugForm\">"
2082         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
2083         "<SELECT NAME=\"bug\" SIZE=5>";
2084     if (versions->setBugs.length() != 0) {
2085         print(con, versions->setBugs);
2086         con << TAG <<
2087            "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
2088     } else {
2089         con << TAG << EMPTY_LIST;
2090     }
2091     con << TAG << "</FORM>";
2092     mainMenuReference(con);
2093     return true;
2094 }
2095 
updateVersion(WWWconnection & con)2096 bool updateVersion(WWWconnection& con)
2097 {
2098     char* software = con.get("software");
2099     key = software;
2100     if (products.select(qSoftware) == 0) {
2101         error(con, "No such software product");
2102         return true;
2103     }
2104     if (sscanf(con.get("version"), "%d.%d", &majorVersion, &minorVersion) != 2)
2105     {
2106         error(con, "Bad version format");
2107         return true;
2108     }
2109     if (strcmp(con.get("action"), "Remove") == 0) {
2110         dbReference<Version> prev, curr = null, next = products->pVersions;
2111         do  {
2112             prev = curr;
2113             if (next == null) {
2114                 error(con, "No such version");
2115                 return true;
2116             }
2117             versions.at(next);
2118             curr = next;
2119             next = versions->pNext;
2120         } while (versions->majorVersionNumber != majorVersion ||
2121                  versions->minorVersionNumber != minorVersion);
2122         if (versions->setBugs.length() != 0) {
2123             error(con, "Can not remove version with non-empty bugs list");
2124             return true;
2125         }
2126         versions.remove();
2127         if (prev == null) {
2128             products->pVersions = next;
2129             products.update();
2130         } else {
2131             versions.at(prev);
2132             versions->pNext = next;
2133             versions.update();
2134         }
2135         con.addPair("action", "Select");
2136         return softwareForm(con);
2137     }
2138     initialVersion = products->pVersions;
2139     if (versions.select(qVersion) == 0) {
2140         error(con, "No such version");
2141         return true;
2142     }
2143     versions->sComment = con.get("comment");
2144     versions->sLabel = con.get("label");
2145     versions.update();
2146     return versionForm(con);
2147 }
2148 
2149 WWWapi::dispatcher dispatchTable[] = {
2150     {"addUserForm", addUserForm},
2151     {"addEngineerForm", addEngineerForm},
2152     {"addSoftwareForm", addSoftwareForm},
2153     {"selectSoftwareForm", selectSoftwareForm},
2154     {"removeSoftwareForm", removeSoftwareForm},
2155     {"selectPersonForm", selectPersonForm},
2156     {"removePersonForm", removePersonForm},
2157     {"selectBugForm", selectBugForm},
2158     {"removeBugForm", removeBugForm},
2159     {"changePasswordForm", changePasswordForm},
2160     {"shutdown", shutdown},
2161     {"userForm", userForm},
2162     {"softwareForm", softwareForm},
2163     {"addUser", addUser},
2164     {"addEngineer", addEngineer},
2165     {"removePerson", removePerson},
2166     {"addSoftware", addSoftware},
2167     {"removeSoftware", removeSoftware},
2168     {"removeBug", removeBug},
2169     {"changePassword", changePassword},
2170     {"updatePerson", updatePerson},
2171     {"login", login},
2172     {"bugQueryForm", bugQueryForm},
2173     {"bugQuery", bugQuery},
2174     {"userForm", userForm},
2175     {"createBugReportForm", createBugReportForm},
2176     {"bugForm", bugForm},
2177     {"createBugReport", createBugReport},
2178     {"bugForm", bugForm},
2179     {"updateBug", updateBug},
2180     {"updateReportForm", updateReportForm},
2181     {"updateWorkAroundForm", updateWorkAroundForm},
2182     {"addReportForm", addReportForm},
2183     {"addReport", addReport},
2184     {"addWorkAroundForm", addWorkAroundForm},
2185     {"addWorkAround", addWorkAround},
2186     {"updateReport", updateReport},
2187     {"updateWorkAround", updateWorkAround},
2188     {"attachToProject", attachToProject},
2189     {"registerSoftware", registerSoftware},
2190     {"softwareForm", softwareForm},
2191     {"updateSoftware", updateSoftware},
2192     {"versionForm", versionForm},
2193     {"updateVersion", updateVersion}
2194 };
2195 
2196 #ifdef USE_EXTERNAL_HTTP_SERVER
2197 CGIapi wwwServer(db, itemsof(dispatchTable), dispatchTable);
2198 char* defaultAddress = "localhost:6101";
2199 socket_t::socket_domain domain = socket_t::sock_local_domain;
2200 #else
2201 HTTPapi wwwServer(db, itemsof(dispatchTable), dispatchTable);
2202 char* defaultAddress = "localhost:80";
2203 socket_t::socket_domain domain = socket_t::sock_global_domain;
2204 #endif
2205 
main(int argc,char * argv[])2206 int main(int argc, char* argv[])
2207 {
2208     char* address = (argc > 1) ? argv[1] : defaultAddress;
2209     if (!wwwServer.open(address, domain)) {
2210         fprintf(stderr, "Failed to open WWW session\n");
2211         return EXIT_FAILURE;
2212     }
2213     if (!db.open(_T("bugdb"))) {
2214         fprintf(stderr, "Failed to open database\n");
2215         return EXIT_FAILURE;
2216     }
2217     qBug = "bugId=",bugId;
2218     qReport = "index=",reportId,"start from",firstReport,"follow by pNext";
2219     qAllReports = "start from",firstReport,"follow by pNext";
2220     qVersion = "majorVersionNumber=",majorVersion,"and minorVersionNumber=",
2221         minorVersion,"start from",initialVersion,"follow by pNext";
2222     qAllVersions = "start from",initialVersion,"follow by pNext";
2223     qPerson = "sName=",&key;
2224     qSoftware = "sName=",&key;
2225 
2226     if (sequencer.select() == 0) {
2227         BugSequencer seq;
2228         seq.nBugs = 0;
2229         insert(seq);
2230     }
2231     if (persons.select() == 0) {
2232         Person administrator;
2233         administrator.sName = "administrator";
2234         administrator.sEmailAddress = "root";
2235         administrator.sPassword = "";
2236         administrator.status = Person::isAdministrator;
2237         administrator.nReports = 0;
2238         insert(administrator);
2239     }
2240     WWWconnection con;
2241     while (wwwServer.connect(con) && wwwServer.serve(con));
2242     db.close();
2243     printf("End of session\n");
2244     return EXIT_SUCCESS;
2245 }
2246