/*
    ldapdiff
    Copyright (C) 2000-2006 Thomas.Reith@rhoen.de

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <lber.h>
#include <ldap.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ldapdiff.h"

static int addentry(LDAP *ld,char *dnval,struct s_modentry *smodentry)
{
 LDAPMod            **lma;
 struct s_modentry   *psmodentry;
 struct s_ldifval    *psmodentryval;
 int                  numval;
 int                  rc;
 int                  count = 0;
 int                  retval = 0;
 int                  numattr = 0;

 psmodentry = smodentry;
 while(psmodentry != NULL){
  numattr++;
  psmodentry = psmodentry->next;
 }
 lma = LDALLOC(numattr + 1,sizeof(LDAPMod*));

 psmodentry = smodentry;
 while(psmodentry != NULL){
  lma[count]           = LDALLOC(1,sizeof(LDAPMod));
  lma[count]->mod_op   = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
  lma[count]->mod_type = psmodentry->var;

  numval = 0;
  psmodentryval = psmodentry->vallist;
  while(psmodentryval != NULL){
   numval++;
   psmodentryval = psmodentryval->next;
  }

  lma[count]->mod_vals.modv_bvals   = LDALLOC(numval+1,sizeof(struct berval*));

  numval        = 0;
  psmodentryval = psmodentry->vallist;
  while(psmodentryval != NULL){
   lma[count]->mod_vals.modv_bvals[numval] = LDALLOC(1,sizeof(struct berval));
   lma[count]->mod_vals.modv_bvals[numval]->bv_val = psmodentryval->val;
   lma[count]->mod_vals.modv_bvals[numval]->bv_len = psmodentryval->val_len;
   numval++;
   psmodentryval = psmodentryval->next;
  } 

  count++;
  psmodentry = psmodentry->next;
 }

#ifndef USE_DEPRECATED_API
 if((rc = ldap_add_ext_s(ld,dnval,lma,NULL,NULL)) != LDAP_SUCCESS){
#else
 if((rc = ldap_add_s(ld,dnval,lma)) != LDAP_SUCCESS){
#endif
  ldiflog(LOG1,"error:   onlineadd    of %s",dnval);
  ldiflog(LOG1,"ldap_err2string(): %s",ldap_err2string(rc));
  retval = 1;
 } 
 else{
  ldiflog(LOG2,"success: add     %s",dnval);
 }

 numattr    = 0;
 psmodentry = smodentry;
 while(psmodentry != NULL){
  numval        = 0;
  psmodentryval = psmodentry->vallist;
  while(psmodentryval != NULL){
   free(lma[numattr]->mod_vals.modv_bvals[numval]);
   numval++;
   psmodentryval = psmodentryval->next;
  } 
  free(lma[numattr]->mod_vals.modv_bvals);
  free(lma[numattr]);
  numattr++;
  psmodentry = psmodentry->next;
 }
 free(lma);

 return retval;
}

static int delentry(LDAP *ld,char *dnval)
{
 int rc;
 int retval = 0;

#ifndef USE_DEPRECATED_API
 if((rc = ldap_delete_ext_s(ld,dnval,NULL,NULL)) != LDAP_SUCCESS){
#else
 if((rc = ldap_delete_s(ld,dnval)) != LDAP_SUCCESS){
#endif
  ldiflog(LOG1,"error: onlinedelete of %s",dnval);
  ldiflog(LOG1,"ldap_err2string(): %s",ldap_err2string(rc));
  retval = 1;
 } 
 else{
  ldiflog(LOG2,"success: delete  %s",dnval);
 }

 return retval;
}

static int modattr(LDAP *ld,char *dnval,char *var,struct s_ldifval *vallist,int mod_op, char *mod_txt)
{
 LDAPMod          **lma;
 struct s_ldifval  *psmodentryval;
 int                rc;
 int                retval = 0;
 int                numval;
 
 switch(mod_op){
  case LDAP_MOD_REPLACE: /* no break */
  case LDAP_MOD_DELETE:  /* no break */
  case LDAP_MOD_ADD:
       if(var != NULL){
        lma    = LDALLOC(2,sizeof(LDAPMod*));
        lma[0] = LDALLOC(1,sizeof(LDAPMod));

        lma[0]->mod_op                          = mod_op|LDAP_MOD_BVALUES;
        lma[0]->mod_type                        = var;
        lma[0]->mod_vals.modv_bvals             = NULL;

        if(vallist != NULL){
         numval        = 0;
         psmodentryval = vallist;
         while(psmodentryval != NULL){
          numval++;
          psmodentryval = psmodentryval->next;
         }
         lma[0]->mod_vals.modv_bvals = LDALLOC(numval+1,sizeof(struct berval*));

         numval        = 0;
         psmodentryval = vallist;
         while(psmodentryval != NULL){
          lma[0]->mod_vals.modv_bvals[numval]          = LDALLOC(1,sizeof(struct berval));
          lma[0]->mod_vals.modv_bvals[numval]->bv_val  = psmodentryval->val;
          lma[0]->mod_vals.modv_bvals[numval]->bv_len  = psmodentryval->val_len;
          numval++;
          psmodentryval = psmodentryval->next;
         }
        }

#ifndef USE_DEPRECATED_API
        if((rc = ldap_modify_ext_s(ld,dnval,lma,NULL,NULL)) != LDAP_SUCCESS){
#else
        if((rc = ldap_modify_s(ld,dnval,lma)) != LDAP_SUCCESS){
#endif
         ldiflog(LOG1,"error: onlinemodify of %s",dnval);
         psmodentryval = vallist;
         while(psmodentryval != NULL){
          ldiflogval(LOG1,"                 %s: %s",var,psmodentryval->val,psmodentryval->val_len);
          psmodentryval = psmodentryval->next;
         }
         ldiflog(LOG1,"ldap_err2string(): %s",ldap_err2string(rc));
         retval = 1;
        } 
        else{
         ldiflog(LOG2,"success: %-7s %s",mod_txt,dnval);
         psmodentryval = vallist;
         while(psmodentryval != NULL){
          ldiflogval(LOG2,"                 %s: %s",var,psmodentryval->val,psmodentryval->val_len);
          psmodentryval = psmodentryval->next;
         }
         if(vallist == NULL){
          ldiflog(LOG2,"                 %s: [no deletion value]",var);
         }
        }

        numval        = 0;
        psmodentryval = vallist;
        while(psmodentryval != NULL){
         free(lma[0]->mod_vals.modv_bvals[numval]);
         numval++;
         psmodentryval = psmodentryval->next;
        }
        free(lma[0]->mod_vals.modv_bvals);
        free(lma[0]);
        free(lma);
       }
       break;

  default:
       ldiflog(LOG0,"fatal error: file %s line %d",__FILE__,__LINE__);
       exit(EXITLDERROR);
 }

 return retval;
}

