void _set_curl_options(SG_context* pCtx, CURL* pCurl)
{
	char * szServerFiles = NULL;
	char * szVerifyCerts = NULL;
	SG_pathname *pServerFiles = NULL;
	CURLcode rc = CURLE_OK;
#ifdef WINDOWS
	SG_bool bExists = SG_FALSE;
	SG_bool bVerifyCerts = SG_TRUE;
#endif
	SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__VERIFY_SSL_CERTS, NULL, &szVerifyCerts, NULL)  );
	if (szVerifyCerts != NULL && (SG_strcmp__null(szVerifyCerts, "false") == 0 || SG_strcmp__null(szVerifyCerts, "FALSE")  == 0))
	{
#ifdef WINDOWS
		bVerifyCerts = SG_FALSE;
#endif
		rc = curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, SG_FALSE);		
	}

	if (rc)
		SG_ERR_THROW(SG_ERR_LIBCURL(rc));


#ifdef WINDOWS
	if (bVerifyCerts)
	{
		SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__SERVER_FILES, NULL, &szServerFiles, NULL)  );
		if (szServerFiles)
		{
			SG_ERR_CHECK(  SG_pathname__alloc__sz(pCtx, &pServerFiles, szServerFiles)  );
			SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, pServerFiles, "ssl") );
			SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, pServerFiles, "curl-ca-bundle.crt") );
			SG_ERR_CHECK(  SG_fsobj__exists__pathname(pCtx, pServerFiles, &bExists, NULL, NULL)  );
		}

		if (bExists)
		{
			rc = curl_easy_setopt(pCurl, CURLOPT_CAINFO, SG_pathname__sz(pServerFiles));	
			if (rc)
				SG_ERR_THROW(SG_ERR_LIBCURL(rc));
		}
		else
		{
			if (pServerFiles)
				SG_ERR_CHECK(  SG_log__report_warning(pCtx, "Could not find root certificate file. Looked for it at: %s. SSL connections will not work.", SG_pathname__sz(pServerFiles))  );
			else
				SG_ERR_CHECK(  SG_log__report_warning(pCtx, "Could not find root certificate file: no server/files path is configured. SSL connections will not work.")  );
		}
	}
#endif

fail:
	SG_PATHNAME_NULLFREE(pCtx, pServerFiles);
	SG_NULLFREE(pCtx, szServerFiles);
	SG_NULLFREE(pCtx, szVerifyCerts);
}
Ejemplo n.º 2
0
static void _sg_jscore_getpaths(SG_context *pCtx)
{
	char * szServerFiles = NULL;

	if (gpJSCoreGlobalState->pPathToDispatchDotJS)
		return;

	// Figure out and store relavant paths...
	SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__SERVER_FILES, NULL, &szServerFiles, NULL)  );

	if (szServerFiles)
	{
		SG_ERR_CHECK(  SG_PATHNAME__ALLOC__SZ(pCtx, &gpJSCoreGlobalState->pPathToDispatchDotJS, szServerFiles)  );
		SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, gpJSCoreGlobalState->pPathToDispatchDotJS, "dispatch.js")  );

		SG_ERR_CHECK(  SG_PATHNAME__ALLOC__SZ(pCtx, &gpJSCoreGlobalState->pPathToCore, szServerFiles)  );
		SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, gpJSCoreGlobalState->pPathToCore, "core")  );

		SG_ERR_CHECK(  SG_PATHNAME__ALLOC__SZ(pCtx, &gpJSCoreGlobalState->pPathToModules, szServerFiles)  );
		SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, gpJSCoreGlobalState->pPathToModules, "modules")  );
	}

