//-< BUGDB.CPP >----------------------------------------------------*--------* // GigaBASE Version 1.0 (c) 1999 GARRET * ? * // (Main Memory Database Management System) * /\| * // * / \ * // Created: 27-Mar-99 K.A. Knizhnik * / [] \ * // Last update: 30-Jun-99 K.A. Knizhnik * GARRET * //-------------------------------------------------------------------*--------* // Example of database Web publishing: Bug Tracking Database //-------------------------------------------------------------------*--------* #include "bugdb.h" //#define USE_EXTERNAL_HTTP_SERVER 1 char const* const eCATEGORY_STRING[] = { "", "CRASH", "PROGRAM_HANGS", "UI_DISPLAY", "UI_BEHAVIOR", "CALCULATION", "ERROR_HANDLING", "PERFORMANCE", "LICENSING", "INSTALLATION", "DOCUMENTATION", "ENHANCEMENT", "HOW_TO_QUESTION", NULL }; char const* const eSTATUS_STRING[] = { "", "OPENED", "FIXED", "CLOSED", "PENDING_ENGINEER", "PENDING_USER", "POSTPONED", "IRREPRODUCIBLE", "WITHDRAWN", "AS_DESIGNED", NULL }; char const* const eSEVERITY_STRING[] = { "", "FATAL", "SERIOUS", "MINOR", NULL }; char const* const eFIXING_PRIORITY_STRING[] = { "", "FIX_IMMEDIATELY", "FIX_BEFORE_NEXT_BUILD_RELEASE", "FIX_BEFORE_NEXT_MINOR_RELEASE", "FIX_BEFORE_NEXT_MAJOR_RELEASE", "FIX_IF_POSSIBLE", "OPTIONAL", NULL }; dbDatabase db; dbCursor allBugs; dbCursor bugs(dbCursorForUpdate); dbCursor reports(dbCursorForUpdate); dbCursor persons(dbCursorForUpdate); dbCursor products(dbCursorForUpdate); dbCursor versions(dbCursorForUpdate); dbCursor sequencer(dbCursorForUpdate); dbQuery qBug; dbQuery qReport; dbQuery qAllReports; dbQuery qVersion; dbQuery qAllVersions; dbQuery qPerson; dbQuery qSoftware; // // Query paramters // char* key; int bugId; int reportId; dbReference firstReport; dbReference initialVersion; int majorVersion; int minorVersion; //- Person ------------------------------------------------ void Person::print(WWWconnection& con) const { con << TAG << ""; } REGISTER(Person); //------- Version --------------------------------------- void Version::print(WWWconnection& con) const { char buf[64]; con << TAG << ""; } int Version::getVersion() const { return majorVersionNumber*100 + minorVersionNumber; } char* Version::getVersionString() const { static char buf[16]; sprintf(buf, "%d.%02d", majorVersionNumber, minorVersionNumber); return buf; } REGISTER(Version); //----- Software ------------------------------------- int Software::getLastVersion() const { if (pVersions == null) { return 0; } versions.at(pVersions); return versions->getVersion(); } char* Software::getLastVersionString() const { if (pVersions == null) { return ""; } versions.at(pVersions); return versions->getVersionString(); } void Software::print(WWWconnection& con) const { con << TAG << ""; } REGISTER(Software); //----- Report ------------------------------------------- void Report::print(WWWconnection& con) const { char buf[64]; if (pAuthor != null) { persons.at(pAuthor); con << TAG << ""; } else { con << TAG << ""; } } REGISTER(Report); //--- Bug ----------------------------------------- void Bug::print(WWWconnection& con) const { con << TAG << ""; } REGISTER(Bug); //---- BugSequencer ------------------------------------- REGISTER(BugSequencer); template void print(WWWconnection& con, dbCursor& cursor) { do { cursor->print(con); } while(cursor.next()); } template void print(WWWconnection& con, dbArray > const& arr) { dbCursor cursor; for (int i = 0, n = (int)arr.length(); i < n; i++) { cursor.at(arr[i])->print(con); } } //--- HTML specific part ------------------------------------------- #define HTML_HEAD "Content-type: text/html\r\n\r\n\ " #define BODY "" #define EMPTY_LIST "" void mainMenuReference(WWWconnection& con) { char* myself = con.get("myself"); if (myself != NULL) { con << TAG << "


Back to main menu
"; } con << TAG << ""; } void error(WWWconnection& con, char const* msg) { con << TAG << HTML_HEAD "BUGDB error" "

" << msg << "

