// ------------------------------------------------------------------------------------------------
// DESCRIPTION  Cloud filestore access credentials info as used by surgeweb caldav and other 
//	cloud locations for http based event & file access, storage and sharing
// ------------------------------------------------------------------------------------------------
// NOTES
// ------------------------------------------------------------------------------------------------
#ifdef __XCODE__
#include "xcode_quiet.h"
#endif

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include "tcplib.h"
#include "smail.h"
#include "lprintf.h"
#include "lib.h"
#include "cloud.h"
#define DMID 4
#include "dmalloc.h"
#include "string_hide.h"
#include "oauth.h"


int imsg(const char * arg_list, ...);


Cloud *cloud_new(char *name)
{
	Cloud *l=NULL;
	l=calloc(1,sizeof(Cloud));
	if (!l) return NULL;
	return l;
}
void cloud_free(Cloud **l)
{
	Cloud *ll=(*l);
	if(*l==NULL) return;
	ffree(ll->type);
	ffree(ll->desc);
	ffree(ll->host_url);
	ffree(ll->root_path);
	ffree(ll->api_path);
	pair_free(&ll->param);
	oa_free(&ll->auth);
	ffree(*l);
}

void cloud_freeall(Cloud** list)
{
	Cloud *l,*next;
	if (!list || !*list) return;
	for(l=*list;l;l=next){
		next=l->next;
		cloud_free(&l);
	}
	*list=NULL;
}
int cloud_add_atend(Cloud **list, Cloud *ident)
{
	Cloud *l,*end=NULL;
	for (l=*list;l!=NULL;l=l->next) end = l;
	if(end){
		end->next=ident;
	}else{
		*list=ident;
	}
	return TRUE;
}
Cloud *cloud_find(Cloud *clouds, int id)
{
	Cloud *l=NULL;
	for(l=clouds;l;l=l->next){
		if(l->id==id)
			break;
	}
	return l;
}
Cloud *cloud_blank(Cloud *clouds)
{
	Cloud *cloud;
	int id,n=0;
	cloud=cloud_new(NULL);
	id=myrand()%90000+10;
	while(cloud_find(clouds,id)){
		id++;n++;
		if(id>90000) id=10;
		if(n>90000) {free(cloud);return NULL;}
	}
	cloud->id=id;
	return cloud;
}
int cloud_load(Cloud** list, char* fname, int *was_encrypted, char *cal_host_url, char *cal_root_path, char *cal_email)	// cf sw_labels_load
{
	char bf[BFSZ],tmp[BFSZ],*p,*s;
	FILE *f;
	Cloud *l=NULL;
	int valid=FALSE;
	char *names[100],*values[100];
	int n,i,count=0;
	OAuth *oa;

	*was_encrypted = true;
	imsg("cloud_loadfile(%s)\n",fname);
	f = fopen(fname,"r");
	if (!f) return FALSE;
	while(fgets(bf,BFSZ,f)) {
		// read file
		lib_strip_crlf(bf);
		if (bf[0]=='#') continue;
		for(p = bf; sisspace(*p); p++);
		if (*p==0) continue;
		if (count>90) continue;	// maybe limit some more sometime

		l=cloud_new("");
		if (!l) {ffree(l); continue;}
		l->id=atoi(p); p=strchr(p,'|');
		if(!p||!*(p+1)) {ffree(l); continue;}
		s=p+1; p=strchr(p+1,'|');
		if(!p||!*(p+1)) {ffree(l); continue;}
		*p=0; 
		lib_bar_decode(s,tmp,BFSZ);
		l->desc=strdup(tmp);
		p++;
		if(strstr(p,"=\"") || lib_strlen(p)==0){
			ncpy(tmp,p,BFSZ-1);
			*was_encrypted = false;
		}else{
			string_unhide(p,tmp,BFSZ,FALSE);
		}

		oa = oa_new();
		l->auth = oa;

		n=lib_token_split_quoted(tmp,names,values,100);
		for(i=0;i<n;i++){
			char *name=names[i], *val=values[i];

			if(strcmp(name,"type")==0) l->type = strdup(val);
			if(strcmp(name,"host_url")==0) {
				if(strcmp(l->type,"lcal")==0){
					// Always initialise calendar url from scratch!
					l->host_url=strdup(cal_host_url);
				}else{
					// use stored param
					l->host_url = strdup(val);
				}
			}
			if(strcmp(name,"root_path")==0) {
				if(strcmp(l->type,"lcal")==0){
					l->root_path=strdup(cal_root_path);
				}else{
					l->root_path = strdup(val);
				}
			}
			if(strcmp(name,"api_path")==0) l->api_path = strdup(val);

			if(strcmp(name,"auth_type")==0) oa->auth_type = strdup(val);
			if(strcmp(name,"state")==0) oa->state = atoi(val);
			if(strcmp(name,"user")==0) {
				if(strcmp(l->type,"lcal")==0){
					oa->user=strdup(cal_email);
				}else{
					oa->user = strdup(val);
				}
			}
			if(strcmp(name,"pass")==0) oa->pass = strdup(val);
			if(strcmp(name,"stored_digest")==0) oa->stored_digest = strdup(val);
			if(strcmp(name,"auth_token")==0) oa->auth_token = strdup(val);
			if(strcmp(name,"token_secret")==0) oa->token_secret = strdup(val);
			
		}

		// add it
		cloud_add_atend(list,l);
		count++;
	}
	fclose(f); f=NULL;
	imsg("surgeweb %d cloud credentials loaded",count);
	return TRUE;
}
int cloud_save(Cloud* clouds, char *fname, int decrypted)
{
	Cloud *l;
	OAuth *oa;
	Pair *p, *param=NULL;
	char fname_old[BFSZ],fname_tmp[BFSZ],bf[BFSZ],tmp[BFSZ],tmp2[BFSZ];
	FILE *f;
	int count=0;
	lprintf(fname_old,BFSZ,"%s_old",fname);
	lprintf(fname_tmp,BFSZ,"%s_tmp",fname);
	f=fopen(fname_tmp,"wb");
	if(!f) return FALSE;

	for (l=clouds;l;l=l->next){
		if(l->del) continue;
		*bf=0;
		pair_add(&param,"type",nullok(l->type));
		pair_add(&param,"host_url",nullok(l->host_url));
		pair_add(&param,"root_path",nullok(l->root_path));		
		pair_add(&param,"api_path",nullok(l->api_path));		
		oa=l->auth;
		pair_add(&param,"auth_type",nullok(oa->auth_type));
		pair_add_int(&param,"state",oa->state);
		pair_add(&param,"user",nullok(oa->user));
		pair_add(&param,"pass",nullok(oa->pass));
		pair_add(&param,"stored_digest",nullok(oa->stored_digest));
		pair_add(&param,"auth_token",nullok(oa->auth_token));
		pair_add(&param,"token_secret",nullok(oa->token_secret));
		pair_reverse(&param);
		for(p=param;p;p=p->next){
			if(lib_strlen(p->val)==0) continue;
			lprintf(tmp,BFSZ,"%s=\"%s\"",p->var,lib_encode_quoteonly(tmp2,p->val,BFSZ-1));
			ncat_sep(bf," ",tmp,BFSZ-1);
		}
		pair_free(&param);
		if(decrypted){
			ncpy(tmp,bf,BFSZ-1);
		}else{
			string_hide(bf,tmp,BFSZ,FALSE);
		}

		lib_bar_encode(l->desc,tmp2,BFSZ);
		lprintf(bf,BFSZ,"%05d|%s|%s",l->id,tmp2,tmp);
		fprintf(f,"%s\n\n",bf);
		count++;
	}
	fclose(f);
	remove(fname_old);
	rename(fname,fname_old);
	rename(fname_tmp,fname);
	remove(fname_old);

	imsg("surgeweb %d clouds saved",count);
	return TRUE;
}