int ldifmodify(LDAP *ld,struct s_mod *smod,struct s_schema *sschema)
{
 struct s_mod      *psmod;
 struct s_modentry *psmodentry;
 int                errcount = 0;
 int                rc = 0;

 psmod = smod;

 while(psmod != NULL){
  switch(psmod->modtype){
   case MODADD:
        errcount += addentry(ld,psmod->dnval,psmod->attrlist);
        break;

   case MODMODIFY:
        psmodentry = psmod->attrlist;
        while(psmodentry != NULL){
         switch(psmodentry->modtype){
          case MODATTRADD:
               errcount += modattr(ld,psmod->dnval,psmodentry->var,psmodentry->vallist,LDAP_MOD_ADD,"add");
               break;
          case MODATTRREPLACE:
               errcount += modattr(ld,psmod->dnval,psmodentry->var,psmodentry->vallist,LDAP_MOD_REPLACE,"replace");
               break;
          case MODATTRDELETE:
               if(ldifschemaequal(sschema,psmodentry->var) == 1){
                errcount += modattr(ld,psmod->dnval,psmodentry->var,psmodentry->vallist,LDAP_MOD_DELETE,"delete");
               }
               else{
                errcount += modattr(ld,psmod->dnval,psmodentry->var,NULL,LDAP_MOD_DELETE,"delete");
               }
               break;
         } 
         psmodentry = psmodentry->next;
        }
        break;

   case MODDELETE:
        errcount += delentry(ld,psmod->dnval);
        break;

  }
  psmod = psmod->next;
 }

 ldiflog(LOG1,"write:  %10d online transactions failed",errcount); 
 
 if(errcount > 0){
  if(strcmp(ldifgetgconf(CONFONLINEERRFATAL),"yes") == 0){
   exit(EXITLDERROR);
  }
  rc = 1;
 } 

 return rc;
}


syntax highlighted by Code2HTML, v. 0.9.1