/*
 * $Id: ossl_x509name.c,v 1.1 2003/10/19 20:30:35 knu Exp $
 * 'OpenSSL for Ruby' project
 * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
 * All rights reserved.
 */
/*
 * This program is licenced under the same licence as Ruby.
 * (See the file 'LICENCE'.)
 */
#include "ossl.h"

#define WrapX509Name(obj, name) obj = Data_Wrap_Struct(cX509Name, 0, X509_NAME_free, name)
#define GetX509Name(obj, name) Data_Get_Struct(obj, X509_NAME, name)

/*
 * Classes
 */
VALUE cX509Name;
VALUE eX509NameError;

/*
 * Public
 */
VALUE 
ossl_x509name_new(X509_NAME *name)
{
	X509_NAME *new = NULL;
	VALUE obj;

	if (!name)
		new = X509_NAME_new();
	else new = X509_NAME_dup(name);
	
	if (!new)
		OSSL_Raise(eX509NameError, "");
	
	WrapX509Name(obj, new);

	return obj;
}

X509_NAME *
ossl_x509name_get_X509_NAME(VALUE obj)
{
	X509_NAME *name = NULL, *new;

	OSSL_Check_Type(obj, cX509Name);
	
	GetX509Name(obj, name);

	if (!(new = X509_NAME_dup(name))) {
		OSSL_Raise(eX509NameError, "");
	}
	
	return new;
}

static VALUE
ossl_x509name_s_new(int argc, VALUE *argv, VALUE *klass)
{
	X509_NAME *name = NULL;
	VALUE obj;

	if(!(name = X509_NAME_new()))
		OSSL_Raise(eX509NameError, "");
	WrapX509Name(obj, name);
	rb_obj_call_init(obj, argc, argv);
	
	return obj;
}

static VALUE 
ossl_x509name_initialize(int argc, VALUE *argv, VALUE self)
{
	X509_NAME *name;
	int i, type;
	VALUE arg, item, key, value;

	GetX509Name(self, name);
	if(rb_scan_args(argc, argv, "01", &arg) == 0){
		return self;
	}

	Check_Type(arg, T_ARRAY);
	for(i = 0; i < RARRAY(arg)->len; i++){
		item = rb_ary_entry(arg, i);   Check_Type(item, T_ARRAY);
		key = rb_ary_entry(item, 0);   Check_Type(key, T_STRING);
		value = rb_ary_entry(item, 1); Check_Type(value, T_STRING);

		type = ASN1_PRINTABLE_type(RSTRING(value)->ptr, -1);
		if (!X509_NAME_add_entry_by_txt(name, RSTRING(key)->ptr, type,
			RSTRING(value)->ptr, RSTRING(value)->len, -1, 0)) {
			OSSL_Raise(eX509NameError, "");
		}
	}
	
	return self;
}

static VALUE 
ossl_x509name_to_a(VALUE self)
{
	X509_NAME *name = NULL;
	X509_NAME_ENTRY *entry = NULL;
	int i,entries = 0;
	char long_name[512];
	const char *short_name = NULL;
	VALUE ary, tmp;
	
	GetX509Name(self, name);

	entries = X509_NAME_entry_count(name);
	ary = rb_ary_new2(entries);
	if (entries < 0) {
		rb_warning("name entries < 0!");
		return ary;
	}	
	for (i=0; i<entries; i++) {
		if (!(entry = X509_NAME_get_entry(name, i))) {
			OSSL_Raise(eX509NameError, "");
		}
		if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name), 
		                     entry->object)) {
			OSSL_Raise(eX509NameError, "");
		}
		short_name = OBJ_nid2sn(OBJ_ln2nid(long_name));
		tmp = rb_ary_new3(2, rb_str_new2(short_name),
			rb_str_new(entry->value->data, entry->value->length));
		rb_ary_push(ary, tmp);
	}

	return ary;
}

/*
 * INIT
 */
void 
Init_ossl_x509name(VALUE module)
{
	eX509NameError = rb_define_class_under(module, "NameError", rb_eStandardError);

	cX509Name = rb_define_class_under(module, "Name", rb_cObject);
	rb_define_singleton_method(cX509Name, "new", ossl_x509name_s_new, -1);
	rb_define_method(cX509Name, "initialize", ossl_x509name_initialize, -1);
	rb_define_method(cX509Name, "to_a", ossl_x509name_to_a, 0);
}