fail:
	SG_NULLFREE(pCtx, szServerFiles);
}
Ejemplo n.º 3
0
void SG_user__get_email_for_repo(SG_context * pCtx, SG_repo* pRepo, const char ** ppsz_email)
{
	char * psz_admin_id = NULL;
	char * psz_userid = NULL;
	const char * psz_email_temp = NULL;
	SG_string * pstr_path = NULL;
	SG_vhash * pvh_userhash = NULL;
	if (pRepo)
	{
		SG_ERR_CHECK(  SG_repo__get_admin_id(pCtx, pRepo, &psz_admin_id)  );

		// we store this userid under the admin scope of the repo we were given
		SG_ERR_CHECK(  SG_string__alloc__format(pCtx, &pstr_path, "%s/%s/%s",
					SG_LOCALSETTING__SCOPE__ADMIN,
					psz_admin_id,
					SG_LOCALSETTING__USERID
					)  );
		SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_string__sz(pstr_path), pRepo, &psz_userid, NULL)  );
		if (psz_userid == NULL || *psz_userid == 0)
			SG_ERR_THROW(SG_ERR_USER_NOT_FOUND);
		SG_ERR_CHECK(  SG_user__lookup_by_userid(pCtx, pRepo, psz_userid, &pvh_userhash)  );
		SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvh_userhash, "email", &psz_email_temp)  );
		SG_ERR_CHECK(  SG_STRDUP(pCtx, psz_email_temp, (char**)ppsz_email)  );
	}

fail:
	SG_VHASH_NULLFREE(pCtx, pvh_userhash);
	SG_NULLFREE(pCtx, psz_admin_id);
	SG_NULLFREE(pCtx, psz_userid);
	SG_STRING_NULLFREE(pCtx, pstr_path);

}
Ejemplo n.º 4
0
/**
 * Find the appropriate external tool to let the user perform a TEXT MERGE
 * on a file.
 *
 * TODO 2010/07/13 For now, this is hard-coded to use DiffMerge.
 * TODO            Later we want to allow them to have multiple
 * TODO            tools configured and/or to use the file suffix
 * TODO            and so on.
 */
static void _resolve__external_tool__lookup(SG_context * pCtx,
											struct _resolve_data * pData,
											const char * pszGid,
											const SG_vhash * pvhIssue,
											SG_string * pStrRepoPath,
											_resolve__external_tool ** ppET)
{
	_resolve__external_tool * pET = NULL;
	SG_repo * pRepo;

	SG_UNUSED( pszGid );
	SG_UNUSED( pvhIssue );

	SG_ERR_CHECK(  SG_pendingtree__get_repo(pCtx, pData->pPendingTree, &pRepo)  );

	SG_ERR_CHECK(  SG_alloc1(pCtx, pET)  );

	// TODO 2010/07/13 Use localsettings to determine WHICH external tool we should use.
	// TODO            (This could be based upon suffixes and/or whatever.)
	// TODO            Then -- for THAT tool -- lookup the program executable path and
	// TODO            the argument list.
	// TODO            Substitute the given pathnames into the argument list.
	// TODO
	// TODO            For now, we just hard-code DiffMerge.

	SG_ERR_CHECK(  SG_strdup(pCtx, "DiffMerge", &pET->pszName)  );

	SG_localsettings__get__sz(pCtx, "merge/diffmerge/program", pRepo, &pET->pszExe, NULL);
	if (SG_context__has_err(pCtx) || (!pET->pszExe) || (!*pET->pszExe))
	{
		SG_context__err_reset(pCtx);
		SG_ERR_THROW2(  SG_ERR_NO_MERGE_TOOL_CONFIGURED,
						(pCtx, "'%s'  Use 'vv localsetting set merge/diffmerge/program' and retry -or- manually merge content and then use 'vv resolve --mark'.",
						 SG_string__sz(pStrRepoPath))  );
	}

	// TODO 2010/07/13 Get argvec.

	*ppET = pET;
	return;

fail:
	_RESOLVE__EXTERNAL_TOOL__NULLFREE(pCtx, pET);
}
Ejemplo n.º 5
0
void MyFn(create_repo)(SG_context * pCtx, SG_repo ** ppRepo)
{
	// caller must free returned value.

	SG_repo * pRepo;
	SG_pathname * pPathnameRepoDir = NULL;
	SG_vhash* pvhPartialDescriptor = NULL;
    char buf_repo_id[SG_GID_BUFFER_LENGTH];
    char buf_admin_id[SG_GID_BUFFER_LENGTH];
	char* pszRepoImpl = NULL;

	VERIFY_ERR_CHECK(  SG_gid__generate(pCtx, buf_repo_id, sizeof(buf_repo_id))  );
	VERIFY_ERR_CHECK(  SG_gid__generate(pCtx, buf_admin_id, sizeof(buf_admin_id))  );

	VERIFY_ERR_CHECK(  SG_PATHNAME__ALLOC(pCtx, &pPathnameRepoDir)  );
	VERIFY_ERR_CHECK(  SG_pathname__set__from_cwd(pCtx, pPathnameRepoDir)  );

	VERIFY_ERR_CHECK(  SG_VHASH__ALLOC(pCtx, &pvhPartialDescriptor)  );

	VERIFY_ERR_CHECK_DISCARD(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__NEWREPO_DRIVER, NULL, &pszRepoImpl, NULL)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_vhash__add__string__sz(pCtx, pvhPartialDescriptor, SG_RIDESC_KEY__STORAGE, pszRepoImpl)  );

	VERIFY_ERR_CHECK(  SG_vhash__add__string__sz(pCtx, pvhPartialDescriptor, SG_RIDESC_FSLOCAL__PATH_PARENT_DIR, SG_pathname__sz(pPathnameRepoDir))  );

	VERIFY_ERR_CHECK(  SG_repo__create_repo_instance(pCtx,pvhPartialDescriptor,SG_TRUE,NULL,buf_repo_id,buf_admin_id,&pRepo)  );

	SG_VHASH_NULLFREE(pCtx, pvhPartialDescriptor);

	{
		const SG_vhash * pvhRepoDescriptor = NULL;
		VERIFY_ERR_CHECK(  SG_repo__get_descriptor(pCtx, pRepo,&pvhRepoDescriptor)  );

		//INFOP("open_repo",("Repo is [%s]",SG_string__sz(pstrRepoDescriptor)));
	}

	*ppRepo = pRepo;

