1 /*---------------------------------------------------------------------------- 2 -- 3 -- Module: xtmDbTools 4 -- 5 -- Project: Xdiary 6 -- System: xtm - X Desktop Calendar 7 -- Subsystem: <> 8 -- Function block: <> 9 -- 10 -- Description: 11 -- Interface to the database containing: 12 -- * Entries. 13 -- * Entries defined for a day. 14 -- * Standing entries. 15 -- * Private entries. 16 -- 17 -- Filename: xtmDbTools.c 18 -- 19 -- Authors: Roger Larsson, Ulrika Bornetun 20 -- Creation date: 1991-05-28 21 -- 22 -- 23 -- (C) Copyright Ulrika Bornetun, Roger Larsson (1995) 24 -- All rights reserved 25 -- 26 -- Permission to use, copy, modify, and distribute this software and its 27 -- documentation for any purpose and without fee is hereby granted, 28 -- provided that the above copyright notice appear in all copies. Ulrika 29 -- Bornetun and Roger Larsson make no representations about the usability 30 -- of this software for any purpose. It is provided "as is" without express 31 -- or implied warranty. 32 ----------------------------------------------------------------------------*/ 33 34 /* SCCS module identifier. */ 35 static char SCCSID[] = "@(#) Module: xtmDbTools.c, Version: 1.4, Date: 95/06/26 22:27:30"; 36 37 38 /*---------------------------------------------------------------------------- 39 -- Include files 40 ----------------------------------------------------------------------------*/ 41 42 /* netinet/in.h doesn't compile with _POSIX_SOURCE on some platforms. */ 43 #ifdef _POSIX_SOURCE 44 #undef _POSIX_SOURCE 45 #define HAD_POSIX 46 #endif 47 48 #include <fcntl.h> 49 #include <stdio.h> 50 #include <unistd.h> 51 #include <ctype.h> 52 #include <sys/stat.h> 53 #include <sys/types.h> 54 55 #include <X11/Intrinsic.h> 56 57 #include "System.h" 58 #include "DirList.h" 59 60 #include "xtmGlobal.h" 61 #include "xtmAccBase.h" 62 #include "xtmDbTools.h" 63 #include "xtmHoliday.h" 64 65 #ifndef XD_NO_NET_ORDER 66 # define NET_BYTE_ORDER 1 67 #endif 68 69 #ifdef NET_BYTE_ORDER 70 #include <netinet/in.h> 71 #endif 72 73 #ifdef HAD_POSIX 74 #ifndef _POSIX_SOURCE 75 #define _POSIX_SOURCE 76 #endif 77 #endif 78 79 80 /*---------------------------------------------------------------------------- 81 -- Macro definitions 82 ----------------------------------------------------------------------------*/ 83 84 /* Try to lock a file this number of times. */ 85 #define MAX_LOCK_TRIES 20 86 87 /* Number of cached db operations records. */ 88 #define MAX_DB_OP_CACHE 1 89 90 /* Access control file. */ 91 #define ACCESS_FILE "dbAccess" 92 93 /* Key for access control file. */ 94 #define KEY_ACCESS_CONTROL "Access" 95 96 /* Exception handling. */ 97 #define raise goto 98 99 100 /*---------------------------------------------------------------------------- 101 -- Type declarations 102 ----------------------------------------------------------------------------*/ 103 104 /* Operations allowed on a database. */ 105 typedef struct { 106 char directory[ 150 ]; 107 UINT32 operations; 108 } DB_OPERATIONS; 109 110 111 /*---------------------------------------------------------------------------- 112 -- Global definitions 113 ----------------------------------------------------------------------------*/ 114 115 /* Name of module. */ 116 static char *module_name = "xtmDbTools"; 117 118 /* Size of the entry key and record. */ 119 static int xtm_db_entry_def_size = 170; 120 static int xtm_db_entry_key_size = 4; 121 122 /* Size of the date key and record. */ 123 static int xtm_db_date_def_size = 256; 124 static int xtm_db_date_key_size = 4; 125 126 /* Size of the standing entry key and record. */ 127 static int xtm_db_stand_entry_def_size = 48; 128 static int xtm_db_stand_entry_key_size = 4; 129 130 /* Size of the private entry key and record. */ 131 static int xtm_db_priv_entry_def_size = 110; 132 static int xtm_db_priv_entry_key_size = 4; 133 134 /* Use file locking? */ 135 static Boolean use_lock = True; 136 137 /* Real an privileged process IDs. */ 138 static int real_gid = -1; 139 static int privileged_gid = -1; 140 141 /* Name of key and data files. */ 142 static char *db_filenames[] = { 143 ENTRY_DB_NAME, 144 ENTRY_DB_NAME_DIR, 145 ENTRY_DB_NAME_PAG, 146 DATE_DB_NAME, 147 DATE_DB_NAME_DIR, 148 DATE_DB_NAME_PAG, 149 STAND_ENTRY_DB_NAME, 150 STAND_ENTRY_DB_NAME_DIR, 151 STAND_ENTRY_DB_NAME_PAG, 152 PRIV_ENTRY_DB_NAME, 153 PRIV_ENTRY_DB_NAME_DIR, 154 PRIV_ENTRY_DB_NAME_PAG, 155 }; 156 157 /* Cache to hold operations allowed on a database. */ 158 static Boolean cache_valid = False; 159 static DB_OPERATIONS db_op_cache[ MAX_DB_OP_CACHE ]; 160 161 162 /*---------------------------------------------------------------------------- 163 -- Function prototypes 164 ----------------------------------------------------------------------------*/ 165 166 static INT32 167 calcCrc( char *text ); 168 169 static XTM_DB_STATUS 170 closeDatabase( XTM_DB_DATABASE database ); 171 172 static XTM_DB_STATUS 173 createFileLock( char *filename, 174 UINT32 operations, 175 int *lock_fd, 176 int *uid_locking ); 177 178 static LST_COMPARE 179 dateSortFunc( XTM_DB_DATE_DEF *element, TIM_TIME_REF date ); 180 181 static XTM_DB_STATUS 182 deleteDate( XTM_DB_DATABASE database, 183 TIM_TIME_REF date ); 184 185 static XTM_DB_STATUS 186 deleteEntry( XTM_DB_DATABASE database, 187 UINT32 id ); 188 189 static XTM_DB_STATUS 190 deleteEntryIdInDate( XTM_DB_DATABASE database_ref, 191 UINT32 entry_id, 192 TIM_TIME_REF date_stamp ); 193 194 static XTM_DB_STATUS 195 deletePrivData( XTM_DB_ENTRY_DATABASES *databases, 196 XTM_DB_ALL_ENTRY_REF entry_ref ); 197 198 static XTM_DB_STATUS 199 deletePrivDb( XTM_DB_ENTRY_DATABASES *databases, 200 UINT32 id ); 201 202 static XTM_DB_STATUS 203 deletePrivText( XTM_DB_ENTRY_DATABASES *databases, 204 UINT32 id ); 205 206 static XTM_DB_STATUS 207 deleteStandEntry( XTM_DB_DATABASE database, 208 UINT32 id ); 209 210 static XTM_DB_STATUS 211 deleteTextFile( char *directory, 212 UINT32 id ); 213 214 static XTM_DB_STATUS 215 doInsertEntry( XTM_DB_ENTRY_DATABASES *databases, 216 XTM_DB_ALL_ENTRY_REF entry_ref, 217 char *text_ref, 218 UINT32 log_flags ); 219 220 static LST_COMPARE 221 entryIdSortFunc( XTM_DB_ENTRY_DEF *element, UINT32 id ); 222 223 static LST_COMPARE 224 entryTimeSortFunc( XTM_DB_ENTRY_DEF *element, TIM_TIME_REF date ); 225 226 static XTM_DB_STATUS 227 fetchDate( XTM_DB_DATABASE database, 228 TIM_TIME_REF date, 229 XTM_DB_DATE_REF entry ); 230 231 static XTM_DB_STATUS 232 fetchEntry( XTM_DB_DATABASE database, 233 UINT32 id, 234 XTM_DB_ENTRY_REF entry ); 235 236 static XTM_DB_STATUS 237 fetchFirstDate( XTM_DB_DATABASE database, 238 XTM_DB_DATE_REF entry ); 239 240 static XTM_DB_STATUS 241 fetchFirstStand( XTM_DB_DATABASE database, 242 XTM_DB_STAND_ENTRY_REF entry ); 243 244 static XTM_DB_STATUS 245 fetchNextDate( XTM_DB_DATABASE database, 246 XTM_DB_DATE_REF entry ); 247 248 static XTM_DB_STATUS 249 fetchNextStand( XTM_DB_DATABASE database, 250 XTM_DB_STAND_ENTRY_REF entry ); 251 252 static XTM_DB_STATUS 253 fetchPrivData( XTM_DB_ENTRY_DATABASES *databases, 254 UINT32 id, 255 XTM_DB_ALL_ENTRY_REF entry_ref, 256 char **text_ref ); 257 258 static XTM_DB_STATUS 259 fetchPrivDb( XTM_DB_ENTRY_DATABASES *databases, 260 UINT32 id, 261 char **text_ref ); 262 263 static XTM_DB_STATUS 264 fetchPrivText( XTM_DB_ENTRY_DATABASES *databases, 265 UINT32 id, 266 char **text_ref ); 267 268 static XTM_DB_STATUS 269 fetchStandEntry( XTM_DB_DATABASE database, 270 UINT32 id, 271 XTM_DB_STAND_ENTRY_REF entry ); 272 273 static XTM_DB_STATUS 274 fetchTextFile( char *directory, 275 UINT32 id, 276 char **text ); 277 278 static void 279 freeFileLock( int *lock_fd ); 280 281 static XTM_DB_STATUS 282 insertDate( XTM_DB_DATABASE database, 283 XTM_DB_DATE_REF entry ); 284 285 static XTM_DB_STATUS 286 insertEntry( XTM_DB_DATABASE database, 287 XTM_DB_ENTRY_REF entry ); 288 289 static XTM_DB_STATUS 290 insertEntryIdInDate( XTM_DB_DATABASE database_ref, 291 UINT32 entry_id, 292 TIM_TIME_REF date_stamp ); 293 294 static XTM_DB_STATUS 295 insertPrivData( XTM_DB_ENTRY_DATABASES *databases, 296 UINT32 id, 297 XTM_DB_ALL_ENTRY_REF entry_ref, 298 char *text_ref ); 299 300 static XTM_DB_STATUS 301 insertPrivDb( XTM_DB_ENTRY_DATABASES *databases, 302 UINT32 id, 303 char *text_ref ); 304 305 static XTM_DB_STATUS 306 insertPrivText( XTM_DB_ENTRY_DATABASES *databases, 307 UINT32 id, 308 char *text_ref ); 309 310 static XTM_DB_STATUS 311 insertStandEntry( XTM_DB_DATABASE database, 312 XTM_DB_STAND_ENTRY_REF entry ); 313 314 static XTM_DB_STATUS 315 insertTextFile( char *directory, 316 UINT32 id, 317 char *text ); 318 319 static XTM_DB_DATABASE 320 openDatabase( XTM_DB_OPEN_REQUEST *open_request ); 321 322 static Boolean 323 updateDbLog( char *directory, 324 UINT32 entry_id, 325 UINT32 flags ); 326 327 328 329 /*---------------------------------------------------------------------------- 330 -- Functions 331 ----------------------------------------------------------------------------*/ 332 333 XTM_DB_STATUS xtmDbChangesInLog(char * directory,TIM_TIME_REF since,XTM_DB_LOG_RECORD changes[],int max_changes,int * no_changes)334 xtmDbChangesInLog( char *directory, 335 TIM_TIME_REF since, 336 XTM_DB_LOG_RECORD changes[], 337 int max_changes, 338 int *no_changes ) 339 { 340 341 /* Variables. */ 342 Boolean back_to_normal = False; 343 int lock_fd = -1; 344 int rec_index; 345 int read_ref; 346 int status; 347 int uid_locking; 348 long offset; 349 UINT32 operations; 350 char filename[ 150 ]; 351 FILE *file_ref; 352 XTM_DB_LOG_HEADER header; 353 XTM_DB_LOG_RECORD log_record; 354 XTM_DB_STATUS db_status; 355 356 357 /* Code. */ 358 359 /* Check the operations that can be done. */ 360 xtmDbCheckDbOperations( directory, False, &operations ); 361 362 /* Go to privileged mode? */ 363 if( flagIsSet( operations, XTM_DB_FLAG_MODE_SETID ) && 364 getegid() != privileged_gid ) { 365 status = setgid( privileged_gid ); 366 back_to_normal = True; 367 } 368 369 /* Lock the file. */ 370 sprintf( filename, "%s/%s", directory, LOCK_FILE ); 371 372 db_status = createFileLock( filename, 373 XTM_DB_FLAG_MODE_READ, 374 &lock_fd, 375 &uid_locking ); 376 if( db_status != XTM_DB_OK ) 377 raise lock_exception; 378 379 380 /* Open the log file. */ 381 sprintf( filename, "%s/%s", directory, LOG_FILE ); 382 383 file_ref = fopen( filename, "r" ); 384 if( file_ref == NULL ) 385 raise exception; 386 387 388 /* Fetch the header record. */ 389 rewind( file_ref ); 390 391 fread( (void *) &header, sizeof( header ), 1, file_ref ); 392 393 #ifdef NET_BYTE_ORDER 394 header.last_changed = ntohl( header.last_changed ); 395 header.current_ref = ntohl( header.current_ref ); 396 header.records = ntohl( header.records ); 397 header.max_log_records = ntohl( header.max_log_records ); 398 #endif 399 400 401 /* Where do we start? */ 402 if( header.records < header.max_log_records ) { 403 read_ref = 0; 404 } else { 405 read_ref = header.current_ref + 1; 406 if( read_ref >= header.max_log_records ) 407 read_ref = 0; 408 } 409 410 rec_index = 0; 411 412 /* Read all records in the log file. */ 413 while( read_ref != header.current_ref && rec_index < max_changes ) { 414 415 offset = sizeof( header ) + read_ref * sizeof( log_record ); 416 fseek( file_ref, offset, 0 ); 417 418 fread( (void *) &log_record, sizeof( log_record ), 1, file_ref ); 419 420 #ifdef NET_BYTE_ORDER 421 log_record.time_stamp = ntohl( log_record.time_stamp ); 422 log_record.entry_id = ntohl( log_record.entry_id ); 423 log_record.flags = ntohl( log_record.flags ); 424 log_record.changed_by = ntohl( log_record.changed_by ); 425 #endif 426 427 /* Do we have a match. */ 428 if( (TIM_TIME_REF) log_record.time_stamp >= since ) { 429 memcpy( &changes[ rec_index ], &log_record, sizeof( log_record ) ); 430 rec_index++; 431 } 432 433 /* Next record. */ 434 read_ref++; 435 if( read_ref >= header.max_log_records ) 436 read_ref = 0; 437 438 } /* while */ 439 440 fclose( file_ref ); 441 442 *no_changes = rec_index; 443 444 445 /* Free the file lock. */ 446 freeFileLock( &lock_fd ); 447 448 /* Back to normal mode? */ 449 if( back_to_normal ) 450 status = setgid( real_gid ); 451 452 return( XTM_DB_OK ); 453 454 455 /* Exception handling. */ 456 exception: 457 if( file_ref != NULL ) 458 fclose( file_ref ); 459 460 if( lock_fd != -1 ) 461 freeFileLock( &lock_fd ); 462 463 if( back_to_normal ) 464 status = setgid( real_gid ); 465 466 return( XTM_DB_ERROR ); 467 468 469 lock_exception: 470 if( back_to_normal ) 471 status = setgid( real_gid ); 472 473 return( db_status ); 474 475 476 477 } /* xtmDbChangesInLog */ 478 479 480 /*----------------------------------------------------------------------*/ 481 482 void xtmDbCheckDbOperations(char * directory,Boolean force_check,UINT32 * operations)483 xtmDbCheckDbOperations( char *directory, 484 Boolean force_check, 485 UINT32 *operations ) 486 { 487 488 /* Variables. */ 489 int status; 490 char filename[ 150 ]; 491 XTM_DB_STATUS db_status; 492 struct stat file_status; 493 494 495 /* Code. */ 496 497 /* Check the cache. */ 498 if( ! force_check && 499 cache_valid && 500 strcmp( directory, db_op_cache[ 0 ].directory ) == 0 ) { 501 *operations = db_op_cache[ 0 ].operations; 502 return; 503 } 504 505 *operations = 0; 506 507 /* Is this the owner? */ 508 status = stat( directory, &file_status ); 509 if( status == 0 && file_status.st_uid == getuid() ) { 510 flagSet( *operations, (XTM_DB_FLAG_MODE_READ | XTM_DB_FLAG_MODE_WRITE | 511 XTM_DB_FLAG_MODE_MSG | XTM_DB_FLAG_MODE_PRIV) ); 512 513 return; 514 } 515 516 517 /* Check privileges within the directory itself. */ 518 sprintf( filename, "%s/%s", directory, ID_FILE ); 519 520 if( access( filename, (R_OK | W_OK | F_OK) ) == 0 ) { 521 flagSet( *operations, (XTM_DB_FLAG_MODE_READ | XTM_DB_FLAG_MODE_WRITE) ); 522 523 } else if( access( filename, (R_OK | F_OK) ) == 0 ) { 524 flagSet( *operations, XTM_DB_FLAG_MODE_READ ); 525 } 526 527 528 /* Access permissions for the Message directory. */ 529 sprintf( filename, "%s/Message", directory ); 530 531 if( access( filename, (W_OK | F_OK) ) == 0 ) { 532 flagSet( *operations, XTM_DB_FLAG_MODE_MSG ); 533 } 534 535 536 /* If we could not read or write, check the access list (if any). */ 537 if( *operations == 0 && real_gid != privileged_gid ) { 538 539 /* Move to privileged level. */ 540 status = setgid( privileged_gid ); 541 542 /* Fetch the operations this user can do. */ 543 db_status = xtmAbGetUserOperations( directory, getuid(), getgid(), 544 operations ); 545 /* Back to user level. */ 546 status = setgid( real_gid ); 547 548 } /* if */ 549 550 551 /* Save in cache. */ 552 cache_valid = True; 553 strcpy( db_op_cache[ 0 ].directory, directory ); 554 db_op_cache[ 0 ].operations = *operations; 555 556 557 return; 558 559 } /* xtmDbCheckDbOperations */ 560 561 562 /*----------------------------------------------------------------------*/ 563 564 XTM_DB_STATUS xtmDbCreateDatabase(XTM_DB_CREATE_REQUEST * create_request)565 xtmDbCreateDatabase( XTM_DB_CREATE_REQUEST *create_request ) 566 { 567 568 /* Variables. */ 569 int file_mode; 570 int status; 571 char filename[ 200 ]; 572 char *data_file; 573 char *key_file; 574 FILE *file_ref; 575 struct stat stat_data; 576 577 578 /* Code. */ 579 580 /* Get the name of the database. */ 581 switch( create_request -> database ) { 582 case XTM_DB_ENTRY_DB: 583 key_file = db_filenames[ 1 ]; 584 data_file = db_filenames[ 2 ]; 585 break; 586 case XTM_DB_DATE_DB: 587 key_file = db_filenames[ 4 ]; 588 data_file = db_filenames[ 5 ]; 589 break; 590 case XTM_DB_STAND_ENTRY_DB: 591 key_file = db_filenames[ 7 ]; 592 data_file = db_filenames[ 8 ]; 593 break; 594 case XTM_DB_PRIV_ENTRY_DB: 595 key_file = db_filenames[ 10 ]; 596 data_file = db_filenames[ 11 ]; 597 break; 598 default: 599 return( XTM_DB_UNKNOWN ); 600 } /* switch */ 601 602 603 /* Fetch the directory data and define the mode for files. */ 604 sprintf( filename, "%s", create_request -> directory ); 605 606 status = stat( filename, &stat_data ); 607 if( status != 0 ) 608 return( XTM_DB_ERROR ); 609 610 file_mode = stat_data.st_mode & (~(S_IXUSR | S_IXGRP | S_IXOTH)); 611 612 613 /* Does the database exist? */ 614 sprintf( filename, "%s/%s", create_request -> directory, key_file ); 615 616 status = stat( filename, &stat_data ); 617 if( status == 0 ) 618 return( XTM_DB_OK ); 619 620 621 /* Create empty key file. */ 622 sprintf( filename, "%s/%s", create_request -> directory, key_file ); 623 624 file_ref = fopen( filename, "w" ); 625 if( file_ref == NULL ) 626 return( XTM_DB_ERROR ); 627 fclose( file_ref ); 628 629 /* Let the key file inherit the permissions from the directory. */ 630 status = chmod( filename, file_mode ); 631 if( status != 0 ) 632 return( XTM_DB_ERROR ); 633 634 635 /* Create empty data file. */ 636 sprintf( filename, "%s/%s", create_request -> directory, data_file ); 637 638 file_ref = fopen( filename, "w" ); 639 if( file_ref == NULL ) 640 return( XTM_DB_ERROR ); 641 fclose( file_ref ); 642 643 /* Let the data file inherit the permissions from the directory. */ 644 status = chmod( filename, file_mode ); 645 if( status != 0 ) 646 return( XTM_DB_ERROR ); 647 648 649 return( XTM_DB_OK ); 650 651 } /* xtmDbCreateDatabase */ 652 653 654 /*----------------------------------------------------------------------*/ 655 656 XTM_DB_STATUS xtmDbFetchFileInfo(char * filename,struct stat * file_info)657 xtmDbFetchFileInfo( char *filename, 658 struct stat *file_info ) 659 { 660 661 /* Variables. */ 662 Boolean back_to_normal = False; 663 int status; 664 UINT32 operations; 665 666 667 /* Code. */ 668 669 /* Check the operations that can be done. */ 670 xtmDbCheckDbOperations( filename, False, &operations ); 671 672 /* Go to privileged mode? */ 673 if( flagIsSet( operations, XTM_DB_FLAG_MODE_SETID ) && 674 getegid() != privileged_gid ) { 675 status = setgid( privileged_gid ); 676 677 back_to_normal = True; 678 } 679 680 /* Fetch file info. */ 681 status = stat( filename, file_info ); 682 683 /* Back to normal mode? */ 684 if( back_to_normal ) 685 setgid( real_gid ); 686 687 if( status != 0 ) 688 return( XTM_DB_ERROR ); 689 690 691 return( XTM_DB_OK ); 692 693 } /* xtmDbFetchFileInfo */ 694 695 696 /*----------------------------------------------------------------------*/ 697 698 XTM_DB_STATUS xtmDbGenerateId(XTM_DB_ID_REQUEST * request,UINT32 * id)699 xtmDbGenerateId( XTM_DB_ID_REQUEST *request, 700 UINT32 *id ) 701 { 702 703 /* Variables. */ 704 Boolean back_to_normal = False; 705 int items; 706 int lock_fd = -1; 707 int status; 708 int uid_locking; 709 UINT32 operations; 710 char buffer[ 50 ]; 711 char filename[ 150 ]; 712 char *char_ref; 713 FILE *file_ref = NULL; 714 XTM_DB_STATUS db_status; 715 716 717 /* Code. */ 718 719 *id = 0; 720 721 /* Check the operations that can be done. */ 722 xtmDbCheckDbOperations( request -> directory, False, &operations ); 723 724 /* Go to privileged mode? */ 725 if( flagIsSet( operations, XTM_DB_FLAG_MODE_SETID ) && 726 getegid() != privileged_gid ) { 727 status = setgid( privileged_gid ); 728 back_to_normal = True; 729 } 730 731 /* Lock the file. */ 732 if( request -> lock_file ) { 733 sprintf( filename, "%s/%s", request -> directory, LOCK_FILE ); 734 735 db_status = createFileLock( filename, 736 XTM_DB_FLAG_MODE_WRITE, 737 &lock_fd, 738 &uid_locking ); 739 if( db_status != XTM_DB_OK ) 740 raise lock_exception; 741 } 742 743 /* Open the identifier file. */ 744 sprintf( filename, "%s/%s", request -> directory, ID_FILE ); 745 746 file_ref = fopen( filename, "r+" ); 747 748 if( file_ref == NULL ) 749 raise exception; 750 751 /* Fetch the old identifier. */ 752 rewind( file_ref ); 753 754 char_ref = fgets( buffer, sizeof( buffer ), file_ref ); 755 if( char_ref == NULL ) 756 raise exception; 757 758 items = sscanf( buffer, "%d", id ); 759 if( items == 1 ) { 760 *id = *id + 1; 761 762 rewind( file_ref ); 763 fprintf( file_ref, "%8d\n", *id ); 764 } 765 766 fclose( file_ref ); 767 768 /* Free the file lock. */ 769 freeFileLock( &lock_fd ); 770 771 /* Back to normal mode? */ 772 if( back_to_normal ) 773 status = setgid( real_gid ); 774 775 if( items == 1 ) 776 return( XTM_DB_OK ); 777 else 778 return( XTM_DB_ERROR ); 779 780 781 /* Exception handling. */ 782 exception: 783 if( file_ref != NULL ) 784 fclose( file_ref ); 785 786 if( lock_fd != -1 ) 787 freeFileLock( &lock_fd ); 788 789 if( back_to_normal ) 790 status = setgid( real_gid ); 791 792 return( XTM_DB_ERROR ); 793 794 795 lock_exception: 796 if( back_to_normal ) 797 status = setgid( real_gid ); 798 799 return( db_status ); 800 801 } /* xtmDbGenerateId */ 802 803 804 /*----------------------------------------------------------------------*/ 805 806 void xtmDbGetEntryPermissions(UINT32 db_operations,int entry_owner,UINT32 entry_flags,UINT32 * can_do_flags)807 xtmDbGetEntryPermissions( UINT32 db_operations, 808 int entry_owner, 809 UINT32 entry_flags, 810 UINT32 *can_do_flags ) 811 { 812 813 /* Code. */ 814 815 *can_do_flags = 0; 816 817 flagSet( *can_do_flags, XTM_DB_PROT_READ ); 818 flagSet( *can_do_flags, XTM_DB_PROT_WRITE ); 819 820 821 /* Can we read the entry. */ 822 if( flagIsSet( entry_flags, XTM_DB_FLAG_PRIVATE ) && 823 flagIsClear( db_operations, XTM_DB_FLAG_MODE_PRIV ) ) 824 flagClear( *can_do_flags, XTM_DB_PROT_READ ); 825 826 827 /* Can we write the entry. */ 828 if( flagIsClear( db_operations, XTM_DB_FLAG_MODE_WRITE ) || 829 (flagIsSet( entry_flags, XTM_DB_FLAG_PRIVATE ) && 830 flagIsClear( db_operations, XTM_DB_FLAG_MODE_PRIV )) ) 831 flagClear( *can_do_flags, XTM_DB_PROT_WRITE ); 832 833 834 /* Can we change the entry? */ 835 if( flagIsSet( *can_do_flags, XTM_DB_PROT_WRITE ) && 836 (entry_owner == getuid() || 837 flagIsClear( entry_flags, XTM_DB_FLAG_ONLY_OWNER_CHANGE )) ) 838 flagSet( *can_do_flags, XTM_DB_PROT_CHANGE ); 839 840 841 /* Can we delete the entry? */ 842 if( flagIsSet( *can_do_flags, XTM_DB_PROT_WRITE ) && 843 (entry_owner == getuid() || 844 flagIsClear( entry_flags, XTM_DB_FLAG_ONLY_OWNER_DELETE )) ) 845 flagSet( *can_do_flags, XTM_DB_PROT_DELETE ); 846 847 848 return; 849 850 } /* xtmDbGetEntryPermissions */ 851 852 853 /*----------------------------------------------------------------------*/ 854 855 XTM_DB_STATUS xtmDbInitializeAuxFiles(char * directory)856 xtmDbInitializeAuxFiles( char *directory ) 857 { 858 859 /* Variables. */ 860 int file_mode; 861 int status; 862 char filename[ 150 ]; 863 FILE *file_ref; 864 struct stat stat_data; 865 866 867 /* Code. */ 868 869 /* Fetch the directory data and define the mode for files. */ 870 sprintf( filename, "%s", directory ); 871 872 status = stat( filename, &stat_data ); 873 if( status != 0 ) 874 return( XTM_DB_ERROR ); 875 876 file_mode = stat_data.st_mode & (~(S_IXUSR | S_IXGRP | S_IXOTH)); 877 878 879 /* Does the id file already exist? */ 880 sprintf( filename, "%s/%s", directory, ID_FILE ); 881 882 status = stat( filename, &stat_data ); 883 if( status != 0 ) { 884 885 /* Open the identifier file. */ 886 file_ref = fopen( filename, "w" ); 887 if( file_ref == NULL ) 888 return( XTM_DB_ERROR ); 889 890 /* Write the start ID. */ 891 fprintf( file_ref, "%8d\n", 11 ); 892 893 fclose( file_ref ); 894 895 /* Let the file inherit the permissions from the directory. */ 896 status = chmod( filename, file_mode ); 897 if( status != 0 ) 898 return( XTM_DB_ERROR ); 899 900 } /* if */ 901 902 903 /* Does the lock file already exist? */ 904 sprintf( filename, "%s/%s", directory, LOCK_FILE ); 905 906 status = stat( filename, &stat_data ); 907 if( status != 0 ) { 908 909 /* Touch the lock file. */ 910 file_ref = fopen( filename, "w" ); 911 if( file_ref == NULL ) 912 return( XTM_DB_ERROR ); 913 914 fclose( file_ref ); 915 916 917 /* Let the file inherit the permissions from the directory. */ 918 status = chmod( filename, file_mode ); 919 if( status != 0 ) 920 return( XTM_DB_ERROR ); 921 922 } /* if */ 923 924 925 /* Does the access file already exist? */ 926 sprintf( filename, "%s/%s", directory, ACCESS_FILE ); 927 928 status = stat( filename, &stat_data ); 929 if( status != 0 ) { 930 931 /* Touch the access file. */ 932 file_ref = fopen( filename, "w" ); 933 if( file_ref == NULL ) 934 return( XTM_DB_ERROR ); 935 936 fclose( file_ref ); 937 938 /* Let the file inherit the permissions from the directory. */ 939 status = chmod( filename, file_mode ); 940 if( status != 0 ) 941 return( XTM_DB_ERROR ); 942 943 } /* if */ 944 945 946 return( XTM_DB_OK ); 947 948 } /* xtmDbInitializeAuxFiles */ 949 950 951 /*----------------------------------------------------------------------*/ 952 953 void xtmDbClearAccessCache()954 xtmDbClearAccessCache() 955 { 956 957 /* Code. */ 958 959 cache_valid = False; 960 961 962 return; 963 964 } /* xtmDbClearAccessCache */ 965 966 967 /*----------------------------------------------------------------------*/ 968 969 void xtmDbInitializeProcessId()970 xtmDbInitializeProcessId() 971 { 972 973 /* Variables. */ 974 int status; 975 976 977 /* Code. */ 978 979 real_gid = getgid(); 980 privileged_gid = getegid(); 981 982 /* Go back to user level. */ 983 status = setgid( getgid() ); 984 985 986 return; 987 988 } /* xtmDbInitializeProcessId */ 989 990 991 /*----------------------------------------------------------------------*/ 992 993 void xtmDbUseFileLock(Boolean use_file_lock)994 xtmDbUseFileLock( Boolean use_file_lock ) 995 { 996 997 /* Code. */ 998 999 use_lock = use_file_lock; 1000 1001 1002 return; 1003 1004 } /* xtmDbUseFileLock */ 1005 1006 1007 /*----------------------------------------------------------------------*/ 1008 1009 Boolean xtmDbDoesStandingMatch(XTM_DB_STAND_ENTRY_REF stand_ref,UINT32 flags,Boolean check_non_wday,TIM_TIME_REF date)1010 xtmDbDoesStandingMatch( XTM_DB_STAND_ENTRY_REF stand_ref, 1011 UINT32 flags, 1012 Boolean check_non_wday, 1013 TIM_TIME_REF date ) 1014 { 1015 1016 /* Variables. */ 1017 Boolean action_non_wday = False; 1018 Boolean display_today = False; 1019 Boolean workday = True; 1020 int day_in_week; 1021 UINT32 stand_flags; 1022 TIM_DELTA_TYPE delta; 1023 TIM_TIME_REF today; 1024 1025 1026 /* Code. */ 1027 1028 day_in_week = TimIndexOfDayInIsoWeek( date ); 1029 today = TimLocalTime( TimMakeTimeNow() ); 1030 1031 today = TimMakeTime( TimIndexOfYear( today ), 1032 TimIndexOfMonth( today ), 1033 TimIndexOfDay( today ), 1034 0, 0, 0 ); 1035 1036 if( TimIsSameDate( today, date ) == TIM_YES ) 1037 display_today = True; 1038 1039 workday = xtmHoIsWorkday( date ); 1040 1041 stand_flags = stand_ref -> flags; 1042 1043 if( check_non_wday ) 1044 action_non_wday= flagIsSet( stand_flags, XTM_DB_FLAG_SE_NWDAY_PREV | 1045 XTM_DB_FLAG_SE_NWDAY_NEXT | 1046 XTM_DB_FLAG_SE_NWDAY_SKIP ); 1047 1048 1049 /* Only for standing and sticky entries. */ 1050 if( flagIsClear( flags, XTM_DB_FETCH_STANDING ) && 1051 flagIsClear( flags, XTM_DB_FETCH_STICKY ) ) 1052 return( False ); 1053 1054 1055 /* Fetch all standing entries? */ 1056 if( flagIsSet( flags, XTM_DB_FETCH_ALL_STANDING ) ) 1057 return( True ); 1058 1059 1060 /* Sticky entries only valid today OR if from and to dates are defined, 1061 valid on the limit days. */ 1062 if( flagIsSet( stand_ref -> flags, XTM_DB_FLAG_SE_STICKY ) ) { 1063 1064 if( display_today ) { 1065 1066 if( stand_ref -> from == 0 && stand_ref -> to == 0 ) 1067 return( True ); 1068 1069 if( (stand_ref -> from != 0 && date < stand_ref -> from) || 1070 (stand_ref -> to != 0 && date > stand_ref -> to) ) 1071 return( False ); 1072 else 1073 return( True ); 1074 } 1075 1076 if( stand_ref -> from != 0 && 1077 stand_ref -> from > today && 1078 stand_ref -> from == date ) 1079 return( True ); 1080 1081 else if( stand_ref -> to != 0 && 1082 stand_ref -> to < today && 1083 stand_ref -> from == date ) 1084 return( True ); 1085 1086 else 1087 return( False ); 1088 1089 } /* if */ 1090 1091 1092 /* Is the entry outside the defined range? */ 1093 if( (stand_ref -> from != 0 && date < stand_ref -> from) || 1094 (stand_ref -> to != 0 && date > stand_ref -> to) ) 1095 return( False ); 1096 1097 1098 /* Valid this week? */ 1099 { 1100 1101 int week_no; 1102 UINT32 week_flags; 1103 UINT32 skip_flag; 1104 1105 week_no = TimIndexOfIsoWeek( date ); 1106 1107 skip_flag = (1 << (week_no % 30)); 1108 if( week_no > 30 ) 1109 week_flags = stand_ref -> skip_week[ 0 ]; 1110 else 1111 week_flags = stand_ref -> skip_week[ 1 ]; 1112 1113 if( flagIsSet( week_flags, skip_flag ) ) 1114 return( False ); 1115 1116 } /* block */ 1117 1118 1119 /* Check action to take on holidays. */ 1120 if( ! workday && action_non_wday ) 1121 return( False ); 1122 1123 1124 /* Special action for workdays? */ 1125 if( action_non_wday ) { 1126 1127 TIM_TIME_REF check_date; 1128 1129 /* Move to next workday. */ 1130 if( flagIsSet( stand_flags, XTM_DB_FLAG_SE_NWDAY_NEXT ) ) { 1131 1132 check_date = date; 1133 TimAddDays( &check_date, -1 ); 1134 1135 while( ! xtmHoIsWorkday( check_date ) ) { 1136 if( xtmDbDoesStandingMatch( stand_ref, flags, False, check_date ) ) 1137 return( True ); 1138 1139 TimAddDays( &check_date, -1 ); 1140 } 1141 1142 } /* if */ 1143 1144 /* Move to previous workday. */ 1145 if( flagIsSet( stand_flags, XTM_DB_FLAG_SE_NWDAY_PREV ) ) { 1146 1147 check_date = date; 1148 TimAddDays( &check_date, 1 ); 1149 1150 while( ! xtmHoIsWorkday( check_date ) ) { 1151 if( xtmDbDoesStandingMatch( stand_ref, flags, False, check_date ) ) 1152 return( True ); 1153 1154 TimAddDays( &check_date, 1 ); 1155 } 1156 1157 } /* if */ 1158 1159 } /* if */ 1160 1161 1162 1163 /* Is this the nth week day in month? */ 1164 if( flagIsSet( stand_flags, XTM_DB_FLAG_SE_DAY_IN_MONTH ) ) { 1165 1166 int day_index; 1167 int index; 1168 int offset = 1; 1169 int this_month; 1170 int weeks = 1; 1171 TIM_TIME_REF tmp_date; 1172 1173 /* We check all valid days, might be more than one. */ 1174 for( day_index = 0; day_index < 7; day_index++ ) { 1175 1176 /* Valid day? */ 1177 if( ! stand_ref -> valid_days[ day_index ] || 1178 (day_index + 1) != day_in_week ) 1179 continue; 1180 1181 /* Correct day in month? */ 1182 if( flagIsSet( stand_flags, XTM_DB_FLAG_SE_1ST ) ) { 1183 offset = (-1); 1184 weeks = 1; 1185 } else if( flagIsSet( stand_flags, XTM_DB_FLAG_SE_2ND ) ) { 1186 offset = (-1); 1187 weeks = 2; 1188 } else if( flagIsSet( stand_flags, XTM_DB_FLAG_SE_3RD ) ) { 1189 offset = (-1); 1190 weeks = 3; 1191 } else if( flagIsSet( stand_flags, XTM_DB_FLAG_SE_1ST_LAST ) ) { 1192 offset = 1; 1193 weeks = 1; 1194 } else if( flagIsSet( stand_flags, XTM_DB_FLAG_SE_2ND_LAST ) ) { 1195 offset = 1; 1196 weeks = 2; 1197 } else if( flagIsSet( stand_flags, XTM_DB_FLAG_SE_3RD_LAST ) ) { 1198 offset = 1; 1199 weeks = 3; 1200 } else { 1201 return( False ); 1202 } 1203 1204 tmp_date = date; 1205 this_month = TimIndexOfMonth( date ); 1206 1207 for( index = 1; index <= weeks; index++ ) { 1208 TimAddDays( &tmp_date, offset * 7 ); 1209 if( TimIndexOfMonth( tmp_date ) != this_month ) 1210 break; 1211 } 1212 1213 if( index == weeks ) 1214 return( True ); 1215 1216 } /* loop */ 1217 1218 return( False ); 1219 1220 } /* if */ 1221 1222 1223 /* Check single valid days. */ 1224 if( stand_ref -> every_n == 0 && 1225 stand_ref -> valid_days[ day_in_week - 1 ] ) 1226 return( True ); 1227 1228 1229 /* Valid every n days? */ 1230 if( stand_ref -> valid_every == XTM_DB_VALID_DAY ) { 1231 TimDelta( stand_ref -> from, date, &delta ); 1232 1233 if( delta.days % stand_ref -> every_n == 0 ) 1234 return( True ); 1235 else 1236 return( False ); 1237 } 1238 1239 1240 /* Valid every n weeks? */ 1241 if( stand_ref -> valid_every == XTM_DB_VALID_WEEK ) { 1242 TimDelta( stand_ref -> from, date, &delta ); 1243 1244 if( delta.weeks % stand_ref -> every_n == 0 && 1245 delta.days % 7 == 0 ) 1246 return( True ); 1247 else 1248 return( False ); 1249 } /* if */ 1250 1251 1252 /* Valid every n months? */ 1253 if( stand_ref -> valid_every == XTM_DB_VALID_MONTH ) { 1254 1255 int check_date; 1256 int check_month; 1257 int days_in_month; 1258 int today_date; 1259 int today_month; 1260 1261 check_date = TimIndexOfDay( stand_ref -> from ); 1262 check_month = TimIndexOfMonth( stand_ref -> from ); 1263 days_in_month = TimDaysInMonth( date ); 1264 today_date = TimIndexOfDay( date ); 1265 today_month = TimIndexOfMonth( date ); 1266 1267 if( abs( check_month - today_month ) % stand_ref -> every_n != 0 ) 1268 return( False ); 1269 1270 if( check_date == today_date || 1271 (check_date > days_in_month && today_date == days_in_month) ) 1272 return( True ); 1273 else 1274 return( False ); 1275 1276 } /* if */ 1277 1278 1279 /* Valid last in month? */ 1280 if( stand_ref -> valid_every == XTM_DB_VALID_MONTH_LAST ) { 1281 1282 int check_month; 1283 int today_month; 1284 1285 check_month = TimIndexOfMonth( stand_ref -> from ); 1286 today_month = TimIndexOfMonth( date ); 1287 1288 if( abs( check_month - today_month ) % stand_ref -> every_n != 0 ) 1289 return( False ); 1290 1291 if( TimIndexOfDay( date ) == TimDaysInMonth( date ) ) 1292 return( True ); 1293 1294 return( False ); 1295 1296 } /* if */ 1297 1298 1299 /* Valid every n years? */ 1300 if( stand_ref -> valid_every == XTM_DB_VALID_YEAR ) { 1301 1302 int check_date; 1303 int check_month; 1304 int days_in_month; 1305 int today_date; 1306 int today_month; 1307 1308 check_date = TimIndexOfDay( stand_ref -> from ); 1309 check_month = TimIndexOfMonth( stand_ref -> from ); 1310 today_date = TimIndexOfDay( date ); 1311 today_month = TimIndexOfMonth( date ); 1312 days_in_month = TimDaysInMonth( date ); 1313 1314 if( abs( TimIndexOfYear( stand_ref -> from ) - 1315 TimIndexOfYear( date ) ) % stand_ref -> every_n != 0 ) 1316 return( False ); 1317 1318 if( check_month == today_month ) { 1319 if( check_date == today_date || 1320 (check_date > days_in_month && check_date == days_in_month) ) 1321 return( True ); 1322 else 1323 return( False ); 1324 } 1325 1326 } /* if */ 1327 1328 1329 return( False ); 1330 1331 } /* xtmDbDoesStandingMatch */ 1332 1333 1334 /*----------------------------------------------------------------------*/ 1335 1336 Boolean xtmDbIsEntryDefined(XTM_DB_ENTRY_DATABASES * database,LST_DESC_TYPE * stand_entries,TIM_TIME_REF cal_date)1337 xtmDbIsEntryDefined( XTM_DB_ENTRY_DATABASES *database, 1338 LST_DESC_TYPE *stand_entries, 1339 TIM_TIME_REF cal_date ) 1340 { 1341 1342 /* Variables. */ 1343 int flags; 1344 int index; 1345 LST_DESC_TYPE entries; 1346 LST_STATUS lst_status; 1347 XTM_DB_ALL_ENTRY_DEF entry_record; 1348 XTM_DB_DATE_DEF date_record; 1349 XTM_DB_STATUS db_status; 1350 1351 1352 /* Code. */ 1353 1354 cal_date = TimMakeTime( TimIndexOfYear( cal_date ), 1355 TimIndexOfMonth( cal_date ), 1356 TimIndexOfDay( cal_date ), 1357 0, 0, 0 ); 1358 1359 /* Any normal entries defined this day? */ 1360 db_status = fetchDate( database -> date_db, cal_date, &date_record ); 1361 if( db_status == XTM_DB_OK ) 1362 return( True ); 1363 1364 /* Check standing entries? */ 1365 if( stand_entries == NULL || 1366 (*stand_entries == NULL && *(stand_entries + 1) == NULL) ) 1367 return( False ); 1368 1369 1370 flags = (XTM_DB_FETCH_STICKY | XTM_DB_FETCH_STANDING); 1371 1372 /* Standing entries are notes and appointments. */ 1373 for( index = 0; index < 2; index++ ) { 1374 1375 entries = *(stand_entries + index); 1376 1377 /* Any entries defined? */ 1378 if( entries == NULL || LstLinkElements( entries ) <= 0 ) 1379 continue; 1380 1381 /* Check the entries in the list. */ 1382 lst_status = LstLinkCurrentFirst( entries ); 1383 while( lst_status == LST_OK ) { 1384 1385 lst_status = LstLinkGetCurrent( entries, &entry_record ); 1386 1387 /* Do we have a match? */ 1388 if( flagIsClear( entry_record.stand_entry.flags, 1389 XTM_DB_FLAG_SE_HIDE_IN_CALENDAR ) ) { 1390 1391 if( xtmDbDoesStandingMatch( &entry_record.stand_entry, 1392 flags, True, cal_date ) ) 1393 return( True ); 1394 1395 } /* if */ 1396 1397 /* Next entry. */ 1398 lst_status = LstLinkCurrentNext( entries ); 1399 1400 } /* while */ 1401 1402 } /* loop */ 1403 1404 1405 return( False ); 1406 1407 } /* xtmDbIsEntryDefined */ 1408 1409 1410 /*----------------------------------------------------------------------*/ 1411 1412 Boolean xtmToIsStandEntryDefined(XTM_GL_BASE_DATA_REF appl_data_ref,LST_DESC_TYPE * stand_entries,TIM_TIME_REF cal_date)1413 xtmToIsStandEntryDefined( XTM_GL_BASE_DATA_REF appl_data_ref, 1414 LST_DESC_TYPE *stand_entries, 1415 TIM_TIME_REF cal_date ) 1416 { 1417 1418 /* Variables. */ 1419 int flags; 1420 int index; 1421 LST_DESC_TYPE entries; 1422 LST_STATUS lst_status; 1423 XTM_DB_ALL_ENTRY_DEF entry_record; 1424 1425 1426 /* Code. */ 1427 1428 if( stand_entries == NULL ) 1429 return( False ); 1430 1431 flags = (XTM_DB_FETCH_STICKY | XTM_DB_FETCH_STANDING); 1432 1433 /* Standing entries are notes and appointments. */ 1434 for( index = 0; index < 2; index++ ) { 1435 1436 entries = *(stand_entries + index); 1437 1438 /* Any entries defined? */ 1439 if( entries == NULL || LstLinkElements( entries ) <= 0 ) 1440 continue; 1441 1442 /* Check the entries in the list. */ 1443 lst_status = LstLinkCurrentFirst( entries ); 1444 while( lst_status == LST_OK ) { 1445 1446 lst_status = LstLinkGetCurrent( entries, &entry_record ); 1447 1448 /* Do we have a match? */ 1449 if( xtmDbDoesStandingMatch( &entry_record.stand_entry, 1450 flags, True, cal_date ) ) 1451 return( True ); 1452 1453 /* Next entry. */ 1454 lst_status = LstLinkCurrentNext( entries ); 1455 1456 } /* while */ 1457 1458 } /* loop */ 1459 1460 return( False ); 1461 1462 } /* xtmToIsStandEntryDefined */ 1463 1464 1465 /*----------------------------------------------------------------------*/ 1466 1467 XTM_DB_STATUS xtmDbCloseEntryDb(XTM_DB_ENTRY_DATABASES * entry_databases)1468 xtmDbCloseEntryDb( XTM_DB_ENTRY_DATABASES *entry_databases ) 1469 { 1470 1471 /* Variables. */ 1472 int status; 1473 1474 1475 /* Code. */ 1476 1477 /* Close entry database. */ 1478 if( entry_databases -> entry_db != NULL ) 1479 closeDatabase( entry_databases -> entry_db ); 1480 1481 1482 /* Close date database. */ 1483 if( entry_databases -> date_db != NULL ) 1484 closeDatabase( entry_databases -> date_db ); 1485 1486 1487 /* Close standing entries database. */ 1488 if( entry_databases -> stand_entry_db != NULL ) 1489 closeDatabase( entry_databases -> stand_entry_db ); 1490 1491 1492 /* Close private entries database. */ 1493 if( entry_databases -> private_db != NULL ) 1494 closeDatabase( entry_databases -> private_db ); 1495 1496 1497 /* Is the database locked? */ 1498 if( entry_databases -> locked && use_lock ) 1499 freeFileLock( &entry_databases -> lock_fd ); 1500 1501 entry_databases -> locked = False; 1502 1503 /* Go to user mode? */ 1504 if( entry_databases -> set_id ) 1505 status = setgid( real_gid ); 1506 1507 1508 return( XTM_DB_OK ); 1509 1510 } /* xtmDbCloseEntryDb */ 1511 1512 1513 /*----------------------------------------------------------------------*/ 1514 1515 XTM_DB_STATUS xtmDbOpenEntryDb(XTM_DB_OPEN_REQUEST * open_request,XTM_DB_ENTRY_DATABASES * entry_databases)1516 xtmDbOpenEntryDb( XTM_DB_OPEN_REQUEST *open_request, 1517 XTM_DB_ENTRY_DATABASES *entry_databases ) 1518 { 1519 1520 /* Variables. */ 1521 int db_dir_size; 1522 int status; 1523 UINT32 operations; 1524 char filename[ 150 ]; 1525 XTM_DB_OPEN_REQUEST single_open_req; 1526 XTM_DB_STATUS db_status; 1527 1528 1529 /* Code. */ 1530 1531 strcpy( entry_databases -> name, open_request -> name ); 1532 1533 /* Check the operations that can be done. */ 1534 xtmDbCheckDbOperations( open_request -> directory, False, &operations ); 1535 1536 single_open_req.directory = open_request -> directory; 1537 single_open_req.lock_timeout = open_request -> lock_timeout; 1538 single_open_req.operations = open_request -> operations; 1539 1540 1541 /* Go to privileged mode? */ 1542 if( flagIsSet( operations, XTM_DB_FLAG_MODE_SETID ) ) 1543 status = setgid( privileged_gid ); 1544 1545 /* Get a file lock. */ 1546 entry_databases -> locked = False; 1547 1548 sprintf( filename, "%s/%s", open_request -> directory, LOCK_FILE ); 1549 1550 db_status = createFileLock( filename, 1551 open_request -> operations, 1552 &entry_databases -> lock_fd, 1553 &open_request -> uid_locking ); 1554 if( db_status != XTM_DB_OK ) 1555 return( db_status ); 1556 1557 entry_databases -> locked = True; 1558 1559 1560 /* Open the entry database. */ 1561 single_open_req.database = XTM_DB_ENTRY_DB; 1562 entry_databases -> entry_db = openDatabase( &single_open_req ); 1563 1564 if( entry_databases -> entry_db == NULL ) 1565 return( XTM_DB_ERROR ); 1566 1567 1568 /* Open the date database. */ 1569 single_open_req.database = XTM_DB_DATE_DB; 1570 entry_databases -> date_db = openDatabase( &single_open_req ); 1571 1572 if( entry_databases -> date_db == NULL ) 1573 return( XTM_DB_ERROR ); 1574 1575 1576 /* Open the standing entries database. */ 1577 single_open_req.database = XTM_DB_STAND_ENTRY_DB; 1578 entry_databases -> stand_entry_db = openDatabase( &single_open_req ); 1579 1580 if( entry_databases -> stand_entry_db == NULL ) 1581 return( XTM_DB_ERROR ); 1582 1583 1584 /* We don't open the private database (only if needed later). */ 1585 entry_databases -> private_db = NULL; 1586 1587 1588 /* Save the database directory. */ 1589 db_dir_size = sizeof( entry_databases -> database_dir ); 1590 1591 strncpy( entry_databases -> database_dir, open_request -> directory, 1592 db_dir_size - 1 ); 1593 1594 entry_databases -> database_dir[ db_dir_size - 1 ] = '\0'; 1595 1596 1597 /* Operations allowed? */ 1598 entry_databases -> operations = operations; 1599 1600 1601 /* Privileged mode? */ 1602 if( flagIsSet( operations, XTM_DB_FLAG_MODE_SETID ) ) 1603 entry_databases -> set_id = True; 1604 else 1605 entry_databases -> set_id = False; 1606 1607 1608 return( XTM_DB_OK ); 1609 1610 } /* xtmDbOpenEntryDb */ 1611 1612 1613 /*----------------------------------------------------------------------*/ 1614 1615 XTM_DB_STATUS xtmDbDeleteEntry(XTM_DB_ENTRY_DATABASES * databases,UINT32 id)1616 xtmDbDeleteEntry( XTM_DB_ENTRY_DATABASES *databases, 1617 UINT32 id ) 1618 { 1619 1620 /* Variables. */ 1621 XTM_DB_STATUS status; 1622 XTM_DB_ALL_ENTRY_DEF entry_record; 1623 1624 1625 /* Code. */ 1626 1627 /* All necessary databases must be open. */ 1628 if( databases -> entry_db == NULL || 1629 databases -> date_db == NULL || 1630 databases -> stand_entry_db == NULL ) 1631 return( XTM_DB_ERROR ); 1632 1633 1634 /* Fetch the entry record (we need some data there). */ 1635 status = fetchEntry( databases -> entry_db, id, &entry_record.entry ); 1636 if( status != XTM_DB_OK ) 1637 return( status ); 1638 1639 1640 /* Delete entry in the private database? */ 1641 (void) deletePrivData( databases, &entry_record ); 1642 1643 1644 /* If an external file is used, delete it. */ 1645 status = deleteTextFile( databases -> database_dir, id ); 1646 1647 1648 /* Delete the entry record. */ 1649 status = deleteEntry( databases -> entry_db, id ); 1650 if( status != XTM_DB_OK ) 1651 return( status ); 1652 1653 1654 /* If this is a normal entry, delete the date reference. */ 1655 if( entry_record.entry.entry_category == XTM_DB_ENTRY_LIST ) { 1656 status = deleteEntryIdInDate( databases -> date_db, 1657 id, 1658 entry_record.entry.date_stamp ); 1659 if( status != XTM_DB_OK ) 1660 return( status ); 1661 } /* if */ 1662 1663 1664 /* Delete the standing entry record? */ 1665 if( entry_record.entry.entry_category == XTM_DB_REP_ENTRY_LIST || 1666 entry_record.entry.entry_category == XTM_DB_STICKY_LIST ) { 1667 1668 status = deleteStandEntry( databases -> stand_entry_db, id ); 1669 if( status != XTM_DB_OK ) 1670 return( status ); 1671 1672 } /* if */ 1673 1674 1675 /* Update the log file. */ 1676 updateDbLog( databases -> database_dir, id, XTM_DB_FLAG_LOG_DELETE ); 1677 1678 1679 return( XTM_DB_OK ); 1680 1681 } /* xtmDbDeleteEntry */ 1682 1683 1684 /*----------------------------------------------------------------------*/ 1685 1686 XTM_DB_STATUS xtmDbFetchEntry(XTM_DB_ENTRY_DATABASES * databases,UINT32 id,XTM_DB_ALL_ENTRY_REF entry_ref,char ** text_ref)1687 xtmDbFetchEntry( XTM_DB_ENTRY_DATABASES *databases, 1688 UINT32 id, 1689 XTM_DB_ALL_ENTRY_REF entry_ref, 1690 char **text_ref ) 1691 { 1692 1693 /* Variables. */ 1694 int index; 1695 XTM_DB_STATUS status; 1696 1697 1698 /* Code. */ 1699 1700 entry_ref -> all_text = NULL; 1701 1702 strcpy( entry_ref -> db_name, databases -> name ); 1703 1704 /* Fetch the entry. */ 1705 status = fetchEntry( databases -> entry_db, id, &entry_ref -> entry ); 1706 if( status != XTM_DB_OK ) 1707 return( status ); 1708 1709 1710 /* Reset the standing part. */ 1711 entry_ref -> stand_entry.id = 0; 1712 entry_ref -> stand_entry.from = 0; 1713 entry_ref -> stand_entry.to = 0; 1714 entry_ref -> stand_entry.every_n = 0; 1715 entry_ref -> stand_entry.valid_every = 0; 1716 entry_ref -> stand_entry.skip_week[ 0 ] = 0; 1717 entry_ref -> stand_entry.skip_week[ 1 ] = 0; 1718 1719 for( index = 0; index < 7; index++ ) 1720 entry_ref -> stand_entry.valid_days[ index ] = 0; 1721 1722 1723 /* If this is a standing or sticky entry, fetch the extra info. */ 1724 if( entry_ref -> entry.entry_category == XTM_DB_REP_ENTRY_LIST || 1725 entry_ref -> entry.entry_category == XTM_DB_STICKY_LIST ) { 1726 1727 status = fetchStandEntry( databases -> stand_entry_db, id, 1728 &entry_ref -> stand_entry ); 1729 if( status != XTM_DB_OK ) 1730 return( status ); 1731 1732 } /* if */ 1733 1734 1735 /* Is the entry in the private area? */ 1736 if( flagIsSet( entry_ref -> entry.flags, XTM_DB_FLAG_IN_PRIV_DB ) ) { 1737 1738 status = fetchPrivData( databases, id, entry_ref, text_ref ); 1739 if( status == XTM_DB_OK ) 1740 return( XTM_DB_OK ); 1741 1742 } /* if */ 1743 1744 1745 /* Do we want to fetch the text separate? */ 1746 if( text_ref == NULL ) 1747 return( XTM_DB_OK ); 1748 1749 1750 /* Fetch text in an external file? */ 1751 *text_ref = NULL; 1752 1753 if( flagIsSet( entry_ref -> entry.flags, XTM_DB_FLAG_EXT_FILE ) ) { 1754 1755 status = fetchTextFile( databases -> database_dir, id, text_ref ); 1756 if( status != XTM_DB_OK ) 1757 return( status ); 1758 1759 } /* if */ 1760 1761 1762 return( XTM_DB_OK ); 1763 1764 } /* xtmDbFetchEntry */ 1765 1766 1767 /*----------------------------------------------------------------------*/ 1768 1769 XTM_DB_STATUS xtmDbInsertEntry(XTM_DB_ENTRY_DATABASES * databases,XTM_DB_ALL_ENTRY_REF entry_ref,char * text_ref)1770 xtmDbInsertEntry( XTM_DB_ENTRY_DATABASES *databases, 1771 XTM_DB_ALL_ENTRY_REF entry_ref, 1772 char *text_ref ) 1773 { 1774 1775 /* Variables. */ 1776 XTM_DB_STATUS status; 1777 1778 1779 /* Code. */ 1780 1781 status = doInsertEntry( databases, 1782 entry_ref, text_ref, 1783 XTM_DB_FLAG_LOG_SAVE ); 1784 1785 1786 return( status ); 1787 1788 } /* xtmDbInsertEntry */ 1789 1790 1791 /*----------------------------------------------------------------------*/ 1792 1793 XTM_DB_STATUS xtmDbFetchDates(XTM_DB_ENTRY_DATABASES * databases,LST_DESC_TYPE * list_ref)1794 xtmDbFetchDates( XTM_DB_ENTRY_DATABASES *databases, 1795 LST_DESC_TYPE *list_ref ) 1796 { 1797 1798 /* Variables. */ 1799 LST_STATUS lst_status; 1800 XTM_DB_STATUS status; 1801 XTM_DB_DATE_DEF record; 1802 1803 1804 /* Code. */ 1805 1806 /* Create a linked list to containg the dates. */ 1807 *list_ref = LstLinkNew( sizeof( record ), NULL ); 1808 1809 /* Fetch the first key in the database. */ 1810 status = fetchFirstDate( databases -> date_db, &record ); 1811 1812 while( status == XTM_DB_OK ) { 1813 1814 /* Insert the date in the sorted list. */ 1815 lst_status = LstLinkSearchFirst( *list_ref, 1816 (void *)(uintptr_t)record.date, 1817 (EQUALS_FUNC_TYPE) dateSortFunc ); 1818 1819 if( lst_status == LST_OK ) 1820 lst_status = LstLinkInsertCurrent( *list_ref, &record ); 1821 else 1822 lst_status = LstLinkInsertLast( *list_ref, &record ); 1823 1824 /* The next date. */ 1825 status = fetchNextDate( databases -> date_db, &record ); 1826 1827 } /* loop */ 1828 1829 1830 return( XTM_DB_OK ); 1831 1832 } /* xtmDbFetchDates */ 1833 1834 1835 /*----------------------------------------------------------------------*/ 1836 1837 XTM_DB_STATUS xtmDbFetchEntriesInDay(XTM_DB_ENTRY_DATABASES * databases,TIM_TIME_REF date,UINT32 flags,LST_DESC_TYPE * entry_list_ref,LST_DESC_TYPE * note_list_ref)1838 xtmDbFetchEntriesInDay( XTM_DB_ENTRY_DATABASES *databases, 1839 TIM_TIME_REF date, 1840 UINT32 flags, 1841 LST_DESC_TYPE *entry_list_ref, 1842 LST_DESC_TYPE *note_list_ref ) 1843 { 1844 1845 /* Variables. */ 1846 int index; 1847 char *text_ref; 1848 LST_STATUS lst_status; 1849 XTM_DB_STATUS status; 1850 XTM_DB_DATE_DEF date_record; 1851 XTM_DB_ALL_ENTRY_DEF entry_record; 1852 XTM_DB_STAND_ENTRY_DEF stand_record; 1853 1854 1855 /* Code. */ 1856 1857 /* Create a linked list to containg the entries. */ 1858 if( flagIsClear( flags, XTM_DB_FETCH_NO_NEW_LIST ) ) { 1859 *entry_list_ref = LstLinkNew( sizeof( XTM_DB_ALL_ENTRY_DEF ), NULL ); 1860 *note_list_ref = LstLinkNew( sizeof( XTM_DB_ALL_ENTRY_DEF ), NULL ); 1861 } 1862 1863 /* Fetch the entry id defined for this day. */ 1864 status = fetchDate( databases -> date_db, date, &date_record ); 1865 1866 1867 /* Fetch all entries defined this day. */ 1868 if( status == XTM_DB_OK ) { 1869 for( index = 0; index < XTM_DB_DATE_ID_SIZE; index++ ) { 1870 1871 /* Do we have an entry? */ 1872 if( date_record.id[ index ] != 0 ) { 1873 1874 /* Fetch the entry. */ 1875 if( flagIsSet( flags, XTM_DB_FETCH_ALL_TEXT ) ) { 1876 status = xtmDbFetchEntry( databases, 1877 date_record.id[ index ], 1878 &entry_record, &text_ref ); 1879 entry_record.all_text = text_ref; 1880 } else { 1881 status = xtmDbFetchEntry( databases, 1882 date_record.id[ index ], 1883 &entry_record, NULL ); 1884 } 1885 1886 if( status != XTM_DB_OK ) 1887 continue; 1888 1889 /* Is this a merged entry? */ 1890 if( flagIsSet( flags, XTM_DB_FETCH_INCLUDE ) ) 1891 flagSet( entry_record.entry.flags, XTM_DB_FLAG_INCLUDE ); 1892 1893 1894 /* Insert in the appointment list or in the note list. */ 1895 switch( entry_record.entry.entry_type ) { 1896 case XTM_DB_DAY_NOTE: 1897 lst_status = LstLinkSearchFirst( 1898 *note_list_ref, 1899 (void *)(uintptr_t)entry_record.entry.time_stamp, 1900 (EQUALS_FUNC_TYPE) entryIdSortFunc ); 1901 1902 if( lst_status == LST_OK ) 1903 lst_status = LstLinkInsertCurrent( *note_list_ref, 1904 &entry_record ); 1905 else 1906 lst_status = LstLinkInsertLast( *note_list_ref, 1907 &entry_record ); 1908 break; 1909 1910 case XTM_DB_DAY_ENTRY: 1911 lst_status = LstLinkSearchFirst( 1912 *entry_list_ref, 1913 (void *)(uintptr_t)entry_record.entry.time_stamp, 1914 (EQUALS_FUNC_TYPE) entryTimeSortFunc ); 1915 1916 if( lst_status == LST_OK ) 1917 lst_status = LstLinkInsertCurrent( *entry_list_ref, 1918 &entry_record ); 1919 else 1920 lst_status = LstLinkInsertLast( *entry_list_ref, 1921 &entry_record ); 1922 break; 1923 1924 default: 1925 fprintf( stderr, "xtmDbTools: xdfe() Unknown entry type %d\n", 1926 entry_record.entry.entry_type ); 1927 return( XTM_DB_ERROR ); 1928 } /* switch */ 1929 1930 } /* if */ 1931 1932 } /* loop */ 1933 1934 } /* if */ 1935 1936 1937 /* Fetch all standing and sticky entries this date? */ 1938 if( flagIsClear(flags, XTM_DB_FETCH_STANDING ) && 1939 flagIsClear(flags, XTM_DB_FETCH_STICKY ) ) 1940 return( XTM_DB_OK ); 1941 1942 status = fetchFirstStand( databases -> stand_entry_db, &stand_record ); 1943 1944 while( status == XTM_DB_OK ) { 1945 1946 Boolean match; 1947 1948 /* Code. */ 1949 1950 /* Does the standing entry fit into the current date? */ 1951 match = xtmDbDoesStandingMatch( &stand_record, flags, True, date ); 1952 1953 /* Did we have a match? */ 1954 if( match ) { 1955 1956 /* Fetch the entry record. */ 1957 if( flagIsSet( flags, XTM_DB_FETCH_ALL_TEXT ) ) { 1958 status = xtmDbFetchEntry( databases, 1959 stand_record.id, 1960 &entry_record, &text_ref ); 1961 entry_record.all_text = text_ref; 1962 } else { 1963 status = xtmDbFetchEntry( databases, 1964 stand_record.id, 1965 &entry_record, NULL ); 1966 } 1967 1968 if( status != XTM_DB_OK ) 1969 return( status ); 1970 1971 /* Copy the standing entry information. */ 1972 memcpy( &entry_record.stand_entry, &stand_record, 1973 sizeof( XTM_DB_STAND_ENTRY_DEF ) ); 1974 1975 1976 /* Is this a merged entry? */ 1977 if( flagIsSet( flags, XTM_DB_FETCH_INCLUDE ) ) 1978 flagSet( entry_record.entry.flags, XTM_DB_FLAG_INCLUDE ); 1979 1980 1981 /* Insert in the appointment list or in the note list. */ 1982 switch( entry_record.entry.entry_type ) { 1983 1984 case XTM_DB_DAY_NOTE: 1985 lst_status = LstLinkSearchFirst( 1986 *note_list_ref, 1987 (void *)(uintptr_t)entry_record.entry.time_stamp, 1988 (EQUALS_FUNC_TYPE) entryIdSortFunc ); 1989 1990 if( lst_status == LST_OK ) 1991 lst_status = LstLinkInsertCurrent( *note_list_ref, 1992 &entry_record ); 1993 else 1994 lst_status = LstLinkInsertLast( *note_list_ref, 1995 &entry_record ); 1996 break; 1997 1998 case XTM_DB_DAY_ENTRY: 1999 lst_status = LstLinkSearchFirst( 2000 *entry_list_ref, 2001 (void *)(uintptr_t)entry_record.entry.time_stamp, 2002 (EQUALS_FUNC_TYPE) entryTimeSortFunc ); 2003 2004 if( lst_status == LST_OK ) 2005 lst_status = LstLinkInsertCurrent( *entry_list_ref, 2006 &entry_record ); 2007 else 2008 lst_status = LstLinkInsertLast( *entry_list_ref, 2009 &entry_record ); 2010 break; 2011 2012 default: 2013 fprintf( stderr, "xtmDbTools: xdfe() Unknown stand entry type %d\n", 2014 entry_record.entry.entry_type ); 2015 return( XTM_DB_ERROR ); 2016 2017 } /* switch */ 2018 2019 } /* if */ 2020 2021 /* Next standing entry. */ 2022 status = fetchNextStand( databases -> stand_entry_db, &stand_record ); 2023 2024 } /* while */ 2025 2026 2027 return( XTM_DB_OK ); 2028 2029 } /* xtmDbFetchEntriesInDay */ 2030 2031 2032 /*----------------------------------------------------------------------*/ 2033 2034 XTM_DB_STATUS xtmDbFetchStandEntries(XTM_DB_ENTRY_DATABASES * databases,LST_DESC_TYPE * entry_list_ref,LST_DESC_TYPE * note_list_ref)2035 xtmDbFetchStandEntries( XTM_DB_ENTRY_DATABASES *databases, 2036 LST_DESC_TYPE *entry_list_ref, 2037 LST_DESC_TYPE *note_list_ref ) 2038 { 2039 2040 /* Variables. */ 2041 LST_STATUS lst_status; 2042 XTM_DB_STATUS status; 2043 XTM_DB_ALL_ENTRY_DEF entry_record; 2044 XTM_DB_STAND_ENTRY_DEF stand_record; 2045 2046 2047 2048 /* Code. */ 2049 2050 /* Create a linked list to containg the entries. */ 2051 *entry_list_ref = LstLinkNew( sizeof( XTM_DB_ALL_ENTRY_DEF ), NULL ); 2052 *note_list_ref = LstLinkNew( sizeof( XTM_DB_ALL_ENTRY_DEF ), NULL ); 2053 2054 /* Fetch all standing entries. */ 2055 status = fetchFirstStand( databases -> stand_entry_db, &stand_record ); 2056 2057 while( status == XTM_DB_OK ) { 2058 2059 /* Fetch the entry record. */ 2060 status = fetchEntry( databases -> entry_db, stand_record.id, 2061 &entry_record.entry ); 2062 if( status != XTM_DB_OK ) 2063 return( status ); 2064 2065 /* Copy the standing entry information. */ 2066 memcpy( &entry_record.stand_entry, &stand_record, 2067 sizeof( XTM_DB_STAND_ENTRY_DEF ) ); 2068 2069 /* Insert in the appointment list or in the note list. */ 2070 switch( entry_record.entry.entry_type ) { 2071 2072 case XTM_DB_DAY_NOTE: 2073 lst_status = LstLinkSearchFirst( 2074 *note_list_ref, 2075 (void *)(uintptr_t)entry_record.entry.time_stamp, 2076 (EQUALS_FUNC_TYPE) entryIdSortFunc ); 2077 2078 if( lst_status == LST_OK ) 2079 lst_status = LstLinkInsertCurrent( *note_list_ref, 2080 &entry_record ); 2081 else 2082 lst_status = LstLinkInsertLast( *note_list_ref, 2083 &entry_record ); 2084 break; 2085 2086 case XTM_DB_DAY_ENTRY: 2087 lst_status = LstLinkSearchFirst( 2088 *entry_list_ref, 2089 (void *)(uintptr_t)entry_record.entry.time_stamp, 2090 (EQUALS_FUNC_TYPE) entryTimeSortFunc ); 2091 2092 if( lst_status == LST_OK ) 2093 lst_status = LstLinkInsertCurrent( *entry_list_ref, 2094 &entry_record ); 2095 else 2096 lst_status = LstLinkInsertLast( *entry_list_ref, 2097 &entry_record ); 2098 break; 2099 2100 default: 2101 fprintf( stderr, "xtmDbTools: xdfse() Unknown entry type %d\n", 2102 entry_record.entry.entry_type ); 2103 return( XTM_DB_ERROR ); 2104 2105 } /* switch */ 2106 2107 /* Next standing entry. */ 2108 status = fetchNextStand( databases -> stand_entry_db, &stand_record ); 2109 2110 } /* while */ 2111 2112 2113 return( XTM_DB_OK ); 2114 2115 } /* xtmDbFetchStandEntries */ 2116 2117 2118 /*----------------------------------------------------------------------*/ 2119 2120 XTM_DB_STATUS xtmDbDeleteMessage(char * db_dir,UINT32 msg_id)2121 xtmDbDeleteMessage( char *db_dir, 2122 UINT32 msg_id ) 2123 { 2124 2125 /* Variables. */ 2126 int status; 2127 char filename[ 200 ]; 2128 char message_dir[ 100 ]; 2129 struct stat file_info; 2130 2131 2132 /* Code. */ 2133 2134 /* Do we have a message directory? */ 2135 sprintf( message_dir, "%s/Message", db_dir ); 2136 2137 status = stat( message_dir, &file_info ); 2138 if( status != 0 ) 2139 sprintf( message_dir, "%s", db_dir ); 2140 2141 2142 /* Search the message file. */ 2143 sprintf( filename, "%s/%s_*_%d", message_dir, XTM_DB_MESSAGE_FILE, msg_id ); 2144 2145 status = DirFindFirst( filename, filename ); 2146 if( status != 0 ) 2147 return( XTM_DB_ERROR ); 2148 2149 DirEnd(); 2150 2151 /* Try to delete the file and ignore all errors. */ 2152 status = unlink( filename ); 2153 2154 2155 return( XTM_DB_OK ); 2156 2157 } /* xtmDbDeleteMessage */ 2158 2159 2160 /*----------------------------------------------------------------------*/ 2161 2162 XTM_DB_STATUS xtmDbFetchMessage(char * db_dir,UINT32 msg_id,XTM_DB_MESSAGE_REF msg_info,char ** message,char ** text)2163 xtmDbFetchMessage( char *db_dir, 2164 UINT32 msg_id, 2165 XTM_DB_MESSAGE_REF msg_info, 2166 char **message, 2167 char **text ) 2168 { 2169 2170 /* Variables. */ 2171 int file_ref; 2172 int position; 2173 int status; 2174 char filename[ 200 ]; 2175 char message_dir[ 100 ]; 2176 char *char_ref; 2177 struct stat file_info; 2178 2179 2180 /* Code. */ 2181 2182 *message = NULL; 2183 *text = NULL; 2184 2185 /* Do we have a message directory? */ 2186 sprintf( message_dir, "%s/Message", db_dir ); 2187 2188 status = stat( message_dir, &file_info ); 2189 if( status != 0 ) 2190 sprintf( message_dir, "%s", db_dir ); 2191 2192 /* Search the message file. */ 2193 sprintf( filename, "%s/%s_*_%d", message_dir, XTM_DB_MESSAGE_FILE, msg_id ); 2194 2195 status = DirFindFirst( filename, filename ); 2196 if( status != 0 ) 2197 return( XTM_DB_ERROR ); 2198 2199 DirEnd(); 2200 2201 /* Open the file for read. */ 2202 file_ref = open( filename, O_RDONLY ); 2203 if( file_ref == -1 ) 2204 return( XTM_DB_ERROR ); 2205 2206 /* Read the message record. */ 2207 lseek( file_ref, 0, SEEK_SET ); 2208 read( file_ref, msg_info, sizeof( XTM_DB_MESSAGE_DEF ) ); 2209 2210 /* Read the message string. */ 2211 if( msg_info -> message_length > 0 ) { 2212 position = sizeof( XTM_DB_MESSAGE_DEF ); 2213 lseek( file_ref, position, SEEK_SET ); 2214 2215 char_ref = SysMalloc( msg_info -> message_length + 1 ); 2216 *(char_ref + msg_info -> message_length) = '\0'; 2217 2218 read( file_ref, char_ref, msg_info -> message_length ); 2219 2220 *message = char_ref; 2221 } 2222 2223 /* Read the text string. */ 2224 if( msg_info -> text_length > 0 ) { 2225 position = sizeof( XTM_DB_MESSAGE_DEF ) + msg_info -> message_length; 2226 lseek( file_ref, position, SEEK_SET ); 2227 2228 char_ref = SysMalloc( msg_info -> text_length + 1 ); 2229 *(char_ref + msg_info -> text_length) = '\0'; 2230 2231 read( file_ref, char_ref, msg_info -> text_length ); 2232 2233 *text = char_ref; 2234 } 2235 2236 close( file_ref ); 2237 2238 return( XTM_DB_OK ); 2239 2240 } /* xtmDbFetchMessage */ 2241 2242 2243 /*----------------------------------------------------------------------*/ 2244 2245 XTM_DB_STATUS xtmDbInsertMessage(char * db_dir,XTM_DB_MESSAGE_REF msg_info,char * message,char * text)2246 xtmDbInsertMessage( char *db_dir, 2247 XTM_DB_MESSAGE_REF msg_info, 2248 char *message, 2249 char *text ) 2250 { 2251 2252 /* Variables. */ 2253 Boolean back_to_normal = False; 2254 int file_mode; 2255 int file_ref; 2256 int status; 2257 UINT32 new_id; 2258 UINT32 id; 2259 UINT32 operations; 2260 char message_dir[ 100 ]; 2261 char filename[ 200 ]; 2262 char file_pattern[ 150 ]; 2263 struct stat file_info; 2264 2265 2266 /* Code. */ 2267 2268 /* Do we have a message directory? */ 2269 sprintf( message_dir, "%s/Message", db_dir ); 2270 2271 status = stat( message_dir, &file_info ); 2272 if( status != 0 ) 2273 sprintf( message_dir, "%s", db_dir ); 2274 2275 2276 /* Fetch id to use. */ 2277 sprintf( file_pattern, "%s/%s_*_*", message_dir, XTM_DB_MESSAGE_FILE ); 2278 2279 new_id = 1; 2280 2281 status = DirFindFirst( file_pattern, filename ); 2282 while( status == 0 ) { 2283 2284 int items; 2285 char *char_ref; 2286 2287 /* Filter out the id of the file. */ 2288 char_ref = strrchr( filename, '_' ); 2289 if( char_ref == NULL ) 2290 return( XTM_DB_ERROR ); 2291 2292 char_ref++; 2293 2294 items = sscanf( char_ref, "%d", &id ); 2295 if( items != 1 ) { 2296 DirEnd(); 2297 return( XTM_DB_ERROR ); 2298 } 2299 2300 if( id > new_id ) 2301 new_id = id; 2302 2303 /* Next Message. */ 2304 status = DirFindNext( filename ); 2305 2306 } /* while */ 2307 2308 new_id++; 2309 2310 /* Check the operations that can be done. */ 2311 xtmDbCheckDbOperations( db_dir, False, &operations ); 2312 2313 /* Go to privileged mode? */ 2314 if( flagIsSet( operations, XTM_DB_FLAG_MODE_SETID ) && 2315 getegid() != privileged_gid ) { 2316 status = setgid( privileged_gid ); 2317 back_to_normal = True; 2318 } 2319 2320 2321 /* Fetch the directory data and define the mode for files. */ 2322 sprintf( filename, "%s", message_dir ); 2323 2324 status = stat( filename, &file_info ); 2325 if( status != 0 ) 2326 raise exception; 2327 2328 file_mode = file_info.st_mode & (~(S_IXUSR | S_IXGRP | S_IXOTH)); 2329 file_mode = (file_mode | S_IROTH); 2330 2331 /* Open the file for write. */ 2332 sprintf( filename, "%s/%s_%s_%d", 2333 message_dir, XTM_DB_MESSAGE_FILE, msg_info -> from, new_id ); 2334 2335 file_ref = open( filename, (O_CREAT | O_RDWR) ); 2336 if( file_ref == -1 ) 2337 raise exception; 2338 2339 /* Write the message record. */ 2340 write( file_ref, msg_info, sizeof( XTM_DB_MESSAGE_DEF ) ); 2341 2342 /* Write the message string. */ 2343 write( file_ref, message, msg_info -> message_length ); 2344 2345 /* Write the message text. */ 2346 write( file_ref, text, msg_info -> text_length ); 2347 2348 close( file_ref ); 2349 2350 2351 /* Let the file inherit the permissions from the directory. */ 2352 status = chmod( filename, file_mode ); 2353 if( status != 0 ) 2354 raise exception; 2355 2356 2357 /* Back to normal uid? */ 2358 if( back_to_normal ) 2359 status = setgid( real_gid ); 2360 2361 2362 return( XTM_DB_OK ); 2363 2364 2365 exception: 2366 if( back_to_normal ) 2367 status = setgid( real_gid ); 2368 2369 return( XTM_DB_ERROR ); 2370 2371 } /* xtmDbInsertMessage */ 2372 2373 2374 /*----------------------------------------------------------------------*/ 2375 2376 static INT32 calcCrc(char * text)2377 calcCrc( char *text ) 2378 { 2379 2380 /* Variables. */ 2381 UINT32 hash = 0; 2382 UINT32 mask = 0; 2383 char *char_ref; 2384 2385 2386 /* Code. */ 2387 2388 if( text == NULL ) 2389 return( 0 ); 2390 2391 char_ref = text; 2392 while( *char_ref != '\0' ) { 2393 2394 hash = (hash << 4) + (*char_ref); 2395 if( (mask = hash & 0xf0000000) ) { 2396 hash = hash ^ (mask >> 24); 2397 hash = hash ^ mask; 2398 } 2399 char_ref++; 2400 } 2401 2402 2403 return( hash % 211 ); 2404 2405 } /* calcCrc */ 2406 2407 2408 /*----------------------------------------------------------------------*/ 2409 2410 static XTM_DB_STATUS closeDatabase(XTM_DB_DATABASE database)2411 closeDatabase( XTM_DB_DATABASE database ) 2412 { 2413 2414 /* Code. */ 2415 2416 dbm_close( (DBM *) database ); 2417 2418 return( XTM_DB_OK ); 2419 2420 } /* closeDatabase */ 2421 2422 2423 /*----------------------------------------------------------------------*/ 2424 2425 static XTM_DB_STATUS createFileLock(char * filename,UINT32 operations,int * lock_fd,int * uid_locking)2426 createFileLock( char *filename, 2427 UINT32 operations, 2428 int *lock_fd, 2429 int *uid_locking ) 2430 { 2431 2432 /* Variables. */ 2433 int lock_type; 2434 int file_mode; 2435 int status; 2436 int tries; 2437 struct flock lock; 2438 2439 2440 /* Code. */ 2441 2442 *uid_locking = 0; 2443 *lock_fd = -1; 2444 2445 if( ! use_lock ) 2446 return( XTM_DB_OK ); 2447 2448 /* Type of lock? */ 2449 file_mode = O_RDONLY; 2450 lock_type = F_RDLCK; 2451 2452 if( flagIsSet( operations, XTM_DB_FLAG_MODE_READ ) ) { 2453 file_mode = O_RDONLY; 2454 lock_type = F_RDLCK; 2455 } 2456 2457 if( flagIsSet( operations, XTM_DB_FLAG_MODE_WRITE ) ) { 2458 file_mode = O_RDWR; 2459 lock_type = F_WRLCK; 2460 } 2461 2462 2463 /* Fetch file descriptor for lock file. */ 2464 *lock_fd = open( filename, file_mode ); 2465 if( *lock_fd < 0 ) 2466 return( XTM_DB_LOCKED ); 2467 2468 2469 /* Lock the file. */ 2470 lock.l_type = lock_type; 2471 lock.l_whence = SEEK_SET; 2472 lock.l_start = 0; 2473 lock.l_len = 0; 2474 2475 tries = 0; 2476 2477 while( tries < MAX_LOCK_TRIES ) { 2478 status = fcntl( *lock_fd, F_SETLK, &lock ); 2479 if( status != -1 ) 2480 break; 2481 2482 sleep( 1 ); 2483 tries++; 2484 } 2485 2486 /* If we could not lock the file, return with error. */ 2487 if( status == -1 ) { 2488 2489 /* Who has the lock? */ 2490 lock.l_type = lock_type; 2491 lock.l_whence = SEEK_SET; 2492 lock.l_start = 0; 2493 lock.l_len = 0; 2494 2495 status = fcntl( *lock_fd, F_GETLK, &lock ); 2496 2497 close( *lock_fd ); 2498 2499 *uid_locking = lock.l_pid; 2500 *lock_fd = -1; 2501 2502 return( XTM_DB_LOCKED ); 2503 2504 } /* if */ 2505 2506 return( XTM_DB_OK ); 2507 2508 } /* createFileLock */ 2509 2510 2511 /*----------------------------------------------------------------------*/ 2512 2513 static LST_COMPARE dateSortFunc(XTM_DB_DATE_DEF * element,TIM_TIME_REF date)2514 dateSortFunc( XTM_DB_DATE_DEF *element, TIM_TIME_REF date ) 2515 { 2516 2517 /* Code. */ 2518 2519 if( element -> date > date ) 2520 return( LST_EQUAL ); 2521 else 2522 return( LST_NOT_EQUAL ); 2523 2524 } /* dateSortFunc */ 2525 2526 2527 /*----------------------------------------------------------------------*/ 2528 2529 static XTM_DB_STATUS deleteDate(XTM_DB_DATABASE database,TIM_TIME_REF date)2530 deleteDate( XTM_DB_DATABASE database, 2531 TIM_TIME_REF date ) 2532 { 2533 2534 /* Variables. */ 2535 int status; 2536 datum key; 2537 XTM_DB_DATE_KEY key_record; 2538 2539 2540 /* Code. */ 2541 2542 if( database == NULL ) 2543 return( XTM_DB_ERROR ); 2544 2545 #ifdef NET_BYTE_ORDER 2546 key_record.date = htonl( date ); 2547 #else 2548 key_record.date = date; 2549 #endif 2550 2551 /* Create the key for the entry. */ 2552 key.dptr = (char *) &key_record; 2553 key.dsize = xtm_db_date_key_size; 2554 2555 /* Delete the entry. */ 2556 status = dbm_delete( (DBM *) database, key ); 2557 if( status != 0 ) 2558 return( XTM_DB_ERROR ); 2559 2560 return( XTM_DB_OK ); 2561 2562 } /* deleteDate */ 2563 2564 2565 /*----------------------------------------------------------------------*/ 2566 2567 static XTM_DB_STATUS deleteEntry(XTM_DB_DATABASE database,UINT32 id)2568 deleteEntry( XTM_DB_DATABASE database, 2569 UINT32 id ) 2570 { 2571 2572 /* Variables. */ 2573 int status; 2574 datum key; 2575 XTM_DB_ENTRY_KEY key_record; 2576 2577 2578 /* Code. */ 2579 2580 if( database == NULL ) 2581 return( XTM_DB_ERROR ); 2582 2583 /* Create the key for the entry. */ 2584 #ifdef NET_BYTE_ORDER 2585 key_record.id = htonl( id ); 2586 #else 2587 key_record.id = id; 2588 #endif 2589 2590 key.dptr = (char *) &key_record; 2591 key.dsize = xtm_db_entry_key_size; 2592 2593 /* Delete the entry. */ 2594 status = dbm_delete( (DBM *) database, key ); 2595 if( status != 0 ) 2596 return( XTM_DB_ERROR ); 2597 2598 2599 return( XTM_DB_OK ); 2600 2601 } /* deleteEntry */ 2602 2603 2604 /*----------------------------------------------------------------------*/ 2605 2606 static XTM_DB_STATUS deleteEntryIdInDate(XTM_DB_DATABASE database_ref,UINT32 entry_id,TIM_TIME_REF date_stamp)2607 deleteEntryIdInDate( XTM_DB_DATABASE database_ref, 2608 UINT32 entry_id, 2609 TIM_TIME_REF date_stamp ) 2610 { 2611 2612 /* Variables. */ 2613 int id_found; 2614 int entry_index; 2615 int index; 2616 XTM_DB_DATE_DEF date_record; 2617 XTM_DB_STATUS status; 2618 2619 2620 /* Code. */ 2621 2622 /* Try to fetch the date record. */ 2623 status = fetchDate( database_ref, date_stamp, &date_record ); 2624 if( status != XTM_DB_OK ) 2625 return( status ); 2626 2627 /* Do we have the entry id in the date record. */ 2628 id_found = 0; 2629 entry_index = -1; 2630 2631 for( index = 0; index < XTM_DB_DATE_ID_SIZE; index++ ) { 2632 if( date_record.id[ index ] != 0 ) 2633 id_found++; 2634 2635 if( date_record.id[ index ] == entry_id ) 2636 entry_index = index; 2637 } 2638 2639 if( entry_index == -1 ) 2640 return( XTM_DB_ERROR ); 2641 2642 /* Entry is not saved anymore. */ 2643 date_record.id[ entry_index ] = 0; 2644 2645 /* Any entries left? */ 2646 if( id_found <= 1 ) 2647 status = deleteDate( database_ref, date_stamp ); 2648 else 2649 status = insertDate( database_ref, &date_record ); 2650 2651 if( status != XTM_DB_OK ) 2652 return( status ); 2653 2654 2655 return( XTM_DB_OK ); 2656 2657 } /* deleteEntryIdInDate */ 2658 2659 2660 /*----------------------------------------------------------------------*/ 2661 2662 static XTM_DB_STATUS deletePrivData(XTM_DB_ENTRY_DATABASES * databases,XTM_DB_ALL_ENTRY_REF entry_ref)2663 deletePrivData( XTM_DB_ENTRY_DATABASES *databases, 2664 XTM_DB_ALL_ENTRY_REF entry_ref ) 2665 { 2666 2667 /* Variables. */ 2668 XTM_DB_STATUS status; 2669 2670 2671 /* Code. */ 2672 2673 if( flagIsClear( entry_ref -> entry.flags, XTM_DB_FLAG_IN_PRIV_DB ) ) 2674 return( XTM_DB_ERROR ); 2675 2676 2677 /* Is the data in an external file? */ 2678 if( flagIsSet( entry_ref -> entry.flags, XTM_DB_FLAG_PRIV_EXT_FILE ) ) 2679 status = deletePrivText( databases, entry_ref -> entry.id ); 2680 else 2681 status = deletePrivDb( databases, entry_ref -> entry.id ); 2682 2683 if( status != XTM_DB_OK ) 2684 return( status ); 2685 2686 2687 return( XTM_DB_OK ); 2688 2689 } /* deletePrivData */ 2690 2691 2692 /*----------------------------------------------------------------------*/ 2693 2694 static XTM_DB_STATUS deletePrivDb(XTM_DB_ENTRY_DATABASES * databases,UINT32 id)2695 deletePrivDb( XTM_DB_ENTRY_DATABASES *databases, 2696 UINT32 id ) 2697 { 2698 2699 /* Variables. */ 2700 int status; 2701 datum key; 2702 XTM_DB_OPEN_REQUEST single_open_req; 2703 XTM_DB_PRIV_KEY key_record; 2704 2705 2706 /* Code. */ 2707 2708 /* Open the database for write. */ 2709 if( databases -> private_db == NULL ) { 2710 single_open_req.database = XTM_DB_PRIV_ENTRY_DB; 2711 single_open_req.directory = databases -> database_dir; 2712 single_open_req.lock_timeout = 0; 2713 2714 if( flagIsSet( databases -> operations, XTM_DB_FLAG_MODE_WRITE ) ) 2715 single_open_req.operations = XTM_DB_FLAG_MODE_WRITE; 2716 else 2717 single_open_req.operations = XTM_DB_FLAG_MODE_READ; 2718 2719 databases -> private_db = openDatabase( &single_open_req ); 2720 if( databases -> private_db == NULL ) 2721 return( XTM_DB_ERROR ); 2722 } 2723 2724 /* Create the key for the entry. */ 2725 #ifdef NET_BYTE_ORDER 2726 key_record.id = htonl( id ); 2727 #else 2728 key_record.id = id; 2729 #endif 2730 2731 key.dptr = (char *) &key_record; 2732 key.dsize = xtm_db_priv_entry_key_size; 2733 2734 /* Delete the entry. */ 2735 status = dbm_delete( (DBM *) databases -> private_db, key ); 2736 if( status != 0 ) 2737 return( XTM_DB_ERROR ); 2738 2739 2740 return( XTM_DB_OK ); 2741 2742 } /* deletePrivDb */ 2743 2744 2745 /*----------------------------------------------------------------------*/ 2746 2747 static XTM_DB_STATUS deletePrivText(XTM_DB_ENTRY_DATABASES * databases,UINT32 id)2748 deletePrivText( XTM_DB_ENTRY_DATABASES *databases, 2749 UINT32 id ) 2750 { 2751 2752 /* Variables. */ 2753 int status; 2754 char filename[ 200 ]; 2755 2756 2757 /* Code. */ 2758 2759 sprintf( filename, "%s/Private/%d.txt", databases -> database_dir, id ); 2760 2761 /* Try to delete the file and ignore all errors. */ 2762 status = unlink( filename ); 2763 2764 2765 return( XTM_DB_OK ); 2766 2767 } /* deletePrivText */ 2768 2769 2770 /*----------------------------------------------------------------------*/ 2771 2772 static XTM_DB_STATUS deleteStandEntry(XTM_DB_DATABASE database,UINT32 id)2773 deleteStandEntry( XTM_DB_DATABASE database, 2774 UINT32 id ) 2775 { 2776 2777 /* Variables. */ 2778 int status; 2779 datum key; 2780 XTM_DB_STAND_ENTRY_KEY key_record; 2781 2782 2783 /* Code. */ 2784 2785 if( database == NULL ) 2786 return( XTM_DB_ERROR ); 2787 2788 /* Create the key for the entry. */ 2789 #ifdef NET_BYTE_ORDER 2790 key_record.id = htonl( id ); 2791 #else 2792 key_record.id = id; 2793 #endif 2794 2795 key.dptr = (char *) &key_record; 2796 key.dsize = xtm_db_stand_entry_key_size; 2797 2798 /* Delete the entry. */ 2799 status = dbm_delete( (DBM *) database, key ); 2800 if( status != 0 ) 2801 return( XTM_DB_ERROR ); 2802 2803 return( XTM_DB_OK ); 2804 2805 } /* deleteStandEntry */ 2806 2807 2808 /*----------------------------------------------------------------------*/ 2809 2810 static XTM_DB_STATUS deleteTextFile(char * directory,UINT32 id)2811 deleteTextFile( char *directory, 2812 UINT32 id ) 2813 { 2814 2815 /* Variables. */ 2816 int status; 2817 char filename[ 200 ]; 2818 2819 2820 /* Code. */ 2821 2822 sprintf( filename, "%s/%d.txt", directory, id ); 2823 2824 /* Try to delete the file and ignore all errors. */ 2825 status = unlink( filename ); 2826 2827 return( XTM_DB_OK ); 2828 2829 } /* deleteTextFile */ 2830 2831 2832 /*----------------------------------------------------------------------*/ 2833 2834 static XTM_DB_STATUS doInsertEntry(XTM_DB_ENTRY_DATABASES * databases,XTM_DB_ALL_ENTRY_REF entry_ref,char * text_ref,UINT32 log_flags)2835 doInsertEntry( XTM_DB_ENTRY_DATABASES *databases, 2836 XTM_DB_ALL_ENTRY_REF entry_ref, 2837 char *text_ref, 2838 UINT32 log_flags ) 2839 { 2840 2841 /* Variables. */ 2842 char *char_ref; 2843 XTM_DB_STATUS status; 2844 2845 2846 /* Code. */ 2847 2848 /* All necessary databases must be open. */ 2849 if( databases -> entry_db == NULL || 2850 databases -> date_db == NULL || 2851 databases -> stand_entry_db == NULL ) 2852 return( XTM_DB_ERROR ); 2853 2854 2855 /* Delete any old file. */ 2856 if( flagIsSet( entry_ref -> entry.flags, XTM_DB_FLAG_EXT_FILE ) ) { 2857 (void) deleteTextFile( databases -> database_dir, 2858 entry_ref -> entry.id ); 2859 2860 flagClear( entry_ref -> entry.flags, XTM_DB_FLAG_EXT_FILE ); 2861 } 2862 2863 2864 /* CRC for th entry. */ 2865 entry_ref -> entry.crc = calcCrc( text_ref ); 2866 2867 /* Entry tag cannot contain spaces. */ 2868 char_ref = entry_ref -> entry.tag; 2869 while( isspace( *char_ref ) ) 2870 char_ref++; 2871 2872 if( *char_ref == '\0' ) 2873 entry_ref -> entry.tag[ 0 ] = '\0'; 2874 2875 /* No alarms for notes. */ 2876 if( entry_ref -> entry.entry_type == XTM_DB_DAY_NOTE ) 2877 flagClear( entry_ref -> entry.flags, XTM_DB_FLAG_ALARM ); 2878 2879 2880 /* Save text in record. */ 2881 if( text_ref != NULL ) { 2882 strncpy( entry_ref -> entry.text, text_ref, XTM_DB_RECORD_TEXT_LEN ); 2883 entry_ref -> entry.text[ XTM_DB_RECORD_TEXT_LEN ] = '\0'; 2884 } 2885 2886 2887 /* Is this a private entry? */ 2888 flagClear( entry_ref -> entry.flags, XTM_DB_FLAG_IN_PRIV_DB ); 2889 2890 if( flagIsSet( entry_ref -> entry.flags, XTM_DB_FLAG_PRIVATE ) ) 2891 (void) insertPrivData( databases, entry_ref -> entry.id, entry_ref, 2892 text_ref ); 2893 2894 2895 /* Insert the long entry text? */ 2896 if( text_ref != NULL ) { 2897 2898 /* Insert the text in a separate file? */ 2899 if( strlen( text_ref ) > XTM_DB_RECORD_TEXT_LEN ) { 2900 flagSet( entry_ref -> entry.flags, XTM_DB_FLAG_EXT_FILE ); 2901 2902 status = insertTextFile( databases -> database_dir, 2903 entry_ref -> entry.id, 2904 text_ref ); 2905 if( status != XTM_DB_OK ) 2906 return( status ); 2907 } 2908 2909 } /* if */ 2910 2911 2912 /* If a sticky note is done, make it a normal note. */ 2913 if( entry_ref -> entry.entry_category == XTM_DB_STICKY_LIST && 2914 flagIsSet( entry_ref -> entry.flags, XTM_DB_FLAG_NOTE_DONE ) ) 2915 entry_ref -> entry.entry_category = XTM_DB_ENTRY_LIST; 2916 2917 2918 /* Replace/create the new entry. */ 2919 status = insertEntry( databases -> entry_db, &entry_ref -> entry ); 2920 if( status != XTM_DB_OK ) 2921 return( status ); 2922 2923 2924 /* Delete any standing entry (will be re-created if necessary). */ 2925 status = deleteStandEntry( databases -> stand_entry_db, 2926 entry_ref -> entry.id ); 2927 2928 /* Standing entry? */ 2929 if( entry_ref -> entry.entry_category == XTM_DB_REP_ENTRY_LIST ) { 2930 2931 flagSet( entry_ref -> stand_entry.flags, XTM_DB_FLAG_SE_STANDING ); 2932 flagClear( entry_ref -> stand_entry.flags, XTM_DB_FLAG_SE_STICKY ); 2933 2934 if( flagIsSet( entry_ref -> entry.flags, XTM_DB_FLAG_HIDE_IN_CALENDAR ) ) 2935 flagSet( entry_ref -> stand_entry.flags, 2936 XTM_DB_FLAG_SE_HIDE_IN_CALENDAR ); 2937 2938 2939 /* Create/replace the standing entry. */ 2940 status = insertStandEntry( databases -> stand_entry_db, 2941 &entry_ref -> stand_entry ); 2942 if( status != XTM_DB_OK ) 2943 return( status ); 2944 2945 } /* if */ 2946 2947 2948 if( entry_ref -> entry.entry_category == XTM_DB_STICKY_LIST && 2949 flagIsClear( entry_ref -> entry.flags, XTM_DB_FLAG_NOTE_DONE ) ) { 2950 2951 flagClear( entry_ref -> stand_entry.flags, XTM_DB_FLAG_SE_STANDING ); 2952 flagSet( entry_ref -> stand_entry.flags, XTM_DB_FLAG_SE_STICKY ); 2953 2954 /* Create/replace the standing entry. */ 2955 status = insertStandEntry( databases -> stand_entry_db, 2956 &entry_ref -> stand_entry ); 2957 if( status != XTM_DB_OK ) 2958 return( status ); 2959 2960 } /* if */ 2961 2962 2963 /* Is this a normal entry? */ 2964 if( entry_ref -> entry.entry_category == XTM_DB_ENTRY_LIST ) { 2965 status = insertEntryIdInDate( databases -> date_db, 2966 entry_ref -> entry.id, 2967 entry_ref -> entry.date_stamp ); 2968 2969 if( status != XTM_DB_OK ) 2970 return( status ); 2971 } /* if */ 2972 2973 2974 /* Update the log file. */ 2975 updateDbLog( databases -> database_dir, entry_ref -> entry.id, log_flags ); 2976 2977 2978 return( XTM_DB_OK ); 2979 2980 } /* doInsertEntry */ 2981 2982 2983 /*----------------------------------------------------------------------*/ 2984 2985 static LST_COMPARE entryIdSortFunc(XTM_DB_ENTRY_DEF * element,UINT32 id)2986 entryIdSortFunc( XTM_DB_ENTRY_DEF *element, UINT32 id ) 2987 { 2988 2989 /* Code. */ 2990 2991 if( element -> id > id ) 2992 return( LST_EQUAL ); 2993 else 2994 return( LST_NOT_EQUAL ); 2995 2996 } /* entryIdSortFunc */ 2997 2998 2999 /*----------------------------------------------------------------------*/ 3000 3001 static LST_COMPARE entryTimeSortFunc(XTM_DB_ENTRY_DEF * element,TIM_TIME_REF date)3002 entryTimeSortFunc( XTM_DB_ENTRY_DEF *element, TIM_TIME_REF date ) 3003 { 3004 3005 /* Code. */ 3006 3007 if( element -> time_stamp > date ) 3008 return( LST_EQUAL ); 3009 else 3010 return( LST_NOT_EQUAL ); 3011 3012 } /* entryTimeSortFunc */ 3013 3014 3015 /*----------------------------------------------------------------------*/ 3016 3017 static XTM_DB_STATUS fetchDate(XTM_DB_DATABASE database,TIM_TIME_REF date,XTM_DB_DATE_REF entry)3018 fetchDate( XTM_DB_DATABASE database, 3019 TIM_TIME_REF date, 3020 XTM_DB_DATE_REF entry ) 3021 { 3022 3023 /* Variables. */ 3024 int index; 3025 datum key; 3026 datum contents; 3027 XTM_DB_DATE_KEY key_record; 3028 3029 3030 /* Code. */ 3031 3032 if( database == NULL ) 3033 return( XTM_DB_ERROR ); 3034 3035 /* Create the key for the entry. */ 3036 #ifdef NET_BYTE_ORDER 3037 key_record.date = htonl( date ); 3038 #else 3039 key_record.date = date; 3040 #endif 3041 3042 key.dptr = (char *) &key_record; 3043 key.dsize = xtm_db_date_key_size; 3044 3045 /* Fetch the entry. */ 3046 contents = dbm_fetch( (DBM *) database, key ); 3047 if( contents.dptr == NULL ) 3048 return( XTM_DB_ERROR ); 3049 3050 /* Copy the contents. */ 3051 memcpy( entry, contents.dptr, xtm_db_date_def_size ); 3052 3053 #ifdef NET_BYTE_ORDER 3054 entry -> date = ntohl( entry -> date ); 3055 3056 for( index = 0; index < XTM_DB_DATE_ID_SIZE; index++ ) 3057 entry -> id[ index ] = ntohl( entry -> id[ index ] ); 3058 #endif 3059 3060 return( XTM_DB_OK ); 3061 3062 } /* fetchDate */ 3063 3064 3065 /*----------------------------------------------------------------------*/ 3066 3067 static XTM_DB_STATUS fetchEntry(XTM_DB_DATABASE database,UINT32 id,XTM_DB_ENTRY_REF entry)3068 fetchEntry( XTM_DB_DATABASE database, 3069 UINT32 id, 3070 XTM_DB_ENTRY_REF entry ) 3071 { 3072 3073 /* Variables. */ 3074 int index; 3075 datum key; 3076 datum contents; 3077 XTM_DB_ENTRY_KEY key_record; 3078 3079 3080 /* Code. */ 3081 3082 if( database == NULL ) 3083 return( XTM_DB_ERROR ); 3084 3085 /* Create the key for the entry. */ 3086 #ifdef NET_BYTE_ORDER 3087 key_record.id = htonl( id ); 3088 #else 3089 key_record.id = id; 3090 #endif 3091 3092 key.dptr = (char *) &key_record; 3093 key.dsize = xtm_db_entry_key_size; 3094 3095 /* Fetch the entry. */ 3096 contents = dbm_fetch( (DBM *) database, key ); 3097 if( contents.dptr == NULL ) 3098 return( XTM_DB_ERROR ); 3099 3100 /* Copy the contents. */ 3101 memcpy( entry, contents.dptr, xtm_db_entry_def_size ); 3102 3103 #ifdef NET_BYTE_ORDER 3104 entry -> id = ntohl( entry -> id ); 3105 entry -> time_stamp = ntohl( entry -> time_stamp ); 3106 entry -> date_stamp = ntohl( entry -> date_stamp ); 3107 entry -> last_update = ntohl( entry -> last_update ); 3108 entry -> owner = ntohl( entry -> owner ); 3109 entry -> duration = ntohs( entry -> duration ); 3110 entry -> flags = ntohl( entry -> flags ); 3111 3112 for( index = 0; index < 5; index++ ) 3113 entry -> alarm_offset[ index ] = ntohs( entry -> alarm_offset[ index ] ); 3114 3115 entry -> crc = ntohl( entry -> crc); 3116 #endif 3117 3118 return( XTM_DB_OK ); 3119 3120 } /* fetchEntry */ 3121 3122 3123 /*----------------------------------------------------------------------*/ 3124 3125 static XTM_DB_STATUS fetchFirstDate(XTM_DB_DATABASE database,XTM_DB_DATE_REF entry)3126 fetchFirstDate( XTM_DB_DATABASE database, 3127 XTM_DB_DATE_REF entry ) 3128 { 3129 3130 /* Variables. */ 3131 datum contents; 3132 TIM_TIME_REF date; 3133 XTM_DB_STATUS status; 3134 3135 3136 /* Code. */ 3137 3138 if( database == NULL ) 3139 return( XTM_DB_ERROR ); 3140 3141 /* Fetch the entry. */ 3142 contents = dbm_firstkey( (DBM *) database ); 3143 if( contents.dptr == NULL ) 3144 return( XTM_DB_ERROR ); 3145 3146 /* Fetch the data. */ 3147 memcpy( &date, contents.dptr, xtm_db_date_key_size ); 3148 3149 #ifdef NET_BYTE_ORDER 3150 date = ntohl( date ); 3151 #endif 3152 3153 status = fetchDate( database, date, entry ); 3154 3155 return( status ); 3156 3157 } /* fetchFirstDate */ 3158 3159 3160 /*----------------------------------------------------------------------*/ 3161 3162 static XTM_DB_STATUS fetchFirstStand(XTM_DB_DATABASE database,XTM_DB_STAND_ENTRY_REF entry)3163 fetchFirstStand( XTM_DB_DATABASE database, 3164 XTM_DB_STAND_ENTRY_REF entry ) 3165 { 3166 3167 /* Variables. */ 3168 int id; 3169 datum contents; 3170 XTM_DB_STATUS status; 3171 3172 3173 /* Code. */ 3174 3175 if( database == NULL ) 3176 return( XTM_DB_ERROR ); 3177 3178 /* Fetch the entry. */ 3179 contents = dbm_firstkey( (DBM *) database ); 3180 if( contents.dptr == NULL ) 3181 return( XTM_DB_ERROR ); 3182 3183 /* Fetch the data. */ 3184 memcpy( &id, contents.dptr, xtm_db_stand_entry_key_size ); 3185 3186 #ifdef NET_BYTE_ORDER 3187 id = ntohl( id ); 3188 #endif 3189 3190 status = fetchStandEntry( database, id, entry ); 3191 3192 return( status ); 3193 3194 } /* fetchFirstStand */ 3195 3196 3197 /*----------------------------------------------------------------------*/ 3198 3199 static XTM_DB_STATUS fetchNextDate(XTM_DB_DATABASE database,XTM_DB_DATE_REF entry)3200 fetchNextDate( XTM_DB_DATABASE database, 3201 XTM_DB_DATE_REF entry ) 3202 { 3203 3204 /* Variables. */ 3205 datum contents; 3206 TIM_TIME_REF date; 3207 XTM_DB_STATUS status; 3208 3209 3210 /* Code. */ 3211 3212 if( database == NULL ) 3213 return( XTM_DB_ERROR ); 3214 3215 /* Fetch the entry. */ 3216 contents = dbm_nextkey( (DBM *) database ); 3217 if( contents.dptr == NULL ) 3218 return( XTM_DB_ERROR ); 3219 3220 /* Fetch the data. */ 3221 memcpy( &date, contents.dptr, xtm_db_date_key_size ); 3222 3223 #ifdef NET_BYTE_ORDER 3224 date = ntohl( date ); 3225 #endif 3226 3227 status = fetchDate( database, date, entry ); 3228 3229 return( status ); 3230 3231 } /* fetchNextDate */ 3232 3233 3234 /*----------------------------------------------------------------------*/ 3235 3236 static XTM_DB_STATUS fetchNextStand(XTM_DB_DATABASE database,XTM_DB_STAND_ENTRY_REF entry)3237 fetchNextStand( XTM_DB_DATABASE database, 3238 XTM_DB_STAND_ENTRY_REF entry ) 3239 { 3240 3241 /* Variables. */ 3242 int id; 3243 datum contents; 3244 XTM_DB_STATUS status; 3245 3246 3247 /* Code. */ 3248 3249 if( database == NULL ) 3250 return( XTM_DB_ERROR ); 3251 3252 /* Fetch the entry. */ 3253 contents = dbm_nextkey( (DBM *) database ); 3254 if( contents.dptr == NULL ) 3255 return( XTM_DB_ERROR ); 3256 3257 /* Fetch the data. */ 3258 memcpy( &id, contents.dptr, xtm_db_stand_entry_key_size ); 3259 3260 #ifdef NET_BYTE_ORDER 3261 id = ntohl( id ); 3262 #endif 3263 3264 status = fetchStandEntry( database, id, entry ); 3265 3266 return( XTM_DB_OK ); 3267 3268 } /* fetchNextStand */ 3269 3270 3271 /*----------------------------------------------------------------------*/ 3272 3273 static XTM_DB_STATUS fetchPrivData(XTM_DB_ENTRY_DATABASES * databases,UINT32 id,XTM_DB_ALL_ENTRY_REF entry_ref,char ** text_ref)3274 fetchPrivData( XTM_DB_ENTRY_DATABASES *databases, 3275 UINT32 id, 3276 XTM_DB_ALL_ENTRY_REF entry_ref, 3277 char **text_ref ) 3278 { 3279 3280 /* Variables. */ 3281 char *db_text; 3282 XTM_DB_STATUS status; 3283 3284 3285 /* Code. */ 3286 3287 /* Default private text. */ 3288 strcpy( entry_ref -> entry.text, "<Private>" ); 3289 3290 if( flagIsClear( entry_ref -> entry.flags, XTM_DB_FLAG_IN_PRIV_DB ) ) 3291 return( XTM_DB_ERROR ); 3292 3293 3294 /* Is the data in an external file? */ 3295 if( flagIsSet( entry_ref -> entry.flags, XTM_DB_FLAG_PRIV_EXT_FILE ) ) 3296 status = fetchPrivText( databases, id, &db_text ); 3297 else 3298 status = fetchPrivDb( databases, id, &db_text ); 3299 3300 if( status != XTM_DB_OK ) 3301 return( status ); 3302 3303 3304 /* Save the fetched text. */ 3305 strncpy( entry_ref -> entry.text, db_text, XTM_DB_RECORD_TEXT_LEN ); 3306 entry_ref -> entry.text[ XTM_DB_RECORD_TEXT_LEN ] = '\0'; 3307 3308 /* Any 'extra' text? */ 3309 if( flagIsSet( entry_ref -> entry.flags, XTM_DB_FLAG_PRIV_EXT_FILE ) ) { 3310 *text_ref = db_text; 3311 } else { 3312 SysFree( db_text ); 3313 3314 if( text_ref != NULL ) 3315 *text_ref = NULL; 3316 } 3317 3318 flagClear( entry_ref -> entry.flags, XTM_DB_FLAG_EXT_FILE ); 3319 3320 3321 return( XTM_DB_OK ); 3322 3323 } /* fetchPrivData */ 3324 3325 3326 /*----------------------------------------------------------------------*/ 3327 3328 static XTM_DB_STATUS fetchPrivDb(XTM_DB_ENTRY_DATABASES * databases,UINT32 id,char ** text_ref)3329 fetchPrivDb( XTM_DB_ENTRY_DATABASES *databases, 3330 UINT32 id, 3331 char **text_ref ) 3332 { 3333 3334 /* Variables. */ 3335 datum key; 3336 datum contents; 3337 XTM_DB_OPEN_REQUEST single_open_req; 3338 XTM_DB_PRIV_DEF data_record; 3339 XTM_DB_PRIV_KEY key_record; 3340 3341 3342 /* Code. */ 3343 3344 *text_ref = NULL; 3345 3346 /* Open the database for read. */ 3347 if( databases -> private_db == NULL ) { 3348 single_open_req.database = XTM_DB_PRIV_ENTRY_DB; 3349 single_open_req.directory = databases -> database_dir; 3350 single_open_req.lock_timeout = 0; 3351 3352 if( flagIsSet( databases -> operations, XTM_DB_FLAG_MODE_WRITE ) ) 3353 single_open_req.operations = XTM_DB_FLAG_MODE_WRITE; 3354 else 3355 single_open_req.operations = XTM_DB_FLAG_MODE_READ; 3356 3357 databases -> private_db = openDatabase( &single_open_req ); 3358 if( databases -> private_db == NULL ) 3359 return( XTM_DB_ERROR ); 3360 } 3361 3362 /* Create the key for the entry. */ 3363 #ifdef NET_BYTE_ORDER 3364 key_record.id = htonl( id ); 3365 #else 3366 key_record.id = id; 3367 #endif 3368 3369 key.dptr = (char *) &key_record; 3370 key.dsize = xtm_db_priv_entry_key_size; 3371 3372 3373 /* Fetch the text. */ 3374 contents = dbm_fetch( (DBM *) databases -> private_db, key ); 3375 3376 if( contents.dptr == NULL ) 3377 return( XTM_DB_ERROR ); 3378 3379 3380 /* Store the text here. */ 3381 memcpy( (char *) &data_record, contents.dptr, xtm_db_priv_entry_def_size ); 3382 3383 #ifdef NET_BYTE_ORDER 3384 data_record.id = ntohl( data_record.id ); 3385 #endif 3386 3387 *text_ref = SysMalloc( XTM_DB_RECORD_TEXT_LEN ); 3388 3389 strcpy( *text_ref, data_record.text ); 3390 3391 3392 return( XTM_DB_OK ); 3393 3394 } /* fetchPrivDb */ 3395 3396 3397 /*----------------------------------------------------------------------*/ 3398 3399 static XTM_DB_STATUS fetchPrivText(XTM_DB_ENTRY_DATABASES * databases,UINT32 id,char ** text_ref)3400 fetchPrivText( XTM_DB_ENTRY_DATABASES *databases, 3401 UINT32 id, 3402 char **text_ref ) 3403 { 3404 3405 /* Variables. */ 3406 int char_read; 3407 int status; 3408 char filename[ 200 ]; 3409 FILE *file_ref; 3410 struct stat file_status; 3411 3412 3413 /* Code. */ 3414 3415 *text_ref = NULL; 3416 3417 /* All private entries hide in the Private directory. */ 3418 /* sprintf( filename, "%s/Private/%d.txt", databases -> private_db, id ); Orig. most certainly wrong. I'm not sure whether the line below is correct, but it might be. RXTN 040597*/ 3419 sprintf( filename, "%s/Private/%d.txt", databases -> database_dir, id ); 3420 3421 3422 /* We need the size of the file. */ 3423 status = stat( filename, &file_status ); 3424 if( status != 0 ) 3425 return( XTM_DB_ERROR ); 3426 3427 3428 /* Allocate space for the file. */ 3429 *text_ref = SysMalloc( file_status.st_size + 5 ); 3430 if( *text_ref == NULL ) 3431 return( XTM_DB_ERROR ); 3432 3433 3434 /* Open the file and read the contents. */ 3435 file_ref = fopen( filename, "r" ); 3436 if( file_ref == NULL ) 3437 return( XTM_DB_ERROR ); 3438 3439 char_read = fread( *text_ref, 1, file_status.st_size + 1, file_ref ); 3440 3441 fclose( file_ref ); 3442 3443 *(*text_ref + char_read) = '\0'; 3444 3445 3446 return( XTM_DB_OK ); 3447 3448 } /* fetchPrivText */ 3449 3450 3451 /*----------------------------------------------------------------------*/ 3452 3453 static XTM_DB_STATUS fetchStandEntry(XTM_DB_DATABASE database,UINT32 id,XTM_DB_STAND_ENTRY_REF entry)3454 fetchStandEntry( XTM_DB_DATABASE database, 3455 UINT32 id, 3456 XTM_DB_STAND_ENTRY_REF entry ) 3457 { 3458 3459 /* Variables. */ 3460 datum key; 3461 datum contents; 3462 XTM_DB_STAND_ENTRY_KEY key_record; 3463 3464 3465 /* Code. */ 3466 3467 if( database == NULL ) 3468 return( XTM_DB_ERROR ); 3469 3470 /* Create the key for the entry. */ 3471 #ifdef NET_BYTE_ORDER 3472 key_record.id = htonl( id ); 3473 #else 3474 key_record.id = id; 3475 #endif 3476 3477 key.dptr = (char *) &key_record; 3478 key.dsize = xtm_db_stand_entry_key_size; 3479 3480 /* Fetch the entry. */ 3481 contents = dbm_fetch( (DBM *) database, key ); 3482 if( contents.dptr == NULL ) 3483 return( XTM_DB_ERROR ); 3484 3485 /* Copy the contents. */ 3486 memcpy( entry, contents.dptr, xtm_db_stand_entry_def_size ); 3487 3488 #ifdef NET_BYTE_ORDER 3489 entry -> id = ntohl( entry -> id ); 3490 entry -> from = ntohl( entry -> from ); 3491 entry -> to = ntohl( entry -> to ); 3492 entry -> flags = ntohl( entry -> flags ); 3493 entry -> every_n = ntohs( entry -> every_n ); 3494 entry -> skip_week[ 0 ] = ntohl( entry -> skip_week[ 0 ] ); 3495 entry -> skip_week[ 1 ] = ntohl( entry -> skip_week[ 1 ] ); 3496 #endif 3497 3498 3499 return( XTM_DB_OK ); 3500 3501 } /* fetchStandEntry */ 3502 3503 3504 /*----------------------------------------------------------------------*/ 3505 3506 static XTM_DB_STATUS fetchTextFile(char * directory,UINT32 id,char ** text)3507 fetchTextFile( char *directory, 3508 UINT32 id, 3509 char **text ) 3510 { 3511 3512 /* Variables. */ 3513 Boolean back_to_normal = False; 3514 int char_read; 3515 int status; 3516 UINT32 operations; 3517 char filename[ 200 ]; 3518 FILE *file_ref; 3519 struct stat file_status; 3520 3521 3522 /* Code. */ 3523 3524 *text = NULL; 3525 3526 /* Check the operations that can be done. */ 3527 xtmDbCheckDbOperations( directory, False, &operations ); 3528 3529 /* Go to privileged mode? */ 3530 if( flagIsSet( operations, XTM_DB_FLAG_MODE_SETID ) && 3531 getegid() != privileged_gid ) { 3532 status = setgid( privileged_gid ); 3533 back_to_normal = True; 3534 } 3535 3536 sprintf( filename, "%s/%d.txt", directory, id ); 3537 3538 /* Does the file exist? */ 3539 status = stat( filename, &file_status ); 3540 if( status != 0 ) 3541 raise exception; 3542 3543 /* Allocate space for the file. */ 3544 *text = SysMalloc( file_status.st_size + 5 ); 3545 if( *text == NULL ) 3546 raise exception; 3547 3548 /* Open the file and read the contents. */ 3549 file_ref = fopen( filename, "r" ); 3550 if( file_ref == NULL ) 3551 raise exception; 3552 3553 char_read = fread( *text, 1, file_status.st_size + 1, file_ref ); 3554 3555 fclose( file_ref ); 3556 3557 *(*text + char_read) = '\0'; 3558 3559 /* Back to normal mode? */ 3560 if( back_to_normal ) 3561 status = setgid( real_gid ); 3562 3563 return( XTM_DB_OK ); 3564 3565 3566 /* Exception handling. */ 3567 exception: 3568 if( back_to_normal ) 3569 status = setgid( real_gid ); 3570 3571 return( XTM_DB_ERROR ); 3572 3573 3574 } /* fetchTextFile */ 3575 3576 3577 /*----------------------------------------------------------------------*/ 3578 3579 static void freeFileLock(int * lock_fd)3580 freeFileLock( int *lock_fd ) 3581 { 3582 3583 /* Variables. */ 3584 int status; 3585 struct flock lock; 3586 3587 3588 /* Code. */ 3589 3590 if( ! use_lock || *lock_fd < 0 ) 3591 return; 3592 3593 /* Unlock the file. */ 3594 lock.l_type = F_UNLCK; 3595 lock.l_whence = SEEK_SET; 3596 lock.l_start = 0; 3597 lock.l_len = 0; 3598 3599 status = fcntl( *lock_fd, F_SETLK, &lock ); 3600 3601 /* If we could not unlock the file, print error message and continue. */ 3602 if( status == -1 ) 3603 fprintf( stderr, "xtmDbTools: ffl(), Cannot unlock file.\n" ); 3604 3605 close( *lock_fd ); 3606 3607 *lock_fd = 0; 3608 3609 return; 3610 3611 } /* freeFileLock */ 3612 3613 3614 /*----------------------------------------------------------------------*/ 3615 3616 static XTM_DB_STATUS insertDate(XTM_DB_DATABASE database,XTM_DB_DATE_REF entry)3617 insertDate( XTM_DB_DATABASE database, 3618 XTM_DB_DATE_REF entry ) 3619 { 3620 3621 /* Variables. */ 3622 int flags; 3623 int index; 3624 int status; 3625 UINT32 date; 3626 datum key; 3627 datum contents; 3628 3629 3630 /* Code. */ 3631 3632 if( database == NULL ) 3633 return( XTM_DB_ERROR ); 3634 3635 /* Fill unused data with NULL. */ 3636 memset( entry -> unused, 0, sizeof( entry -> unused ) ); 3637 3638 flags = DBM_INSERT; 3639 3640 /* Create the key for the entry. */ 3641 #ifdef NET_BYTE_ORDER 3642 date = htonl( entry -> date ); 3643 #else 3644 date = entry -> date; 3645 #endif 3646 3647 key.dptr = (char *) &date; 3648 key.dsize = xtm_db_date_key_size; 3649 3650 /* Create the contents for the entry. */ 3651 contents.dptr = (char *) entry; 3652 contents.dsize = xtm_db_date_def_size; 3653 3654 #ifdef NET_BYTE_ORDER 3655 entry -> date = htonl( entry -> date ); 3656 3657 for( index = 0; index < XTM_DB_DATE_ID_SIZE; index++ ) 3658 entry -> id[ index ] = htonl( entry -> id[ index ] ); 3659 #endif 3660 3661 /* Insert/replace the entry. */ 3662 status = dbm_store( (DBM *) database, key, contents, flags ); 3663 3664 if( status != 0 ) { 3665 flags = DBM_REPLACE; 3666 3667 status = dbm_store( (DBM *) database, key, contents, flags ); 3668 } 3669 3670 #ifdef NET_BYTE_ORDER 3671 entry -> date = ntohl( entry -> date ); 3672 3673 for( index = 0; index < XTM_DB_DATE_ID_SIZE; index++ ) 3674 entry -> id[ index ] = ntohl( entry -> id[ index ] ); 3675 #endif 3676 3677 if( status != 0 ) 3678 return( XTM_DB_ERROR ); 3679 3680 3681 return( XTM_DB_OK ); 3682 3683 } /* insertDate */ 3684 3685 3686 /*----------------------------------------------------------------------*/ 3687 3688 static XTM_DB_STATUS insertEntry(XTM_DB_DATABASE database,XTM_DB_ENTRY_REF entry)3689 insertEntry( XTM_DB_DATABASE database, 3690 XTM_DB_ENTRY_REF entry ) 3691 { 3692 3693 /* Variables. */ 3694 int flags; 3695 int index; 3696 int status; 3697 datum key; 3698 datum contents; 3699 XTM_DB_ENTRY_KEY key_record; 3700 3701 3702 /* Code. */ 3703 3704 if( database == NULL ) 3705 return( XTM_DB_ERROR ); 3706 3707 /* Fill unused data with NULL. */ 3708 memset( entry -> unused, 0, sizeof( entry -> unused ) ); 3709 3710 flags = DBM_INSERT; 3711 3712 /* Set the owner of the entry. */ 3713 entry -> owner = getuid(); 3714 3715 /* Last update. */ 3716 entry -> last_update = (UINT32) TimMakeTimeNow(); 3717 3718 /* Create the key for the entry. */ 3719 #ifdef NET_BYTE_ORDER 3720 key_record.id = htonl( entry -> id ); 3721 #else 3722 key_record.id = entry -> id; 3723 #endif 3724 3725 key.dptr = (char *) &key_record; 3726 key.dsize = xtm_db_entry_key_size; 3727 3728 /* Create the contents for the entry. */ 3729 contents.dptr = (char *) entry; 3730 contents.dsize = xtm_db_entry_def_size; 3731 3732 #ifdef NET_BYTE_ORDER 3733 entry -> id = htonl( entry -> id ); 3734 entry -> time_stamp = htonl( entry -> time_stamp ); 3735 entry -> date_stamp = htonl( entry -> date_stamp ); 3736 entry -> last_update = htonl( entry -> last_update ); 3737 entry -> owner = htonl( entry -> owner ); 3738 entry -> duration = htons( entry -> duration ); 3739 entry -> flags = htonl( entry -> flags ); 3740 3741 for( index = 0; index < 5; index++ ) 3742 entry -> alarm_offset[ index ] = htons( entry -> alarm_offset[ index ] ); 3743 3744 entry -> crc = htonl( entry -> crc ); 3745 #endif 3746 3747 /* Insert/replace the entry. */ 3748 status = dbm_store( (DBM *) database, key, contents, flags ); 3749 3750 if( status != 0 ) { 3751 flags = DBM_REPLACE; 3752 3753 status = dbm_store( (DBM *) database, key, contents, flags ); 3754 } 3755 3756 #ifdef NET_BYTE_ORDER 3757 entry -> id = ntohl( entry -> id ); 3758 entry -> time_stamp = ntohl( entry -> time_stamp ); 3759 entry -> date_stamp = ntohl( entry -> date_stamp ); 3760 entry -> last_update = ntohl( entry -> last_update ); 3761 entry -> owner = ntohl( entry -> owner ); 3762 entry -> duration = ntohs( entry -> duration ); 3763 entry -> flags = ntohl( entry -> flags ); 3764 3765 for( index = 0; index < 5; index++ ) 3766 entry -> alarm_offset[ index ] = ntohs( entry -> alarm_offset[ index ] ); 3767 3768 entry -> crc = ntohl( entry -> crc ); 3769 #endif 3770 3771 if( status != 0 ) 3772 return( XTM_DB_ERROR ); 3773 3774 return( XTM_DB_OK ); 3775 3776 } /* insertEntry */ 3777 3778 3779 /*----------------------------------------------------------------------*/ 3780 3781 static XTM_DB_STATUS insertEntryIdInDate(XTM_DB_DATABASE database_ref,UINT32 entry_id,TIM_TIME_REF date_stamp)3782 insertEntryIdInDate( XTM_DB_DATABASE database_ref, 3783 UINT32 entry_id, 3784 TIM_TIME_REF date_stamp ) 3785 { 3786 3787 /* Variables. */ 3788 int index; 3789 XTM_DB_DATE_DEF date_record; 3790 XTM_DB_STATUS status; 3791 3792 3793 /* Code. */ 3794 3795 /* Try to fetch the date record. */ 3796 status = fetchDate( database_ref, date_stamp, &date_record ); 3797 3798 if( status != XTM_DB_OK ) { 3799 memset( &date_record, 0, xtm_db_date_def_size ); 3800 3801 date_record.date = date_stamp; 3802 } 3803 3804 /* Do we have the entry id in the date record. */ 3805 for( index = 0; index < XTM_DB_DATE_ID_SIZE; index++ ) { 3806 if( date_record.id[ index ] == entry_id ) 3807 return( XTM_DB_OK ); 3808 } 3809 3810 /* Add the entry id to the date record. */ 3811 for( index = 0; index < XTM_DB_DATE_ID_SIZE; index++ ) { 3812 if( date_record.id[ index ] == 0 ) 3813 break; 3814 } 3815 3816 if( index == XTM_DB_DATE_ID_SIZE ) 3817 return( XTM_DB_ERROR ); 3818 3819 /* Insert the new entry id and save the date record. */ 3820 date_record.id[ index ] = entry_id; 3821 3822 status = insertDate( database_ref, &date_record ); 3823 if( status != XTM_DB_OK ) 3824 return( status ); 3825 3826 return( XTM_DB_OK ); 3827 3828 } /* insertEntryIdInDate */ 3829 3830 3831 /*----------------------------------------------------------------------*/ 3832 3833 static XTM_DB_STATUS insertPrivData(XTM_DB_ENTRY_DATABASES * databases,UINT32 id,XTM_DB_ALL_ENTRY_REF entry_ref,char * text_ref)3834 insertPrivData( XTM_DB_ENTRY_DATABASES *databases, 3835 UINT32 id, 3836 XTM_DB_ALL_ENTRY_REF entry_ref, 3837 char *text_ref ) 3838 { 3839 3840 /* Variables. */ 3841 Boolean in_db; 3842 XTM_DB_STATUS status; 3843 3844 3845 /* Code. */ 3846 3847 /* Any privileges to do this? */ 3848 if( flagIsClear( databases -> operations, XTM_DB_FLAG_MODE_PRIV ) ) { 3849 flagClear( entry_ref -> entry.flags, XTM_DB_FLAG_PRIVATE ); 3850 3851 return( XTM_DB_OK ); 3852 } 3853 3854 3855 /* Does the data fit into a database entry? */ 3856 if( text_ref == NULL ) { 3857 status = insertPrivDb( databases, id, entry_ref -> entry.text ); 3858 in_db = True; 3859 } else if( strlen( text_ref ) <= XTM_DB_RECORD_TEXT_LEN ) { 3860 status = insertPrivDb( databases, id, text_ref ); 3861 in_db = True; 3862 } else { 3863 status = insertPrivText( databases, id, text_ref ); 3864 in_db = False; 3865 } 3866 3867 if( status != XTM_DB_OK ) 3868 return( status ); 3869 3870 3871 flagSet( entry_ref -> entry.flags, XTM_DB_FLAG_IN_PRIV_DB ); 3872 flagClear( entry_ref -> entry.flags, XTM_DB_FLAG_EXT_FILE ); 3873 3874 /* If inserted in external file, flag this. */ 3875 if( ! in_db ) 3876 flagSet( entry_ref -> entry.flags, XTM_DB_FLAG_PRIV_EXT_FILE ); 3877 3878 3879 /* Do not leave the original text. */ 3880 strcpy( entry_ref -> entry.text, "<Private>" ); 3881 if( text_ref != NULL ) 3882 *text_ref = '\0'; 3883 3884 3885 return( XTM_DB_OK ); 3886 3887 } /* insertPrivData */ 3888 3889 3890 /*----------------------------------------------------------------------*/ 3891 3892 static XTM_DB_STATUS insertPrivDb(XTM_DB_ENTRY_DATABASES * databases,UINT32 id,char * text_ref)3893 insertPrivDb( XTM_DB_ENTRY_DATABASES *databases, 3894 UINT32 id, 3895 char *text_ref ) 3896 { 3897 3898 /* Variables. */ 3899 int flags; 3900 int status; 3901 datum key; 3902 datum contents; 3903 XTM_DB_OPEN_REQUEST single_open_req; 3904 XTM_DB_PRIV_DEF data_record; 3905 XTM_DB_PRIV_KEY key_record; 3906 3907 3908 /* Code. */ 3909 3910 /* Open the database for write. */ 3911 if( databases -> private_db == NULL ) { 3912 single_open_req.database = XTM_DB_PRIV_ENTRY_DB; 3913 single_open_req.directory = databases -> database_dir; 3914 single_open_req.lock_timeout = 0; 3915 3916 if( flagIsSet( databases -> operations, XTM_DB_FLAG_MODE_WRITE ) ) 3917 single_open_req.operations = XTM_DB_FLAG_MODE_WRITE; 3918 else 3919 single_open_req.operations = XTM_DB_FLAG_MODE_READ; 3920 3921 databases -> private_db = openDatabase( &single_open_req ); 3922 if( databases -> private_db == NULL ) 3923 return( XTM_DB_ERROR ); 3924 } 3925 3926 /* Fill unused data with NULL. */ 3927 memset( data_record.unused, 0, sizeof( data_record.unused ) ); 3928 3929 flags = DBM_INSERT; 3930 3931 /* Create the key and contents of the entry. */ 3932 #ifdef NET_BYTE_ORDER 3933 key_record.id = htonl( id ); 3934 data_record.id = htonl( id ); 3935 #else 3936 key_record.id = id; 3937 data_record.id = id; 3938 #endif 3939 3940 strcpy( data_record.text, text_ref ); 3941 3942 key.dptr = (char *) &key_record; 3943 key.dsize = xtm_db_priv_entry_key_size; 3944 3945 contents.dptr = (char *) &data_record; 3946 contents.dsize = xtm_db_priv_entry_def_size; 3947 3948 3949 /* Try insert/replace entry. */ 3950 status = dbm_store( (DBM *) databases -> private_db, key, 3951 contents, flags ); 3952 3953 if( status != 0 ) { 3954 flags = DBM_REPLACE; 3955 3956 status = dbm_store( (DBM *) databases -> private_db, key, 3957 contents, flags ); 3958 } 3959 3960 if( status != 0 ) 3961 return( XTM_DB_ERROR ); 3962 3963 3964 return( XTM_DB_OK ); 3965 3966 } /* insertPrivDb */ 3967 3968 3969 /*----------------------------------------------------------------------*/ 3970 3971 static XTM_DB_STATUS insertPrivText(XTM_DB_ENTRY_DATABASES * databases,UINT32 id,char * text_ref)3972 insertPrivText( XTM_DB_ENTRY_DATABASES *databases, 3973 UINT32 id, 3974 char *text_ref ) 3975 { 3976 3977 /* Variables. */ 3978 int char_written; 3979 int file_mode; 3980 int status; 3981 char filename[ 200 ]; 3982 FILE *file_ref; 3983 struct stat file_status; 3984 3985 3986 /* Code. */ 3987 3988 /* Fetch protection of the directory. */ 3989 sprintf( filename, "%s/Private", databases -> database_dir ); 3990 3991 status = stat( filename, &file_status ); 3992 if( status != 0 ) 3993 return( XTM_DB_ERROR ); 3994 3995 file_mode = file_status.st_mode & (~(S_IXUSR | S_IXGRP | S_IXOTH)); 3996 3997 3998 /* All private entries hide in the Private directory. */ 3999 sprintf( filename, "%s/Private/%d.txt", databases -> database_dir, id ); 4000 4001 4002 /* Open the file and write the contents. */ 4003 file_ref = fopen( filename, "w" ); 4004 if( file_ref == NULL ) 4005 return( XTM_DB_ERROR ); 4006 4007 char_written = fwrite( text_ref, 1, strlen( text_ref ), file_ref ); 4008 4009 fclose( file_ref ); 4010 4011 4012 /* Let the file inherit the permissions from the directory. */ 4013 status = chmod( filename, file_mode ); 4014 if( status != 0 ) 4015 return( XTM_DB_ERROR ); 4016 4017 4018 if( char_written <= 0 ) 4019 return( XTM_DB_ERROR ); 4020 4021 4022 return( XTM_DB_OK ); 4023 4024 } /* insertPrivText */ 4025 4026 4027 /*----------------------------------------------------------------------*/ 4028 4029 static XTM_DB_STATUS insertStandEntry(XTM_DB_DATABASE database,XTM_DB_STAND_ENTRY_REF entry)4030 insertStandEntry( XTM_DB_DATABASE database, 4031 XTM_DB_STAND_ENTRY_REF entry ) 4032 { 4033 4034 /* Variables. */ 4035 int flags; 4036 int status; 4037 datum key; 4038 datum contents; 4039 XTM_DB_STAND_ENTRY_KEY key_record; 4040 4041 4042 /* Code. */ 4043 4044 if( database == NULL ) 4045 return( XTM_DB_ERROR ); 4046 4047 /* Fill unused data with NULL. */ 4048 memset( entry -> unused, 0, sizeof( entry -> unused ) ); 4049 4050 flags = DBM_REPLACE; 4051 4052 /* Create the key for the entry. */ 4053 #ifdef NET_BYTE_ORDER 4054 key_record.id = htonl( entry -> id ); 4055 #else 4056 key_record.id = entry -> id; 4057 #endif 4058 4059 key.dptr = (char *) &key_record; 4060 key.dsize = xtm_db_stand_entry_key_size; 4061 4062 /* Create the contents for the entry. */ 4063 contents.dptr = (char *) entry; 4064 contents.dsize = xtm_db_stand_entry_def_size; 4065 4066 #ifdef NET_BYTE_ORDER 4067 entry -> id = htonl( entry -> id ); 4068 entry -> from = htonl( entry -> from ); 4069 entry -> to = htonl( entry -> to ); 4070 entry -> flags = htonl( entry -> flags ); 4071 entry -> every_n = htons( entry -> every_n ); 4072 entry -> skip_week[ 0 ] = htonl( entry -> skip_week[ 0 ] ); 4073 entry -> skip_week[ 1 ] = htonl( entry -> skip_week[ 1 ] ); 4074 #endif 4075 4076 /* Insert/replace the entry. */ 4077 status = dbm_store( (DBM *) database, key, contents, flags ); 4078 4079 if( status != 0 ) { 4080 flags = DBM_REPLACE; 4081 4082 status = dbm_store( (DBM *) database, key, contents, flags ); 4083 } 4084 4085 #ifdef NET_BYTE_ORDER 4086 entry -> id = ntohl( entry -> id ); 4087 entry -> from = ntohl( entry -> from ); 4088 entry -> to = ntohl( entry -> to ); 4089 entry -> flags = ntohl( entry -> flags ); 4090 entry -> every_n = ntohs( entry -> every_n ); 4091 entry -> skip_week[ 0 ] = ntohl( entry -> skip_week[ 0 ] ); 4092 entry -> skip_week[ 1 ] = ntohl( entry -> skip_week[ 1 ] ); 4093 #endif 4094 4095 if( status != 0 ) 4096 return( XTM_DB_ERROR ); 4097 4098 4099 return( XTM_DB_OK ); 4100 4101 } /* insertStandEntry */ 4102 4103 4104 /*----------------------------------------------------------------------*/ 4105 4106 static XTM_DB_STATUS insertTextFile(char * directory,UINT32 id,char * text)4107 insertTextFile( char *directory, 4108 UINT32 id, 4109 char *text ) 4110 { 4111 4112 /* Variables. */ 4113 int char_written; 4114 int file_mode; 4115 int status; 4116 char filename[ 200 ]; 4117 FILE *file_ref; 4118 struct stat stat_data; 4119 4120 4121 /* Code. */ 4122 4123 /* Fetch the directory data and define the mode for files. */ 4124 sprintf( filename, "%s", directory ); 4125 4126 status = stat( filename, &stat_data ); 4127 if( status != 0 ) 4128 return( XTM_DB_ERROR ); 4129 4130 file_mode = stat_data.st_mode & (~(S_IXUSR | S_IXGRP | S_IXOTH)); 4131 4132 4133 /* Open the file and write the contents. */ 4134 sprintf( filename, "%s/%d.txt", directory, id ); 4135 4136 file_ref = fopen( filename, "w" ); 4137 if( file_ref == NULL ) 4138 return( XTM_DB_ERROR ); 4139 4140 char_written = fwrite( text, 1, strlen( text ), file_ref ); 4141 4142 fclose( file_ref ); 4143 4144 4145 /* Let the file inherit the permissions from the directory. */ 4146 status = chmod( filename, file_mode ); 4147 if( status != 0 ) 4148 return( XTM_DB_ERROR ); 4149 4150 4151 if( char_written <= 0 ) 4152 return( XTM_DB_ERROR ); 4153 4154 return( XTM_DB_OK ); 4155 4156 } /* insertTextFile */ 4157 4158 4159 /*----------------------------------------------------------------------*/ 4160 4161 static XTM_DB_DATABASE openDatabase(XTM_DB_OPEN_REQUEST * open_request)4162 openDatabase( XTM_DB_OPEN_REQUEST *open_request ) 4163 { 4164 4165 /* Variables. */ 4166 int flags; 4167 char filename[ 200 ]; 4168 char *key_file; 4169 DBM *dbm_ref; 4170 4171 4172 /* Code. */ 4173 4174 /* Get the name of the database. */ 4175 switch( open_request -> database ) { 4176 case XTM_DB_ENTRY_DB: 4177 key_file = db_filenames[ 0 ]; 4178 break; 4179 case XTM_DB_DATE_DB: 4180 key_file = db_filenames[ 3 ]; 4181 break; 4182 case XTM_DB_STAND_ENTRY_DB: 4183 key_file = db_filenames[ 6 ]; 4184 break; 4185 case XTM_DB_PRIV_ENTRY_DB: 4186 key_file = db_filenames[ 9 ]; 4187 break; 4188 default: 4189 return( NULL ); 4190 } /* switch */ 4191 4192 /* Open the database. */ 4193 sprintf( filename, "%s/%s", open_request -> directory, key_file ); 4194 4195 flags = 0; 4196 4197 if( flagIsSet( open_request -> operations, XTM_DB_FLAG_MODE_READ ) ) 4198 flagSet( flags, O_RDONLY ); 4199 4200 if( flagIsSet( open_request -> operations, XTM_DB_FLAG_MODE_WRITE ) ) 4201 flagSet( flags, O_RDWR ); 4202 4203 dbm_ref = dbm_open( filename, flags, 0660 ); 4204 4205 return( (XTM_DB_DATABASE) dbm_ref ); 4206 4207 } /* openDatabase */ 4208 4209 4210 /*----------------------------------------------------------------------*/ 4211 4212 static Boolean updateDbLog(char * directory,UINT32 entry_id,UINT32 flags)4213 updateDbLog( char *directory, 4214 UINT32 entry_id, 4215 UINT32 flags ) 4216 { 4217 4218 /* Variables. */ 4219 int file_mode; 4220 int status; 4221 char filename[ 200 ]; 4222 long offset; 4223 struct stat stat_data; 4224 FILE *file_ref; 4225 XTM_DB_LOG_HEADER header; 4226 XTM_DB_LOG_RECORD log_record; 4227 4228 4229 /* Code. */ 4230 4231 sprintf( filename, "%s/%s", directory, LOG_FILE ); 4232 4233 /* Open the log file for write. */ 4234 file_ref = fopen( filename, "r+" ); 4235 4236 /* If the file did not exist, create it. */ 4237 if( file_ref == NULL ) { 4238 4239 /* Let the log file inherit the directory protection. */ 4240 status = stat( directory, &stat_data ); 4241 if( status != 0 ) 4242 return( False ); 4243 4244 file_mode = stat_data.st_mode & (~(S_IXUSR | S_IXGRP | S_IXOTH)); 4245 4246 /* Open the file. */ 4247 file_ref = fopen( filename, "w" ); 4248 if( file_ref == NULL ) 4249 return( False ); 4250 4251 /* We start all over again. */ 4252 header.last_changed = (UINT32) TimMakeTimeNow(); 4253 header.current_ref = 0; 4254 header.records = 0; 4255 header.max_log_records = XTM_DB_MAX_LOG_RECORDS; 4256 4257 #ifdef NET_BYTE_ORDER 4258 header.last_changed = htonl( header.last_changed ); 4259 header.current_ref = htonl( header.current_ref ); 4260 header.records = htonl( header.records ); 4261 header.max_log_records = htonl( header.max_log_records ); 4262 #endif 4263 4264 memset( header.unused, 0, sizeof( header.unused ) ); 4265 4266 /* Write the record to the file. */ 4267 rewind( file_ref ); 4268 4269 fwrite( (void *) &header, sizeof( header ), 1, file_ref ); 4270 4271 fclose( file_ref ); 4272 4273 /* Set file protection. */ 4274 status = chmod( filename, file_mode ); 4275 if( status != 0 ) 4276 return( False ); 4277 4278 /* Re-open the file for append. */ 4279 file_ref = fopen( filename, "r+" ); 4280 if( file_ref == NULL ) 4281 return( False ); 4282 4283 } /* if */ 4284 4285 4286 /* Fetch the header record. */ 4287 rewind( file_ref ); 4288 4289 fread( (void *) &header, sizeof( header ), 1, file_ref ); 4290 4291 #ifdef NET_BYTE_ORDER 4292 header.last_changed = ntohl( header.last_changed ); 4293 header.current_ref = ntohl( header.current_ref ); 4294 header.records = ntohl( header.records ); 4295 header.max_log_records = ntohl( header.max_log_records ); 4296 #endif 4297 4298 /* Create the log record. */ 4299 log_record.time_stamp = (UINT32) TimMakeTimeNow(); 4300 log_record.entry_id = entry_id; 4301 log_record.flags = flags; 4302 log_record.changed_by = (INT32) getuid(); 4303 4304 #ifdef NET_BYTE_ORDER 4305 log_record.time_stamp = htonl( log_record.time_stamp ); 4306 log_record.entry_id = htonl( log_record.entry_id ); 4307 log_record.flags = htonl( log_record.flags ); 4308 log_record.changed_by = htonl( log_record.changed_by ); 4309 #endif 4310 4311 4312 /* Save the log record. */ 4313 offset = sizeof( header ) + header.current_ref * sizeof( log_record ); 4314 fseek( file_ref, offset, 0 ); 4315 4316 fwrite( (void *) &log_record, sizeof( log_record ), 1, file_ref ); 4317 4318 4319 /* Calculate the new positions for the next record. */ 4320 header.current_ref++; 4321 if( header.current_ref >= header.max_log_records ) 4322 header.current_ref = 0; 4323 4324 header.records++; 4325 4326 #ifdef NET_BYTE_ORDER 4327 header.last_changed = htonl( header.last_changed ); 4328 header.current_ref = htonl( header.current_ref ); 4329 header.records = htonl( header.records ); 4330 header.max_log_records = htonl( header.max_log_records ); 4331 #endif 4332 4333 /* Save the header record. */ 4334 rewind( file_ref ); 4335 4336 fwrite( (void *) &header, sizeof( header ), 1, file_ref ); 4337 4338 4339 /* That's it. */ 4340 fclose( file_ref ); 4341 4342 4343 return( True ); 4344 4345 } /* updateDbLog */ 4346