1 //-< BUGDB.CPP  >----------------------------------------------------*--------*
2 // GigaBASE                  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>"
838             "</HEAD><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><H2>" << name << "</H2><FONT SIZE=\"+1\">"
890         "<UL><LI><A HREF=\"" << con.getStub() << "?socket="
891         << con.getAddress() << "&page=createBugReportForm&myself="
892         << URL << myself << "\">Create bug report</A>";
893     if (persons->sEmailAddress[0] != '\0') {
894         con << TAG <<
895             "<LI><A HREF=\"mailto:" << persons->sEmailAddress
896             << "\">Send e-mail</A>"
897             "<LI><A HREF=\"" << con.getStub() << "?socket=" << con.getAddress()
898             << "&page=bugQueryForm&myself=" << URL << myself
899             << "\">Find a bug</A>";
900     }
901     if (strcmp(myself, name) == 0 || selfStatus == Person::isAdministrator) {
902         con << TAG << "<LI><A HREF=\"" << con.getStub() << "?socket="
903             << con.getAddress() << "&page=changePasswordForm&myself="
904             << URL << myself << "&name=" << URL << name <<
905             "\">Change password</A>";
906     }
907     con << TAG <<
908         "</UL></FONT><P><TABLE><TR><TH ALIGN=LEFT>Person name:</TH>"
909         "<TD><FORM METHOD=POST ACTION=\""
910         << con.getStub() << "\"><INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
911         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\""
912         "updatePerson\"><INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself
913         << "\"><INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
914         "<INPUT TYPE=text NAME=\"newname\" SIZE=30 VALUE=\""
915         << name << "\"><INPUT TYPE=submit VALUE=\"Change\"></FORM></TD></TR>"
916         "<TR><TH ALIGN=LEFT>E-Mail:</TH>"
917         "<TD><FORM METHOD=POST ACTION=\""
918         << con.getStub() << "\"><INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
919         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\""
920         "updatePerson\"><INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself
921         << "\"><INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
922         "<INPUT TYPE=text NAME=\"email\" SIZE=30 VALUE=\""
923         << persons->sEmailAddress << "\">"
924         "<INPUT TYPE=submit VALUE=\"Change\"></FORM></TD></TR>";
925     if (persons->status != Person::isUser) {
926         con << TAG << "<TR><TH ALIGN=LEFT>Projects:</TH>"
927             "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
928             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
929             << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
930             "VALUE=\"softwareForm\">"
931             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
932             "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
933             "<SELECT NAME=\"software\" SIZE=1>";
934         if (persons->setProjects.length() != 0) {
935             print(con, persons->setProjects);
936             con << TAG <<
937                 "</SELECT><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">"
938                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Detach\">";
939         } else {
940             con << TAG << EMPTY_LIST;
941         }
942         if (products.select() != 0) {
943             con << TAG <<
944                 "</FORM></TD></TR>"
945                 "<TR><TH ALIGN=LEFT>Attach to project:</TH>"
946                 "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
947                 "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
948                 << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
949                 "VALUE=\"attachToProject\">"
950                 "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<"\">"
951                 "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
952                 "<SELECT NAME=\"software\" SIZE=1>";
953             print(con, products);
954             con << TAG << "</SELECT><INPUT TYPE=submit VALUE=\"Attach\">";
955         }
956         con << TAG <<
957             "</FORM></TD></TR>"
958             "<TR><TH ALIGN=LEFT>Find a person:</TH>"
959             "<TD><FORM METHOD=POST ACTION=\""
960             << con.getStub() << "\">"
961             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
962             << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
963             "VALUE=\"userForm\">"
964             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
965             "<INPUT TYPE=text NAME=\"name\" SIZE=30>"
966             "<INPUT TYPE=submit VALUE=\"Find\"></FORM></TD></TR>";
967     }
968     con << TAG << "<TR><TH ALIGN=LEFT>Used software:</TH>"
969         "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
970         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
971         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
972         "VALUE=\"softwareForm\">"
973         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
974         "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
975         "<SELECT NAME=\"software\" SIZE=1>";
976     if (persons->setUsedSoftware.length() != 0) {
977         print(con, persons->setUsedSoftware);
978         con << TAG <<
979             "</SELECT><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">"
980             "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Unregister\">";
981     } else {
982         con << TAG << EMPTY_LIST;
983     }
984     if (products.select() != 0) {
985         con << TAG <<
986             "</FORM></TD></TR>"
987             "<TR><TH ALIGN=LEFT>Register as software user:</TH>"
988             "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
989             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
990             << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
991             "VALUE=\"registerSoftware\">"
992             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
993             "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
994             "<SELECT NAME=\"software\" SIZE=1>";
995         print(con, products);
996         con << TAG << "</SELECT><INPUT TYPE=submit VALUE=\"Register\">";
997     }
998     con << TAG << "</FORM></TD></TR></TABLE><P>"
999         "<B>Reported bugs:</B><BR>"
1000         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1001         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1002         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
1003         "VALUE=\"bugForm\">"
1004         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1005         "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
1006         "<SELECT NAME=\"bug\" SIZE=5>";
1007     if (persons->setReportedBugs.length() != 0) {
1008         print(con, persons->setReportedBugs);
1009         con << TAG <<
1010            "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
1011     } else {
1012         con << TAG << EMPTY_LIST;
1013     }
1014     con << TAG << "</FORM><P>";
1015     if (persons->status != Person::isUser) {
1016         con << TAG <<
1017             "<P><B>Assigned bugs:</B><BR>"
1018             "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1019             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1020             << con.getAddress() << "\"><INPUT TYPE=hidden "
1021             "NAME=\"page\" VALUE=\"bugForm\">"
1022             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1023             "<INPUT TYPE=hidden NAME=\"name\" VALUE=\"" << name << "\">"
1024             "<SELECT NAME=\"bug\" SIZE=5>";
1025         if (persons->setAssignedBugs.length() != 0) {
1026             print(con, persons->setAssignedBugs);
1027             con << TAG <<
1028                 "</SELECT><BR>"
1029                 "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">&nbsp;"
1030                 "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Deassign\">";
1031         } else {
1032             con << TAG << EMPTY_LIST;
1033         }
1034         con << TAG << "</FORM>";
1035     }
1036     if (strcmp(name, myself) == 0) {
1037         con << TAG << "</BODY></HTML>";
1038     } else {
1039         mainMenuReference(con);
1040     }
1041     return true;
1042 }
1043 
1044 
createBugReportForm(WWWconnection & con)1045 bool createBugReportForm(WWWconnection& con)
1046 {
1047     int i;
1048     sequencer.select();
1049     con << TAG <<
1050         HTML_HEAD "<TITLE>Bug</TITLE></HEAD>"
1051         BODY
1052         "<H2>Bug</H2>"
1053         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1054         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1055         << con.getAddress() << "\"><INPUT TYPE=hidden "
1056         "NAME=\"page\" VALUE=\"createBugReport\">"
1057         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\""<<con.get("myself")<<"\">"
1058         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << ++sequencer->nBugs << ">"
1059         "<TABLE><TH ALIGN=LEFT>Summary:</TH>"
1060         "<TD><INPUT TYPE=text NAME=\"summary\" SIZE=40></TD></TR>"
1061         "<TR><TH ALIGN=LEFT>Category:</TH>"
1062         "<TD><SELECT NAME=\"category\" SIZE=1>";
1063     for (i = 1; eCATEGORY_STRING[i] != NULL; i++) {
1064         con << TAG << "<OPTION SELECTED VALUE=" << i << ">"
1065             << eCATEGORY_STRING[i] << "</OPTION>";
1066     }
1067     con << TAG << "</SELECT></TD></TR>"
1068         "<TR><TH ALIGN=LEFT>Severity:</TH>"
1069         "<TD><SELECT NAME=\"severity\" SIZE=1>";
1070     for (i = 1; eSEVERITY_STRING[i] != NULL; i++) {
1071         con << TAG << "<OPTION SELECTED VALUE=" << i << ">"
1072             << eSEVERITY_STRING[i] << "</OPTION>";
1073     }
1074     con << TAG <<
1075         "</SELECT></TD></TR>"
1076         "<TR><TH ALIGN=LEFT>Priority:</TH>"
1077         "<TD><SELECT NAME=\"priority\" SIZE=1>";
1078     for (i = 1; eFIXING_PRIORITY_STRING[i] != NULL; i++) {
1079         con << TAG << "<OPTION SELECTED VALUE=" << i << ">"
1080             << eFIXING_PRIORITY_STRING[i] << "</OPTION>";
1081     }
1082     con << TAG <<
1083         "</SELECT></TD></TR>"
1084         "<TR><TH ALIGN=LEFT>Software:</TH>"
1085         "<TD><SELECT NAME=\"software\" SIZE=1>";
1086     if (products.select() != 0) {
1087         print(con, products);
1088     }
1089     con << TAG <<
1090             "</SELECT></TD></TR>"
1091             "<TR><TH ALIGN=LEFT>Version:</TH>"
1092             "<TD><INPUT TYPE=text NAME=\"version\"></TD></TR>"
1093             "<TR><TH ALIGN=LEFT>Platform:</TH>"
1094             "<TD><INPUT TYPE=text NAME=\"platform\"></TD></TR>"
1095             "<TR><TH ALIGN=LEFT>OS:</TH>"
1096             "<TD><INPUT TYPE=text NAME=\"os\"></TD></TR></TABLE><P>"
1097             "<INPUT TYPE=submit VALUE=\"Submit\">&nbsp;"
1098             "<INPUT TYPE=reset></FORM>";
1099     mainMenuReference(con);
1100     sequencer.update();
1101     return true;
1102 }
1103 
1104 bool bugForm(WWWconnection& con);
1105 
createBugReport(WWWconnection & con)1106 bool createBugReport(WWWconnection& con)
1107 {
1108     key = con.get("myself");
1109     if (persons.select(qPerson) == 0) {
1110         error(con, "Author unknown");
1111         return true;
1112     }
1113     key = con.get("software");
1114     if (products.select(qSoftware) == 0) {
1115         error(con, "No such software product");
1116         return true;
1117     }
1118     if (sscanf(con.get("version"), "%d.%d", &majorVersion, &minorVersion) != 2)
1119     {
1120         error(con, "Bad version format");
1121         return true;
1122     }
1123     initialVersion = products->pVersions;
1124     if (versions.select(qVersion) == 0) {
1125         error(con, "No such software product version");
1126         return true;
1127     }
1128 
1129     Bug bug;
1130     bug.bugId = atoi(con.get("bug"));
1131     bug.sOneLineSummary = con.get("summary");
1132     bug.eCategory = atoi(con.get("category"));
1133     bug.eFixingPriority = atoi(con.get("priority"));
1134     bug.eSeverity = atoi(con.get("severity"));
1135     bug.sOperatingSystem = con.get("os");
1136     bug.sHardwarePlatform = con.get("platform");
1137     bug.pReportedBy = persons.currentId();
1138     bug.pAssignedTo = null;
1139     bug.pSoftware = products.currentId();
1140     bug.pVersion = versions.currentId();
1141     bug.nReports = 0;
1142     insert(bug);
1143     con.addPair("action", "Select");
1144     return bugForm(con);
1145 }
1146 
bugForm(WWWconnection & con)1147 bool bugForm(WWWconnection& con)
1148 {
1149     int i;
1150     char* bugStr = con.get("bug");
1151     bugId = atoi(bugStr);
1152     if (bugs.select(qBug) == 0) {
1153         error(con, "No bug was selected");
1154         return true;
1155     }
1156     char* myself = con.get("myself");
1157     if (strcmp(con.get("action"), "Remove") == 0) {
1158         dbReference<Bug> pBug = bugs.currentId();
1159         bugId = atoi(con.get("relatedbug"));
1160         if (bugs.select(qBug) == 0) {
1161             error(con, "No such bug");
1162             return true;
1163         }
1164         int i = rindex(bugs->setSimilarBugs, pBug);
1165         if (i < 0) {
1166             error(con, "No such related bug");
1167             return true;
1168         }
1169         bugs->setSimilarBugs.remove(i);
1170         bugs.update();
1171         con.addPair("action", "Select");
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><BODY>"
1197         "<H2>Bug in " << products->sName << " v. "
1198         << versions->getVersionString() << "</H2>"
1199         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1200         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1201         << con.getAddress() << "\"><INPUT TYPE=hidden "
1202         "NAME=\"page\" VALUE=\"updateBug\">"
1203         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1204         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1205         "<TABLE><TH ALIGN=LEFT>Summary:</TH>"
1206         "<TD><INPUT TYPE=text NAME=\"summary\" SIZE=40 VALUE=\""
1207         << bugs->sOneLineSummary << "\"></TD></TR>"
1208         "<TR><TH ALIGN=LEFT>Category:</TH>"
1209         "<TD><SELECT NAME=\"category\" SIZE=1>"
1210         "<OPTION SELECTED VALUE=" << bugs->eCategory << ">"
1211         << eCATEGORY_STRING[bugs->eCategory] << "</OPTION>";
1212     for (i = 1; eCATEGORY_STRING[i] != NULL; i++) {
1213         con << TAG << "<OPTION VALUE=" << i << ">"
1214             << eCATEGORY_STRING[i] << "</OPTION>";
1215     }
1216     con << TAG <<
1217         "</SELECT></TD></TR>"
1218         "<TR><TH ALIGN=LEFT>Severity:</TH>"
1219         "<TD><SELECT NAME=\"severity\" SIZE=1>"
1220         "<OPTION SELECTED VALUE=" << bugs->eSeverity << ">"
1221         << eSEVERITY_STRING[bugs->eSeverity] << "</OPTION>";
1222     for (i = 1; eSEVERITY_STRING[i] != NULL; i++) {
1223         con << TAG << "<OPTION  VALUE=" << i << ">"
1224             << eSEVERITY_STRING[i] << "</OPTION>";
1225     }
1226     con << TAG <<
1227         "</SELECT></TD></TR>"
1228         "<TR><TH ALIGN=LEFT>Priority:</TH>"
1229         "<TD><SELECT NAME=\"priority\" SIZE=1>"
1230         "<OPTION SELECTED VALUE=" << bugs->eFixingPriority << ">"
1231         << eFIXING_PRIORITY_STRING[bugs->eFixingPriority] << "</OPTION>";
1232     for (i = 1; eFIXING_PRIORITY_STRING[i] != NULL; i++) {
1233         con << TAG << "<OPTION VALUE=" << i << ">"
1234             << eFIXING_PRIORITY_STRING[i] << "</OPTION>";
1235     }
1236     con << TAG <<
1237         "</SELECT></TD></TR>"
1238         "<TR><TH ALIGN=LEFT>Platform:</TH>"
1239         "<TD><INPUT TYPE=text NAME=\"platform\" VALUE=\""
1240         << bugs->sHardwarePlatform << "\"></TD></TR>"
1241         "<TR><TH ALIGN=LEFT>OS:</TH>"
1242         "<TD><INPUT TYPE=text NAME=\"os\"VALUE=\""
1243         << bugs->sOperatingSystem << "\"></TD></TR>"
1244         "<TR><TH ALIGN=LEFT>Assigned to:</TH>"
1245         "<TD><SELECT SIZE=1 NAME=\"name\">";
1246     if (bugs->pAssignedTo != null) {
1247         persons.at(bugs->pAssignedTo);
1248         con << TAG << "<OPTION SELECTED VALUE=\"" << persons->sName
1249             << "\">" <<  persons->sName << "</OPTION>";
1250     } else {
1251         con << TAG << "<OPTION SELECTED VALUE=\"\"></OPTION>";
1252     }
1253     print(con, products->setEngineers);
1254     con << TAG << "</SELECT></TD></TR>"
1255         "<TR><TH ALIGN=LEFT>Similar with:</TH>"
1256         "<TD><SELECT NAME=\"similar\" SIZE=1>"
1257         "<OPTION SELECTED VALUE=\"\"></OPTION>";
1258     allBugs.select();
1259     print(con, allBugs);
1260     con << TAG << "</SELECT></TD></TR></TABLE><BR>";
1261 
1262     if (personStatus != Person::isUser) {
1263         con << TAG <<
1264             "<INPUT TYPE=submit NAME=\"action\" VALUE=\"Update\">&nbsp;"
1265             "<INPUT TYPE=reset VALUE=\"Reset\">";
1266     }
1267     con << TAG << "</FORM><P><FORM METHOD=POST ACTION=\"" << con.getStub()
1268         << "\"><INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1269         << con.getAddress() << "\">"
1270         "<INPUT TYPE=hidden NAME=\"page\" VALUE=\"updateReportForm\">"
1271         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1272         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1273         "<B>Report history:</B><BR><SELECT NAME=\"report\" SIZE=5>";
1274     firstReport = bugs->pReportHistory;
1275     if (reports.select(qAllReports) != 0) {
1276         print(con, reports);
1277         con << TAG <<
1278             "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">"
1279             "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Add\">";
1280         if (personStatus == Person::isAdministrator) {
1281             con << TAG <<
1282                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
1283         }
1284     } else {
1285         con << TAG << EMPTY_LIST
1286             "<BR><INPUT TYPE=submit  NAME=\"action\" VALUE=\"Add\">";
1287     }
1288     con << TAG << "</FORM><P>";
1289 
1290     con << TAG <<
1291         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1292         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1293         << con.getAddress() << "\"><INPUT TYPE=hidden "
1294         "NAME=\"page\" VALUE=\"updateWorkAroundForm\">"
1295         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1296         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1297         "<B>Work arounds:</B><BR><SELECT NAME=\"workaround\" SIZE=5>";
1298     firstReport = bugs->pWorkArounds;
1299     if (reports.select(qAllReports) != 0) {
1300         print(con, reports);
1301         con << TAG <<
1302             "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">"
1303             "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Add\">";
1304         if (personStatus == Person::isAdministrator) {
1305             con << TAG <<
1306                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
1307         }
1308     } else {
1309         con << TAG << EMPTY_LIST
1310             "<BR><INPUT TYPE=submit  NAME=\"action\" VALUE=\"Add\">";
1311     }
1312     con << TAG << "</FORM><P>";
1313 
1314     if (bugs->setSimilarBugs.length() != 0) {
1315         con << TAG <<
1316             "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1317             "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1318             << con.getAddress() << "\"><INPUT TYPE=hidden "
1319             "NAME=\"page\" VALUE=\"bugForm\">"
1320             "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1321             "<INPUT TYPE=hidden NAME=\"relatedbug\" VALUE=" << bugStr << ">"
1322             "<B>Similar bugs:</B><BR><SELECT NAME=\"bug\" SIZE=1>";
1323         print(con, bugs->setSimilarBugs);
1324         con << TAG <<
1325             "</SELECT><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
1326         if (personStatus == Person::isAdministrator) {
1327             con << TAG <<
1328                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
1329         }
1330         con << TAG << "</FORM><P>";
1331     }
1332     con << TAG <<
1333         "</FORM><P>"
1334         "<FONT SIZE=\"+1\"><UL>";
1335     if (personStatus == Person::isUser) {
1336         if (bugs->pAssignedTo != null) {
1337             persons.at(bugs->pAssignedTo);
1338             con << TAG << "<LI>Assigned to <A HREF=\"mailto:"
1339                 << persons->sEmailAddress << "\">"
1340                 << persons->sName << "</A>";
1341         }
1342         persons.at(bugs->pReportedBy);
1343         con << TAG << "<LI>Reported by <A HREF=\"mailto:"
1344             << persons->sEmailAddress << "\">"
1345             << persons->sName << "</A></OL></FONT>";
1346     } else {
1347         if (bugs->pAssignedTo != null) {
1348             persons.at(bugs->pAssignedTo);
1349             con << TAG << "<LI>Assigned to <A HREF=\"" << con.getStub()
1350                 << "?socket=" << con.getAddress()
1351                 << "&page=userForm&myself=" << URL << myself
1352                 << "&name=" << URL << persons->sName << "\">"
1353                 << persons->sName << "</A>";
1354         }
1355         persons.at(bugs->pReportedBy);
1356         con << TAG
1357             << "<LI>Reported by <A HREF=\"" << con.getStub() << "?socket="
1358             << con.getAddress()
1359             << "&page=userForm&myself=" << URL << myself
1360             << "&name=" << URL << persons->sName << "\">"
1361             << persons->sName << "</A></OL></FONT>";
1362     }
1363     mainMenuReference(con);
1364     return true;
1365 }
1366 
updateBug(WWWconnection & con)1367 bool updateBug(WWWconnection& con)
1368 {
1369     char* bugStr = con.get("bug");
1370     bugId = atoi(bugStr);
1371     if (bugs.select(qBug) == 0) {
1372         error(con, "No such bug");
1373         return true;
1374     }
1375     char* similar = con.get("similar");
1376     if (*similar != '\0') {
1377         int id = atoi(similar);
1378         if (id != bugId) {
1379             bugId = id;
1380             if (allBugs.select(qBug) != 0) {
1381                 if (rindex(bugs->setSimilarBugs, allBugs.currentId()) < 0) {
1382                     bugs->setSimilarBugs.append(allBugs.currentId());
1383                 }
1384             }
1385         }
1386     }
1387     key = con.get("name");
1388     if (*key != '\0') {
1389         if (persons.select(qPerson) == 0 ||
1390             persons->status == Person::isUser)
1391         {
1392             error(con, "No such engineer");
1393             return true;
1394         }
1395         bugs->pAssignedTo = persons.currentId();
1396     }
1397     bugs.update();
1398     return bugForm(con);
1399 }
1400 
1401 
addReportForm(WWWconnection & con)1402 bool addReportForm(WWWconnection& con)
1403 {
1404     char* bugStr = con.get("bug");
1405     bugId = atoi(bugStr);
1406     if (bugs.select(qBug) == 0) {
1407         error(con, "No such bug");
1408         return true;
1409     }
1410     con << TAG <<
1411         HTML_HEAD "<TITLE>Bug report</TITLE></HEAD>"
1412         BODY
1413         "<H2>Bug report</H2>"
1414         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1415         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1416         << con.getAddress() << "\"><INPUT TYPE=hidden "
1417         "NAME=\"page\" VALUE=\"addReport\">"
1418         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1419         "<INPUT TYPE=hidden NAME=\"index\" VALUE=" << ++bugs->nReports
1420         << "><INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself")
1421         << "\"><B>Status: &nbsp;</B><SELECT SIZE=1 NAME=\"status\">";
1422     for (int i = 1; eSTATUS_STRING[i] != NULL; i++) {
1423         con << TAG << "<OPTION VALUE=" << i << ">" << eSTATUS_STRING[i]
1424             << "</OPTION>";
1425     }
1426     con << TAG <<
1427         "</SELECT><P>"
1428         "<B>Bug description:</B><P>"
1429         "<TEXTAREA COLS=40 ROWS=5 NAME=\"description\"></TEXTAREA><P>"
1430         "<INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
1431         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
1432     bugs.update();
1433     mainMenuReference(con);
1434     return true;
1435 }
1436 
addReport(WWWconnection & con)1437 bool addReport(WWWconnection& con)
1438 {
1439     bugId = atoi(con.get("bug"));
1440     if (bugs.select(qBug) == 0) {
1441         error(con, "No such bug");
1442         return true;
1443     }
1444     key = con.get("myself");
1445     if (persons.select(qPerson) == 0) {
1446         error(con, "No such person");
1447         return true;
1448     }
1449     reportId = atoi(con.get("index"));
1450     firstReport = bugs->pReportHistory;
1451     if (reports.select(qReport) == 0) {
1452         Report report;
1453         report.pAuthor = persons.currentId();
1454         persons->nReports += 1;
1455         report.sDescription = con.get("description");
1456         report.index = reportId;
1457         report.pNext = bugs->pReportHistory;
1458         report.status = atoi(con.get("status"));
1459         report.creationDate = dbDateTime::current();
1460         bugs->pReportHistory = insert(report);
1461         persons.update();
1462         bugs.update();
1463     }
1464     con.addPair("action", "Select");
1465     return bugForm(con);
1466 }
1467 
addWorkAroundForm(WWWconnection & con)1468 bool addWorkAroundForm(WWWconnection& con)
1469 {
1470     char* bugStr = con.get("bug");
1471     bugId = atoi(bugStr);
1472     if (bugs.select(qBug) == 0) {
1473         error(con, "No such bug");
1474         return true;
1475     }
1476     con << TAG <<
1477         HTML_HEAD "<TITLE>Work around</TITLE></HEAD>"
1478         BODY
1479         "<H2>Work around</H2>"
1480         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1481         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1482         << con.getAddress() << "\"><INPUT TYPE=hidden "
1483         "NAME=\"page\" VALUE=\"addWorkAround\">"
1484         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1485         "<INPUT TYPE=hidden NAME=\"index\" VALUE=" << ++bugs->nReports
1486         << "><INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << con.get("myself")
1487         << "\"><B>Status: &nbsp;</B><SELECT SIZE=1 NAME=\"status\">";
1488     for (int i = 1; eSTATUS_STRING[i] != NULL; i++) {
1489         con << TAG << "<OPTION VALUE=" << i << ">" << eSTATUS_STRING[i]
1490             << "</OPTION>";
1491     }
1492     con << TAG <<
1493         "</SELECT><P>"
1494         "<B>Description:</B><P>"
1495         "<TEXTAREA COLS=40 ROWS=5 NAME=\"description\"></TEXTAREA><P>"
1496         "<INPUT TYPE=submit VALUE=\"Add\">&nbsp;"
1497         "<INPUT TYPE=reset VALUE=\"Reset\"></FORM>";
1498     bugs.update();
1499     mainMenuReference(con);
1500     return true;
1501 }
1502 
addWorkAround(WWWconnection & con)1503 bool addWorkAround(WWWconnection& con)
1504 {
1505     bugId = atoi(con.get("bug"));
1506     if (bugs.select(qBug) == 0) {
1507         error(con, "No such bug");
1508         return true;
1509     }
1510     key = con.get("myself");
1511     if (persons.select(qPerson) == 0) {
1512         error(con, "No such person");
1513         return true;
1514     }
1515     reportId = atoi(con.get("index"));
1516     firstReport = bugs->pWorkArounds;
1517     if (reports.select(qReport) == 0) {
1518         Report report;
1519         report.pAuthor = persons.currentId();
1520         persons->nReports += 1;
1521         report.sDescription = con.get("description");
1522         report.index = reportId;
1523         report.pNext = bugs->pWorkArounds;
1524         report.status = atoi(con.get("status"));
1525         report.creationDate = dbDateTime::current();
1526         bugs->pWorkArounds = insert(report);
1527         persons.update();
1528         bugs.update();
1529     }
1530     con.addPair("action", "Select");
1531     return bugForm(con);
1532 }
1533 
updateReportForm(WWWconnection & con)1534 bool updateReportForm(WWWconnection& con)
1535 {
1536     if (strcmp(con.get("action"), "Add") == 0) {
1537         return addReportForm(con);
1538     }
1539     char* bugStr = con.get("bug");
1540     bugId = atoi(bugStr);
1541     if (bugs.select(qBug) == 0) {
1542         error(con, "No such bug");
1543         return true;
1544     }
1545     char* report = con.get("report");
1546     if (report == NULL) {
1547         error(con, "No report was selected");
1548         return true;
1549     }
1550     int index = atoi(report);
1551     dbReference<Report> prev, curr = null, next = bugs->pReportHistory;
1552     do  {
1553         prev = curr;
1554         if (next == null) {
1555             error(con, "No such report");
1556             return true;
1557         }
1558         reports.at(next);
1559         curr = next;
1560         next = reports->pNext;
1561     } while (reports->index != index);
1562 
1563     if (strcmp(con.get("action"), "Remove") == 0) {
1564         reports.remove();
1565         bugs->nReports -= 1;
1566         if (prev == null) {
1567             bugs->pReportHistory = next;
1568         } else {
1569             reports.at(prev);
1570             reports->pNext = next;
1571             reports.update();
1572         }
1573         bugs.update();
1574         con.addPair("action", "Select");
1575         return bugForm(con);
1576     }
1577     char date[64];
1578     reports->creationDate.asString(date, sizeof date);
1579     char* myself = con.get("myself");
1580     key = myself;
1581     if (persons.select(qPerson) == 0) {
1582         error(con, "No such person");
1583         return true;
1584     }
1585     int personStatus = persons->status;
1586     persons.at(reports->pAuthor);
1587     con << TAG <<
1588         HTML_HEAD "<TITLE>Bug report from " << date << "</TITLE></HEAD>"
1589         BODY
1590         "<H2>Bug report from " << date << "</H2>"
1591         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1592         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1593         << con.getAddress() << "\"><INPUT TYPE=hidden "
1594         "NAME=\"page\" VALUE=\"updateReport\">"
1595         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1596         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1597         "\"><INPUT TYPE=hidden NAME=\"report\" VALUE=" << index << ">"
1598         "<B>Created by ";
1599     if (personStatus == Person::isUser) {
1600         con << TAG << "<A HREF=\"mailto:"
1601             << persons->sEmailAddress << "\">"
1602             << persons->sName << "</A>";
1603     } else {
1604         con << TAG <<
1605             "<A HREF=\"" << con.getStub() << "?socket="
1606             << con.getAddress()
1607             << "&page=userForm&myself=" << URL << myself
1608             << "&name=" << URL << persons->sName << "\">"
1609             << persons->sName << "</A>";
1610     }
1611     con << TAG << "<P>Status: </B><SELECT SIZE=1 NAME=\"status\">"
1612         "<OPTION SELECTED VALUE=" << reports->status << ">"
1613         << eSTATUS_STRING[reports->status] << "</OPTION>";
1614     for (int i = 1; eSTATUS_STRING[i] != NULL; i++) {
1615         con << TAG << "<OPTION VALUE=" << i << ">" << eSTATUS_STRING[i]
1616             << "</OPTION>";
1617     }
1618     con << TAG <<
1619         "</SELECT><P>"
1620         "<B>Bug description:</B><BR>"
1621         "<TEXTAREA COLS=40 ROWS=5 NAME=\"description\">"
1622         << reports->sDescription << "</TEXTAREA><P>";
1623     if (personStatus != Person::isUser) {
1624         con << TAG <<
1625             "<INPUT TYPE=submit VALUE=\"Update\">&nbsp;"
1626             "<INPUT TYPE=reset VALUE=\"Reset\">";
1627     }
1628     con << TAG << "</FORM>";
1629     mainMenuReference(con);
1630     return true;
1631 }
1632 
updateWorkAroundForm(WWWconnection & con)1633 bool updateWorkAroundForm(WWWconnection& con)
1634 {
1635     if (strcmp(con.get("action"), "Add") == 0) {
1636         return addWorkAroundForm(con);
1637     }
1638     char* bugStr = con.get("bug");
1639     bugId = atoi(bugStr);
1640     if (bugs.select(qBug) == 0) {
1641         error(con, "No such bug");
1642         return true;
1643     }
1644     char* workaround = con.get("workaround");
1645     int index = atoi(workaround);
1646     dbReference<Report> prev, curr = null, next = bugs->pWorkArounds;
1647     do  {
1648         prev = curr;
1649         if (next == null) {
1650             error(con, "No such report");
1651             return true;
1652         }
1653         reports.at(next);
1654         curr = next;
1655         next = reports->pNext;
1656     } while (reports->index != index);
1657 
1658     if (strcmp(con.get("action"), "Remove") == 0) {
1659         reports.remove();
1660         bugs->nReports -= 1;
1661         if (prev == null) {
1662             bugs->pWorkArounds = next;
1663         } else {
1664             reports.at(prev);
1665             reports->pNext = next;
1666             reports.update();
1667         }
1668         bugs.update();
1669         con.addPair("action", "Select");
1670         return bugForm(con);
1671     }
1672     char date[64];
1673     reports->creationDate.asString(date, sizeof date);
1674     char* myself = con.get("myself");
1675     key = myself;
1676     if (persons.select(qPerson) == 0) {
1677         error(con, "No such person");
1678         return true;
1679     }
1680     int personStatus = persons->status;
1681     persons.at(reports->pAuthor);
1682     con << TAG <<
1683         HTML_HEAD "<TITLE>Work around " << date << "</TITLE></HEAD>"
1684         BODY
1685         "<H2>Work around " << date << "</H2>"
1686         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1687         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1688         << con.getAddress() << "\"><INPUT TYPE=hidden "
1689         "NAME=\"page\" VALUE=\"updateWorkAround\">"
1690         "<INPUT TYPE=hidden NAME=\"bug\" VALUE=" << bugStr << ">"
1691         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1692         "\"><INPUT TYPE=hidden NAME=\"workaround\" VALUE=" << index <<
1693         "><B>Created by ";
1694     if (personStatus == Person::isUser) {
1695         con << TAG << "<A HREF=\"mailto:"
1696             << persons->sEmailAddress << "\">"
1697             << persons->sName << "</A>";
1698     } else {
1699         con << TAG <<
1700             "<A HREF=\"" << con.getStub() << "?socket="
1701             << con.getAddress()
1702             << "&page=userForm&myself=" << URL << myself
1703             << "&name=" << URL << persons->sName << "\">"
1704             << persons->sName << "</A>";
1705     }
1706     con << TAG << "<P>Status: </B><SELECT SIZE=1 NAME=\"status\">"
1707         "<OPTION SELECTED VALUE=" << reports->status << ">"
1708         << eSTATUS_STRING[reports->status] << "</OPTION>";
1709     for (int i = 1; eSTATUS_STRING[i] != NULL; i++) {
1710         con << TAG << "<OPTION VALUE=" << i << ">" << eSTATUS_STRING[i]
1711             << "</OPTION>";
1712     }
1713     con << TAG <<
1714         "</SELECT><P>"
1715         "<B>Bug description:</B><BR>"
1716         "<TEXTAREA COLS=40 ROWS=5 NAME=\"description\">"
1717         << reports->sDescription << "</TEXTAREA><P>";
1718     if (personStatus != Person::isUser) {
1719         con << TAG <<
1720             "<INPUT TYPE=submit VALUE=\"Update\">&nbsp;"
1721             "<INPUT TYPE=reset VALUE=\"Reset\">";
1722     }
1723     con << TAG << "</FORM>";
1724     mainMenuReference(con);
1725     return true;
1726 }
1727 
updateReport(WWWconnection & con)1728 bool updateReport(WWWconnection& con)
1729 {
1730     bugId = atoi(con.get("bug"));
1731     if (bugs.select(qBug) == 0) {
1732         error(con, "No such bug");
1733         return true;
1734     }
1735     reportId = atoi(con.get("report"));
1736     firstReport = bugs->pReportHistory;
1737     if (reports.select(qReport) == 0) {
1738         error(con, "No report was selected");
1739         return true;
1740     }
1741     reports->sDescription = con.get("description");
1742     reports->status = atoi(con.get("status"));
1743     reports.update();
1744     con.addPair("action", "Select");
1745     return bugForm(con);
1746 }
1747 
updateWorkAround(WWWconnection & con)1748 bool updateWorkAround(WWWconnection& con)
1749 {
1750     bugId = atoi(con.get("bug"));
1751     if (bugs.select(qBug) == 0) {
1752         error(con, "No such bug");
1753         return true;
1754     }
1755     reportId = atoi(con.get("workaround"));
1756     firstReport = bugs->pWorkArounds;
1757     if (reports.select(qReport) == 0) {
1758         error(con, "No report was selected");
1759         return true;
1760     }
1761     reports->sDescription = con.get("description");
1762     reports->status = atoi(con.get("status"));
1763     reports.update();
1764     con.addPair("action", "Select");
1765     return bugForm(con);
1766 }
1767 
1768 
attachToProject(WWWconnection & con)1769 bool attachToProject(WWWconnection& con)
1770 {
1771     key = con.get("name");
1772     if (persons.select(qPerson) == 0 || persons->status == Person::isUser) {
1773         error(con, "No such engineer");
1774     } else {
1775         key = con.get("software");
1776         if (products.select(qSoftware) == 0) {
1777             error(con, "No such software product");
1778         } else {
1779             if (rindex(products->setEngineers, persons.currentId()) >= 0) {
1780                 error(con, "Engineer already attached to the project");
1781             } else {
1782                 products->setEngineers.append(persons.currentId());
1783                 products.update();
1784                 return userForm(con);
1785             }
1786         }
1787     }
1788     return true;
1789 }
1790 
1791 
registerSoftware(WWWconnection & con)1792 bool registerSoftware(WWWconnection& con)
1793 {
1794     key = con.get("name");
1795     if (persons.select(qPerson) == 0) {
1796         error(con, "No such person");
1797     } else {
1798         key = con.get("software");
1799         if (products.select(qSoftware) == 0) {
1800             error(con, "No such software product");
1801         } else {
1802             if (rindex(products->setUsers, persons.currentId()) >= 0) {
1803                 error(con, "User already registered this software");
1804             } else {
1805                 products->setUsers.append(persons.currentId());
1806                 products.update();
1807                 return userForm(con);
1808             }
1809         }
1810     }
1811     return true;
1812 }
1813 
1814 
softwareForm(WWWconnection & con)1815 bool softwareForm(WWWconnection& con)
1816 {
1817     char* software = con.get("software");
1818     if (software == NULL) {
1819         error(con, "No software product was selected");
1820         return true;
1821     }
1822     key = software;
1823     if (products.select(qSoftware) == 0) {
1824         error(con, "No such software product");
1825         return true;
1826     }
1827     if (strcmp(con.get("action"), "Detach") == 0) {
1828         key = con.get("name");
1829         if (persons.select(qPerson) == 0) {
1830             error(con, "No such person");
1831             return true;
1832         }
1833         int i = rindex(persons->setProjects, products.currentId());
1834         if (i < 0) {
1835             error(con, "Person was not attached to the project");
1836             return true;
1837         }
1838         persons->setProjects.remove(i);
1839         persons.update();
1840         return userForm(con);
1841     }
1842     if (strcmp(con.get("action"), "Unregister") == 0) {
1843         key = con.get("name");
1844         if (persons.select(qPerson) == 0) {
1845             error(con, "No such person");
1846             return true;
1847         }
1848         int i = rindex(persons->setUsedSoftware, products.currentId());
1849         if (i < 0) {
1850             error(con, "Person was not registered");
1851             return true;
1852         }
1853         persons->setProjects.remove(i);
1854         persons.update();
1855         return userForm(con);
1856     }
1857     char* myself = con.get("myself");
1858     key = myself;
1859     if (persons.select(qPerson) == 0) {
1860         error(con, "No such person");
1861         return true;
1862     }
1863     int personStatus = persons->status;
1864     con << TAG <<
1865         HTML_HEAD "<TITLE>" << software << "</TITLE></HEAD>"
1866         BODY
1867         "<H2>" << software << "</H2>"
1868         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1869         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
1870         << con.getAddress() << "\"><INPUT TYPE=hidden "
1871         "NAME=\"page\" VALUE=\"updateSoftware\">"
1872         "<INPUT TYPE=hidden NAME=\"software\" VALUE=\"" << software << "\">"
1873         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
1874         "<TABLE><TR><TH ALIGN=LEFT>Product name:</TH>"
1875         "<TD><INPUT TYPE=text NAME=\"newname\" VALUE=\"" << software << "\">"
1876         "</TD></TR>";
1877     if (products->pVersions != null) {
1878         versions.at(products->pVersions);
1879         con << TAG <<
1880             "<TR><TH ALIGN=LEFT>Current version:</TH>"
1881             "<TD><INPUT TYPE=text NAME=\"version\" SIZE=8 VALUE=\""
1882             << versions->getVersionString() << "\"></TD></TR>"
1883             "<TR><TH ALIGN=LEFT>Current version label:</TH>"
1884             "<TD><INPUT TYPE=text NAME=\"label\" SIZE=20 VALUE=\""
1885             << versions->sLabel << "\"></TD></TR>"
1886             "<TR><TH ALIGN=LEFT>Current version comment:</TH>"
1887             "<TD><INPUT TYPE=text NAME=\"comment\" SIZE=40 VALUE=\""
1888             << versions->sComment << "\"></TD></TR>";
1889     } else {
1890         con << TAG <<
1891             "<TR><TH ALIGN=LEFT>Current version:</TH>"
1892             "<TD><INPUT TYPE=text NAME=\"version\" SIZE=8></TD></TR>"
1893             "<TR><TH ALIGN=LEFT>Current version label:</TH>"
1894             "<TD><INPUT TYPE=text NAME=\"label\" SIZE=20></TD></TR>"
1895             "<TR><TH ALIGN=LEFT>Current version comment:</TH>"
1896             "<TD><INPUT TYPE=text NAME=\"comment\" SIZE=40></TD></TR>";
1897     }
1898     con << TAG << "</TABLE><BR>";
1899     if (personStatus != Person::isUser) {
1900         con << TAG <<
1901             "<INPUT TYPE=submit VALUE=\"Update\">&nbsp;<INPUT TYPE=reset>";
1902     }
1903     con << TAG << "</FORM><P>"
1904         "<TABLE><TR><TH ALIGN=LEFT>Engineers:</TH>"
1905         "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1906         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress()
1907         << "\"><INPUT TYPE=HIDDEN NAME=\"page\" VALUE=\"userForm\">"
1908         "<INPUT TYPE=HIDDEN NAME=\"myself\" VALUE=\"" << myself <<
1909         "\"><SELECT NAME=\"name\" SIZE=1>";
1910     if (products->setEngineers.length() != 0) {
1911         print(con, products->setEngineers);
1912         con << TAG << "</SELECT>";
1913         if (personStatus != Person::isUser) {
1914             con << TAG << "<INPUT TYPE=submit VALUE=\"Select\">";
1915         }
1916     } else {
1917         con << TAG << EMPTY_LIST;
1918     }
1919     con << TAG <<
1920         "</FORM></TD></TR>"
1921         "<TR><TH ALIGN=LEFT>Users:</TH>"
1922         "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1923         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress()
1924         << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"userForm\">"
1925         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1926         "\"><SELECT NAME=\"name\" SIZE=1>";
1927     if (products->setUsers.length() != 0) {
1928         print(con, products->setUsers);
1929         con << TAG << "</SELECT>";
1930         if (personStatus != Person::isUser) {
1931             con << TAG << "<INPUT TYPE=submit VALUE=\"Select\">";
1932         }
1933     } else {
1934         con << TAG << EMPTY_LIST;
1935     }
1936     con << TAG <<
1937         "</FORM></TD></TR>"
1938         "<TR><TH ALIGN=LEFT>Bugs:</TH>"
1939         "<TD><FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
1940         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress()
1941         << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"bugForm\">"
1942         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1943         "\"><SELECT NAME=\"bug\" SIZE=1>";
1944     if (products->setBugs.length() != 0) {
1945         print(con, products->setBugs);
1946         con << TAG <<
1947             "</SELECT><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
1948     } else {
1949         con << TAG << EMPTY_LIST;
1950     }
1951     con << TAG <<
1952         "</FORM></TD></TR>"
1953         "<TR><TH ALIGN=LEFT>Versions:</TH><TD>"
1954         "<FORM METHOD=POST ACTION=\""<<con.getStub() << "\">"
1955         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\"" << con.getAddress()
1956         << "\"><INPUT TYPE=hidden NAME=\"page\" VALUE=\"versionForm\">"
1957         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself <<
1958         "\"><INPUT TYPE=HIDDEN NAME=\"software\" VALUE=\"" << software <<
1959         "\"><SELECT NAME=\"version\" SIZE=1>";
1960     initialVersion = products->pVersions;
1961     if (versions.select(qAllVersions) != 0) {
1962         print(con, versions);
1963         con << TAG << "</SELECT><INPUT TYPE=submit VALUE=\"Select\">";
1964     } else {
1965         con << TAG << EMPTY_LIST;
1966     }
1967     con << TAG << "</FORM></TD></TR></TABLE>";
1968     mainMenuReference(con);
1969     return true;
1970 }
1971 
1972 
updateSoftware(WWWconnection & con)1973 bool updateSoftware(WWWconnection& con)
1974 {
1975     char* software = con.get("software");
1976     key = software;
1977     if (products.select(qSoftware) == 0) {
1978         error(con, "No such software product");
1979         return true;
1980     }
1981     Version version;
1982     char* currentVersion = con.get("version");
1983     version.sLabel = con.get("label");
1984     version.sComment = con.get("comment");
1985     if (sscanf(currentVersion, "%d.%d", &majorVersion, &minorVersion) != 2)
1986     {
1987         error(con, "Bad version number (MAJOR.MINOR expected)");
1988         return true;
1989     }
1990     products->sName = con.get("newname");
1991     version.majorVersionNumber = majorVersion;
1992     version.minorVersionNumber = minorVersion;
1993     version.released = dbDateTime::current();
1994     if (products->pVersions != null) {
1995         initialVersion = products->pVersions;
1996         if (versions.select(qVersion) != 0) {
1997             versions->sComment = version.sComment;
1998             versions->sLabel = version.sLabel;
1999         } else {
2000             versions.at(products->pVersions);
2001             if (versions->majorVersionNumber > majorVersion ||
2002                 (versions->majorVersionNumber == majorVersion &&
2003                  versions->minorVersionNumber > minorVersion))
2004             {
2005                 error(con, "Version number less than of current version");
2006                 return true;
2007             }
2008             version.pNext = products->pVersions;
2009             products->pVersions = insert(version);
2010         }
2011     } else {
2012         version.pNext = null;
2013         products->pVersions = insert(version);
2014     }
2015     products.update();
2016     con.addPair("name", con.get("myself"));
2017     return userForm(con);
2018 }
2019 
2020 
versionForm(WWWconnection & con)2021 bool versionForm(WWWconnection& con)
2022 {
2023     char* software = con.get("software");
2024     char* myself = con.get("myself");
2025     char  buf[64];
2026     key = software;
2027     if (products.select(qSoftware) == 0) {
2028         error(con, "No such software product");
2029         return true;
2030     }
2031     char* versionString = con.get("version");
2032     if (sscanf(versionString, "%d.%d", &majorVersion, &minorVersion) != 2) {
2033         error(con, "Bad version format");
2034         return true;
2035     }
2036     initialVersion = products->pVersions;
2037     if (versions.select(qVersion) == 0) {
2038         error(con, "No such version");
2039         return true;
2040     }
2041     key = myself;
2042     if (persons.select(qPerson) == 0) {
2043         error(con, "No such person");
2044         return true;
2045     }
2046     con << TAG <<
2047         HTML_HEAD "<TITLE>" << software << " v. " << versionString <<
2048         "</TITLE></HEAD>"
2049         BODY
2050         "<H2>"  << software << " v. " << versionString << "</H2>"
2051         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
2052         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
2053         << con.getAddress() << "\"><INPUT TYPE=hidden "
2054         "NAME=\"page\" VALUE=\"updateVersion\">"
2055         "<INPUT TYPE=hidden NAME=\"software\" VALUE=\"" << software << "\">"
2056         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
2057         "<INPUT TYPE=hidden NAME=\"version\" VALUE=\"" << versionString <<"\">"
2058         "<TABLE><TR><TH ALIGN=LEFT>Released:</TH>"
2059         "<TD>" << versions->released.asString(buf, sizeof buf) << "</TD></TR>"
2060         "<TR><TH ALIGN=LEFT>Label:</TH>"
2061         "<TD><INPUT TYPE=text NAME=\"label\" SIZE=20 VALUE=\""
2062         << versions->sLabel << "\"></TD></TR>"
2063         "<TR><TH ALIGN=LEFT>Comment:</TH>"
2064         "<TD><INPUT TYPE=text NAME=\"comment\" SIZE=40 VALUE=\""
2065         << versions->sComment << "\"></TD></TR></TABLE>";
2066     if (persons->status != Person::isUser) {
2067         con << TAG <<
2068             "<P><INPUT TYPE=submit NAME=\"action\" VALUE=\"Update\">";
2069         if (persons->status == Person::isAdministrator) {
2070             con << TAG <<
2071                 "&nbsp;<INPUT TYPE=submit NAME=\"action\" VALUE=\"Remove\">";
2072         }
2073         con << TAG << "&nbsp;<INPUT TYPE=reset>";
2074     }
2075     con << TAG << "<P></FORM>"
2076         "<B>Bugs:</B><BR>"
2077         "<FORM METHOD=POST ACTION=\"" << con.getStub() << "\">"
2078         "<INPUT TYPE=HIDDEN NAME=\"socket\" VALUE=\""
2079         << con.getAddress() << "\"><INPUT TYPE=hidden NAME=\"page\" "
2080         "VALUE=\"bugForm\">"
2081         "<INPUT TYPE=hidden NAME=\"myself\" VALUE=\"" << myself << "\">"
2082         "<SELECT NAME=\"bug\" SIZE=5>";
2083     if (versions->setBugs.length() != 0) {
2084         print(con, versions->setBugs);
2085         con << TAG <<
2086            "</SELECT><BR><INPUT TYPE=submit NAME=\"action\" VALUE=\"Select\">";
2087     } else {
2088         con << TAG << EMPTY_LIST;
2089     }
2090     con << TAG << "</FORM>";
2091     mainMenuReference(con);
2092     return true;
2093 }
2094 
updateVersion(WWWconnection & con)2095 bool updateVersion(WWWconnection& con)
2096 {
2097     char* software = con.get("software");
2098     key = software;
2099     if (products.select(qSoftware) == 0) {
2100         error(con, "No such software product");
2101         return true;
2102     }
2103     if (sscanf(con.get("version"), "%d.%d", &majorVersion, &minorVersion) != 2)
2104     {
2105         error(con, "Bad version format");
2106         return true;
2107     }
2108     if (strcmp(con.get("action"), "Remove") == 0) {
2109         dbReference<Version> prev, curr = null, next = products->pVersions;
2110         do  {
2111             prev = curr;
2112             if (next == null) {
2113                 error(con, "No such version");
2114                 return true;
2115             }
2116             versions.at(next);
2117             curr = next;
2118             next = versions->pNext;
2119         } while (versions->majorVersionNumber != majorVersion ||
2120                  versions->minorVersionNumber != minorVersion);
2121         if (versions->setBugs.length() != 0) {
2122             error(con, "Can not remove version with non-empty bugs list");
2123             return true;
2124         }
2125         versions.remove();
2126         if (prev == null) {
2127             products->pVersions = next;
2128             products.update();
2129         } else {
2130             versions.at(prev);
2131             versions->pNext = next;
2132             versions.update();
2133         }
2134         con.addPair("action", "Select");
2135         return softwareForm(con);
2136     }
2137     initialVersion = products->pVersions;
2138     if (versions.select(qVersion) == 0) {
2139         error(con, "No such version");
2140         return true;
2141     }
2142     versions->sComment = con.get("comment");
2143     versions->sLabel = con.get("label");
2144     versions.update();
2145     return versionForm(con);
2146 }
2147 
2148 WWWapi::dispatcher dispatchTable[] = {
2149     {"addUserForm", addUserForm},
2150     {"addEngineerForm", addEngineerForm},
2151     {"addSoftwareForm", addSoftwareForm},
2152     {"selectSoftwareForm", selectSoftwareForm},
2153     {"removeSoftwareForm", removeSoftwareForm},
2154     {"selectPersonForm", selectPersonForm},
2155     {"removePersonForm", removePersonForm},
2156     {"selectBugForm", selectBugForm},
2157     {"removeBugForm", removeBugForm},
2158     {"changePasswordForm", changePasswordForm},
2159     {"shutdown", shutdown},
2160     {"userForm", userForm},
2161     {"softwareForm", softwareForm},
2162     {"addUser", addUser},
2163     {"addEngineer", addEngineer},
2164     {"removePerson", removePerson},
2165     {"addSoftware", addSoftware},
2166     {"removeSoftware", removeSoftware},
2167     {"removeBug", removeBug},
2168     {"changePassword", changePassword},
2169     {"updatePerson", updatePerson},
2170     {"login", login},
2171     {"bugQueryForm", bugQueryForm},
2172     {"bugQuery", bugQuery},
2173     {"userForm", userForm},
2174     {"createBugReportForm", createBugReportForm},
2175     {"bugForm", bugForm},
2176     {"createBugReport", createBugReport},
2177     {"bugForm", bugForm},
2178     {"updateBug", updateBug},
2179     {"updateReportForm", updateReportForm},
2180     {"updateWorkAroundForm", updateWorkAroundForm},
2181     {"addReportForm", addReportForm},
2182     {"addReport", addReport},
2183     {"addWorkAroundForm", addWorkAroundForm},
2184     {"addWorkAround", addWorkAround},
2185     {"updateReport", updateReport},
2186     {"updateWorkAround", updateWorkAround},
2187     {"attachToProject", attachToProject},
2188     {"registerSoftware", registerSoftware},
2189     {"softwareForm", softwareForm},
2190     {"updateSoftware", updateSoftware},
2191     {"versionForm", versionForm},
2192     {"updateVersion", updateVersion}
2193 };
2194 
2195 #ifdef USE_EXTERNAL_HTTP_SERVER
2196 CGIapi wwwServer(db, itemsof(dispatchTable), dispatchTable);
2197 char* defaultAddress = "localhost:6101";
2198 socket_t::socket_domain domain = socket_t::sock_local_domain;
2199 #else
2200 HTTPapi wwwServer(db, itemsof(dispatchTable), dispatchTable);
2201 char* defaultAddress = "localhost:80";
2202 socket_t::socket_domain domain = socket_t::sock_global_domain;
2203 #endif
2204 
main(int argc,char * argv[])2205 int __cdecl main(int argc, char* argv[])
2206 {
2207     char* address = (argc > 1) ? argv[1] : defaultAddress;
2208     if (!wwwServer.open(address, domain)) {
2209         fprintf(stderr, "Failed to open WWW session\n");
2210         return EXIT_FAILURE;
2211     }
2212     if (!db.open("bugdb.dbs")) {
2213         fprintf(stderr, "Failed to open database\n");
2214         return EXIT_FAILURE;
2215     }
2216     qBug = "bugId=",bugId;
2217     qReport = "index=",reportId,"start from",firstReport,"follow by pNext";
2218     qAllReports = "start from",firstReport,"follow by pNext";
2219     qVersion = "majorVersionNumber=",majorVersion,"and minorVersionNumber=",
2220         minorVersion,"start from",initialVersion,"follow by pNext";
2221     qAllVersions = "start from",initialVersion,"follow by pNext";
2222     qPerson = "sName=",&key;
2223     qSoftware = "sName=",&key;
2224 
2225     if (sequencer.select() == 0) {
2226         BugSequencer seq;
2227         seq.nBugs = 0;
2228         insert(seq);
2229     }
2230     if (persons.select() == 0) {
2231         Person administrator;
2232         administrator.sName = "administrator";
2233         administrator.sEmailAddress = "root";
2234         administrator.sPassword = "";
2235         administrator.status = Person::isAdministrator;
2236         administrator.nReports = 0;
2237         insert(administrator);
2238     }
2239     WWWconnection con;
2240     while (wwwServer.connect(con) && wwwServer.serve(con));
2241     db.close();
2242     printf("End of session\n");
2243     return EXIT_SUCCESS;
2244 }
2245 
2246