fail:
	SG_VHASH_NULLFREE(pCtx, pvhPartialDescriptor);
	SG_PATHNAME_NULLFREE(pCtx, pPathnameRepoDir);

    SG_NULLFREE(pCtx, pszRepoImpl);
}
void MyFn(create_repo)(SG_context * pCtx, SG_repo** ppRepo)
{
	SG_repo* pRepo = NULL;
	SG_pathname* pPath_repo = NULL;
	char buf_repo_id[SG_GID_BUFFER_LENGTH];
	char buf_admin_id[SG_GID_BUFFER_LENGTH];
	SG_vhash* pvhPartialDescriptor = NULL;
	char* pszRepoImpl = NULL;

	VERIFY_ERR_CHECK(  SG_gid__generate(pCtx, buf_repo_id, sizeof(buf_repo_id))  );
	VERIFY_ERR_CHECK(  SG_gid__generate(pCtx, buf_admin_id, sizeof(buf_admin_id))  );

	/* Get our paths fixed up */
	VERIFY_ERR_CHECK(  SG_PATHNAME__ALLOC(pCtx, &pPath_repo)  );
	VERIFY_ERR_CHECK(  SG_pathname__set__from_cwd(pCtx, pPath_repo)  );
	VERIFY_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, pPath_repo, "repo")  );

	SG_fsobj__mkdir__pathname(pCtx, pPath_repo);
	SG_context__err_reset(pCtx);

	// Create the repo
	VERIFY_ERR_CHECK(  SG_VHASH__ALLOC(pCtx, &pvhPartialDescriptor)  );
	VERIFY_ERR_CHECK_DISCARD(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__NEWREPO_DRIVER, NULL, &pszRepoImpl, NULL)  );
    if (pszRepoImpl)
    {
        VERIFY_ERR_CHECK_DISCARD(  SG_vhash__add__string__sz(pCtx, pvhPartialDescriptor, SG_RIDESC_KEY__STORAGE, pszRepoImpl)  );
    }

	VERIFY_ERR_CHECK(  SG_vhash__add__string__sz(pCtx, pvhPartialDescriptor, SG_RIDESC_FSLOCAL__PATH_PARENT_DIR, SG_pathname__sz(pPath_repo))  );
	VERIFY_ERR_CHECK(  SG_repo__create_repo_instance(pCtx,NULL,pvhPartialDescriptor,SG_TRUE,NULL,buf_repo_id,buf_admin_id,&pRepo)  );

	*ppRepo = pRepo;

	// Fall through to common cleanup

