1 /***************************************************************************
2  begin       : Wed Oct 03 2018
3  copyright   : (C) 2018 by Martin Preuss
4  email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  * This file is part of the project "AqBanking".                           *
8  * Please see toplevel file COPYING of that project for license details.   *
9  ***************************************************************************/
10 
11 
12 #ifdef AQBANKING_WITH_PLUGIN_BANKINFO_DE
13 # include "src/libs/plugins/bankinfo/de/de.h"
14 #endif
15 
16 
17 
AB_Banking_CreateImBankInfoPlugin(AB_BANKING * ab,const char * modname)18 AB_BANKINFO_PLUGIN *AB_Banking_CreateImBankInfoPlugin(AB_BANKING *ab, const char *modname)
19 {
20   if (modname && *modname) {
21 #ifdef AQBANKING_WITH_PLUGIN_BANKINFO_DE
22     if (strcasecmp(modname, "de")==0)
23       return AB_BankInfoPluginDE_new(ab);
24 #endif
25     DBG_ERROR(AQBANKING_LOGDOMAIN, "Plugin [%s] not compiled-in", modname);
26   }
27 
28   return NULL;
29 }
30 
31 
32 
AB_Banking_LoadBankInfoPlugin(AB_BANKING * ab,const char * modname)33 AB_BANKINFO_PLUGIN *AB_Banking_LoadBankInfoPlugin(AB_BANKING *ab, const char *modname)
34 {
35   GWEN_PLUGIN *pl;
36 
37   pl=GWEN_PluginManager_GetPlugin(ab_pluginManagerBankInfo, modname);
38   if (pl) {
39     AB_BANKINFO_PLUGIN *bip;
40 
41     bip=AB_Plugin_BankInfo_Factory(pl, ab);
42     if (!bip) {
43       DBG_ERROR(AQBANKING_LOGDOMAIN, "Error in plugin [%s]: No bank info created", modname);
44       return NULL;
45     }
46     return bip;
47   }
48   else {
49     DBG_INFO(AQBANKING_LOGDOMAIN, "Plugin [%s] not found", modname);
50     return NULL;
51   }
52 }
53 
54 
55 
AB_Banking_FindBankInfoPlugin(AB_BANKING * ab,const char * country)56 AB_BANKINFO_PLUGIN *AB_Banking_FindBankInfoPlugin(AB_BANKING *ab, const char *country)
57 {
58   AB_BANKINFO_PLUGIN *bip;
59 
60   bip=AB_BankInfoPlugin_List_First(ab_bankInfoPlugins);
61   while (bip) {
62     if (strcasecmp(AB_BankInfoPlugin_GetCountry(bip), country)==0)
63       break;
64     bip=AB_BankInfoPlugin_List_Next(bip);
65   }
66 
67   return bip;
68 }
69 
70 
71 
AB_Banking_GetBankInfoPlugin(AB_BANKING * ab,const char * country)72 AB_BANKINFO_PLUGIN *AB_Banking_GetBankInfoPlugin(AB_BANKING *ab, const char *country)
73 {
74   AB_BANKINFO_PLUGIN *bip;
75 
76   assert(ab);
77   assert(country);
78 
79   bip=AB_Banking_FindBankInfoPlugin(ab, country);
80   if (bip)
81     return bip;
82   bip=AB_Banking_CreateImBankInfoPlugin(ab, country);
83   if (bip)
84     return bip;
85   bip=AB_Banking_LoadBankInfoPlugin(ab, country);
86   if (bip)
87     AB_BankInfoPlugin_List_Add(bip, ab_bankInfoPlugins);
88 
89   return bip;
90 }
91 
92 
93 
AB_Banking_GetBankInfo(AB_BANKING * ab,const char * country,const char * branchId,const char * bankId)94 AB_BANKINFO *AB_Banking_GetBankInfo(AB_BANKING *ab,
95                                     const char *country,
96                                     const char *branchId,
97                                     const char *bankId)
98 {
99   AB_BANKINFO_PLUGIN *bip;
100 
101   assert(ab);
102   assert(country);
103   bip=AB_Banking_GetBankInfoPlugin(ab, country);
104   if (!bip) {
105     DBG_INFO(AQBANKING_LOGDOMAIN, "BankInfo plugin for country \"%s\" not found", country);
106     return 0;
107   }
108 
109   return AB_BankInfoPlugin_GetBankInfo(bip, branchId, bankId);
110 }
111 
112 
113 
AB_Banking_GetBankInfoByTemplate(AB_BANKING * ab,const char * country,AB_BANKINFO * tbi,AB_BANKINFO_LIST2 * bl)114 int AB_Banking_GetBankInfoByTemplate(AB_BANKING *ab,
115                                      const char *country,
116                                      AB_BANKINFO *tbi,
117                                      AB_BANKINFO_LIST2 *bl)
118 {
119   AB_BANKINFO_PLUGIN *bip;
120 
121   assert(ab);
122   assert(country);
123   bip=AB_Banking_GetBankInfoPlugin(ab, country);
124   if (!bip) {
125     DBG_INFO(AQBANKING_LOGDOMAIN,
126              "BankInfo plugin for country \"%s\" not found",
127              country);
128     return 0;
129   }
130 
131   return AB_BankInfoPlugin_GetBankInfoByTemplate(bip, tbi, bl);
132 }
133 
134 
135 
AB_Banking_CheckAccount(AB_BANKING * ab,const char * country,const char * branchId,const char * bankId,const char * accountId)136 AB_BANKINFO_CHECKRESULT AB_Banking_CheckAccount(AB_BANKING *ab,
137                                                 const char *country,
138                                                 const char *branchId,
139                                                 const char *bankId,
140                                                 const char *accountId)
141 {
142   AB_BANKINFO_PLUGIN *bip;
143 
144   assert(ab);
145   assert(country);
146   bip=AB_Banking_GetBankInfoPlugin(ab, country);
147   if (!bip) {
148     DBG_INFO(AQBANKING_LOGDOMAIN, "BankInfo plugin for country \"%s\" not found", country);
149     return AB_BankInfoCheckResult_UnknownResult;
150   }
151 
152   return AB_BankInfoPlugin_CheckAccount(bip, branchId, bankId, accountId);
153 }
154 
155 
156 
AB_Banking__TransformIban(const char * iban,int len,char * newIban,int maxLen)157 int AB_Banking__TransformIban(const char *iban, int len, char *newIban, int maxLen)
158 {
159   int i, j;
160   const char *p;
161   char *s;
162 
163   assert(iban);
164   /* format IBAN */
165   i=0;
166   j=0;
167   p=iban;
168   s=newIban;
169   while (j<len && i<maxLen) {
170     int c;
171 
172     c=toupper(*p);
173     if (c!=' ') {
174       if (c>='A' && c<='Z') {
175         c=10+(c-'A');
176         *s='0'+(c/10);
177         s++;
178         i++;
179         if (i>=maxLen) {
180           DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (too long)");
181           return -1;
182         }
183         *s='0'+(c%10);
184         s++;
185         i++;
186       }
187       else if (isdigit(c)) {
188         *s=c;
189         s++;
190         i++;
191       }
192       else {
193         DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (bad char)");
194         return -1;
195       }
196     }
197     p++;
198     j++;
199   } /* while */
200   if (j<len) {
201     DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (too long)");
202     return -1;
203   }
204   *s=0;
205 
206   return 0;
207 }
208 
209 
210 
AB_Banking_CheckIban(const char * iban)211 int AB_Banking_CheckIban(const char *iban)
212 {
213   char newIban[256];
214   char tmp[10];
215   int i;
216   unsigned int j;
217   const char *p;
218   char *s;
219 
220   if (strlen(iban)<5) {
221     DBG_INFO(AQBANKING_LOGDOMAIN, "Bad IBAN (too short) [%s]", iban);
222     return -1;
223   }
224   p=iban;
225   if (!(*p >= 'A' && *p++ <= 'Z' && *p >= 'A' && *p++ <= 'Z')) {
226     DBG_INFO(AQBANKING_LOGDOMAIN, "Bad IBAN (country code not in upper case) [%s]", iban);
227     return -1;
228   }
229   p+=2;
230 
231   /* convert IBAN+4 to buffer */
232   if (AB_Banking__TransformIban(p, strlen(p),
233                                 newIban, sizeof(newIban)-1)) {
234     DBG_INFO(AQBANKING_LOGDOMAIN, "here");
235     return -1;
236   }
237 
238   /* append country and checksum */
239   p=iban;
240   s=newIban+strlen(newIban);
241   if (AB_Banking__TransformIban(p, 4, s, sizeof(newIban)-strlen(newIban)-1)) {
242     DBG_INFO(AQBANKING_LOGDOMAIN, "here");
243     return -1;
244   }
245 
246   /* calculate checksum in 9er steps */
247   p=newIban;
248   tmp[0]=0;
249   j=0;
250   while (*p) {
251     for (i=strlen(tmp); i<9;  i++) {
252       if (!*p)
253         break;
254       tmp[i]=*(p++);
255     }
256     tmp[i]=0;
257     if (1!=sscanf(tmp, "%u", &j)) {
258       DBG_INFO(AQBANKING_LOGDOMAIN, "Bad IBAN (bad char) [%s]", iban);
259       return -1;
260     }
261     j=j%97; /* modulo 97 */
262     snprintf(tmp, sizeof(tmp), "%u", j);
263   } /* while */
264 
265   if (j!=1) {
266     DBG_INFO(AQBANKING_LOGDOMAIN, "Bad IBAN (bad checksum) [%s]", iban);
267     return 1;
268   }
269 
270   DBG_DEBUG(AQBANKING_LOGDOMAIN, "IBAN is valid [%s]", iban);
271   return 0;
272 }
273 
274 
275 
AB_Banking_MakeGermanIban(const char * bankCode,const char * accountNumber,GWEN_BUFFER * ibanBuf)276 int AB_Banking_MakeGermanIban(const char *bankCode, const char *accountNumber, GWEN_BUFFER *ibanBuf)
277 {
278   GWEN_BUFFER *tbuf;
279   int i;
280   char numbuf[32];
281   char tmp[10];
282   int rv;
283   unsigned int j;
284   const char *p;
285 
286   /* create BBAN */
287   tbuf=GWEN_Buffer_new(0, 256, 0, 1);
288 
289   /* bank code */
290   i=strlen(bankCode);
291   if (i<8)
292     GWEN_Buffer_FillWithBytes(tbuf, '0', 8-i);
293   rv=AB_Banking__TransformIban(bankCode, strlen(bankCode), numbuf, sizeof(numbuf)-1);
294   if (rv<0) {
295     GWEN_Buffer_free(tbuf);
296     DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad bank code (bad char) (%d)", rv);
297     return rv;
298   }
299   GWEN_Buffer_AppendString(tbuf, numbuf);
300 
301   /* account number */
302   i=strlen(accountNumber);
303   if (i<10)
304     GWEN_Buffer_FillWithBytes(tbuf, '0', 10-i);
305   rv=AB_Banking__TransformIban(accountNumber, strlen(accountNumber), numbuf, sizeof(numbuf)-1);
306   if (rv<0) {
307     GWEN_Buffer_free(tbuf);
308     DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad account number (bad char) (%d)", rv);
309     return rv;
310   }
311   GWEN_Buffer_AppendString(tbuf, numbuf);
312 
313   /* add "DE00" */
314   GWEN_Buffer_AppendString(tbuf, "131400");
315 
316   /* calculate checksum in 9er steps */
317   p=GWEN_Buffer_GetStart(tbuf);
318   tmp[0]=0;
319   j=0;
320   while (*p) {
321     for (i=strlen(tmp); i<9;  i++) {
322       if (!*p)
323         break;
324       tmp[i]=*(p++);
325     }
326     tmp[i]=0;
327     if (1!=sscanf(tmp, "%u", &j)) {
328       GWEN_Buffer_free(tbuf);
329       DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (bad char)");
330       return -1;
331     }
332     j=j%97; /* modulo 97 */
333     snprintf(tmp, sizeof(tmp), "%u", j);
334   } /* while */
335 
336   /* j contains the modulus */
337   snprintf(tmp, sizeof(tmp), "%02u", 98-j);
338 
339   GWEN_Buffer_AppendString(ibanBuf, "DE"); /* DE */
340   GWEN_Buffer_AppendString(ibanBuf, tmp);  /* checksum */
341   i=strlen(bankCode);                      /* bank code */
342   if (i<8)
343     GWEN_Buffer_FillWithBytes(ibanBuf, '0', 8-i);
344   GWEN_Buffer_AppendString(ibanBuf, bankCode);
345 
346   i=strlen(accountNumber);                  /* account number */
347   if (i<10)
348     GWEN_Buffer_FillWithBytes(ibanBuf, '0', 10-i);
349   GWEN_Buffer_AppendString(ibanBuf, accountNumber);
350 
351 
352   DBG_INFO(AQBANKING_LOGDOMAIN, "IBAN is %s", GWEN_Buffer_GetStart(ibanBuf));
353   GWEN_Buffer_free(tbuf);
354   return 0;
355 }
356 
357 
358 
359