"; mainMenuReference(con); } void message(WWWconnection& con, char const* msg) { con << TAG << HTML_HEAD "BUGDB message" "

" << msg << "

"; mainMenuReference(con); } bool addUserForm(WWWconnection& con) { con << TAG << HTML_HEAD "Enter new user" BODY "

Add user

" "
" "" "" "" "" "" "
User name:
E-mail:

" " " "

"; mainMenuReference(con); return true; } bool addEngineerForm(WWWconnection& con) { con << TAG << HTML_HEAD "Enter new engineer" BODY "

Add engineer

" "
" "" "" "" "" "" "
Engineer name:
E-mail:

" " " "

"; mainMenuReference(con); return true; } bool addSoftwareForm(WWWconnection& con) { con << TAG << HTML_HEAD "Enter new software product" BODY "

Add software product

" "
" "" "" "" "" "" "" "" "" "" "" "
Software name:
Version number:
Version label:
Version comment:

 " "

"; mainMenuReference(con); return true; } bool selectSoftwareForm(WWWconnection& con) { con << TAG << HTML_HEAD "Select software product" BODY "

Select software product

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return true; } bool removeSoftwareForm(WWWconnection& con) { con << TAG << HTML_HEAD "Remove software product" BODY "

Remove software product

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return true; } bool selectPersonForm(WWWconnection& con) { con << TAG << HTML_HEAD "Select a person" BODY "

Select a person

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return true; } bool removePersonForm(WWWconnection& con) { con << TAG << HTML_HEAD "Remove a person" BODY "

Remove a person

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return true; } bool selectBugForm(WWWconnection& con) { con << TAG << HTML_HEAD "Select a bug" BODY "

Select a bug

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return true; } bool removeBugForm(WWWconnection& con) { con << TAG << HTML_HEAD "Remove a bug" BODY "

Remove a bug

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return true; } bool changePasswordForm(WWWconnection& con) { con << TAG << HTML_HEAD "Change password" BODY "

Change password

" "
" "" "" "" "" "" "" "
New password:
Re-type password:

" " " "" "

"; con << TAG << ""; mainMenuReference(con); return true; } bool shutdown(WWWconnection& con) { con << TAG << HTML_HEAD "BUGDB message" "

BUGDB server is terminated

"; return false; } bool userForm(WWWconnection& con); bool userGroupForm(WWWconnection& con); bool softwareForm(WWWconnection& con); bool addUser(WWWconnection& con) { Person person; person.sName = key = con.get("name"); person.sEmailAddress = con.get("email"); person.sPassword = ""; person.status = Person::isUser; person.nReports = 0; if (persons.select(qPerson) != 0) { error(con, "Person already exists"); return true; } insert(person); return userForm(con); } bool addEngineer(WWWconnection& con) { Person person; person.sName = key = con.get("name"); person.sEmailAddress = con.get("email"); person.sPassword = ""; person.status = Person::isEngineer; person.nReports = 0; if (persons.select(qPerson) != 0) { error(con, "Person already exists"); return true; } insert(person); return userForm(con); } bool removePerson(WWWconnection& con) { key = con.get("name"); if (key == NULL) { error(con, "No person was selected"); return true; } if (persons.select(qPerson) == 0) { error(con, "No such person"); } else if (persons->nReports > 0 || persons->setReportedBugs.length() > 0) { error(con, "It is not possible to delete person who is author " "of existed bug reports"); } else { persons.remove(); message(con, "Person is removed"); } return true; } bool addSoftware(WWWconnection& con) { Software software; Version version; software.sName = key = con.get("software"); if (products.select(qSoftware) != 0) { error(con, "Software product already exists"); return true; } char* versionStr = con.get("version"); if (sscanf(versionStr, "%d.%d", &version.majorVersionNumber, &version.minorVersionNumber) != 2) { error(con, "Bad version number (MAJOR.MINOR expected)"); return true; } version.sComment = con.get("comment"); version.sLabel = con.get("label"); version.released = dbDateTime::current(); software.pVersions = insert(version); insert(software); con.addPair("action", "Select"); return softwareForm(con); } bool removeSoftware(WWWconnection& con) { key = con.get("software"); if (products.select(qSoftware) == 0) { error(con, "No such software product"); return true; } if (products->setBugs.length() != 0) { error(con, "Can not remove software with non-empty reported bug list"); return true; } products.remove(); message(con, "Software product is removed"); return true; } bool removeBug(WWWconnection& con) { char* bug = con.get("bug"); if (bug == NULL) { error(con, "No bug was selected"); } else { bugId = atoi(bug); if (bugs.select(qBug) == 0) { error(con, "No such bug"); } else { if (bugs->pReportHistory != null || bugs->pWorkArounds != null) { error(con, "Can not remove bug with existed reports"); return true; } bugs.remove(); message(con, "Bug is removed"); } } return true; } bool changePassword(WWWconnection& con) { char* password = con.get("password"); char* password2 = con.get("password2"); if (strcmp(password, password2) != 0) { error(con, "Passwords are not equal"); } else { key = con.get("name"); if (persons.select(qPerson) == 0) { error(con, "No such person"); } else { persons->sPassword = password; persons.update(); message(con, "Password changed"); } } return true; } bool updatePerson(WWWconnection& con) { char* name = con.get("name"); key = name; if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } else { char* newName = con.get("newname"); char* eMail = con.get("email"); if (eMail != NULL) { persons->sEmailAddress = eMail; } if (newName != NULL) { persons->sName = newName; con.addPair("name", newName); if (strcmp(name, con.get("myself")) == 0) { con.addPair("myself", newName); } } persons.update(); } return userForm(con); } bool login(WWWconnection& con) { char* name = con.get("name"); key = con.get("name"); if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } if (!persons->checkPassword(con.get("password"))) { error(con, "Incorrect password"); return true; } con.addPair("myself", name); return userForm(con); } bool bugQueryForm(WWWconnection& con) { int i; con << TAG << HTML_HEAD "Query to locate bug" BODY "

Bug query

" "
" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " to
Description substring:
Category:
Severity:
Fixing priority:
Platform:
OS
Software:
Assigned to:
Reported by:
Major version number:from " " to
Minor version number:from

" " " "" "

"; return true; } bool bugQuery(WWWconnection& con) { char* p; dbQuery query; query.reset(); p = con.get("software"); if (*p != '\0') { query.add("pSoftware.sName like").add(p); } int4 category = atoi(con.get("category")); if (category != 0) { query.And("eCategory=").add(category); } int4 severity = atoi(con.get("severity")); if (severity != 0) { query.And("eSeverity=").add(severity); } int4 priority = atoi(con.get("priority")); if (priority != 0) { query.And("eFixingPriority=").add(priority); } p = con.get("os"); if (*p != '\0') { query.And("sOperatingSystem like").add(p); } p = con.get("platform"); if (*p != '\0') { query.And("sHardwarePlatform like").add(p); } p = con.get("engineer"); if (*p != '\0') { query.And("pAssignedTo is not null and pAssignedTo.sName like").add(p); } p = con.get("user"); if (*p != '\0') { query.And("pReportedBy.sName like").add(p); } p = con.get("summary"); if (*p != '\0') { query.And("sOneLineSummary like").add(p); } p = con.get("minmajor"); int minMajorVersionNumber = (*p == '\0') ? 0 : atoi(p); p = con.get("maxmajor"); int maxMajorVersionNumber = (*p == '\0') ? INT_MAX : atoi(p); p = con.get("minminor"); int minMinorVersionNumber = (*p == '\0') ? 0 : atoi(p); p = con.get("maxminor"); int maxMinorVersionNumber = (*p == '\0') ? INT_MAX : atoi(p); if (minMajorVersionNumber != 0) { if (maxMajorVersionNumber != INT_MAX) { query.And("pVersion.majorVersionNumber between") .add(minMajorVersionNumber) .add("and").add(maxMajorVersionNumber); } else { query.And("pVersion.majorVersionNumber>=") .add(minMajorVersionNumber); } } else if (maxMajorVersionNumber != INT_MAX) { query.And("pVersion.majorVersionNumber<=").add(maxMajorVersionNumber); } if (minMinorVersionNumber != 0) { if (maxMinorVersionNumber != INT_MAX) { query.And("pVersion.minorVersionNumber between") .add(minMinorVersionNumber) .add("and").add(maxMinorVersionNumber); } else { query.And("pVersion.minorVersionNumber>=") .add(minMinorVersionNumber); } } else if (maxMinorVersionNumber != INT_MAX) { query.And("pVersion.minorVersionNumber<=").add(maxMinorVersionNumber); } con << TAG << HTML_HEAD "List of selected bugs" BODY "

Selected bugs

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return true; } bool userForm(WWWconnection& con) { char* name = con.get("name"); if (name == NULL) { error(con, "No person was selected"); return true; } char* myself = con.get("myself"); key = myself; if (persons.select(qPerson) == 0) { error(con, "Person authorization failed"); return true; } int selfStatus = persons->status; key = name; if (persons.select(qPerson) == 0) { error(con, "Person not found"); return true; } if (persons->status == Person::isAdministrator) { con << TAG << HTML_HEAD "BUGDB Administrator" "" "

Administrator menu

" "" "" ""; if (selfStatus == Person::isAdministrator) { con << TAG << ""; } con << TAG << ""; return true; } con << HTML_HEAD "" << name << "" "

" << name << "

" "

" "" "" ""; if (persons->status != Person::isUser) { con << TAG << "" "" "" "" "" ""; } con << TAG << "" "" "" "
Person name:
" "
E-Mail:
" "sEmailAddress << "\">" "
Projects:
" "" "" "" "" " "; } else { con << TAG << EMPTY_LIST; } if (products.select() != 0) { con << TAG << "
Attach to project:
" "" "" "" ""; } con << TAG << "
Find a person:
" "" "" "" "
Used software:
" "" "" "" "" " "; } else { con << TAG << EMPTY_LIST; } if (products.select() != 0) { con << TAG << "
Register as software user:
" "" "" "" ""; } con << TAG << "

" "Reported bugs:
" "

" "" "" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "

"; if (persons->status != Person::isUser) { con << TAG << "

Assigned bugs:
" "

" "" "" "" "
" " " ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; } if (strcmp(name, myself) == 0) { con << TAG << ""; } else { mainMenuReference(con); } return true; } bool createBugReportForm(WWWconnection& con) { int i; sequencer.select(); con << TAG << HTML_HEAD "Bug" BODY "

Bug

" "
" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
Summary:
Category:
Severity:
Priority:
Software:
Version:
Platform:
OS:

" " " "

"; mainMenuReference(con); sequencer.update(); return true; } bool bugForm(WWWconnection& con); bool createBugReport(WWWconnection& con) { key = con.get("myself"); if (persons.select(qPerson) == 0) { error(con, "Author unknown"); return true; } key = con.get("software"); if (products.select(qSoftware) == 0) { error(con, "No such software product"); return true; } if (sscanf(con.get("version"), "%d.%d", &majorVersion, &minorVersion) != 2) { error(con, "Bad version format"); return true; } initialVersion = products->pVersions; if (versions.select(qVersion) == 0) { error(con, "No such software product version"); return true; } Bug bug; bug.bugId = atoi(con.get("bug")); bug.sOneLineSummary = con.get("summary"); bug.eCategory = atoi(con.get("category")); bug.eFixingPriority = atoi(con.get("priority")); bug.eSeverity = atoi(con.get("severity")); bug.sOperatingSystem = con.get("os"); bug.sHardwarePlatform = con.get("platform"); bug.pReportedBy = persons.currentId(); bug.pAssignedTo = null; bug.pSoftware = products.currentId(); bug.pVersion = versions.currentId(); bug.nReports = 0; insert(bug); con.addPair("action", "Select"); return bugForm(con); } bool bugForm(WWWconnection& con) { int i; char* bugStr = con.get("bug"); bugId = atoi(bugStr); if (bugs.select(qBug) == 0) { error(con, "No bug was selected"); return true; } char* myself = con.get("myself"); if (strcmp(con.get("action"), "Remove") == 0) { dbReference pBug = bugs.currentId(); bugId = atoi(con.get("relatedbug")); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } int i = rindex(bugs->setSimilarBugs, pBug); if (i < 0) { error(con, "No such related bug"); return true; } bugs->setSimilarBugs.remove(i); bugs.update(); con.addPair("action", "Select"); return bugForm(con); } key = myself; if (persons.select(qPerson) == 0) { error(con, "No such user"); return true; } if (strcmp(con.get("action"), "Deassign") == 0) { int i = rindex(persons->setAssignedBugs, bugs.currentId()); if (i < 0) { error(con, "Bug was not assigned"); return true; } persons->setAssignedBugs.remove(i); persons.update(); con.addPair("name", myself); return userForm(con); } int personStatus = persons->status; products.at(bugs->pSoftware); versions.at(bugs->pVersion); con << TAG << HTML_HEAD "Bug in " << products->sName << " v. " << versions->getVersionString() << "" "

Bug in " << products->sName << " v. " << versions->getVersionString() << "

" "
" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
Summary:sOneLineSummary << "\">
Category:
Severity:
Priority:
Platform:sHardwarePlatform << "\">
OS:sOperatingSystem << "\">
Assigned to:
Similar with:

"; if (personStatus != Person::isUser) { con << TAG << " " ""; } con << TAG << "

" "" "" "" "Report history:

" " "; if (personStatus == Person::isAdministrator) { con << TAG << " "; } } else { con << TAG << EMPTY_LIST "
"; } con << TAG << "

"; con << TAG << "

" "" "" "" "Work arounds:

" " "; if (personStatus == Person::isAdministrator) { con << TAG << " "; } } else { con << TAG << EMPTY_LIST "
"; } con << TAG << "

"; if (bugs->setSimilarBugs.length() != 0) { con << TAG << "

" "" "" "" "Similar bugs:
"; if (personStatus == Person::isAdministrator) { con << TAG << " "; } con << TAG << "

"; } con << TAG << "

" "

    "; if (personStatus == Person::isUser) { if (bugs->pAssignedTo != null) { persons.at(bugs->pAssignedTo); con << TAG << "
  • Assigned to sEmailAddress << "\">" << persons->sName << ""; } persons.at(bugs->pReportedBy); con << TAG << "
  • Reported by sEmailAddress << "\">" << persons->sName << ""; } else { if (bugs->pAssignedTo != null) { persons.at(bugs->pAssignedTo); con << TAG << "
  • Assigned to " << persons->sName << ""; } persons.at(bugs->pReportedBy); con << TAG << "
  • Reported by " << persons->sName << ""; } mainMenuReference(con); return true; } bool updateBug(WWWconnection& con) { char* bugStr = con.get("bug"); bugId = atoi(bugStr); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } char* similar = con.get("similar"); if (*similar != '\0') { int id = atoi(similar); if (id != bugId) { bugId = id; if (allBugs.select(qBug) != 0) { if (rindex(bugs->setSimilarBugs, allBugs.currentId()) < 0) { bugs->setSimilarBugs.append(allBugs.currentId()); } } } } key = con.get("name"); if (*key != '\0') { if (persons.select(qPerson) == 0 || persons->status == Person::isUser) { error(con, "No such engineer"); return true; } bugs->pAssignedTo = persons.currentId(); } bugs.update(); return bugForm(con); } bool addReportForm(WWWconnection& con) { char* bugStr = con.get("bug"); bugId = atoi(bugStr); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } con << TAG << HTML_HEAD "Bug report" BODY "

    Bug report

    " "
    " "" "" "Status:  

    " "Bug description:

    " "

    " " " "

    "; bugs.update(); mainMenuReference(con); return true; } bool addReport(WWWconnection& con) { bugId = atoi(con.get("bug")); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } key = con.get("myself"); if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } reportId = atoi(con.get("index")); firstReport = bugs->pReportHistory; if (reports.select(qReport) == 0) { Report report; report.pAuthor = persons.currentId(); persons->nReports += 1; report.sDescription = con.get("description"); report.index = reportId; report.pNext = bugs->pReportHistory; report.status = atoi(con.get("status")); report.creationDate = dbDateTime::current(); bugs->pReportHistory = insert(report); persons.update(); bugs.update(); } con.addPair("action", "Select"); return bugForm(con); } bool addWorkAroundForm(WWWconnection& con) { char* bugStr = con.get("bug"); bugId = atoi(bugStr); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } con << TAG << HTML_HEAD "Work around" BODY "

    Work around

    " "
    " "" "" "Status:  

    " "Description:

    " "

    " " " "

    "; bugs.update(); mainMenuReference(con); return true; } bool addWorkAround(WWWconnection& con) { bugId = atoi(con.get("bug")); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } key = con.get("myself"); if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } reportId = atoi(con.get("index")); firstReport = bugs->pWorkArounds; if (reports.select(qReport) == 0) { Report report; report.pAuthor = persons.currentId(); persons->nReports += 1; report.sDescription = con.get("description"); report.index = reportId; report.pNext = bugs->pWorkArounds; report.status = atoi(con.get("status")); report.creationDate = dbDateTime::current(); bugs->pWorkArounds = insert(report); persons.update(); bugs.update(); } con.addPair("action", "Select"); return bugForm(con); } bool updateReportForm(WWWconnection& con) { if (strcmp(con.get("action"), "Add") == 0) { return addReportForm(con); } char* bugStr = con.get("bug"); bugId = atoi(bugStr); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } char* report = con.get("report"); if (report == NULL) { error(con, "No report was selected"); return true; } int index = atoi(report); dbReference prev, curr = null, next = bugs->pReportHistory; do { prev = curr; if (next == null) { error(con, "No such report"); return true; } reports.at(next); curr = next; next = reports->pNext; } while (reports->index != index); if (strcmp(con.get("action"), "Remove") == 0) { reports.remove(); bugs->nReports -= 1; if (prev == null) { bugs->pReportHistory = next; } else { reports.at(prev); reports->pNext = next; reports.update(); } bugs.update(); con.addPair("action", "Select"); return bugForm(con); } char date[64]; reports->creationDate.asString(date, sizeof date); char* myself = con.get("myself"); key = myself; if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } int personStatus = persons->status; persons.at(reports->pAuthor); con << TAG << HTML_HEAD "Bug report from " << date << "" BODY "

    Bug report from " << date << "

    " "
    " "" "" "" "Created by "; if (personStatus == Person::isUser) { con << TAG << "sEmailAddress << "\">" << persons->sName << ""; } else { con << TAG << "" << persons->sName << ""; } con << TAG << "

    Status:

    " "Bug description:
    " "

    "; if (personStatus != Person::isUser) { con << TAG << " " ""; } con << TAG << "

    "; mainMenuReference(con); return true; } bool updateWorkAroundForm(WWWconnection& con) { if (strcmp(con.get("action"), "Add") == 0) { return addWorkAroundForm(con); } char* bugStr = con.get("bug"); bugId = atoi(bugStr); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } char* workaround = con.get("workaround"); int index = atoi(workaround); dbReference prev, curr = null, next = bugs->pWorkArounds; do { prev = curr; if (next == null) { error(con, "No such report"); return true; } reports.at(next); curr = next; next = reports->pNext; } while (reports->index != index); if (strcmp(con.get("action"), "Remove") == 0) { reports.remove(); bugs->nReports -= 1; if (prev == null) { bugs->pWorkArounds = next; } else { reports.at(prev); reports->pNext = next; reports.update(); } bugs.update(); con.addPair("action", "Select"); return bugForm(con); } char date[64]; reports->creationDate.asString(date, sizeof date); char* myself = con.get("myself"); key = myself; if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } int personStatus = persons->status; persons.at(reports->pAuthor); con << TAG << HTML_HEAD "Work around " << date << "" BODY "

    Work around " << date << "

    " "
    " "" "" "Created by "; if (personStatus == Person::isUser) { con << TAG << "sEmailAddress << "\">" << persons->sName << ""; } else { con << TAG << "" << persons->sName << ""; } con << TAG << "

    Status:

    " "Bug description:
    " "

    "; if (personStatus != Person::isUser) { con << TAG << " " ""; } con << TAG << "

    "; mainMenuReference(con); return true; } bool updateReport(WWWconnection& con) { bugId = atoi(con.get("bug")); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } reportId = atoi(con.get("report")); firstReport = bugs->pReportHistory; if (reports.select(qReport) == 0) { error(con, "No report was selected"); return true; } reports->sDescription = con.get("description"); reports->status = atoi(con.get("status")); reports.update(); con.addPair("action", "Select"); return bugForm(con); } bool updateWorkAround(WWWconnection& con) { bugId = atoi(con.get("bug")); if (bugs.select(qBug) == 0) { error(con, "No such bug"); return true; } reportId = atoi(con.get("workaround")); firstReport = bugs->pWorkArounds; if (reports.select(qReport) == 0) { error(con, "No report was selected"); return true; } reports->sDescription = con.get("description"); reports->status = atoi(con.get("status")); reports.update(); con.addPair("action", "Select"); return bugForm(con); } bool attachToProject(WWWconnection& con) { key = con.get("name"); if (persons.select(qPerson) == 0 || persons->status == Person::isUser) { error(con, "No such engineer"); } else { key = con.get("software"); if (products.select(qSoftware) == 0) { error(con, "No such software product"); } else { if (rindex(products->setEngineers, persons.currentId()) >= 0) { error(con, "Engineer already attached to the project"); } else { products->setEngineers.append(persons.currentId()); products.update(); return userForm(con); } } } return true; } bool registerSoftware(WWWconnection& con) { key = con.get("name"); if (persons.select(qPerson) == 0) { error(con, "No such person"); } else { key = con.get("software"); if (products.select(qSoftware) == 0) { error(con, "No such software product"); } else { if (rindex(products->setUsers, persons.currentId()) >= 0) { error(con, "User already registered this software"); } else { products->setUsers.append(persons.currentId()); products.update(); return userForm(con); } } } return true; } bool softwareForm(WWWconnection& con) { char* software = con.get("software"); if (software == NULL) { error(con, "No software product was selected"); return true; } key = software; if (products.select(qSoftware) == 0) { error(con, "No such software product"); return true; } if (strcmp(con.get("action"), "Detach") == 0) { key = con.get("name"); if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } int i = rindex(persons->setProjects, products.currentId()); if (i < 0) { error(con, "Person was not attached to the project"); return true; } persons->setProjects.remove(i); persons.update(); return userForm(con); } if (strcmp(con.get("action"), "Unregister") == 0) { key = con.get("name"); if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } int i = rindex(persons->setUsedSoftware, products.currentId()); if (i < 0) { error(con, "Person was not registered"); return true; } persons->setProjects.remove(i); persons.update(); return userForm(con); } char* myself = con.get("myself"); key = myself; if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } int personStatus = persons->status; con << TAG << HTML_HEAD "" << software << "" BODY "

    " << software << "

    " "
    " "" "" "" "" ""; if (products->pVersions != null) { versions.at(products->pVersions); con << TAG << "" "" "" "" "" ""; } else { con << TAG << "" "" "" "" "" ""; } con << TAG << "
    Product name:" "
    Current version:getVersionString() << "\">
    Current version label:sLabel << "\">
    Current version comment:sComment << "\">
    Current version:
    Current version label:
    Current version comment:

    "; if (personStatus != Person::isUser) { con << TAG << " "; } con << TAG << "

    " "" "" "" "" "" "" "
    Engineers:
    " "" ""; if (personStatus != Person::isUser) { con << TAG << ""; } } else { con << TAG << EMPTY_LIST; } con << TAG << "
    Users:
    " "" ""; if (personStatus != Person::isUser) { con << TAG << ""; } } else { con << TAG << EMPTY_LIST; } con << TAG << "
    Bugs:
    " "" ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "
    Versions:" "
    " "" ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "
    "; mainMenuReference(con); return true; } bool updateSoftware(WWWconnection& con) { char* software = con.get("software"); key = software; if (products.select(qSoftware) == 0) { error(con, "No such software product"); return true; } Version version; char* currentVersion = con.get("version"); version.sLabel = con.get("label"); version.sComment = con.get("comment"); if (sscanf(currentVersion, "%d.%d", &majorVersion, &minorVersion) != 2) { error(con, "Bad version number (MAJOR.MINOR expected)"); return true; } products->sName = con.get("newname"); version.majorVersionNumber = majorVersion; version.minorVersionNumber = minorVersion; version.released = dbDateTime::current(); if (products->pVersions != null) { initialVersion = products->pVersions; if (versions.select(qVersion) != 0) { versions->sComment = version.sComment; versions->sLabel = version.sLabel; } else { versions.at(products->pVersions); if (versions->majorVersionNumber > majorVersion || (versions->majorVersionNumber == majorVersion && versions->minorVersionNumber > minorVersion)) { error(con, "Version number less than of current version"); return true; } version.pNext = products->pVersions; products->pVersions = insert(version); } } else { version.pNext = null; products->pVersions = insert(version); } products.update(); con.addPair("name", con.get("myself")); return userForm(con); } bool versionForm(WWWconnection& con) { char* software = con.get("software"); char* myself = con.get("myself"); char buf[64]; key = software; if (products.select(qSoftware) == 0) { error(con, "No such software product"); return true; } char* versionString = con.get("version"); if (sscanf(versionString, "%d.%d", &majorVersion, &minorVersion) != 2) { error(con, "Bad version format"); return true; } initialVersion = products->pVersions; if (versions.select(qVersion) == 0) { error(con, "No such version"); return true; } key = myself; if (persons.select(qPerson) == 0) { error(con, "No such person"); return true; } con << TAG << HTML_HEAD "" << software << " v. " << versionString << "" BODY "

    " << software << " v. " << versionString << "

    " "
    " "" "" "" "" "" "" "" "" "" "
    Released:" << versions->released.asString(buf, sizeof buf) << "
    Label:sLabel << "\">
    Comment:sComment << "\">
    "; if (persons->status != Person::isUser) { con << TAG << "

    "; if (persons->status == Person::isAdministrator) { con << TAG << " "; } con << TAG << " "; } con << TAG << "

    " "Bugs:
    " "
    " "" "" "
    "; } else { con << TAG << EMPTY_LIST; } con << TAG << "
    "; mainMenuReference(con); return true; } bool updateVersion(WWWconnection& con) { char* software = con.get("software"); key = software; if (products.select(qSoftware) == 0) { error(con, "No such software product"); return true; } if (sscanf(con.get("version"), "%d.%d", &majorVersion, &minorVersion) != 2) { error(con, "Bad version format"); return true; } if (strcmp(con.get("action"), "Remove") == 0) { dbReference prev, curr = null, next = products->pVersions; do { prev = curr; if (next == null) { error(con, "No such version"); return true; } versions.at(next); curr = next; next = versions->pNext; } while (versions->majorVersionNumber != majorVersion || versions->minorVersionNumber != minorVersion); if (versions->setBugs.length() != 0) { error(con, "Can not remove version with non-empty bugs list"); return true; } versions.remove(); if (prev == null) { products->pVersions = next; products.update(); } else { versions.at(prev); versions->pNext = next; versions.update(); } con.addPair("action", "Select"); return softwareForm(con); } initialVersion = products->pVersions; if (versions.select(qVersion) == 0) { error(con, "No such version"); return true; } versions->sComment = con.get("comment"); versions->sLabel = con.get("label"); versions.update(); return versionForm(con); } WWWapi::dispatcher dispatchTable[] = { {"addUserForm", addUserForm}, {"addEngineerForm", addEngineerForm}, {"addSoftwareForm", addSoftwareForm}, {"selectSoftwareForm", selectSoftwareForm}, {"removeSoftwareForm", removeSoftwareForm}, {"selectPersonForm", selectPersonForm}, {"removePersonForm", removePersonForm}, {"selectBugForm", selectBugForm}, {"removeBugForm", removeBugForm}, {"changePasswordForm", changePasswordForm}, {"shutdown", shutdown}, {"userForm", userForm}, {"softwareForm", softwareForm}, {"addUser", addUser}, {"addEngineer", addEngineer}, {"removePerson", removePerson}, {"addSoftware", addSoftware}, {"removeSoftware", removeSoftware}, {"removeBug", removeBug}, {"changePassword", changePassword}, {"updatePerson", updatePerson}, {"login", login}, {"bugQueryForm", bugQueryForm}, {"bugQuery", bugQuery}, {"userForm", userForm}, {"createBugReportForm", createBugReportForm}, {"bugForm", bugForm}, {"createBugReport", createBugReport}, {"bugForm", bugForm}, {"updateBug", updateBug}, {"updateReportForm", updateReportForm}, {"updateWorkAroundForm", updateWorkAroundForm}, {"addReportForm", addReportForm}, {"addReport", addReport}, {"addWorkAroundForm", addWorkAroundForm}, {"addWorkAround", addWorkAround}, {"updateReport", updateReport}, {"updateWorkAround", updateWorkAround}, {"attachToProject", attachToProject}, {"registerSoftware", registerSoftware}, {"softwareForm", softwareForm}, {"updateSoftware", updateSoftware}, {"versionForm", versionForm}, {"updateVersion", updateVersion} }; #ifdef USE_EXTERNAL_HTTP_SERVER CGIapi wwwServer(db, itemsof(dispatchTable), dispatchTable); char* defaultAddress = "localhost:6101"; socket_t::socket_domain domain = socket_t::sock_local_domain; #else HTTPapi wwwServer(db, itemsof(dispatchTable), dispatchTable); char* defaultAddress = "localhost:80"; socket_t::socket_domain domain = socket_t::sock_global_domain; #endif int __cdecl main(int argc, char* argv[]) { char* address = (argc > 1) ? argv[1] : defaultAddress; if (!wwwServer.open(address, domain)) { fprintf(stderr, "Failed to open WWW session\n"); return EXIT_FAILURE; } if (!db.open("bugdb.dbs")) { fprintf(stderr, "Failed to open database\n"); return EXIT_FAILURE; } qBug = "bugId=",bugId; qReport = "index=",reportId,"start from",firstReport,"follow by pNext"; qAllReports = "start from",firstReport,"follow by pNext"; qVersion = "majorVersionNumber=",majorVersion,"and minorVersionNumber=", minorVersion,"start from",initialVersion,"follow by pNext"; qAllVersions = "start from",initialVersion,"follow by pNext"; qPerson = "sName=",&key; qSoftware = "sName=",&key; if (sequencer.select() == 0) { BugSequencer seq; seq.nBugs = 0; insert(seq); } if (persons.select() == 0) { Person administrator; administrator.sName = "administrator"; administrator.sEmailAddress = "root"; administrator.sPassword = ""; administrator.status = Person::isAdministrator; administrator.nReports = 0; insert(administrator); } WWWconnection con; while (wwwServer.connect(con) && wwwServer.serve(con)); db.close(); printf("End of session\n"); return EXIT_SUCCESS; }