int cloud_findmove(Cloud *clouds)
{
	Cloud *l,*l_last=NULL;
	int track=FALSE;

	// Show tags to move them
	for(l=clouds;l;l=l->next){
		l->move=0;
		if(l->del) continue;
		if(strcmp(l->type,"alias")==0 || strcmp(l->type,"self")==0) continue;
		if(track){
			l_last->move++;
			l->move++;
		}
		l_last=l;
		track=TRUE;
	}
	if(l_last && l_last->move) l_last->move=3;
	return TRUE;
}
int cloud_move(Cloud *clouds, int cloud, int dir)
{
	Cloud *list[100],*l,*l2;
	int tot=0,i;

	cloud_findmove(clouds);

	for(l=clouds;l;l=l->next){
		if (tot>90) continue;	// maybe limit some more sometime
		list[tot]=l;
		tot++;
	}
	for(i=0;i<tot;i++){
		l=list[i];
		if(l->id!=cloud) continue;
		if(dir<0 && (l->move==1 || l->move==2) && (i<tot-1)){	// Move down
			l2=list[i];
			list[i]=list[i+1];
			list[i+1]=l2;
			break;
		}
		if(dir>0 && (l->move==2 || l->move==3) && (i>0)){		// Move up
			l2=list[i];
			list[i]=list[i-1];
			list[i-1]=l2;
			break;
		}
	}
	for(i=0;i<tot;i++){
		l=list[i];
		if(i<tot-1){
			l->next=list[i+1];
		}else{
			l->next=NULL;
		}
	}
	return TRUE;
}
int cloud_count(Cloud *clouds)
{
	Cloud *cloud;
	int n=0;
	if (!clouds) return 0;
	for(cloud=clouds;cloud;cloud=cloud->next){
		if(cloud->del)continue;
		n++;
	}
	return n;
}

int cloud_split_fname(char *path_name, char*path,char*name,char*display)
{
	char bf[BFSZ], *s;

	ncpy(bf,path_name,BFSZ-1);
	s=strchr_last(bf,'/');
	if(s) *(s+1)=0;
	ncpy(path,bf,BFSZ-1);

	ncpy(bf,path_name,BFSZ-1);
	s=strchr_last(bf,'/');
	if(!s) s=bf;
	ncpy(name,s+1,BFSZ-1);

	ncpy(bf,name,BFSZ-1);
	s=strchr_last(bf,'/');
	if(s) *(s)=0;
	ncpy(display,bf,BFSZ-1);

	return TRUE;
}