fail:
	SG_VHASH_NULLFREE(pCtx, pvhPartialDescriptor);
	SG_PATHNAME_NULLFREE(pCtx, pPath_repo);

    SG_NULLFREE(pCtx, pszRepoImpl);
}
static void _remote_clone_allowed(SG_context* pCtx)
{
	char* pszSetting = NULL;
	SG_bool bAllowed = SG_TRUE;

	SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__SERVER_CLONE_ALLOWED, NULL, &pszSetting, NULL);
	if(!SG_context__has_err(pCtx) && pszSetting != NULL)
		bAllowed = (strcmp(pszSetting, "true")==0);
	if(SG_context__has_err(pCtx))
	{
		SG_log__report_error__current_error(pCtx);
		SG_context__err_reset(pCtx);
	}

	if (!bAllowed)
		SG_ERR_THROW(SG_ERR_SERVER_DISALLOWED_REPO_CREATE_OR_DELETE);

	/* fall through */
fail:
	SG_NULLFREE(pCtx, pszSetting);
}
Ejemplo n.º 8
0
/**
 *	Let the UI dispatch methods know where to find their template files.
 */
void _sgui_set_templatePath(SG_context * pCtx)
{
	SG_pathname *collateralRoot = NULL;
	SG_pathname * templatePath = NULL;
    char* psz = NULL;

    SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__SSI_DIR, NULL, &psz, NULL)  );
    SG_ERR_CHECK(  SG_pathname__alloc__sz(pCtx, &collateralRoot, psz)  );
	SG_ERR_CHECK(  SG_PATHNAME__ALLOC__PATHNAME_SZ(pCtx, &templatePath, collateralRoot, "templates")  );

    SG_NULLFREE(pCtx, psz);
	SG_PATHNAME_NULLFREE(pCtx, collateralRoot);

	_sg_uridispatch__templatePath = templatePath;

	return;
fail:
    SG_NULLFREE(pCtx, psz);
	SG_PATHNAME_NULLFREE(pCtx, templatePath);
	SG_PATHNAME_NULLFREE(pCtx, collateralRoot);
}
Ejemplo n.º 9
0
void GetProfileSettings(
	SG_context* pCtx, 
	const char* szProfile,
	char** ppszDest, 
	char** ppszSrc, 
	SG_int64* plSyncIntervalMinutes,
	LPWSTR* ppwszErr)
{
	static const LPWSTR ERR_NO_DEST = L"No destination repository is configured.";
	static const LPWSTR ERR_NO_SRC = L"No source repository is configured.";

	char* pszDest = NULL;
	char* pszSrc = NULL;
	SG_variant* pvMinutes = NULL;
	SG_string* pstrConfigPath = NULL;
	SG_uint64 lMinutes;
	LPWSTR pwszErr = NULL;

	/* It's kind of icky, but we copy these error strings so the balloon code that displays them doesn't have to
	   be very smart and can always free the message string.  (Generic unhandled errors aren't constant, so it has
	   to free those.) I'm not sure making the balloon code more complexso this can be simpler is a net win, so I'm 
	   leaving this be. But it is icky. */

	SG_ERR_CHECK(  SG_string__alloc__format(pCtx, &pstrConfigPath, "%s/%s/%s", CONFIG_ROOT, szProfile, CONFIG_DEST)  );
	SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_string__sz(pstrConfigPath), NULL, &pszDest, NULL)  );
	SG_ERR_CHECK(  SG_string__clear(pCtx, pstrConfigPath)  );
	if (!pszDest || !pszDest[0])
	{
		size_t len_in_chars = 0;
		if (FAILED(  StringCchLength(ERR_NO_DEST, STRSAFE_MAX_CCH, &len_in_chars)  ))
			SG_ERR_THROW(SG_ERR_GETLASTERROR(GetLastError()));
		pwszErr = (LPWSTR)malloc(sizeof(wchar_t) * (len_in_chars + 1));
		if (FAILED(  StringCchCopy(pwszErr, len_in_chars + 1, ERR_NO_DEST)  ))
			SG_ERR_THROW(SG_ERR_GETLASTERROR(GetLastError()));
	}

	SG_ERR_CHECK(  SG_string__append__format(pCtx, pstrConfigPath, "%s/%s/%s", CONFIG_ROOT, szProfile, CONFIG_SRC)  );
	SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_string__sz(pstrConfigPath), NULL, &pszSrc, NULL)  );
	SG_ERR_CHECK(  SG_string__clear(pCtx, pstrConfigPath)  );
	if (!pwszErr)
	{
		if (!pszSrc || !pszSrc[0])
		{
			size_t len_in_chars = 0;
			if (FAILED(  StringCchLength(ERR_NO_SRC, STRSAFE_MAX_CCH, &len_in_chars)  ))
				SG_ERR_THROW(SG_ERR_GETLASTERROR(GetLastError()));
			pwszErr = (LPWSTR)malloc(sizeof(wchar_t) * (len_in_chars + 1));
			if (FAILED(  StringCchCopy(pwszErr, len_in_chars + 1, ERR_NO_SRC)  ))
				SG_ERR_THROW(SG_ERR_GETLASTERROR(GetLastError()));
		}
	}

	SG_ERR_CHECK(  SG_string__append__format(pCtx, pstrConfigPath, "%s/%s/%s", CONFIG_ROOT, szProfile, CONFIG_INTERVAL)  );
	SG_ERR_CHECK(  SG_localsettings__get__variant(pCtx, SG_string__sz(pstrConfigPath), NULL, &pvMinutes, NULL)  );

	if (!pvMinutes)
		lMinutes = DEFAULT_SYNC_EVERY_N_MINUTES;
	else
		SG_ERR_CHECK(  SG_variant__get__uint64(pCtx, pvMinutes, &lMinutes)  );

	if (plSyncIntervalMinutes)
		*plSyncIntervalMinutes = lMinutes;
	SG_RETURN_AND_NULL(pszDest, ppszDest);
	SG_RETURN_AND_NULL(pszSrc, ppszSrc);

	SG_RETURN_AND_NULL(pwszErr, ppwszErr);

	/* common cleanup */
