68 include_once(__DIR__ .
"/spdxutils.php");
70 include_once(__DIR__ .
"/version.php");
71 include_once(__DIR__ .
"/services.php");
164 function __construct()
167 $args = getopt(
"", array(self::OUTPUT_FORMAT_KEY.
'::'));
169 if (array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)) {
176 parent::__construct(
$agentName, AGENT_VERSION, AGENT_REV);
178 $this->uploadDao = $this->container->get(
'dao.upload');
179 $this->clearingDao = $this->container->get(
'dao.clearing');
180 $this->licenseDao = $this->container->get(
'dao.license');
181 $this->
dbManager = $this->container->get(
'db.manager');
182 $this->renderer = $this->container->get(
'twig.environment');
183 $this->renderer->setCache(
false);
185 $this->agentSpecifLongOptions[] = self::UPLOAD_ADDS.
':';
186 $this->agentSpecifLongOptions[] = self::OUTPUT_FORMAT_KEY.
':';
201 if ((!array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)
202 ||
$args[self::OUTPUT_FORMAT_KEY] ===
"")
203 && array_key_exists(self::UPLOAD_ADDS,
$args)) {
206 if (!array_key_exists(self::UPLOAD_ADDS,
$args) ||
$args[self::UPLOAD_ADDS] ===
"") {
221 if (array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)) {
222 $possibleOutputFormat =
trim(
$args[self::OUTPUT_FORMAT_KEY]);
223 if (in_array($possibleOutputFormat, explode(
',',self::AVAILABLE_OUTPUT_FORMATS))) {
224 $this->outputFormat = $possibleOutputFormat;
227 $this->licenseMap =
new LicenseMap($this->
dbManager, $this->groupId, LicenseMap::REPORT,
true);
229 $docLicense = $this->licenseDao->getLicenseByShortName(self::DATA_LICENSE);
230 $docLicenseId = $docLicense->getId() .
"-" . md5($docLicense->getText());
232 ->setLicenseObj($docLicense)
233 ->setListedLicense(
true)
234 ->setCustomText(
false)
235 ->setTextPrinted(
true);
237 $additionalUploadIds = array_key_exists(self::UPLOAD_ADDS,
$args) ? explode(
',',
$args[self::UPLOAD_ADDS]) : array();
238 $packageIds = array($uploadId);
239 foreach ($additionalUploadIds as $additionalId) {
241 $packageIds[] = $additionalId;
243 $this->
writeReport($packageNodes, $packageIds, $uploadId);
254 $prefix = $this->outputFormat .
"-";
256 switch ($this->outputFormat) {
258 $postfix =
".xml" . $postfix;
264 $prefix .=
"copyright-";
269 $postfix =
".xml" . $postfix;
276 return $prefix . $partname . $postfix;
288 if ($this->filebasename ==
null) {
289 $fileName =
strtoupper($this->outputFormat).
"_".$packageName;
290 switch ($this->outputFormat) {
292 $fileName .=
".spdx.rdf";
295 $fileName .=
".spdx";
304 $fileName .=
".jsonld";
307 $fileName .=
".json";
310 $fileName .=
".spdx.rdf";
313 $fileName .=
".spdx";
316 $this->filebasename = $fileName;
329 $fileBase = $SysConf[
'FOSSOLOGY'][
'path'].
"/report/";
341 $url=$SysConf[
'SYSCONFIG'][
'FOSSologyURL'];
342 if (substr( $url, 0, 4 ) !==
"http") {
356 $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
358 $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId,$uploadTreeTableName);
361 $filesWithLicenses = $this->reportutils
362 ->getFilesWithLicensesFromClearings($itemTreeBounds, $this->groupId,
363 $this, $this->licensesInDocument);
366 $this->reportutils->addClearingStatus($filesWithLicenses,$itemTreeBounds, $this->groupId);
369 $scannerIDs = $this->reportutils->addScannerResults($filesWithLicenses, $itemTreeBounds, $this->groupId, $this->licensesInDocument);
370 $licenseComment =
"";
371 if (!empty($scannerIDs)) {
376 $this->reportutils->addCopyrightResults($filesWithLicenses, $uploadId);
379 $upload = $this->uploadDao->getUpload($uploadId);
380 $fileNodes = $this->
generateFileNodes($filesWithLicenses, $upload->getTreeTableName(), $uploadId);
382 $mainLicenseIds = $this->clearingDao->getMainLicenseIds($uploadId, $this->groupId);
383 $customMainLicenseTexts = $this->clearingDao->getMainLicenseReportInfos($uploadId, $this->groupId);
384 $mainLicenses = array();
385 foreach ($mainLicenseIds as $licId) {
386 $reportedLicenseId = $this->licenseMap->getProjectedId($licId);
387 $mainLicense = $this->licenseDao->getLicenseById($reportedLicenseId, $this->groupId);
388 if ($mainLicense ===
null) {
390 "spdx: Warning: main license ID {$reportedLicenseId} not found; skipping."
394 $customText = $customMainLicenseTexts[$licId] ??
null;
395 if (!empty($customText)) {
396 $reportLicId = $mainLicense->getId() .
"-" . md5($customText);
397 $prefix = $stateOsselot ? LicenseRef::SPDXREF_PREFIX : LicenseRef::SPDXREF_PREFIX_FOSSOLOGY;
398 $customShortName = $prefix . $mainLicense->getShortName() .
"-" . md5($customText);
400 $mainLicense->getId(),
402 $mainLicense->getFullName(),
403 $mainLicense->getRisk(),
405 $mainLicense->getUrl(),
406 $mainLicense->getDetectorType(),
410 ->setLicenseObj($customLicense)
411 ->setCustomText(
true)
412 ->setListedLicense(
false);
414 $reportLicId = $mainLicense->getId() .
"-" . md5($mainLicense->getText());
415 if (!array_key_exists($reportLicId, $this->licensesInDocument)) {
416 $listedLicense = stripos($mainLicense->getSpdxId(),
417 LicenseRef::SPDXREF_PREFIX) !== 0;
419 ->setLicenseObj($mainLicense)
420 ->setCustomText(
false)
421 ->setListedLicense($listedLicense);
424 $mainLicenses[] = $reportLicId;
426 $mainLicenseString = [];
427 if ($this->outputFormat ==
"spdx2tv" ||
428 $this->outputFormat ==
"spdx2csv" ||
429 $this->outputFormat ==
"spdx3tv") {
430 foreach ($mainLicenses as $mainLicense) {
431 $shortName = $this->licensesInDocument[$mainLicense]
432 ->getLicenseObj()->getShortName();
434 LicenseRef::SPDXREF_PREFIX)) {
435 $mainLicenseString[] = $shortName;
437 $mainLicenseString[] = $this->licensesInDocument[$mainLicense]
438 ->getLicenseObj()->getSpdxId();
441 if ($this->outputFormat ==
"spdx2tv") {
444 foreach ($mainLicenseString as $i => $licId) {
449 $mainLicenseString[$i] =
"LicenseRef-$licId";
457 $hashes = $this->uploadDao->getUploadHashes($uploadId);
459 $reportInfo = $this->uploadDao->getReportInfo($uploadId);
460 $componentId = $reportInfo[
'ri_component_id'];
461 $componentType = $reportInfo[
'ri_component_type'];
462 $componentVersion = $reportInfo[
'ri_version'];
463 $generalAssessment = $reportInfo[
'ri_general_assesment'];
464 $releaseDate = $reportInfo[
'ri_release_date'];
465 if ($componentId ==
"NA") {
468 if ($componentVersion ==
"NA") {
469 $componentVersion =
"";
471 if ($generalAssessment ==
"NA") {
472 $generalAssessment =
"";
474 if ($releaseDate ==
"NA") {
477 $timeStamp = strtotime($releaseDate);
478 if ($timeStamp != -1) {
479 $releaseDate = date(
"Y-m-d\\T00:00:00\\Z", $timeStamp);
485 $componentType =
"maven-central";
487 $componentType =
"purl";
489 if (!empty($componentType)) {
498 'packageId' => $uploadId,
500 'packageName' => $upload->getFilename(),
501 'packageVersion' => $componentVersion,
502 'releaseDate' => $releaseDate,
503 'generalAssessment' => $generalAssessment,
504 'uploadName' => $upload->getFilename(),
505 'componentType' => $componentType,
506 'componentId' => htmlspecialchars($componentId),
507 'sha1' => $hashes[
'sha1'],
508 'md5' => $hashes[
'md5'],
509 'sha256' => $hashes[
'sha256'],
511 'mainLicenses' => $mainLicenses,
512 'mainLicenseString' => $mainLicenseString,
513 'licenseComments' => $licenseComment,
514 'fileNodes' => $fileNodes,
515 'obligations' => $obligations,
516 'licenseList' => $this->licensesInDocument,
517 'EnableOsselotExport' => $stateOsselot
528 $func =
function($scannerId) use (
$agentDao)
530 return $agentDao->getAgentName($scannerId).
" (".
$agentDao->getAgentRev($scannerId).
")";
532 $scannerNames = array_map($func, $scannerIds);
533 return "licenseInfoInFile determined by Scanners:\n - ".implode(
"\n - ",$scannerNames);
546 if (!array_key_exists($licenses, $filesWithLicenses)) {
547 $filesWithLicenses[$licenses][
'files']=array();
548 $filesWithLicenses[$licenses][
'copyrights']=array();
550 if (empty($copyrights)) {
551 $copyrights = array();
553 $filesWithLicenses[$licenses][
'files'][$file] = $fullPath;
554 foreach ($copyrights as $copyright) {
555 if (!in_array($copyright, $filesWithLicenses[$licenses][
'copyrights'])) {
556 $filesWithLicenses[$licenses][
'copyrights'][] = $copyright;
569 $licensesWithFiles = array();
570 $treeDao = $this->container->get(
'dao.tree');
572 foreach ($filesWithLicenses as $fileId => $fileNode) {
573 $filesProceeded += 1;
574 if (($filesProceeded&2047)==0) {
577 $fullPath = $treeDao->getFullPath($fileId, $treeTableName, 0);
578 if (! empty($fileNode->getConcludedLicenses())) {
580 foreach ($fileNode->getConcludedLicenses() as $license) {
581 $licenses[] = $this->licensesInDocument[$license]
582 ->getLicenseObj()->getSpdxId();
587 $licenses, $fileNode->getCopyrights(), $fileId, $fullPath);
589 if (! empty($fileNode->getScanners())) {
590 $implodedLicenses = [];
591 foreach ($fileNode->getScanners() as $license) {
592 $implodedLicenses[] = $this->licensesInDocument[$license]
593 ->getLicenseObj()->getSpdxId();
597 if ($fileNode->isCleared()) {
598 $msgLicense =
"None (scanners found: " . $implodedLicenses .
")";
600 $msgLicense =
"NoLicenseConcluded (scanners found: " . $implodedLicenses .
")";
603 if ($fileNode->isCleared()) {
604 $msgLicense =
"None";
606 $msgLicense =
"NoLicenseConcluded";
610 $fileNode->getCopyrights(), $fileId, $fullPath);
613 return $licensesWithFiles;
622 $upload = $this->uploadDao->getUpload($uploadId);
623 $packageName = $upload->getFilename();
625 $this->uri = $this->
getUri($packageName);
626 $this->filename = $this->
getFileName($packageName);
635 protected function writeReport(&$packageNodes, $packageIds, $uploadId)
639 $fileBase = dirname($this->filename);
641 if (!is_dir($fileBase)) {
642 mkdir($fileBase, 0777,
true);
646 $organizationName = $SysConf[
'SYSCONFIG'][
"ReportHeaderText"] ??
'FOSSology';
647 $version = $SysConf[
'BUILD'][
'VERSION'];
649 $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
650 $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId,$uploadTreeTableName);
653 $filesWithLicenses = $this->reportutils
654 ->getFilesWithLicensesFromClearings($itemTreeBounds, $this->groupId,
655 $this, $this->licensesInDocument);
657 $upload = $this->uploadDao->getUpload($uploadId);
658 $this->
generateFileNodes($filesWithLicenses, $upload->getTreeTableName(), $uploadId);
659 $this->declaredLicenseFileIds = array_unique(array_diff($this->declaredLicenseFileIds, $this->concludedLicenseFileIds));
660 $this->concludedLicenseFileIds = array_unique($this->concludedLicenseFileIds);
661 $this->validateLicenseIdentifiers();
663 'documentName' => $fileBase,
665 'userName' => $this->container->get(
'dao.user')->getUserName($this->userId) .
" (" . $this->container->get(
'dao.user')->getUserEmail($this->userId) .
")",
666 'organisation' => $organizationName,
667 'concludedLicenseFileIds'=>$this->concludedLicenseFileIds,
668 'declaredLicenseFileIds'=>$this->declaredLicenseFileIds,
669 'toolVersion' =>
'fossology-' . $version,
670 'packageNodes' => $packageNodes,
671 'packageIds' => $packageIds,
672 'dataLicense' => $this->getSPDXDataLicense(),
673 'licenseList' => $this->licensesInDocument,
674 'EnableOsselotExport' => $stateOsselot,
680 $message = preg_replace(
'/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/',
'?',$message);
682 file_put_contents($this->filename, $message);
694 $this->reportutils->updateOrInsertReportgenEntry($uploadId,
$jobId, $fileName);
697 protected function validateLicenseIdentifiers()
700 foreach ($this->licensesInDocument as $licenseInfo) {
701 $license = $licenseInfo->getLicenseObj();
702 $spdxId = $license->getSpdxId();
703 $shortName = $license->getShortName();
705 if (!SpdxLicenseValidator::isLicenseRef($spdxId)) {
708 if (preg_match(
'/[^a-zA-Z0-9.\-\s]/', $shortName)) {
709 $idstring = SpdxLicenseValidator::extractIdstring($spdxId);
710 $fossologyPrefix = substr(LicenseRef::SPDXREF_PREFIX_FOSSOLOGY,
711 strlen(LicenseRef::SPDXREF_PREFIX));
712 if (strpos($idstring, $fossologyPrefix) === 0) {
713 $idstring = substr($idstring, strlen($fossologyPrefix));
715 $issues[] = sprintf(
" \"%s\" -> sanitized to \"%s\"",
716 $shortName, $idstring);
720 if (!empty($issues)) {
721 error_log(
"spdx: License shortnames with invalid SPDX characters were sanitized:\n"
722 . implode(
"\n", $issues));
734 return $this->renderer->load($templateName)->render($vars);
747 if (strcmp($this->outputFormat,
"dep5") !== 0) {
764 $treeDao = $this->container->get(
'dao.tree');
768 $textToBePrinted = [];
769 foreach ($filesWithLicenses as $fileId => $fileData) {
770 $filesProceeded += 1;
771 if (($filesProceeded & 2047) == 0) {
772 $this->
heartbeat($filesProceeded - $lastValue);
773 $lastValue = $filesProceeded;
775 $hashes = $treeDao->getItemHashes($fileId);
776 $fileName = $treeDao->getFullPath($fileId, $treeTableName, 0);
780 foreach ($fileData->getConcludedLicenses() as $license) {
781 $this->concludedLicenseFileIds[] = $fileId;
782 if (! $this->licensesInDocument[$license]->isTextPrinted()) {
783 $textToBePrinted[] = $license;
786 foreach ($fileData->getScanners() as $license) {
787 $this->declaredLicenseFileIds[] = $fileId;
788 if (! $this->licensesInDocument[$license]->isTextPrinted()) {
789 $textToBePrinted[] = $license;
792 $concludedLicensesString = [];
793 if ($this->outputFormat ==
"spdx2tv" ||
794 $this->outputFormat ==
"spdx2csv" ||
795 $this->outputFormat ==
"spdx3tv") {
796 foreach ($fileData->getConcludedLicenses() as $license) {
797 $shortName = $this->licensesInDocument[$license]
798 ->getLicenseObj()->getShortName();
800 LicenseRef::SPDXREF_PREFIX)) {
801 $concludedLicensesString[] = $shortName;
803 $concludedLicensesString[] = $this->licensesInDocument[$license]
804 ->getLicenseObj()->getSpdxId();
807 if ($this->outputFormat ==
"spdx2tv") {
809 foreach ($concludedLicensesString as $j => $licId) {
814 $concludedLicensesString[$j] =
"LicenseRef-$licId";
825 if (!$stateWoInfos ||
826 ($stateWoInfos && (!empty($fileData->getConcludedLicenses()) ||
827 !empty($fileData->getScanners()) || !empty($fileData->getCopyrights())))) {
828 $fileData->setAcknowledgements(
830 $fileData->setComments(
832 $dataTemplate = array(
834 'sha1' => $hashes[
'sha1'],
835 'md5' => $hashes[
'md5'],
836 'sha256' => $hashes[
'sha256'],
838 'fileName' => $fileName,
839 'fileDirName' => dirname($fileName),
840 'fileBaseName' => basename($fileName),
841 'fileData' => $fileData,
842 'licenseList' => $this->licensesInDocument,
843 'concludedLicensesString' => $concludedLicensesString,
844 'licenseCommentState' => $stateComment,
845 'EnableOsselotExport' =>$stateOsselot,
850 foreach ($textToBePrinted as $license) {
851 $this->licensesInDocument[$license]->setTextPrinted(
true);
854 $this->
heartbeat($filesProceeded - $lastValue);
872 foreach ($licensesWithFiles as $licenseId=>$entry) {
873 $filesProceeded += count($entry[
'files']);
874 if ($filesProceeded&(~2047) > $lastStep) {
875 $this->
heartbeat($filesProceeded - $lastValue);
876 $lastStep = $filesProceeded&(~2047) + 2048;
877 $lastValue = $filesProceeded;
881 if (strrpos($licenseId,
"NoLicenseConcluded (scanners found: ", -strlen($licenseId)) !==
false) {
882 $comment = substr($licenseId,20,strlen($licenseId)-21);
883 $licenseId =
"NoLicenseConcluded";
884 } elseif (strrpos($licenseId,
"None (scanners found: ", -strlen($licenseId)) !==
false) {
885 $comment = substr($licenseId,6,strlen($licenseId)-7);
890 'fileNames'=>$entry[
'files'],
891 'license'=>$licenseId,
892 'copyrights'=>$entry[
'copyrights'],
893 'comment'=>$comment));
895 $this->
heartbeat($filesProceeded - $lastValue);
911 if ($upload->getTreeTableName()==
'uploadtree_a') {
912 $sql = $upload->getTreeTableName().
' WHERE upload_fk=$1 AND';
913 $param[] = $upload->getId();
915 $sql = $upload->getTreeTableName().
' WHERE';
916 $stmt .=
'.'.$upload->getTreeTableName();
919 $sql =
"SELECT STRING_AGG(lower_sha1,'') concat_sha1 FROM
920 (SELECT LOWER(pfile_sha1) lower_sha1 FROM pfile, $sql pfile_fk=pfile_pk AND parent IS NOT NULL ORDER BY pfile_sha1) templist";
921 $filelistPack = $this->
dbManager->getSingleRow($sql,$param,$stmt);
923 return sha1($filelistPack[
'concat_sha1']);
935 $sql =
"SELECT ri_spdx_selection FROM report_info WHERE upload_fk = $1";
936 $getCommentState = $this->
dbManager->getSingleRow($sql, array($uploadId), __METHOD__.
'.SPDX_license_comment');
937 if (!empty($getCommentState[
'ri_spdx_selection'])) {
938 $getCommentStateSingle = explode(
',', $getCommentState[
'ri_spdx_selection']);
939 if ($getCommentStateSingle[$key] ===
"checked") {
953 $licenses = $this->licenseClearedGetter->getCleared($uploadId, $this,
956 $licensesMain = $this->licenseMainGetter->getCleared($uploadId, $this,
959 list($obligations, $_) = $this->obligationsGetter->getObligations(
960 $licenses[
'statements'], $licensesMain[
'statements'], $uploadId,
962 if (empty($obligations)) {
965 return array_column($obligations,
"text");
975 $dataLic = $this->licenseDao->getLicenseByShortName(self::DATA_LICENSE);
976 return $dataLic->getId() .
"-" . md5($dataLic->getText());
992 $localList = array_values($this->licensesInDocument);
1000 for ($i = 0; $i < count($localList) - 1; $i++) {
1001 if ((! $localList[$i]->isCustomText() && ! $localList[$i + 1]->isCustomText()) &&
1002 $localList[$i]->getLicenseObj()->getSpdxId() ===
1003 $localList[$i + 1]->getLicenseObj()->getSpdxId()) {
1004 $newShortName = $localList[$i + 1]->getLicenseObj()->getShortName();
1006 $localList[$i + 1]->getLicenseObj()->getShortName(),
1007 LicenseRef::SPDXREF_PREFIX)) {
1008 $newShortName = LicenseRef::SPDXREF_PREFIX .
1009 $localList[$i + 1]->getLicenseObj()->getShortName();
1010 $newShortName = preg_replace(
'/\+$/',
'-or-later', $newShortName);
1012 $md5 = md5($localList[$i + 1]->getLicenseObj()->getText());
1013 $reportedLicenseShortname =
"$newShortName-$md5";
1014 $licIndex = $localList[$i + 1]->getLicenseObj()->getId() .
"-$md5";
1015 $oldLicObj = $this->licensesInDocument[$licIndex]->getLicenseObj();
1016 $this->licensesInDocument[$licIndex]->setLicenseObj(
1017 new License($oldLicObj->getId(), $reportedLicenseShortname,
1018 $oldLicObj->getFullName(), $oldLicObj->getRisk(),
1019 $oldLicObj->getText(), $oldLicObj->getUrl(),
1020 $oldLicObj->getDetectorType(), $oldLicObj->getSpdxId()));
1026 $agent =
new SpdxAgent();
1027 $agent->scheduler_connect();
1028 $agent->run_scheduler_event_loop();
1029 $agent->scheduler_disconnect(0);
Structure of an Agent with all required parameters.
heartbeat($newProcessed)
Send hear beat to the scheduler.
Contains the constants and helpers for authentication of user.
Wrapper class for license map.
Validate and sanitize SPDX LicenseRef identifiers.
static stringStartsWith($haystack, $needle)
const DEFAULT_OUTPUT_FORMAT
Default output format.
getLicenseComment($scannerIds)
getFileName($packageName)
Get absolute path for report.
getVerificationCode(Upload $upload)
Get a unique identifier for a given upload.
getTemplateFile($partname)
Get TWIG template file based on output format.
const UPLOAD_ADDS
Argument for additional uploads.
getObligations(int $uploadId, int $groupId)
processUploadId($uploadId)
Given an upload ID, process the items in it.
const DATA_LICENSE
Data license for SPDX reports.
updateReportTable($uploadId, $jobId, $fileName)
Update the reportgen table with new report path.
preWorkOnArgs($args)
Parse arguments.
renderString($templateName, $vars)
Render a twig template.
const AVAILABLE_OUTPUT_FORMATS
Output formats available.
renderPackage($uploadId)
Given an upload id, render the report string.
getFileBasename($packageName)
Generate report basename based on upload name.
generateFileNodesByLicenses($filesWithLicenses, $treeTableName)
For each file, generate the nodes by licenses.
toLicensesWithFiles(&$filesWithLicenses, $treeTableName)
Map findings to the files.
generateFileNodes($filesWithLicenses, $treeTableName, $uploadId)
Generate report nodes for files.
getSPDXReportConf($uploadId, $key)
Get spdx license comment state for a given upload.
toLicensesWithFilesAdder(&$filesWithLicenses, $licenses, $copyrights, $file, $fullPath)
Map licenses, copyrights, files and full path to filesWithLicenses array.
generateFileNodesByFiles($filesWithLicenses, $treeTableName, $uploadId)
For each file, generate the nodes by files.
writeReport(&$packageNodes, $packageIds, $uploadId)
Write the report the file and update report table.
computeUri($uploadId)
For a given upload, compute the URI and filename for the report.
const OUTPUT_FORMAT_KEY
Argument key for output format.
getUri($packageName)
Get the URI for the given package.
deduplicateLicenseList()
De-duplicate license list by comparing licenses with the same SPDX ID.
static preWorkOnArgsFlp($args, $key1, $key2)
For a given set of arguments assign $args[$key1] and $args[$key2].
static implodeLicenses($licenses)
Implode licenses with "AND" or "OR".
static removeEmptyLicenses($licenses)
static cleanTextArray($texts)
char * trim(char *ptext)
Trimming whitespace.
int jobId
The id of the job.
fo_dbManager * dbManager
fo_dbManager object
FUNCTION char * strtoupper(char *s)
Helper function to upper case a string.
Namespace used by SPDX2 agent.