summaryrefslogtreecommitdiff
path: root/ucmm/ucmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'ucmm/ucmm.c')
-rwxr-xr-x[-rw-r--r--]ucmm/ucmm.c615
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) {