fail:
	SG_NULLFREE(pCtx, pszDest);
	SG_NULLFREE(pCtx, pszSrc);
	SG_VARIANT_NULLFREE(pCtx, pvMinutes);
	SG_STRING_NULLFREE(pCtx, pstrConfigPath);

	if (pwszErr)
		free(pwszErr);
}
Ejemplo n.º 10
0
static void _set_up_logging(
	SG_context * pCtx,
	SG_log_console__data * pcLogStdData,
	SG_log_text__data * pcLogFileData,
	SG_log_text__writer__daily_path__data * pcLogFileWriterData)
{
	// Code coppied from _my_main() in sg.c

	char * szLogLevel = NULL;
	char * szLogPath = NULL;
	SG_uint32							  logFileFlags = SG_LOG__FLAG__HANDLER_TYPE__ALL;
	// find the appropriate log path
	SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__LOG_PATH, NULL, &szLogPath, NULL)  );


	// get the configured log level
	SG_ERR_CHECK(  SG_localsettings__get__sz(pCtx, SG_LOCALSETTING__LOG_LEVEL, NULL, &szLogLevel, NULL)  );

	// register the stdout logger
	SG_ERR_CHECK(  SG_log_console__set_defaults(pCtx, pcLogStdData)  );
	SG_ERR_CHECK(  SG_log_console__register(pCtx, pcLogStdData, NULL, SG_LOG__FLAG__HANDLER_TYPE__NORMAL)  );

	// register the file logger
	SG_ERR_CHECK(  SG_log_text__set_defaults(pCtx, pcLogFileData)  );
	pcLogFileData->fWriter             = SG_log_text__writer__daily_path;
	pcLogFileData->pWriterData         = pcLogFileWriterData;
	pcLogFileData->szRegisterMessage   = NULL;
	pcLogFileData->szUnregisterMessage = NULL;
	if (szLogLevel != NULL)
	{
		if (SG_stricmp(szLogLevel, "quiet") == 0)
		{
			logFileFlags = SG_LOG__FLAG__HANDLER_TYPE__QUIET;
			pcLogFileData->bLogVerboseOperations = SG_FALSE;
			pcLogFileData->bLogVerboseValues     = SG_FALSE;
			pcLogFileData->szVerboseFormat       = NULL;
			pcLogFileData->szInfoFormat          = NULL;
		}
		else if (SG_stricmp(szLogLevel, "normal") == 0)
		{
			logFileFlags = SG_LOG__FLAG__HANDLER_TYPE__NORMAL;
			pcLogFileData->bLogVerboseOperations = SG_FALSE;
			pcLogFileData->bLogVerboseValues     = SG_FALSE;
			pcLogFileData->szVerboseFormat       = NULL;
		}
		else if (SG_stricmp(szLogLevel, "verbose") == 0)
		{
			logFileFlags = SG_LOG__FLAG__HANDLER_TYPE__ALL;
			pcLogFileData->szRegisterMessage   = "---- vscript started logging ----";
			pcLogFileData->szUnregisterMessage = "---- vscript stopped logging ----";
		}
	}
	logFileFlags |= SG_LOG__FLAG__DETAILED_MESSAGES;
	SG_ERR_CHECK(  SG_log_text__writer__daily_path__set_defaults(pCtx, pcLogFileWriterData)  );
	pcLogFileWriterData->bReopen          = SG_FALSE;
	pcLogFileWriterData->ePermissions     = 0666;
	if (szLogPath != NULL)
		SG_ERR_CHECK(  SG_PATHNAME__ALLOC__SZ(pCtx, &pcLogFileWriterData->pBasePath, szLogPath)  );
	else
		SG_ERR_CHECK(  SG_PATHNAME__ALLOC__LOG_DIRECTORY(pCtx, &pcLogFileWriterData->pBasePath)  );
	pcLogFileWriterData->szFilenameFormat = "vscript-%d-%02d-%02d.log";
	SG_ERR_CHECK(  SG_log_text__register(pCtx, pcLogFileData, NULL, logFileFlags)  );

