diff options
Diffstat (limited to 'ucmm/ucmm.c')
-rwxr-xr-x[-rw-r--r--] | ucmm/ucmm.c | 615 |
1 files changed, 300 insertions, 315 deletions
diff --git a/ucmm/ucmm.c b/ucmm/ucmm.c index 52bd8f0..7f823c0 100644..100755 --- a/ucmm/ucmm.c +++ b/ucmm/ucmm.c @@ -143,7 +143,7 @@ static char *buf2hex(unsigned char *buf, int len) { } -/* Install a profile for a given monitor */ +/* Install a profile for a given monitor. */ /* Either EDID or display_name may be NULL, but not both. */ /* Any existing association is overwritten. Installed profiles */ /* are not deleted. */ @@ -153,7 +153,7 @@ ucmm_error ucmm_install_monitor_profile( int edid_len, /* Length of edid data */ char *display_name, /* Fall back device association, */ /* the X11 display name */ - char *profile /* Path to profile to be installed. */ + char *sprof /* Path to profile to be installed. */ ) { char *config_file = CONFIG_FILE; char *profile_dir = PROFILE_DIR; @@ -165,7 +165,7 @@ ucmm_error ucmm_install_monitor_profile( if (edid != NULL) edid_hash = fnv_32_buf(edid, edid_len); - debug2((errout,"ucmm_install_monitor_profile called with profile '%s', edid 0x%x, disp '%s'\n",profile,edid_hash,display_name)); + debug2((errout,"ucmm_install_monitor_profile called with profile '%s', edid 0x%x, disp '%s', scope '%s'\n",sprof,edid_hash,display_name, ucmm_scope_string(scope))); /* Verify that we've been given a suitable ICC profile */ /* And read it into a memory buffer */ @@ -173,8 +173,8 @@ ucmm_error ucmm_install_monitor_profile( icmFile *fp; icc *icco; - if ((fp = new_icmFileStd_name(profile,"r")) == NULL) { - debug2((errout,"Unable to ope file '%s'\n",profile)); + if ((fp = new_icmFileStd_name(sprof,"r")) == NULL) { + debug2((errout,"Unable to ope file '%s'\n",sprof)); return ucmm_invalid_profile; } @@ -185,7 +185,7 @@ ucmm_error ucmm_install_monitor_profile( } if (icco->read(icco,fp,0) != 0) { - debug2((errout,"icc read of '%s' failed\n",profile)); + debug2((errout,"icc read of '%s' failed\n",sprof)); icco->del(icco); fp->del(fp); return ucmm_invalid_profile; @@ -193,7 +193,7 @@ ucmm_error ucmm_install_monitor_profile( if (icco->header->deviceClass != icSigDisplayClass || icco->header->colorSpace != icSigRgbData) { - debug2((errout,"profile '%s' isn't an RGB display profile\n",profile)); + debug2((errout,"profile '%s' isn't an RGB display profile\n",sprof)); icco->del(icco); fp->del(fp); return ucmm_invalid_profile; @@ -215,6 +215,7 @@ ucmm_error ucmm_install_monitor_profile( if ((npaths = xdg_bds(&er, &paths, xdg_conf, xdg_write, scope == ucmm_local_system ? xdg_local : xdg_user, + xdg_none, config_file)) == 0) { return ucmm_open_config; } @@ -225,21 +226,22 @@ ucmm_error ucmm_install_monitor_profile( xdg_free(paths, npaths); /* Combined sub-path and profile name */ - if ((data_pathfile = malloc(strlen(profile_dir) + 1 + strlen(profile) + 1)) == NULL) + if ((data_pathfile = malloc(strlen(profile_dir) + 1 + strlen(sprof) + 1)) == NULL) return ucmm_resource; strcpy(data_pathfile, profile_dir); if (strlen(data_pathfile) > 1 && data_pathfile[strlen(data_pathfile)-1] != '/') strcat(data_pathfile, "/"); - if ((tt = strrchr(profile, '/')) != NULL) /* Get base name of profile */ + if ((tt = strrchr(sprof, '/')) != NULL) /* Get base name of profile */ tt++; else - tt = profile; + tt = sprof; strcat(data_pathfile, tt); if ((npaths = xdg_bds(&er, &paths, xdg_conf, xdg_write, scope == ucmm_local_system ? xdg_local : xdg_user, + xdg_none, data_pathfile)) == 0) { free(data_pathfile); free(conf_name); @@ -265,12 +267,12 @@ ucmm_error ucmm_install_monitor_profile( /* Read in the ICC profile, then set the X11 atom value */ #if defined(O_BINARY) || defined(_O_BINARY) - if ((fp = fopen(profile,"rb")) == NULL) + if ((fp = fopen(sprof,"rb")) == NULL) #else - if ((fp = fopen(profile,"r")) == NULL) + if ((fp = fopen(sprof,"r")) == NULL) #endif { - debug2((errout,"Can't open file '%s'\n",profile)); + debug2((errout,"Can't open file '%s'\n",sprof)); free(conf_name); free(data_name); return ucmm_profile_copy; @@ -278,7 +280,7 @@ ucmm_error ucmm_install_monitor_profile( /* Figure out how big it is */ if (fseek(fp, 0, SEEK_END)) { - debug2((errout,"Seek '%s' to EOF failed\n",profile)); + debug2((errout,"Seek '%s' to EOF failed\n",sprof)); free(conf_name); free(data_name); return ucmm_profile_copy; @@ -286,21 +288,21 @@ ucmm_error ucmm_install_monitor_profile( psize = (unsigned long)ftell(fp); if (fseek(fp, 0, SEEK_SET)) { - debug2((errout,"Seek '%s' to SOF failed\n",profile)); + debug2((errout,"Seek '%s' to SOF failed\n",sprof)); free(conf_name); free(data_name); return ucmm_profile_copy; } if ((pdata = (unsigned char *)malloc(psize)) == NULL) { - debug2((errout,"Failed to allocate buffer for profile '%s'\n",profile)); + debug2((errout,"Failed to allocate buffer for profile '%s'\n",sprof)); free(conf_name); free(data_name); return ucmm_profile_copy; } if (fread(pdata, 1, psize, fp) != psize) { - debug2((errout,"Failed to read profile '%s' into buffer\n",profile)); + debug2((errout,"Failed to read profile '%s' into buffer\n",sprof)); free(conf_name); free(data_name); return ucmm_profile_copy; @@ -311,6 +313,7 @@ ucmm_error ucmm_install_monitor_profile( /* Write the profile to its location */ if (mkpdirs(data_name)) { debug2((errout,"Can't create directories for file '%s'\n",data_name)); + free(pdata); free(conf_name); free(data_name); return ucmm_profile_copy; @@ -322,6 +325,7 @@ ucmm_error ucmm_install_monitor_profile( #endif { debug2((errout,"Can't create file '%s'\n",data_name)); + free(pdata); free(conf_name); free(data_name); return ucmm_profile_copy; @@ -329,11 +333,14 @@ ucmm_error ucmm_install_monitor_profile( if (fwrite(pdata, 1, psize, fp) != psize) { debug2((errout,"Failed to write profile '%s' into buffer\n",data_name)); + free(pdata); free(conf_name); free(data_name); return ucmm_profile_copy; } + free(pdata); + if (fclose(fp) != 0) { debug2((errout,"Failed to close profile '%s' into buffer\n",data_name)); free(conf_name); @@ -353,7 +360,8 @@ ucmm_error ucmm_install_monitor_profile( char *mname; /* Name of key to match to */ char *mval; /* Value to match */ int ix = 0; - int recno = -1; /* Number of the last record read */ + int recno = -1; /* Number of the last record read */ + char *xprofile = NULL; /* Path to existing profile, if any */ /* Open the configuration file for modification */ if (mkpdirs(conf_name)) { @@ -425,6 +433,7 @@ ucmm_error ucmm_install_monitor_profile( free(pp); continue; } + free(pp); if (ii > recno) /* Track biggest, so we know what to create next */ recno = ii; if ((pp = jc_get_nth_elem(key, 3)) != NULL && strcmp(pp, mname) == 0 && type == jc_string && strcmp(data, mval) == 0) { @@ -442,11 +451,32 @@ ucmm_error ucmm_install_monitor_profile( if (recno <= 0) recno = 1; debug2((errout, "Adding a new record %d\n",recno)); + + /* Delete any existing profile profile */ } else { + char *key; + jc_type type; + unsigned char *data; + size_t dataSize; + debug2((errout, "Replacing record %d\n",recno)); + + /* Get the existing profile path from the record */ + sprintf(keyn1, "devices/display/%d/ICC_PROFILE", recno); + key = keyn1; + debug2((errout,"Looking up record %d key '%s'\n",recno,keyn1)); + + if ((ev = jc->get_key(jc, -1, &key, &type, &data, &dataSize, NULL)) != jc_ok + || type != jc_string) { + debug2((errout,"jcnf locate/get_key failed with error %d\n",ev)); + } + if ((xprofile = strdup(data)) == NULL) { + debug2((errout,"jcnf get_key malloc failed\n")); + } + debug2((errout,"Existin profile '%s'\n",xprofile)); } - /* Write the record */ + /* Write the new/updated record */ sprintf(keyn1, "devices/display/%d/%s", recno, mname); sprintf(keyn2, "devices/display/%d/ICC_PROFILE", recno); if ((ev = jc->set_key(jc, -1, keyn1, jc_string, mval, strlen(mval)+1, NULL)) != jc_ok @@ -459,299 +489,54 @@ ucmm_error ucmm_install_monitor_profile( return ucmm_set_config; } free(mval); + debug2((errout,"Updated record\n")); - /* write to record the EDID or display name and the profile path */ - if ((ev = jc->update(jc)) != 0) { - debug2((errout,"jcnf write to '%s' failed with error %d\n",conf_name,ev)); - jc->del(jc); - free(conf_name); - free(data_name); - return ucmm_save_config; - } - debug2((errout,"Updated config file '%s'\n",conf_name)); - - /* We're done with this */ - jc->del(jc); - free(conf_name); - free(data_name); - } - debug2((errout,"ucmm done profile install\n")); - return ucmm_ok; -} - -/* Un-install a profile for a given monitor. */ -/* Either EDID or display_name may be NULL, but not both. */ -/* The monitor is left with no profile association. If a profile */ -/* name is provided and matches the one that was associated with */ -/* the monitor, and has no other association, then it will be deleted */ -/* from the data directory. */ -/* Return an error code */ -ucmm_error ucmm_uninstall_monitor_profile( - ucmm_scope scope, /* Scope of instalation */ - unsigned char *edid, /* Primary device identifier, NULL if none. */ - int edid_len, /* Length of edid data */ - char *display_name, /* Fall back device association, */ - char *profile /* Base name of profile to be deleted. NULL if not to be deleted. */ -) { - char *config_file = CONFIG_FILE; - char *profile_dir = PROFILE_DIR; - char *conf_name = NULL; /* Configuration path to use */ - char *data_name = NULL; /* Data path to use */ - char *dprof = NULL; /* Destination for profile */ - unsigned int edid_hash = 0; - - if (edid != NULL) - edid_hash = fnv_32_buf(edid, edid_len); - - debug2((errout,"ucmm_uninstall_monitor_profile called with profile '%s', edid 0x%x, disp '%s'\n",profile,edid_hash,display_name)); - - /* Locate the directories where the config file is, */ - /* and where the profile should be too. */ - { - int npaths; - xdg_error er; - char *data_pathfile; /* Path & name of destination */ - char **paths; - char *tt; - - if ((npaths = xdg_bds(&er, &paths, xdg_conf, xdg_read, - scope == ucmm_local_system ? xdg_local : xdg_user, - config_file)) == 0) { - return ucmm_open_config; - } - if ((conf_name = strdup(paths[0])) == NULL) { - xdg_free(paths, npaths); - return ucmm_resource; - } - xdg_free(paths, npaths); - - if (profile != NULL) { - /* Combined sub-path and profile name */ - if ((data_pathfile = malloc(strlen(profile_dir) + 1 + strlen(profile) + 1)) == NULL) - return ucmm_resource; - strcpy(data_pathfile, profile_dir); - - if (strlen(data_pathfile) > 1 && data_pathfile[strlen(data_pathfile)-1] != '/') - strcat(data_pathfile, "/"); - - if ((tt = strrchr(profile, '/')) != NULL) /* Get base name of profile */ - tt++; - else - tt = profile; - strcat(data_pathfile, tt); - - if ((npaths = xdg_bds(&er, &paths, xdg_conf, xdg_read, - scope == ucmm_local_system ? xdg_local : xdg_user, - data_pathfile)) == 0) { - free(data_pathfile); - free(conf_name); - return ucmm_open_config; - } - free(data_pathfile); - if ((data_name = strdup(paths[0])) == NULL) { - free(conf_name); - xdg_free(paths, npaths); - return ucmm_resource; - } - xdg_free(paths, npaths); - } - } - - debug2((errout,"config file = '%s'\n",conf_name)); - if (data_name != NULL) - debug2((errout,"data file = '%s'\n",data_name)); - - /* Get the config file */ - { - jc_error ev; - jcnf *jc; - char keyn1[100]; - char *mname; /* Name of key to match to */ - char *mval; /* Value to match */ - int ix; - int recno = -1; /* Number of the last record read */ - - /* Open the configuration file for modification */ - if (mkpdirs(conf_name)) { - debug2((errout,"Can't create directories for file '%s'\n",conf_name)); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_open_config; - } - - if ((jc = new_jcnf(&ev, conf_name, jc_modify, jc_create)) == NULL) { - debug2((errout,"new_jcnf '%s' failed with error %d\n",conf_name,ev)); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_open_config; - } - - /* if EDID supplied, Locate a matching EDID */ - if (edid != NULL) { - mname = "EDID"; - if ((mval = buf2hex(edid, edid_len)) == NULL) { - jc->del(jc); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_resource; - } - - /* Else fall back to X11 display name and screen */ - } else { - if (display_name == NULL) { - jc->del(jc); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_no_edid_or_display; - } - mname = "NAME"; - if ((mval = strdup(display_name)) == NULL) { - jc->del(jc); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_resource; - } - } - - debug2((errout,"Searching for %s = '%s'\n",mname,mval)); - for (ix = 0;;ix++) { - char *key, *pp; - jc_type type; - unsigned char *data; - size_t dataSize; - int ii; - - if ((ev = jc->locate_key(jc, &ix, "devices/display/", 0, 0)) != jc_ok - || (ev = jc->get_key(jc, ix, &key, &type, &data, &dataSize, NULL)) != jc_ok) { - if (ev == jc_ix_oorange) { - break; - } - debug2((errout,"jcnf locate/get_key failed with error %d\n",ev)); - free(mval); - jc->del(jc); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_open_config; - } - - if ((pp = jc_get_nth_elem(key, 2)) == NULL) { - continue; - } - if ((ii = atoi(pp)) == 0) { - free(pp); - continue; - } - if (ii > recno) /* Track biggest, so we know what to create next */ - recno = ii; - if ((pp = jc_get_nth_elem(key, 3)) != NULL && strcmp(pp, mname) == 0 && type == jc_string && strcmp(data, mval) == 0) { - /* Found matching record */ - free(pp); - break; - } - if (pp != NULL) - free(pp); - } - - if (ev == jc_ix_oorange) { - debug2((errout,"No matching display was found\n")); - free(mval); - jc->del(jc); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_monitor_not_found; - /* (Should we delete the file anyway ???) */ - } - free(mval); - - debug2((errout,"Deleting record %d key '%s'\n",recno,keyn1)); - - /* Delete the record */ - sprintf(keyn1, "devices/display/%d/", recno); - - for (ix = -1;;ix--) { - if ((ev = jc->locate_key(jc, &ix, keyn1, 0, 1)) == jc_ok) { - if ((ev = jc->delete_key(jc, ix, NULL)) != jc_ok) { - debug2((errout,"jcnf delete_key failed with error %d\n",ev)); - jc->del(jc); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_delete_key; - } - } else { - if (ev == jc_ix_oorange) { - break; - } - debug2((errout,"jcnf locate/get_key failed with error %d\n",ev)); - jc->del(jc); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_open_config; - } - } - - if (data_name != NULL) { - /* See if the profile is used by any other device */ + if (xprofile != NULL) { - debug2((errout, "Searching for any reference to profile '%s'\n",data_name)); + /* See if the profile is used by any device in this scope's config */ + /* (including just installed profile) */ + debug2((errout, "Searching for any other reference to existin gprofile '%s'\n",xprofile)); for (ix = 0;;ix++) { char *key, *pp; - jc_type type; unsigned char *data; + jc_type type; size_t dataSize; - + if ((ev = jc->locate_key(jc, &ix, "devices/display/", 0, 0)) != jc_ok || (ev = jc->get_key(jc, ix, &key, &type, &data, &dataSize, NULL)) != jc_ok) { - if (ev == jc_ix_oorange) { + if (ev == jc_ix_oorange) break; - } debug2((errout,"jcnf locate/get_key failed with error %d\n",ev)); - jc->del(jc); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_access_config; + break; } if ((pp = jc_get_nth_elem(key, 3)) == NULL) continue; if (strcmp(pp,"ICC_PROFILE") != 0 || type != jc_string - || strcmp(data, data_name) != 0) { + || strcmp(data, xprofile) != 0) { free(pp); continue; } free(pp); + debug2((errout, "Found reference at ix %d - not deleting %d\n",ix)); break; } - /* If not, delete the file */ + + /* If not, delete the profile */ if (ev == jc_ix_oorange) { - debug2((errout,"Deleting profile '%s'\n",data_name)); - if (unlink(data_name) != 0) { - debug2((errout,"ucmm unlink '%s' failed\n",data_name)); - jc->del(jc); - free(conf_name); - if (data_name != NULL) - free(data_name); - return ucmm_access_config; - } + debug2((errout,"Deleting existing profile '%s'\n",xprofile)); + if (unlink(xprofile) != 0) + debug2((errout,"ucmm unlink '%s' failed\n",xprofile)); } + free(xprofile); } - /* Update the config */ + /* write to record the EDID or display name and the profile path */ if ((ev = jc->update(jc)) != 0) { debug2((errout,"jcnf write to '%s' failed with error %d\n",conf_name,ev)); jc->del(jc); free(conf_name); - if (data_name != NULL) - free(data_name); + free(data_name); return ucmm_save_config; } debug2((errout,"Updated config file '%s'\n",conf_name)); @@ -759,36 +544,59 @@ ucmm_error ucmm_uninstall_monitor_profile( /* We're done with this */ jc->del(jc); free(conf_name); - if (data_name != NULL) - free(data_name); + free(data_name); } - debug2((errout,"ucmm done profile un-install\n")); + debug2((errout,"ucmm done profile install\n")); return ucmm_ok; } -/* Get an associated monitor profile. */ +/* Internal support function: */ +/* Locate an associated config record for a given device or name */ /* Return ucmm_no_profile if there is no installed profile for this */ /* monitor. */ /* Return an error code */ -ucmm_error ucmm_get_monitor_profile( +static ucmm_error ucmm_get_monitor_config( + char **pprofile, /* Return path to profile - free after use */ + int *precno, /* Return record no where display was located */ + jcnf **pjc, /* Return open jcnf */ unsigned char *edid, /* Primary device identifier, NULL if none. */ int edid_len, /* Length of edid data */ char *display_name, /* Fall back device association, */ - char **profile /* Return path to profile. free() afterwards. */ + jc_mod modify, /* Flag, nz to open for modification */ + ucmm_scope mscope /* If modify, specifies scope */ ) { - int scope; + int sscope, escope, scope; char *config_file = "color.jcnf"; - char *conf_name = NULL; /* Configuration path to use */ + char *conf_name; /* Path to config file, free() afterwards. */ unsigned int edid_hash = 0; + *pprofile = NULL; /* In case of failure */ + *precno = -1; + *pjc = NULL; + if (edid != NULL) edid_hash = fnv_32_buf(edid, edid_len); - debug2((errout,"ucmm_get_monitor_profile called edid 0x%x, disp '%s'\n",edid_hash,display_name)); + debug2((errout,"ucmm_get_monitor_config called edid 0x%x, modify %d, scope %d, disp '%s'\n",edid_hash,modify,scope,display_name)); + + if (modify == jc_modify) { + if (mscope == ucmm_user) { + sscope = 0; + escope = 0; + } else { /* Just local system */ + sscope = 1; + escope = 1; + } + } else { /* User and local system */ + sscope = 0; + escope = 1; + } /* Look at user then local system scope */ - for (scope = 0; scope < 2; scope++) { + for (scope = sscope; scope <= escope; scope++) { + debug2((errout," checking scope %d\n",scope)); + /* Locate the directories where the config file is, */ { int npaths; @@ -796,9 +604,12 @@ ucmm_error ucmm_get_monitor_profile( char **paths; char *tt; - if ((npaths = xdg_bds(&er, &paths, xdg_conf, xdg_read, - scope == ucmm_local_system ? xdg_local : xdg_user, + /* Open specific user/local (i.e. "write" semantics) */ + if ((npaths = xdg_bds(&er, &paths, xdg_conf, xdg_write, + scope == 0 ? xdg_user : xdg_local, + xdg_none, config_file)) == 0) { + debug2((errout," xdg_bds returned no paths\n")); continue; } if ((conf_name = strdup(paths[0])) == NULL) { @@ -808,25 +619,29 @@ ucmm_error ucmm_get_monitor_profile( xdg_free(paths, npaths); } + debug2((errout," xdg_bds returned config path '%s'\n",conf_name)); + /* Get the config file */ { + jcnf *jc; /* Return open jcnf */ jc_error ev; - jcnf *jc; char keyn1[100]; char *mname; /* Name of key to match to */ char *mval; /* Value to match */ int ix; - int recno = -1; /* Number of the last record read */ + int recno = -1; /* Number of the last record read */ char *key, *pp; jc_type type; unsigned char *data; size_t dataSize; - /* Open the configuration file for reading */ - if ((jc = new_jcnf(&ev, conf_name, jc_read, jc_no_create)) == NULL) { + /* Open the configuration file for reading or modification */ + if ((jc = new_jcnf(&ev, conf_name, modify, jc_no_create)) == NULL) { debug2((errout,"new_jcnf '%s' failed with error %d\n",conf_name,ev)); + free(conf_name); continue; /* Try the next scope */ } + free(conf_name); /* if EDID supplied, Locate a matching EDID */ if (edid != NULL) { @@ -834,7 +649,6 @@ ucmm_error ucmm_get_monitor_profile( if ((mval = buf2hex(edid, edid_len)) == NULL) { debug2((errout,"buf2jex failed\n")); jc->del(jc); - free(conf_name); return ucmm_resource; } @@ -843,14 +657,12 @@ ucmm_error ucmm_get_monitor_profile( if (display_name == NULL) { debug2((errout,"No EDID and display name failed\n")); jc->del(jc); - free(conf_name); return ucmm_no_edid_or_display; } mname = "NAME"; if ((mval = strdup(display_name)) == NULL) { debug2((errout,"strdup failed\n")); jc->del(jc); - free(conf_name); return ucmm_resource; } } @@ -867,10 +679,9 @@ ucmm_error ucmm_get_monitor_profile( debug2((errout,"jcnf locate/get_key failed with error %d\n",ev)); free(mval); jc->del(jc); - free(conf_name); return ucmm_open_config; } - + if ((pp = jc_get_nth_elem(key, 2)) == NULL) { continue; } @@ -878,10 +689,14 @@ ucmm_error ucmm_get_monitor_profile( free(pp); continue; } + free(pp); if (ii > recno) /* Track biggest, so we know what to create next */ recno = ii; - if ((pp = jc_get_nth_elem(key, 3)) != NULL && strcmp(pp, mname) == 0 && type == jc_string - && strcmp(data, mval) == 0) { + + if ((pp = jc_get_nth_elem(key, 3)) != NULL + && strcmp(pp, mname) == 0 + && type == jc_string + && strcmp(data, mval) == 0) { /* Found matching record */ free(pp); break; @@ -890,11 +705,13 @@ ucmm_error ucmm_get_monitor_profile( free(pp); } + free(mval); if (ev == jc_ix_oorange) { debug2((errout,"No matching display was found\n")); + jc->del(jc); + jc = NULL; continue; /* On to the next scope */ } - free(mval); /* Get the profile path from the record */ sprintf(keyn1, "devices/display/%d/ICC_PROFILE", recno); @@ -905,32 +722,200 @@ ucmm_error ucmm_get_monitor_profile( || type != jc_string) { debug2((errout,"jcnf locate/get_key failed with error %d\n",ev)); jc->del(jc); - free(conf_name); if (ev == jc_ix_oorange) { continue; /* try the next config */ } return ucmm_access_config; } - if ((*profile = strdup(data)) == NULL) { + if ((*pprofile = strdup(data)) == NULL) { debug2((errout,"jcnf get_key malloc failed\n")); jc->del(jc); - free(conf_name); return ucmm_resource; } - - /* We're done with this */ - jc->del(jc); - free(conf_name); + + /* We've found what we were looking for */ + *pjc = jc; + *precno = recno; + return ucmm_ok; - debug2((errout,"Returning current profile '%s'\n",data)); } } debug2((errout,"Failed to find a current profile\n")); return ucmm_no_profile; } + +/* Un-install a profile for a given monitor. */ +/* Either EDID or display_name may be NULL, but not both. */ +/* The monitor is left with no profile association. If a profile */ +/* name is provided and matches the one that was associated with */ +/* the monitor, and has no other association, then it will be deleted */ +/* from the data directory. */ +/* Return an error code */ +ucmm_error ucmm_uninstall_monitor_profile( + ucmm_scope scope, /* Scope of instalation */ + unsigned char *edid, /* Primary device identifier, NULL if none. */ + int edid_len, /* Length of edid data */ + char *display_name /* Fall back device association, */ +) { + char keyn1[100]; + char *dprof = NULL; /* Destination profile to be deleted */ + unsigned int edid_hash = 0; + jcnf *jc = NULL; + int recno = -1; + int ix; + ucmm_error ev = ucmm_ok; + + if (edid != NULL) + edid_hash = fnv_32_buf(edid, edid_len); + + debug2((errout,"ucmm_uninstall_monitor_profile called with edid hash 0x%x, disp '%s'\n",edid_hash,display_name)); + + /* Locate the config record containing the config file entry. */ + if ((ev = ucmm_get_monitor_config(&dprof, &recno, &jc, edid, edid_len, display_name, + jc_modify, scope)) != ucmm_ok) { + return ev; + } + + debug2((errout,"config file = '%s'\n",jc->fname)); + + /* Delete the record */ + sprintf(keyn1, "devices/display/%d/", recno); + + for (ix = -1;;ix--) { + if ((ev = jc->locate_key(jc, &ix, keyn1, 0, 1)) == jc_ok) { + if ((ev = jc->delete_key(jc, ix, NULL)) != jc_ok) { + debug2((errout,"jcnf delete_key failed with error %d\n",ev)); + jc->del(jc); + if (dprof != NULL) + free(dprof); + return ucmm_delete_key; + } + } else { + if (ev == jc_ix_oorange) { + break; + } + debug2((errout,"jcnf locate/get_key failed with error %d\n",ev)); + jc->del(jc); + if (dprof != NULL) + free(dprof); + return ucmm_open_config; + } + } + + /* See if the profile is used by any other device in this scope's config */ + debug2((errout, "Searching for any other reference to profile '%s'\n",dprof)); + for (ix = 0;;ix++) { + char *key, *pp; + jc_type type; + unsigned char *data; + size_t dataSize; + + if ((ev = jc->locate_key(jc, &ix, "devices/display/", 0, 0)) != jc_ok + || (ev = jc->get_key(jc, ix, &key, &type, &data, &dataSize, NULL)) != jc_ok) { + if (ev == jc_ix_oorange) { + break; + } + debug2((errout,"jcnf locate/get_key failed with error %d\n",ev)); + jc->del(jc); + if (dprof != NULL) + free(dprof); + return ucmm_access_config; + } + if ((pp = jc_get_nth_elem(key, 3)) == NULL) + continue; + if (strcmp(pp,"ICC_PROFILE") != 0 + || type != jc_string + || strcmp(data, dprof) != 0) { + free(pp); + continue; + } + free(pp); + debug2((errout, "Found reference at ix %d - not deleting %d\n",ix)); + break; + } + + /* If not, delete the file */ + if (ev == jc_ix_oorange) { + debug2((errout,"Deleting profile '%s'\n",dprof)); + if (unlink(dprof) != 0) { + debug2((errout,"ucmm unlink '%s' failed\n",dprof)); + jc->del(jc); + if (dprof != NULL) + free(dprof); + return ucmm_access_config; + } + } + + /* Update the config */ + if ((ev = jc->update(jc)) != 0) { + debug2((errout,"jcnf write to '%s' failed with error %d\n",jc->fname,ev)); + jc->del(jc); + if (dprof != NULL) + free(dprof); + return ucmm_save_config; + } + debug2((errout,"Updated config file '%s'\n",jc->fname)); + + /* We're done with this */ + jc->del(jc); + if (dprof != NULL) + free(dprof); + + debug2((errout,"ucmm done profile un-install\n")); + return ucmm_ok; +} + +/* Get an associated monitor profile. */ +/* Return ucmm_no_profile if there is no installed profile for this */ +/* monitor. */ +/* Return an error code */ +ucmm_error ucmm_get_monitor_profile( + unsigned char *edid, /* Primary device identifier, NULL if none. */ + int edid_len, /* Length of edid data */ + char *display_name, /* Fall back device association, */ + char **profile /* Return path to profile. free() afterwards. */ +) { + unsigned int edid_hash = 0; + jcnf *jc = NULL; + int recno; + ucmm_error ev = ucmm_ok; + + if (edid != NULL) + edid_hash = fnv_32_buf(edid, edid_len); + + debug2((errout,"ucmm_get_monitor_profile called with edid hash 0x%x, disp '%s'\n",edid_hash,display_name)); + + /* Locate the config record containing the config file entry. */ + /* (ucmm_user is ignored for jc_read) */ + if ((ev = ucmm_get_monitor_config(profile, &recno, &jc, edid, edid_len, display_name, + jc_read, ucmm_user)) != ucmm_ok) { + return ev; + } + + debug2((errout,"config file = '%s'\n",jc->fname)); + + /* We're done with this */ + jc->del(jc); + + debug2((errout,"Returning current profile '%s'\n",*profile)); + + return ucmm_ok; +} +/* Return an ASCII error message string interpretation of scope enum */ +char *ucmm_scope_string(ucmm_scope scope) { + + switch (scope) { + case ucmm_user: + return "User"; + case ucmm_local_system: + return "Local system"; + } + return "Unknown scope"; +} + /* Return an ASCII error message string interpretation of an error number */ char *ucmm_error_string(ucmm_error erno) { |