/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/


#ifndef _CONDOR_CLAIMID_PARSER_H
#define _CONDOR_CLAIMID_PARSER_H

// ClaimIdParser knows how to extract parts of a claim id string.
// It expects the following format (generated by the starter's claim.C)
// "<ip:port>#...#secret_cookie"

class ClaimIdParser {
 public:
	ClaimIdParser()
	{ }
	ClaimIdParser(char const *claim_id):
		m_claim_id(claim_id)
	{ }
	ClaimIdParser(char const *session_id,char const *session_info,char const *session_key)
	{
		formatstr(m_claim_id,"%s#%s%s",
						   session_id ? session_id : "",
						   session_info ? session_info : "",
						   session_key ? session_key : "");
		ASSERT( !session_info || !strchr(session_info,'#') );
		ASSERT( !session_key || !strchr(session_key,'#') );
	}
	void setClaimId(char const *claim_id) {
		m_claim_id = claim_id;
		m_sinful_part = "";
		m_public_part = "";
	}
	char const *claimId() {
		return m_claim_id.c_str();
	}
	char const *startdSinfulAddr() {
		if( m_sinful_part.empty() ) {
			char const *str = m_claim_id.c_str();
			char const *end;
			if ( str[0] == '<' ) {
				end = strchr(str, '>');
				if ( end != NULL ) {
					end++;
				}
			} else {
				end = strchr(str, '#');
			}
			if (end) m_sinful_part.assign(str,end);
		}
		return m_sinful_part.c_str();
	}
	char const *publicClaimId() {
		if( m_public_part.empty() ) {
			char const *str = m_claim_id.c_str();
			char const *end = strrchr(str,'#');
			if (end) {
				m_public_part.assign(str,end);
				m_public_part += "#...";
			}
		}
		return m_public_part.c_str();
	}

	char const *secSessionId(bool ignore_session_info=false) {
			// This must return the same thing for both the schedd and
			// the startd, so be careful making any version-incompatible
			// changes.
		if( !ignore_session_info && !secSessionInfo() ) {
				// There is no session info, so no security session
				// was created.
			return "";
		}
		if( m_session_id.empty() ) {
			char const *str = m_claim_id.c_str();
			char const *end = strrchr(str,'#');
			if (end) m_session_id.assign(str,end);
		}
		return m_session_id.c_str();
	}
	char const *secSessionKey() {
			// expected format: blah#blah#...#[session_info]SESSION_KEY
		char const *str = m_claim_id.c_str();
		char const *ptr = strrchr(str,'#');
		if(ptr) {
			ptr+=1;
		}
		char const *ptr2 = strrchr(str,']');
		if(ptr2) {
			ptr2+=1;
		}
		if( ptr2 > ptr ) {
				// skip past the session info
			ptr = ptr2;
		}
		return ptr ? ptr : "";
	}
	char const *secSessionInfo() {
			// expected format: blah#blah#...#[session_info]SESSION_KEY
		if( m_session_info.empty() ) {
			char const *str = m_claim_id.c_str();
			char const *ptr = strrchr(str,'#');
			char const *endptr;
			if( !ptr ) {
				return "";
			}
			ptr+=1;
			if( *ptr != '[' ) {
				return "";
			}
			endptr = strrchr(str,']');
			if(!endptr || endptr < ptr) {
				return "";
			}
			m_session_info.assign(ptr,endptr+1);
		}

		return m_session_info.c_str();
	}
	void setSecSessionInfo(char const *session_info) {
		if(session_info) {
			ASSERT(session_info[0] == '[');
			ASSERT(session_info[strlen(session_info)-1] == ']');
			ASSERT(strchr(session_info,'#') == NULL);
		}

		std::string new_claim_id(secSessionId(true));
		char const *session_key = secSessionKey();
		formatstr_cat(new_claim_id,"#%s%s",
			session_info ? session_info : "",
			session_key ? session_key : "");

			// reset everything using the new claim id
		*this = ClaimIdParser(new_claim_id.c_str());
	}

	// extract the version info from the session info
	CondorVersionInfo secSessionInfoVersion()
	{
		int maj=0,min=0,sub=0;
		// call secSessionInfo to force the m_session_info member to populate
		if (secSessionInfo() && !m_session_info.empty()) {
			// then we can look inside it to find the ShortVersion
			auto ver = m_session_info.find("ShortVersion=\"");
			if (ver != std::string::npos) {
				const char * short_version = m_session_info.c_str() + ver + 14;
				char *pos = NULL;
				maj = strtol(short_version, &pos, 10);
				min = (pos[0] == '.') ? strtol(pos+1, &pos, 10) : 0;
				sub = (pos[0] == '.') ? strtol(pos+1, &pos, 10) : 0;
			}
		}
		return {maj,min,sub};
	}

 private:
	std::string m_claim_id;
	std::string m_public_part;
	std::string m_sinful_part;

		// The following fields are for SEC_ENABLE_MATCH_PASSWORD_AUTHENTICATION
	std::string m_session_id;
	std::string m_session_info;
};

#endif
