00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifdef HAVE_CONFIG_H
00021 # include <config.h>
00022 #endif
00023
00024 #include <unistd.h>
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <fcntl.h>
00028 #include <errno.h>
00029 #include <string.h>
00030 #include <math.h>
00031 #include <ctype.h>
00032
00033 #include <glib.h>
00034
00035 #include "libuau.h"
00036 #include "network.h"
00037 #include "error.h"
00038 #include "util.h"
00039 #include "install.h"
00040 #include "ftp.h"
00041
00042 #ifdef WITH_DMALLOC
00043 # include <dmalloc.h>
00044 #endif
00045
00046 #ifdef WITH_LEAKBUG
00047 # include <leakbug.h>
00048 #endif
00049
00050 static int compareAlphaNumeric(const char *v1, const char *v2);
00051
00052 static void categorizeUpdates(GPtrArray *updates, const AProgInfo *progInfo);
00053 static gboolean isIncompatible(AUpdate *update, const AProgInfo *progInfo);
00054 static gboolean isOld(AUpdate *update, const AProgInfo *progInfo);
00055
00056
00070 gboolean
00071 luau_getUpdateInfo(AUpdate *updateInfo, const char* updateID, const AProgInfo *progInfo) {
00072 GPtrArray *allUpdates = luau_checkForUpdates(progInfo);
00073 AUpdate *temp;
00074 gboolean found = FALSE;
00075 int i;
00076
00077 for (i = 0; i < allUpdates->len; ++i) {
00078 temp = g_ptr_array_index(allUpdates, i);
00079 if (lutil_streq(temp->id, updateID)) {
00080 luau_copyUpdate(updateInfo, temp);
00081 found = TRUE;
00082 break;
00083 }
00084 }
00085 luau_freeUpdateArray(allUpdates);
00086
00087 return found;
00088 }
00089
00100 GPtrArray *
00101 luau_checkForUpdates(const AProgInfo *info) {
00102 GPtrArray *result;
00103
00104 DBUGOUT("Checking for updates for %s: %s", info->id, info->url);
00105 result = luau_net_queryServer(info);
00106
00107 categorizeUpdates(result, info);
00108
00109 return result;
00110 }
00111
00121 gboolean
00122 luau_installUpdate(const AProgInfo *info, const AUpdate *newUpdate, const APkgType type) {
00123 char *filename, *actualFilename;
00124 gboolean result;
00125
00126 filename = lutil_getTempFilename();
00127
00128 actualFilename = luau_downloadUpdate(info, newUpdate, type, filename);
00129 result = luau_installPackage(actualFilename, type);
00130
00131 g_free(filename);
00132 g_free(actualFilename);
00133
00134 return result;
00135 }
00136
00151 char *
00152 luau_downloadUpdate(const AProgInfo *info, const AUpdate *newUpdate, const APkgType type, const char* downloadTo) {
00153 char *actualFilename = NULL, *temp;
00154 APackage *pkg;
00155 struct stat fileinfo;
00156 int ret;
00157 gboolean result = FALSE;
00158
00159 if (downloadTo != NULL && downloadTo[0] != '\0') {
00160 while (result == FALSE) {
00161 ret = stat(downloadTo, &fileinfo);
00162 if (ret == -1) {
00163 if (errno != ENOENT) {
00164 ERROR("Can't write to %s: %s", downloadTo, strerror(errno));
00165 return NULL;
00166 } else {
00167 actualFilename = g_strdup(downloadTo);
00168 result = TRUE;
00169 }
00170 } else {
00171 if (S_ISREG(fileinfo.st_mode)) {
00172 ret = lutil_error_prompt("File Exists", "The specified download location already exists. What would you like to do?", 2, 0, "Overwrite", "Cancel");
00173 if (ret == 0) {
00174 DBUGOUT("File '%s' exists: overwriting", downloadTo);
00175 result = TRUE;
00176 } else {
00177 ERROR("File '%s' exists: not overwriting", downloadTo);
00178 return NULL;
00179 }
00180 } else if (S_ISDIR(fileinfo.st_mode)) {
00181 DBUGOUT("Is a directory: writing into that directory");
00182 pkg = luau_getUpdatePackage(newUpdate, type);
00183 temp = luau_getPackageURL(pkg);
00184 DBUGOUT("Preparing to download: %s", temp);
00185 temp = g_path_get_basename(temp);
00186 actualFilename = lutil_vstrcreate(downloadTo, "/", temp, NULL);
00187 g_free(temp);
00188 downloadTo = actualFilename;
00189
00190 } else {
00191 DBUGOUT("FIFO, device, symlink, or socket given: treating as regular file");
00192 result = TRUE;
00193 }
00194 }
00195 }
00196
00197 if (actualFilename == NULL)
00198 actualFilename = g_strdup(downloadTo);
00199 } else {
00200 ERROR("No filename given!");
00201 return NULL;
00202 }
00203
00204 result = luau_net_downloadUpdate(info, newUpdate, type, actualFilename);
00205
00206 if (result == FALSE) {
00207 g_free(actualFilename);
00208 ERROR("Could not download specified update");
00209 actualFilename = NULL;
00210 }
00211
00212 return actualFilename;
00213 }
00214
00222 gboolean
00223 luau_installPackage(const char *filename, const APkgType type) {
00224 gboolean result = FALSE;
00225
00226 switch (type) {
00227 case LUAU_RPM:
00228 result = luau_install_rpm(filename);
00229 break;
00230 case LUAU_DEB:
00231 result = luau_install_deb(filename);
00232 break;
00233 case LUAU_SRC:
00234 result = luau_install_src(filename);
00235 break;
00236 case LUAU_EXEC:
00237 result = luau_install_exec(filename);
00238 break;
00239 case LUAU_AUTOPKG:
00240 result = luau_install_autopkg(filename);
00241 break;
00242 default:
00243 ERROR("Invalid packager type qualifier: %d", type);
00244 result = FALSE;
00245 }
00246
00247
00248
00249
00250 return result;
00251 }
00252
00261 void
00262 luau_registerErrorFunc(AErrorFunc errorFunc) {
00263 lutil_error_setErrorFunc(errorFunc);
00264 }
00265
00276 void
00277 luau_registerPromptFunc(APromptFunc promptFunc) {
00278 lutil_error_setPromptFunc(promptFunc);
00279 }
00280
00291 void
00292 luau_registerProgressCallback(AProgressCallback callback) {
00293 lutil_ftp_setCallbackFunc(callback);
00294 }
00295
00302 void
00303 luau_resetErrorFunc(void) {
00304 lutil_error_resetErrorFunc();
00305 }
00306
00313 void
00314 luau_resetPromptFunc(void) {
00315 lutil_error_resetPromptFunc();
00316 }
00317
00323 void
00324 luau_resetProgressCallback(void) {
00325 lutil_ftp_resetCallbackFunc();
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00343 APackage *
00344 luau_getUpdatePackage(const AUpdate *update, APkgType pkgType) {
00345 GPtrArray *updateArray = update->packages;
00346 APackage *temp, *result = NULL;
00347 int i;
00348
00349 for (i = 0; i < updateArray->len; ++i) {
00350 temp = g_ptr_array_index(updateArray, i);
00351 if (temp->type == pkgType) {
00352 result = temp;
00353 break;
00354 }
00355 }
00356
00357 if (result == NULL) {
00358 ERROR("No package of type %s in selected update!", luau_packageTypeString(pkgType));
00359 return NULL;
00360 } else {
00361 return result;
00362 }
00363 }
00364
00372 char *
00373 luau_dateString(const ADate *date) {
00374
00375 char* string;
00376 if (date == NULL) {
00377 string = g_strdup("(null)");
00378 } else {
00379 string = lutil_mprintf("%.2d/%.2d/%.4d", date->month, date->day, date->year);
00380 }
00381 return string;
00382 }
00383
00393 gboolean
00394 luau_parseDate(ADate *date, const char *string) {
00395 int ret;
00396
00397 if (string == NULL) {
00398 date->year = 0;
00399 date->month = 0;
00400 date->day = 0;
00401 return FALSE;
00402 }
00403
00404 memset(date, 0, sizeof(ADate));
00405 ret = sscanf(string, "%hd/%hd/%d", &(date->month), &(date->day), &(date->year));
00406
00407 return (ret == 3);
00408 }
00409
00420 int
00421 luau_datecmp(ADate *d1, ADate *d2) {
00422 int result;
00423
00424 if (d1 == NULL || d2 == NULL)
00425 return 0;
00426 else if ((result = lutil_intcmp(d1->year, d2->year)) != 0)
00427 return result;
00428 else if ((result = lutil_intcmp(d1->month, d2->month)) != 0)
00429 return result;
00430 else
00431 return lutil_intcmp(d1->day, d2->day);
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472 int
00473 luau_versioncmp(const char *required, const char *current) {
00474 GContainer *reqElements, *curElements;
00475 char *req, *cur;
00476 int max, i, len, result, x, y;
00477
00478 result = 0;
00479
00480 req = g_strdup(required);
00481 cur = g_strdup(current);
00482
00483 lutil_strToLower(req);
00484 lutil_strToLower(cur);
00485
00486
00487 len = strlen(req);
00488 for (i = 0; i < len; ++i) {
00489 if (req[i] == '-' || req[i] == '_' || req[i] == '/' || req[i] == '+' || req[i] == '\\')
00490 req[i] = '.';
00491 }
00492
00493 len = strlen(cur);
00494 for (i = 0; i < len; ++i) {
00495 if (cur[i] == '-' || cur[i] == '_' || cur[i] == '/' || cur[i] == '+' || cur[i] == '\\')
00496 cur[i] = '.';
00497 }
00498
00499
00500 reqElements = lutil_gsplit(".", req);
00501 curElements = lutil_gsplit(".", cur);
00502
00503 g_free(req);
00504 g_free(cur);
00505
00506
00507 if (reqElements->len > curElements->len)
00508 max = reqElements->len;
00509 else
00510 max = curElements->len;
00511
00512 for (i = 0; i < max; ++i) {
00513
00514
00515
00516 req = (i < reqElements->len) ? g_container_index(reqElements, i) : NULL;
00517 cur = (i < curElements->len) ? g_container_index(curElements, i) : NULL;
00518
00519
00520 if ((req != NULL && lutil_streq(req, "x")) || (cur != NULL && lutil_streq(cur, "x"))) {
00521 result = 0;
00522 break;
00523 }
00524
00525 if (lutil_containsAlpha(cur) || lutil_containsAlpha(req)) {
00526 result = compareAlphaNumeric(req, cur);
00527
00528 if (result != 0)
00529 break;
00530 } else if (req == NULL) {
00531 result = -1;
00532 break;
00533 } else if (cur == NULL) {
00534 result = 1;
00535 break;
00536 } else {
00537 x = atoi(req);
00538 y = atoi(cur);
00539
00540 if (x != y) {
00541 result = (x < y) ? -1 : 1;
00542 break;
00543 }
00544 }
00545 }
00546
00547 g_container_destroy(reqElements);
00548 g_container_destroy(curElements);
00549
00550 return result;
00551 }
00552
00560 gboolean
00561 luau_isOfType(APkgType query, APkgType type) {
00562 return ( (query & type) == 0 ? FALSE : TRUE);
00563 }
00564
00574 char *
00575 luau_multPackageTypeString(APkgType types) {
00576 char *str = lutil_createString(25);
00577 int n;
00578
00579 str[0] = '\0';
00580 if (luau_isOfType(types, LUAU_RPM))
00581 strcat(str, "RPM ");
00582 if (luau_isOfType(types, LUAU_DEB))
00583 strcat(str, "DEB ");
00584 if (luau_isOfType(types, LUAU_SRC))
00585 strcat(str, "SRC ");
00586 if (luau_isOfType(types, LUAU_EXEC))
00587 strcat(str, "EXEC ");
00588 if (luau_isOfType(types, LUAU_AUTOPKG))
00589 strcat(str, "AUTOPKG ");
00590
00591 if ((n = strlen(str)) != 0) {
00592 str[n-1] = '\0';
00593 } else if (types == LUAU_EMPTY) {
00594 strcpy(str, "(none)");
00595 } else {
00596 ERROR("Unrecognized package type: %d", types);
00597 strcpy(str, "UNKNOWN");
00598 }
00599
00600 return str;
00601 }
00602
00612 const char *
00613 luau_packageTypeString(APkgType type) {
00614 const char *str = NULL;
00615
00616 if (type == LUAU_RPM)
00617 str = "RPM";
00618 else if (type == LUAU_DEB)
00619 str = "DEB";
00620 else if (type == LUAU_SRC)
00621 str = "SRC";
00622 else if (type == LUAU_EXEC)
00623 str = "EXEC";
00624 else if (type == LUAU_AUTOPKG)
00625 str = "AUTOPKG";
00626 else if (type == LUAU_EMPTY)
00627 str = "(none)";
00628 else
00629 str = "UNKNOWN";
00630
00631 return str;
00632 }
00633
00643 APkgType
00644 luau_parsePkgType(const char* typeString) {
00645 APkgType type = LUAU_UNKNOWN;
00646 if (lutil_streq(typeString, "RPM")) type = LUAU_RPM;
00647 else if (lutil_streq(typeString, "DEB")) type = LUAU_DEB;
00648 else if (lutil_streq(typeString, "SRC")) type = LUAU_SRC;
00649 else if (lutil_streq(typeString, "EXEC")) type = LUAU_EXEC;
00650 else if (lutil_streq(typeString, "autopackage")) type = LUAU_AUTOPKG;
00651 else if (lutil_streq(typeString, "AUTOPKG")) type = LUAU_AUTOPKG;
00652 return type;
00653 }
00654
00655 char *
00656 luau_getPackageURL(APackage *pkgInfo) {
00657 GPtrArray *mirrors = pkgInfo->mirrors;
00658 char *loc = NULL;
00659 int percentage, random, i;
00660
00661 #ifdef DEBUG
00662 for (i = 0; i < mirrors->len; i += 2)
00663 DBUGOUT("URL: %s; weight: %d\n", (char*)g_ptr_array_index(mirrors, i+1), GPOINTER_TO_INT (g_ptr_array_index(mirrors, i)));
00664 #endif
00665
00666 if (mirrors == NULL || mirrors->len == 0)
00667 return NULL;
00668 else if (mirrors->len == 2)
00669 return g_ptr_array_index(mirrors, 1);
00670
00671 random = rand() % 100;
00672
00673 for (i = 0; i < mirrors->len; i+=2) {
00674 percentage = GPOINTER_TO_INT( g_ptr_array_index(mirrors, i) );
00675 if (random <= percentage) {
00676 loc = g_ptr_array_index(mirrors, i+1);
00677 break;
00678 } else {
00679 random -= percentage;
00680 }
00681 }
00682
00683 if (loc == NULL && mirrors->len >= 2)
00684 loc = g_ptr_array_index(mirrors, 1);
00685
00686 return loc;
00687 }
00688
00696 GSList *
00697 luau_packageTypeList(APkgType types) {
00698 GSList *list = NULL;
00699
00700 if (luau_isOfType(types, LUAU_RPM))
00701 list = g_slist_append(list, GINT_TO_POINTER (LUAU_RPM));
00702 if (luau_isOfType(types, LUAU_DEB))
00703 list = g_slist_append(list, GINT_TO_POINTER (LUAU_DEB));
00704 if (luau_isOfType(types, LUAU_SRC))
00705 list = g_slist_append(list, GINT_TO_POINTER (LUAU_SRC));
00706 if (luau_isOfType(types, LUAU_EXEC))
00707 list = g_slist_append(list, GINT_TO_POINTER (LUAU_EXEC));
00708 if (luau_isOfType(types, LUAU_AUTOPKG))
00709 list = g_slist_append(list, GINT_TO_POINTER (LUAU_AUTOPKG));
00710
00711 return list;
00712 }
00713
00721 const char *
00722 luau_updateTypeString(AUpdateType type) {
00723 switch (type) {
00724 case LUAU_SOFTWARE: return "Software";
00725 case LUAU_MESSAGE: return "Message";
00726 case LUAU_LIBUPDATE: return "Luau Config";
00727 default: return "UNKNOWN";
00728 }
00729 }
00730
00737 char *
00738 luau_progInfoString(const AProgInfo *info) {
00739 char *str, *keywordsStr, *dateStr;
00740
00741 keywordsStr = luau_keywordsString(info->keywords);
00742 dateStr = luau_dateString(info->date);
00743 str = lutil_mprintf("{ ID => %s,\n Name => %s,\n Desc => %s,\n URL => %s,\n Version => %s,\n Date => %s,\n Keywords => %s\n}",
00744 info->id, info->fullname, info->desc, info->url, info->version, dateStr, keywordsStr);
00745
00746 g_free(keywordsStr);
00747 g_free(dateStr);
00748
00749 return str;
00750 }
00751
00759 char *
00760 luau_keywordsString(const GPtrArray *keywords) {
00761 GContainer *keyCont;
00762 char *str;
00763
00764 if (keywords == NULL)
00765 str = g_strdup("");
00766 else {
00767 keyCont = g_container_new_from_data(GCONT_PTR_ARRAY, (void*)keywords);
00768 str = lutil_strjoin(", ", keyCont);
00769 g_container_free(keyCont, FALSE);
00770 }
00771
00772 return str;
00773 }
00774
00781 void
00782 luau_setKeyword(GPtrArray *keywords, const char *newKeyword) {
00783 if (keywords != NULL && newKeyword != NULL)
00784 g_ptr_array_add(keywords, g_strdup(newKeyword));
00785 }
00786
00795 gboolean
00796 luau_unsetKeyword(GPtrArray *keywords, const char *oldKeyword) {
00797 int i;
00798 gboolean found = FALSE;
00799 char *curr;
00800
00801 for (i = 0; i < keywords->len; ++i) {
00802 curr = g_ptr_array_index(keywords, i);
00803 if (lutil_streq(curr, oldKeyword)) {
00804 found = TRUE;
00805 g_ptr_array_remove_index_fast(keywords, i);
00806 break;
00807 }
00808 }
00809
00810 return found;
00811 }
00812
00820 gboolean
00821 luau_checkKeyword(const GPtrArray *keywords, const char *needle) {
00822 GContainer *cont;
00823 gboolean result;
00824
00825 if (keywords != NULL && needle != NULL) {
00826 cont = g_container_new_from_data(GCONT_PTR_ARRAY, (void*)keywords);
00827 result = lutil_findString(cont, needle);
00828 g_container_free(cont, FALSE);
00829 }
00830 else
00831 result = FALSE;
00832
00833 return result;
00834 }
00835
00842 gboolean
00843 luau_isIncompatible(AUpdate *update) {
00844 if (update != NULL && update->keywords != NULL)
00845 return luau_checkKeyword(update->keywords, "_incompatible");
00846 else
00847 return FALSE;
00848 }
00849
00856 gboolean
00857 luau_isHidden(AUpdate *update) {
00858 if (update != NULL && update->keywords != NULL)
00859 return luau_checkKeyword(update->keywords, "_hidden");
00860 else
00861 return FALSE;
00862 }
00863
00864 gboolean
00865 luau_isOld(AUpdate *update) {
00866 if (update != NULL && update->keywords != NULL)
00867 return luau_checkKeyword(update->keywords, "_old");
00868 else
00869 return FALSE;
00870 }
00871
00872 gboolean
00873 luau_isVisible(AUpdate *update) {
00874 return !(luau_isOld(update) || luau_isHidden(update) || luau_isIncompatible(update));
00875 }
00876
00889 gboolean
00890 luau_satisfiesInterface(const AInterface *wanted, const AInterface *needed) {
00891 return ((wanted->major == needed->major) && (wanted->minor >= needed->minor));
00892 }
00893
00894 gboolean
00895 luau_satisfiesQuant(const AQuantifier *needed, const AProgInfo *installed) {
00896 gboolean result;
00897 int compare;
00898
00899
00900
00901
00902
00903 if (needed->dtype == LUAU_QUANT_DATA_INTERFACE) {
00904 if (needed->qtype == LUAU_QUANT_FOR)
00905 result = luau_satisfiesInterface(&(installed->interface), (AInterface*) needed->data);
00906 else {
00907 ERROR("Interface quantifiers can only be of type 'for', not of 'from' or 'to'");
00908 result = TRUE;
00909 }
00910 } else if (needed->dtype == LUAU_QUANT_DATA_KEYWORD) {
00911 if (needed->qtype == LUAU_QUANT_FOR)
00912 result = luau_checkKeyword(installed->keywords, (char*)needed->data);
00913 else {
00914 ERROR("Keyword quantifiers can only be of type 'for', not of 'from' or 'to'");
00915 result = TRUE;
00916 }
00917 } else if (needed->dtype == LUAU_QUANT_DATA_DATE || needed->dtype == LUAU_QUANT_DATA_VERSION) {
00918 if (needed->dtype == LUAU_QUANT_DATA_DATE)
00919 compare = luau_datecmp(installed->date, (ADate*) needed->data);
00920 else
00921 compare = luau_versioncmp(installed->version, (const char *) needed->data);
00922
00923 if (needed->qtype == LUAU_QUANT_FOR)
00924 result = (compare == 0);
00925 else if (needed->qtype == LUAU_QUANT_FROM)
00926 result = (compare != -1);
00927 else if (needed->qtype == LUAU_QUANT_TO)
00928 result = (compare == -1);
00929 else {
00930 ERROR("Internal Error: Unrecognized quantifier type (%d)", needed->qtype);
00931 result = TRUE;
00932 }
00933 } else {
00934 ERROR("Internal Error: Unrecognized quantifier data type (%d)", needed->dtype);
00935 result = TRUE;
00936 }
00937
00938 return result;
00939 }
00940
00941 AQuantDataType
00942 luau_parseQuantDataType(const char *str) {
00943 AQuantDataType type;
00944
00945 if (lutil_strcaseeq(str, "version"))
00946 type = LUAU_QUANT_DATA_VERSION;
00947 else if (lutil_strcaseeq(str, "interface"))
00948 type = LUAU_QUANT_DATA_INTERFACE;
00949 else if (lutil_strcaseeq(str, "date"))
00950 type = LUAU_QUANT_DATA_DATE;
00951 else if (lutil_strcaseeq(str, "keyword"))
00952 type = LUAU_QUANT_DATA_KEYWORD;
00953 else
00954 type = LUAU_QUANT_DATA_INVALID;
00955
00956 return type;
00957 }
00958
00969 gboolean
00970 luau_parseInterface(AInterface *interface, const char *intStr) {
00971 gboolean result = FALSE;
00972 int ret = 0;
00973
00974 interface->major = -1;
00975 interface->minor = -1;
00976
00977 if (intStr != NULL) {
00978 if (lutil_isCompletelyBlank(intStr))
00979 result = TRUE;
00980 else {
00981 ret = sscanf(intStr, "%d.%d", &(interface->major), &(interface->minor));
00982 result = (ret == 2);
00983 }
00984 }
00985
00986 return result;
00987 }
00988
00997 char *
00998 luau_interfaceString(const AInterface *interface) {
00999 char *ret;
01000
01001 if (interface->major == -1 && interface->minor == -1)
01002 ret = g_strdup("");
01003 else
01004 ret = lutil_mprintf("%d.%d", interface->major, interface->minor);
01005
01006 return ret;
01007 }
01008
01009
01010
01011
01018 void
01019 luau_copyUpdate(AUpdate *dest, const AUpdate *src) {
01020 APackage *destPkg, *srcPkg;
01021 int i;
01022
01023 if (dest == NULL || src == NULL) {
01024 DBUGOUT("Null pointer passed to luau_copyUpdate");
01025 } else {
01026
01027 dest->id = g_strdup(src->id);
01028 dest->shortDesc = g_strdup(src->shortDesc);
01029 dest->fullDesc = g_strdup(src->fullDesc);
01030 dest->newVersion = g_strdup(src->newVersion);
01031 dest->newURL = g_strdup(src->newURL);
01032
01033 dest->type = src->type;
01034 dest->availableFormats = src->availableFormats;
01035 luau_copyInterface(&(dest->interface), &(src->interface));
01036
01037 if (src->keywords != NULL) {
01038 GContainer *destCont, *srcCont;
01039
01040 dest->keywords = g_ptr_array_new();
01041 destCont = g_container_new_from_data(GCONT_PTR_ARRAY, dest->keywords);
01042 srcCont = g_container_new_from_data(GCONT_PTR_ARRAY, src->keywords);
01043 g_container_copy(destCont, srcCont);
01044 g_container_free(srcCont, FALSE);
01045 g_container_free(destCont, FALSE);
01046 } else {
01047 dest->keywords = NULL;
01048 }
01049 if (src->packages != NULL) {
01050 dest->packages = g_ptr_array_new();
01051 for (i = 0; i < src->packages->len; ++i) {
01052 srcPkg = g_ptr_array_index(src->packages, i);
01053 destPkg = g_malloc(sizeof(APackage));
01054
01055 luau_copyPackage(destPkg, srcPkg);
01056 g_ptr_array_add(dest->packages, destPkg);
01057 }
01058 } else {
01059 dest->packages = NULL;
01060 }
01061
01062 if (src->date != NULL) {
01063 dest->date = g_malloc(sizeof(ADate));
01064 luau_copyDate(dest->date, src->date);
01065 } else {
01066 dest->date = NULL;
01067 }
01068
01069 if (src->quantifiers != NULL) {
01070 dest->quantifiers = g_ptr_array_new();
01071 luau_copyQuants(dest->quantifiers, src->quantifiers);
01072 } else {
01073 dest->quantifiers = NULL;
01074 }
01075
01076
01077
01078
01079
01080
01081
01082 }
01083 }
01084
01085 void
01086 luau_copyPackage(APackage *dest, const APackage *src) {
01087 int i, curr;
01088 if (dest == NULL || src == NULL) {
01089 DBUGOUT("Null pointer passed to luau_copyPackage");
01090 } else {
01091 dest->type = src->type;
01092 dest->size = src->size;
01093 strncpy(dest->md5sum, src->md5sum, 33);
01094 if (src->mirrors != NULL) {
01095 dest->mirrors = g_ptr_array_new();
01096 for (i = 0; i < src->mirrors->len; i++) {
01097 if (i%2)
01098 g_ptr_array_add(dest->mirrors, g_strdup(g_ptr_array_index(src->mirrors, i)));
01099 else {
01100 curr = GPOINTER_TO_INT (g_ptr_array_index(src->mirrors, i));
01101 g_ptr_array_add(dest->mirrors, GINT_TO_POINTER (curr));
01102 }
01103 }
01104 }
01105 }
01106
01107 #ifdef DEBUG
01108 for (i = 0; i < dest->mirrors->len; i += 2)
01109 DBUGOUT("URL: %s; weight: %d\n", (char*)g_ptr_array_index(dest->mirrors, i+1), GPOINTER_TO_INT (g_ptr_array_index(dest->mirrors, i)));
01110 #endif
01111
01112 }
01113
01120 void
01121 luau_copyProgInfo(AProgInfo *dest, const AProgInfo *src) {
01122 if (dest == NULL || src == NULL) {
01123 DBUGOUT("Null pointer passed to luau_copyProgInfo");
01124 } else {
01125 dest->id = g_strdup(src->id);
01126 dest->shortname = g_strdup(src->shortname);
01127 dest->fullname = g_strdup(src->fullname);
01128 dest->desc = g_strdup(src->desc);
01129 dest->url = g_strdup(src->url);
01130 dest->version = g_strdup(src->version);
01131
01132 luau_copyInterface(&(dest->interface), &(src->interface));
01133
01134 if (src->date != NULL) {
01135 dest->date = g_malloc(sizeof(ADate));
01136 luau_copyDate(dest->date, src->date);
01137 } else {
01138 dest->date = NULL;
01139 }
01140 if (src->keywords != NULL) {
01141 GContainer *srcCont, *destCont;
01142 dest->keywords = g_ptr_array_new();
01143 srcCont = g_container_new_from_data(GCONT_PTR_ARRAY, src->keywords);
01144 destCont = g_container_new_from_data(GCONT_PTR_ARRAY, dest->keywords);
01145 g_container_copy(destCont, srcCont);
01146 g_container_free(srcCont, FALSE);
01147 g_container_free(destCont, FALSE);
01148 } else {
01149 dest->keywords = NULL;
01150 }
01151 }
01152 }
01153
01160 void
01161 luau_copyInterface(AInterface *dest, const AInterface *src) {
01162 if (dest == NULL || src == NULL) {
01163 DBUGOUT("Null pointer passed to luau_copyInterface");
01164 } else {
01165 dest->major = src->major;
01166 dest->minor = src->minor;
01167 }
01168 }
01169
01176 void
01177 luau_copyDate(ADate *dest, const ADate *src) {
01178 if (dest == NULL || src == NULL) {
01179 DBUGOUT("Null pointer passed to luau_copyDate");
01180 } else {
01181 dest->year = src->year;
01182 dest->month = src->month;
01183 dest->day = src->day;
01184 }
01185 }
01186
01187 void
01188 luau_copyQuants(GPtrArray *dest, const GPtrArray *src) {
01189 AQuantifier *quant;
01190 int i;
01191
01192 for (i = 0; i < src->len; ++i) {
01193 quant = g_malloc(sizeof(AQuantifier));
01194 luau_copyQuant(quant, g_ptr_array_index(src, i));
01195 g_ptr_array_add(dest, quant);
01196 }
01197 }
01198
01199 void
01200 luau_copyQuant(AQuantifier *dest, const AQuantifier *src) {
01201 dest->qtype = src->qtype;
01202 dest->dtype = src->dtype;
01203
01204 switch (dest->dtype) {
01205 case LUAU_QUANT_DATA_DATE:
01206 dest->data = g_malloc(sizeof(ADate));
01207 luau_copyDate(dest->data, src->data);
01208 break;
01209
01210 case LUAU_QUANT_DATA_VERSION:
01211 case LUAU_QUANT_DATA_INTERFACE:
01212 case LUAU_QUANT_DATA_KEYWORD:
01213 dest->data = g_strdup(src->data);
01214 break;
01215
01216 default:
01217 ERROR("Invalid Quantifier Data type - can't copy");
01218 }
01219 }
01220
01221
01222
01223
01229 void
01230 luau_freeUpdateArray(GPtrArray *updates) {
01231 AUpdate *curr;
01232 int i;
01233
01234 if (updates != NULL) {
01235 for (i = 0; i < updates->len; ++i) {
01236 curr = g_ptr_array_index(updates, i);
01237 luau_freeUpdateInfo(curr);
01238 g_free(curr);
01239 }
01240
01241 g_ptr_array_free(updates, TRUE);
01242 }
01243 }
01244
01250 void
01251 luau_freeProgInfo(AProgInfo *ptr) {
01252 if (ptr != NULL) {
01253 int i;
01254 nnull_g_free(ptr->id);
01255 nnull_g_free(ptr->shortname);
01256 nnull_g_free(ptr->fullname);
01257 nnull_g_free(ptr->desc);
01258 nnull_g_free(ptr->url);
01259 nnull_g_free(ptr->version);
01260 nnull_g_free(ptr->displayVersion);
01261 nnull_g_free(ptr->date);
01262 if (ptr->keywords != NULL) {
01263 for (i = 0; i < ptr->keywords->len; ++i)
01264 g_free(g_ptr_array_index(ptr->keywords, i));
01265 g_ptr_array_free(ptr->keywords, TRUE);
01266 }
01267 } else {
01268 ERROR("Attempt to free NULL pointer");
01269 }
01270 }
01271
01277 void
01278 luau_freeUpdateInfo(AUpdate *ptr) {
01279 APackage *pkg;
01280 AQuantifier *quant;
01281 int i;
01282
01283 if (ptr != NULL) {
01284 nnull_g_free(ptr->id);
01285 nnull_g_free(ptr->date);
01286 nnull_g_free(ptr->shortDesc);
01287 nnull_g_free(ptr->fullDesc);
01288 nnull_g_free(ptr->newVersion);
01289 nnull_g_free(ptr->newURL);
01290
01291 if (ptr->keywords != NULL) {
01292 for (i = 0; i < ptr->keywords->len; ++i)
01293 g_free(g_ptr_array_index(ptr->keywords, i));
01294 g_ptr_array_free(ptr->keywords, TRUE);
01295 }
01296 if (ptr->packages != NULL) {
01297 for (i = 0; i < ptr->packages->len; ++i) {
01298 pkg = g_ptr_array_index(ptr->packages, i);
01299 luau_freePkgInfo(pkg);
01300 g_free(pkg);
01301 }
01302 g_ptr_array_free(ptr->packages, TRUE);
01303 }
01304 if (ptr->quantifiers != NULL) {
01305 for (i = 0; i < ptr->quantifiers->len; ++i) {
01306 quant = g_ptr_array_index(ptr->quantifiers, i);
01307 g_free(quant->data);
01308 g_free(quant);
01309 }
01310 g_ptr_array_free(ptr->quantifiers, TRUE);
01311 }
01312 } else {
01313 ERROR("Attempt to free NULL pointer");
01314 }
01315 }
01316
01322 void
01323 luau_freePkgInfo(APackage *ptr) {
01324 int i;
01325
01326 if (ptr != NULL) {
01327 if (ptr->mirrors != NULL) {
01328 for (i = 1; i < ptr->mirrors->len; i+=2)
01329 g_free(g_ptr_array_index(ptr->mirrors, i));
01330 g_ptr_array_free(ptr->mirrors, TRUE);
01331 }
01332 } else {
01333 ERROR("Attempt to free NULL pointer");
01334 }
01335 }
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347 static int
01348 compareAlphaNumeric(const char *v1, const char *v2) {
01349 int i, len1, len2, limit, result = 0;
01350
01351 if (v1 == NULL)
01352 v1 = "";
01353 if (v2 == NULL)
01354 v2 = "";
01355
01356
01357 len1 = strlen(v1);
01358 len2 = strlen(v2);
01359 if (len1 > len2)
01360 limit = len1;
01361 else
01362 limit = len2;
01363
01364 for (i = 0; i < limit; ++i) {
01365 char char1, char2;
01366 int val1, val2;
01367
01368
01369 if (i < len1)
01370 char1 = v1[i];
01371 else
01372 char1 = '\0';
01373
01374 if (i < len2)
01375 char2 = v2[i];
01376 else
01377 char2 = '\0';
01378
01379
01380
01381 if (! isdigit(char1) && char2 == '\0')
01382 return -1;
01383
01384
01385 if (isdigit(v1[i]))
01386 val1 = atoi(v1 + i);
01387 else if (char1 == '\0')
01388 val1 = 0;
01389 else
01390 val1 = -1;
01391
01392 if (isdigit(v2[i]))
01393 val2 = atoi(v2 + i);
01394 else if (char2 == '\0')
01395 val2 = 0;
01396 else
01397 val2 = -1;
01398
01399
01400 if (val1 != -1 || val2 != -1) {
01401 if (val1 > val2) {
01402 result = 1;
01403 break;
01404 } else if (val1 < val2) {
01405 result = -1;
01406 break;
01407 } else if (val1 >= 10) {
01408
01409 i += log10(val1);
01410 }
01411 } else if (char1 < char2) {
01412 result = -1;
01413 break;
01414 } else if (char1 > char2) {
01415 result = 1;
01416 break;
01417 }
01418 }
01419
01420 return result;
01421 }
01422
01423
01431 static void
01432 categorizeUpdates(GPtrArray *updates, const AProgInfo *progInfo) {
01433 AUpdate *curr;
01434 int i;
01435
01436 if (updates == NULL)
01437 return;
01438
01439 for (i = 0; i < updates->len; ++i) {
01440 curr = g_ptr_array_index(updates, i);
01441 if (isIncompatible(curr, progInfo))
01442 luau_setKeyword(curr->keywords, "_incompatible");
01443 if (isOld(curr, progInfo))
01444 luau_setKeyword(curr->keywords, "_old");
01445 }
01446 }
01447
01455 static gboolean
01456 isIncompatible(AUpdate *update, const AProgInfo *progInfo) {
01457 AQuantifier *curr;
01458 gboolean compatible = TRUE;
01459 int i;
01460
01461 if (update->quantifiers == NULL)
01462 compatible = TRUE;
01463 else {
01464 for (i = 0; i < update->quantifiers->len; ++i) {
01465 curr = g_ptr_array_index(update->quantifiers, i);
01466
01467 if (! luau_satisfiesQuant(curr, progInfo)) {
01468 compatible = FALSE;
01469 break;
01470 }
01471 }
01472 }
01473
01474 return (!compatible);
01475 }
01476
01477 static gboolean
01478 isOld(AUpdate *update, const AProgInfo *progInfo) {
01479 gboolean result;
01480 int ret;
01481
01482 if (update->newVersion == NULL || progInfo->version == NULL)
01483 result = FALSE;
01484 else {
01485 ret = luau_versioncmp(update->newVersion, progInfo->version);
01486 result = (ret != 1);
01487 }
01488
01489 return result;
01490 }
01491
01492
01493
01494