fail:
	SG_context__err_reset(pCtx);

	SG_NULLFREE(pCtx, szLogPath);
	SG_NULLFREE(pCtx, szLogLevel);
}
void SG_cmd_util__get_username_for_repo(
	SG_context *pCtx,
	const char *szRepoName,
	char **ppUsername
	)
{
	SG_string * pUsername = NULL;
	SG_repo * pRepo = NULL;
	char * psz_username = NULL;
	SG_curl * pCurl = NULL;
	SG_string * pUri = NULL;
	SG_string * pResponse = NULL;
	SG_int32 responseStatusCode = 0;
	SG_vhash * pRepoInfo = NULL;
	char * psz_userid = NULL;
	SG_varray * pUsers = NULL;

	SG_NULLARGCHECK_RETURN(ppUsername);

	if(!szRepoName)
	{
		// Look up username based on 'whoami' of repo associated with cwd.

		SG_ERR_IGNORE(  SG_cmd_util__get_repo_from_cwd(pCtx, &pRepo, NULL)  );
		if(pRepo)
			SG_ERR_IGNORE(  SG_user__get_username_for_repo(pCtx, pRepo, &psz_username)  );
		SG_REPO_NULLFREE(pCtx, pRepo);
	}
	else if(SG_sz__starts_with(szRepoName, "http://") || SG_sz__starts_with(szRepoName, "https://"))
	{
		// Look up username based on 'whoami' of admin id of remote repo.

		SG_ERR_CHECK(  SG_curl__alloc(pCtx, &pCurl)  );

		SG_ERR_CHECK(  SG_STRING__ALLOC__SZ(pCtx, &pUri, szRepoName)  );
		SG_ERR_CHECK(  SG_string__append__sz(pCtx, pUri, ".json")  );

		SG_ERR_CHECK(  SG_curl__reset(pCtx, pCurl)  );
		SG_ERR_CHECK(  SG_curl__setopt__sz(pCtx, pCurl, CURLOPT_URL, SG_string__sz(pUri))  );

		SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pResponse)  );
		SG_ERR_CHECK(  SG_curl__set__write_string(pCtx, pCurl, pResponse)  );

		SG_ERR_CHECK(  SG_curl__perform(pCtx, pCurl)  );
		SG_ERR_CHECK(  SG_curl__getinfo__int32(pCtx, pCurl, CURLINFO_RESPONSE_CODE, &responseStatusCode)  );

		if(responseStatusCode==200)
		{
			const char * szAdminId = NULL;
			SG_ERR_CHECK(  SG_VHASH__ALLOC__FROM_JSON__STRING(pCtx, &pRepoInfo, pResponse)  );
			SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pRepoInfo, SG_SYNC_REPO_INFO_KEY__ADMIN_ID, &szAdminId)  );

			SG_ERR_CHECK(  SG_string__clear(pCtx, pUri)  );
			SG_ERR_CHECK(  SG_string__append__format(pCtx, pUri, "/admin/%s/whoami/userid", szAdminId)  );
			SG_ERR_IGNORE(  SG_localsettings__get__sz(pCtx, SG_string__sz(pUri), NULL, &psz_userid, NULL)  );

			if(psz_userid)
			{
				// We now have the userid. Look up the username.


				SG_ERR_CHECK(  SG_string__clear(pCtx, pUri)  );
				SG_ERR_CHECK(  SG_string__append__format(pCtx, pUri, "%s/users.json", szRepoName)  );

				SG_ERR_CHECK(  SG_curl__reset(pCtx, pCurl)  );
				SG_ERR_CHECK(  SG_curl__setopt__sz(pCtx, pCurl, CURLOPT_URL, SG_string__sz(pUri))  );

				SG_ERR_CHECK(  SG_string__clear(pCtx, pResponse)  );
				SG_ERR_CHECK(  SG_curl__set__write_string(pCtx, pCurl, pResponse)  );

				SG_ERR_CHECK(  SG_curl__perform(pCtx, pCurl)  );
				SG_ERR_CHECK(  SG_curl__getinfo__int32(pCtx, pCurl, CURLINFO_RESPONSE_CODE, &responseStatusCode)  );

				if(responseStatusCode==200)
				{
					SG_uint32 i, nUsers;
					SG_ERR_CHECK(  SG_VARRAY__ALLOC__FROM_JSON__STRING(pCtx, &pUsers, pResponse)  );
					SG_ERR_CHECK(  SG_varray__count(pCtx, pUsers, &nUsers)  );
					for(i=0; i<nUsers; ++i)
					{
						SG_vhash * pUser = NULL;
						const char * psz_recid = NULL;
						SG_ERR_CHECK(  SG_varray__get__vhash(pCtx, pUsers, i, &pUser)  );
						SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pUser, "recid", &psz_recid)  );
						if(!strcmp(psz_recid, psz_userid))
						{
							const char * psz_name = NULL;
							SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pUser, "name", &psz_name)  );
							SG_ERR_CHECK(  SG_STRDUP(pCtx, psz_name, &psz_username)  );
							break;
						}
					}
					SG_VARRAY_NULLFREE(pCtx, pUsers);
				}
				
				SG_NULLFREE(pCtx, psz_userid);
			}

			SG_VHASH_NULLFREE(pCtx, pRepoInfo);
		}

		SG_STRING_NULLFREE(pCtx, pResponse);
		SG_STRING_NULLFREE(pCtx, pUri);
		SG_CURL_NULLFREE(pCtx, pCurl);
	}
	else
	{
		// Look up username based on 'whoami' of repo provided.

		SG_ERR_CHECK(  SG_REPO__OPEN_REPO_INSTANCE(pCtx, szRepoName, &pRepo)  );
		SG_ERR_IGNORE(  SG_user__get_username_for_repo(pCtx, pRepo, &psz_username)  );
		SG_REPO_NULLFREE(pCtx, pRepo);
	}

	*ppUsername = psz_username;

	return;
fail:
	SG_STRING_NULLFREE(pCtx, pUsername);
	SG_REPO_NULLFREE(pCtx, pRepo);
	SG_NULLFREE(pCtx, psz_username);
	SG_CURL_NULLFREE(pCtx, pCurl);
	SG_STRING_NULLFREE(pCtx, pUri);
	SG_STRING_NULLFREE(pCtx, pResponse);
	SG_VHASH_NULLFREE(pCtx, pRepoInfo);
	SG_NULLFREE(pCtx, psz_userid);
	SG_VARRAY_NULLFREE(pCtx, pUsers);
}