8af49d12be6b1cdcb563ba9691f0a9498c316536
[kamenim/samba.git] / source3 / libsmb / libsmb_context.c
1 /* 
2    Unix SMB/Netbios implementation.
3    SMB client library implementation
4    Copyright (C) Andrew Tridgell 1998
5    Copyright (C) Richard Sharpe 2000, 2002
6    Copyright (C) John Terpstra 2000
7    Copyright (C) Tom Jansen (Ninja ISD) 2002 
8    Copyright (C) Derrell Lipman 2003-2008
9    Copyright (C) Jeremy Allison 2007, 2008
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "libsmbclient.h"
27 #include "libsmb_internal.h"
28
29
30 /*
31  * Is the logging working / configfile read ? 
32  */
33 static int SMBC_initialized = 0;
34
35
36
37 /*
38  * Get a new empty handle to fill in with your own info
39  */
40 SMBCCTX *
41 smbc_new_context(void)
42 {
43         SMBCCTX *context;
44         
45         /*
46          * All newly added context fields should be placed in
47          * SMBC_internal_data, not directly in SMBCCTX.
48          */
49 #undef OLD
50 #define OLD(field)      context->field
51 #undef NEW
52 #define NEW(field)      context->internal->field
53         
54         context = SMB_MALLOC_P(SMBCCTX);
55         if (!context) {
56                 errno = ENOMEM;
57                 return NULL;
58         }
59         
60         ZERO_STRUCTP(context);
61         
62         context->internal = SMB_MALLOC_P(struct SMBC_internal_data);
63         if (!context->internal) {
64                 SAFE_FREE(context);
65                 errno = ENOMEM;
66                 return NULL;
67         }
68         
69         /* Initialize the context and establish reasonable defaults */
70         ZERO_STRUCTP(context->internal);
71         
72         OLD(config.debug)              = 0;
73         OLD(config.timeout)            = 20000; /* 20 seconds */
74         
75         NEW(full_time_names)           = False;
76         NEW(share_mode)                = SMBC_SHAREMODE_DENY_NONE;
77         NEW(smb_encryption_level)      = 0;
78         OLD(options.browse_max_lmb_count)      = 3;    /* # LMBs to query */
79         OLD(options.urlencode_readdir_entries) = False;
80         OLD(options.one_share_per_server)      = False;
81         
82         OLD(server.get_auth_data_fn)        = SMBC_get_auth_data;
83         OLD(server.check_server_fn)         = SMBC_check_server;
84         OLD(server.remove_unused_server_fn) = SMBC_remove_unused_server;
85         
86         OLD(cache.server_cache_data)        = NULL;
87         OLD(cache.add_cached_server_fn)     = SMBC_add_cached_server;
88         OLD(cache.get_cached_server_fn)     = SMBC_get_cached_server;
89         OLD(cache.remove_cached_server_fn)  = SMBC_remove_cached_server;
90         OLD(cache.purge_cached_servers_fn)  = SMBC_purge_cached_servers;
91         
92         OLD(posix_emu.open_fn)               = SMBC_open_ctx;
93         OLD(posix_emu.creat_fn)              = SMBC_creat_ctx;
94         OLD(posix_emu.read_fn)               = SMBC_read_ctx;
95         OLD(posix_emu.write_fn)              = SMBC_write_ctx;
96         OLD(posix_emu.close_fn)              = SMBC_close_ctx;
97         OLD(posix_emu.unlink_fn)             = SMBC_unlink_ctx;
98         OLD(posix_emu.rename_fn)             = SMBC_rename_ctx;
99         OLD(posix_emu.lseek_fn)              = SMBC_lseek_ctx;
100         NEW(posix_emu.ftruncate_fn)          = SMBC_ftruncate_ctx;
101         OLD(posix_emu.stat_fn)               = SMBC_stat_ctx;
102         OLD(posix_emu.fstat_fn)              = SMBC_fstat_ctx;
103         OLD(posix_emu.opendir_fn)            = SMBC_opendir_ctx;
104         OLD(posix_emu.closedir_fn)           = SMBC_closedir_ctx;
105         OLD(posix_emu.readdir_fn)            = SMBC_readdir_ctx;
106         OLD(posix_emu.getdents_fn)           = SMBC_getdents_ctx;
107         OLD(posix_emu.mkdir_fn)              = SMBC_mkdir_ctx;
108         OLD(posix_emu.rmdir_fn)              = SMBC_rmdir_ctx;
109         OLD(posix_emu.telldir_fn)            = SMBC_telldir_ctx;
110         OLD(posix_emu.lseekdir_fn)           = SMBC_lseekdir_ctx;
111         OLD(posix_emu.fstatdir_fn)           = SMBC_fstatdir_ctx;
112         OLD(posix_emu.chmod_fn)              = SMBC_chmod_ctx;
113         OLD(posix_emu.utimes_fn)             = SMBC_utimes_ctx;
114         OLD(posix_emu.setxattr_fn)           = SMBC_setxattr_ctx;
115         OLD(posix_emu.getxattr_fn)           = SMBC_getxattr_ctx;
116         OLD(posix_emu.removexattr_fn)        = SMBC_removexattr_ctx;
117         OLD(posix_emu.listxattr_fn)          = SMBC_listxattr_ctx;
118         
119         OLD(printing.open_print_job_fn)      = SMBC_open_print_job_ctx;
120         OLD(printing.print_file_fn)          = SMBC_print_file_ctx;
121         OLD(printing.list_print_jobs_fn)     = SMBC_list_print_jobs_ctx;
122         OLD(printing.unlink_print_job_fn)    = SMBC_unlink_print_job_ctx;
123         
124         return context;
125 #undef OLD
126 #undef NEW
127 }
128
129 /*
130  * Free a context
131  *
132  * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed
133  * and thus you'll be leaking memory if not handled properly.
134  *
135  */
136 int
137 smbc_free_context(SMBCCTX *context,
138                   int shutdown_ctx)
139 {
140         if (!context) {
141                 errno = EBADF;
142                 return 1;
143         }
144         
145         if (shutdown_ctx) {
146                 SMBCFILE * f;
147                 DEBUG(1,("Performing aggressive shutdown.\n"));
148                 
149                 f = context->internal->files;
150                 while (f) {
151                         (context->posix_emu.close_fn)(context, f);
152                         f = f->next;
153                 }
154                 context->internal->files = NULL;
155                 
156                 /* First try to remove the servers the nice way. */
157                 if (context->cache.purge_cached_servers_fn(context)) {
158                         SMBCSRV * s;
159                         SMBCSRV * next;
160                         DEBUG(1, ("Could not purge all servers, "
161                                   "Nice way shutdown failed.\n"));
162                         s = context->internal->servers;
163                         while (s) {
164                                 DEBUG(1, ("Forced shutdown: %p (fd=%d)\n",
165                                           s, s->cli->fd));
166                                 cli_shutdown(s->cli);
167                                 (context->cache.remove_cached_server_fn)(context,
168                                                                          s);
169                                 next = s->next;
170                                 DLIST_REMOVE(context->internal->servers, s);
171                                 SAFE_FREE(s);
172                                 s = next;
173                         }
174                         context->internal->servers = NULL;
175                 }
176         }
177         else {
178                 /* This is the polite way */
179                 if ((context->cache.purge_cached_servers_fn)(context)) {
180                         DEBUG(1, ("Could not purge all servers, "
181                                   "free_context failed.\n"));
182                         errno = EBUSY;
183                         return 1;
184                 }
185                 if (context->internal->servers) {
186                         DEBUG(1, ("Active servers in context, "
187                                   "free_context failed.\n"));
188                         errno = EBUSY;
189                         return 1;
190                 }
191                 if (context->internal->files) {
192                         DEBUG(1, ("Active files in context, "
193                                   "free_context failed.\n"));
194                         errno = EBUSY;
195                         return 1;
196                 }
197         }
198         
199         /* Things we have to clean up */
200         SAFE_FREE(context->config.workgroup);
201         SAFE_FREE(context->config.netbios_name);
202         SAFE_FREE(context->config.user);
203         
204         DEBUG(3, ("Context %p successfully freed\n", context));
205         SAFE_FREE(context);
206         return 0;
207 }
208
209
210 /**
211  * Deprecated interface.  Do not use.  Instead, use the various
212  * smbc_setOption*() functions or smbc_setFunctionAuthDataWithContext().
213  */
214 void
215 smbc_option_set(SMBCCTX *context,
216                 char *option_name,
217                 ... /* option_value */)
218 {
219         va_list ap;
220         union {
221                 int i;
222                 bool b;
223                 smbc_get_auth_data_with_context_fn auth_fn;
224                 void *v;
225                 const char *s;
226         } option_value;
227         
228         va_start(ap, option_name);
229         
230         if (strcmp(option_name, "debug_to_stderr") == 0) {
231                 option_value.b = (bool) va_arg(ap, int);
232                 smbc_setOptionDebugToStderr(context, option_value.b);
233                 
234         } else if (strcmp(option_name, "full_time_names") == 0) {
235                 option_value.b = (bool) va_arg(ap, int);
236                 smbc_setOptionFullTimeNames(context, option_value.b);
237                 
238         } else if (strcmp(option_name, "open_share_mode") == 0) {
239                 option_value.i = va_arg(ap, int);
240                 smbc_setOptionOpenShareMode(context, option_value.i);
241                 
242         } else if (strcmp(option_name, "auth_function") == 0) {
243                 option_value.auth_fn =
244                         va_arg(ap, smbc_get_auth_data_with_context_fn);
245                 smbc_setFunctionAuthDataWithContext(context, option_value.auth_fn);
246                 
247         } else if (strcmp(option_name, "user_data") == 0) {
248                 option_value.v = va_arg(ap, void *);
249                 smbc_setOptionUserData(context, option_value.v);
250                 
251         } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
252                 option_value.s = va_arg(ap, const char *);
253                 if (strcmp(option_value.s, "none") == 0) {
254                         smbc_setOptionSmbEncryptionLevel(context,
255                                                          SMBC_ENCRYPTLEVEL_NONE);
256                 } else if (strcmp(option_value.s, "request") == 0) {
257                         smbc_setOptionSmbEncryptionLevel(context,
258                                                          SMBC_ENCRYPTLEVEL_REQUEST);
259                 } else if (strcmp(option_value.s, "require") == 0) {
260                         smbc_setOptionSmbEncryptionLevel(context,
261                                                          SMBC_ENCRYPTLEVEL_REQUIRE);
262                 }
263                 
264         } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
265                 option_value.i = va_arg(ap, int);
266                 smbc_setOptionBrowseMaxLmbCount(context, option_value.i);
267                 
268         } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
269                 option_value.b = (bool) va_arg(ap, int);
270                 smbc_setOptionUrlEncodeReaddirEntries(context, option_value.b);
271                 
272         } else if (strcmp(option_name, "one_share_per_server") == 0) {
273                 option_value.b = (bool) va_arg(ap, int);
274                 smbc_setOptionOneSharePerServer(context, option_value.b);
275                 
276         } else if (strcmp(option_name, "use_kerberos") == 0) {
277                 option_value.b = (bool) va_arg(ap, int);
278                 smbc_setOptionUseKerberos(context, option_value.b);
279                 
280         } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
281                 option_value.b = (bool) va_arg(ap, int);
282                 smbc_setOptionFallbackAfterKerberos(context, option_value.b);
283                 
284         } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) {
285                 option_value.b = (bool) va_arg(ap, int);
286                 smbc_setOptionNoAutoAnonymousLogin(context, option_value.b);
287         }
288         
289         va_end(ap);
290 }
291
292
293 /*
294  * Deprecated interface.  Do not use.  Instead, use the various
295  * smbc_getOption*() functions.
296  */
297 void *
298 smbc_option_get(SMBCCTX *context,
299                 char *option_name)
300 {
301         int             bits;
302         
303         if (strcmp(option_name, "debug_stderr") == 0) {
304 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
305                 return (void *) (intptr_t) smbc_getOptionDebugToStderr(context);
306 #else
307                 return (void *) smbc_getOptionDebugToStderr(context);
308 #endif
309                 
310         } else if (strcmp(option_name, "full_time_names") == 0) {
311 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
312                 return (void *) (intptr_t) smbc_getOptionFullTimeNames(context);
313 #else
314                 return (void *) smbc_getOptionFullTimeNames(context);
315 #endif
316                 
317         } else if (strcmp(option_name, "open_share_mode") == 0) {
318 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
319                 return (void *) (intptr_t) smbc_getOptionOpenShareMode(context);
320 #else
321                 return (void *) smbc_getOptionOpenShareMode(context);
322 #endif
323                 
324         } else if (strcmp(option_name, "auth_function") == 0) {
325                 return (void *) smbc_getFunctionAuthDataWithContext(context);
326                 
327         } else if (strcmp(option_name, "user_data") == 0) {
328                 return smbc_getOptionUserData(context);
329                 
330         } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
331                 switch(smbc_getOptionSmbEncryptionLevel(context))
332                 {
333                 case 0:
334                         return (void *) "none";
335                 case 1:
336                         return (void *) "request";
337                 case 2:
338                         return (void *) "require";
339                 }
340                 
341         } else if (strcmp(option_name, "smb_encrypt_on") == 0) {
342                 SMBCSRV *s;
343                 unsigned int num_servers = 0;
344                 
345                 for (s = context->internal->servers; s; s = s->next) {
346                         num_servers++;
347                         if (s->cli->trans_enc_state == NULL) {
348                                 return (void *)false;
349                         }
350                 }
351 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
352                 return (void *) (intptr_t) (bool) (num_servers > 0);
353 #else
354                 return (void *) (bool) (num_servers > 0);
355 #endif
356                 
357         } else if (strcmp(option_name, "browse_max_lmb_count") == 0) {
358 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
359                 return (void *) (intptr_t) smbc_getOptionBrowseMaxLmbCount(context);
360 #else
361                 return (void *) smbc_getOptionBrowseMaxLmbCount(context);
362 #endif
363                 
364         } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) {
365 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
366                 return (void *)(intptr_t) smbc_getOptionUrlEncodeReaddirEntries(context);
367 #else
368                 return (void *) (bool) smbc_getOptionUrlEncodeReaddirEntries(context);
369 #endif
370                 
371         } else if (strcmp(option_name, "one_share_per_server") == 0) {
372 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
373                 return (void *) (intptr_t) smbc_getOptionOneSharePerServer(context);
374 #else
375                 return (void *) (bool) smbc_getOptionOneSharePerServer(context);
376 #endif
377                 
378         } else if (strcmp(option_name, "use_kerberos") == 0) {
379                 bits = context->flags.bits;
380 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
381                 return (void *) (intptr_t) smbc_getOptionUseKerberos(context);
382 #else
383                 return (void *) (bool) smbc_getOptionUseKerberos(context);
384 #endif
385                 
386         } else if (strcmp(option_name, "fallback_after_kerberos") == 0) {
387 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
388                 return (void *)(intptr_t) smbc_getOptionFallbackAfterKerberos(context);
389 #else
390                 return (void *) (bool) smbc_getOptionFallbackAfterKerberos(context);
391 #endif
392                 
393         } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) {
394 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
395                 return (void *) (intptr_t) smbc_getOptionNoAutoAnonymousLogin(context);
396 #else
397                 return (void *) (bool) smbc_getOptionNoAutoAnonymousLogin(context);
398 #endif
399         }
400         
401         return NULL;
402 }
403
404
405 /*
406  * Initialize the library, etc.
407  *
408  * We accept a struct containing handle information.
409  * valid values for info->debug from 0 to 100,
410  * and insist that info->fn must be non-null.
411  */
412 SMBCCTX *
413 smbc_init_context(SMBCCTX *context)
414 {
415         int pid;
416         char *user = NULL;
417         char *home = NULL;
418         extern bool in_client;
419         
420         if (!context) {
421                 errno = EBADF;
422                 return NULL;
423         }
424         
425         /* Do not initialise the same client twice */
426         if (context->internal->initialized) {
427                 return 0;
428         }
429         
430         if (!context->server.get_auth_data_fn ||
431             context->config.debug < 0 ||
432             context->config.debug > 100) {
433                 
434                 errno = EINVAL;
435                 return NULL;
436                 
437         }
438         
439         if (!SMBC_initialized) {
440                 /*
441                  * Do some library-wide intializations the first time we get
442                  * called
443                  */
444                 bool conf_loaded = False;
445                 TALLOC_CTX *frame = talloc_stackframe();
446                 
447                 /* Set this to what the user wants */
448                 DEBUGLEVEL = context->config.debug;
449                 
450                 load_case_tables();
451                 
452                 setup_logging("libsmbclient", True);
453                 if (context->internal->debug_stderr) {
454                         dbf = x_stderr;
455                         x_setbuf(x_stderr, NULL);
456                 }
457                 
458                 /* Here we would open the smb.conf file if needed ... */
459                 
460                 in_client = True; /* FIXME, make a param */
461                 
462                 home = getenv("HOME");
463                 if (home) {
464                         char *conf = NULL;
465                         if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) {
466                                 if (lp_load(conf, True, False, False, True)) {
467                                         conf_loaded = True;
468                                 } else {
469                                         DEBUG(5, ("Could not load config file: %s\n",
470                                                   conf));
471                                 }
472                                 SAFE_FREE(conf);
473                         }
474                 }
475                 
476                 if (!conf_loaded) {
477                         /*
478                          * Well, if that failed, try the get_dyn_CONFIGFILE
479                          * Which points to the standard locn, and if that
480                          * fails, silently ignore it and use the internal
481                          * defaults ...
482                          */
483                         
484                         if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) {
485                                 DEBUG(5, ("Could not load config file: %s\n",
486                                           get_dyn_CONFIGFILE()));
487                         } else if (home) {
488                                 char *conf;
489                                 /*
490                                  * We loaded the global config file.  Now lets
491                                  * load user-specific modifications to the
492                                  * global config.
493                                  */
494                                 if (asprintf(&conf,
495                                              "%s/.smb/smb.conf.append",
496                                              home) > 0) {
497                                         if (!lp_load(conf, True, False, False, False)) {
498                                                 DEBUG(10,
499                                                       ("Could not append config file: "
500                                                        "%s\n",
501                                                        conf));
502                                         }
503                                         SAFE_FREE(conf);
504                                 }
505                         }
506                 }
507                 
508                 load_interfaces();  /* Load the list of interfaces ... */
509                 
510                 reopen_logs();  /* Get logging working ... */
511                 
512                 /*
513                  * Block SIGPIPE (from lib/util_sock.c: write())
514                  * It is not needed and should not stop execution
515                  */
516                 BlockSignals(True, SIGPIPE);
517                 
518                 /* Done with one-time initialisation */
519                 SMBC_initialized = 1;
520                 
521                 TALLOC_FREE(frame);
522         }
523         
524         if (!context->config.user) {
525                 /*
526                  * FIXME: Is this the best way to get the user info?
527                  */
528                 user = getenv("USER");
529                 /* walk around as "guest" if no username can be found */
530                 if (!user) context->config.user = SMB_STRDUP("guest");
531                 else context->config.user = SMB_STRDUP(user);
532         }
533         
534         if (!context->config.netbios_name) {
535                 /*
536                  * We try to get our netbios name from the config. If that
537                  * fails we fall back on constructing our netbios name from
538                  * our hostname etc
539                  */
540                 if (global_myname()) {
541                         context->config.netbios_name = SMB_STRDUP(global_myname());
542                 }
543                 else {
544                         /*
545                          * Hmmm, I want to get hostname as well, but I am too
546                          * lazy for the moment
547                          */
548                         pid = sys_getpid();
549                         context->config.netbios_name = (char *)SMB_MALLOC(17);
550                         if (!context->config.netbios_name) {
551                                 errno = ENOMEM;
552                                 return NULL;
553                         }
554                         slprintf(context->config.netbios_name, 16,
555                                  "smbc%s%d", context->config.user, pid);
556                 }
557         }
558         
559         DEBUG(1, ("Using netbios name %s.\n", context->config.netbios_name));
560         
561         if (!context->config.workgroup) {
562                 if (lp_workgroup()) {
563                         context->config.workgroup = SMB_STRDUP(lp_workgroup());
564                 }
565                 else {
566                         /* TODO: Think about a decent default workgroup */
567                         context->config.workgroup = SMB_STRDUP("samba");
568                 }
569         }
570         
571         DEBUG(1, ("Using workgroup %s.\n", context->config.workgroup));
572         
573         /* shortest timeout is 1 second */
574         if (context->config.timeout > 0 && context->config.timeout < 1000)
575                 context->config.timeout = 1000;
576         
577         /*
578          * FIXME: Should we check the function pointers here?
579          */
580         
581         context->internal->initialized = True;
582         
583         return context;
584 }
585
586
587 /* Return the verion of samba, and thus libsmbclient */
588 const char *
589 smbc_version(void)
590 {
591         return samba_version_string();
592 }
593
594
595 /** Get the netbios name used for making connections */
596 char *
597 smbc_getNetbiosName(SMBCCTX *c)
598 {
599         return c->config.netbios_name;
600 }
601
602 /** Set the netbios name used for making connections */
603 void
604 smbc_setNetbiosName(SMBCCTX *c, char * netbios_name)
605 {
606         c->config.netbios_name = netbios_name;
607 }
608
609 /** Get the workgroup used for making connections */
610 char *
611 smbc_getWorkgroup(SMBCCTX *c)
612 {
613         return c->config.workgroup;
614 }
615
616 /** Set the workgroup used for making connections */
617 void
618 smbc_setWorkgroup(SMBCCTX *c, char * workgroup)
619 {
620         c->config.workgroup = workgroup;
621 }
622
623 /** Get the username used for making connections */
624 char *
625 smbc_getUser(SMBCCTX *c)
626 {
627         return c->config.user;
628 }
629
630 /** Set the username used for making connections */
631 void
632 smbc_setUser(SMBCCTX *c, char * user)
633 {
634         c->config.user = user;
635 }
636
637 /** Get the debug level */
638 int
639 smbc_getDebug(SMBCCTX *c)
640 {
641         return c->config.debug;
642 }
643
644 /** Set the debug level */
645 void
646 smbc_setDebug(SMBCCTX *c, int debug)
647 {
648         c->config.debug = debug;
649 }
650
651 /**
652  * Get the timeout used for waiting on connections and response data
653  * (in milliseconds)
654  */
655 int
656 smbc_getTimeout(SMBCCTX *c)
657 {
658         return c->config.timeout;
659 }
660
661 /**
662  * Set the timeout used for waiting on connections and response data
663  * (in milliseconds)
664  */
665 void
666 smbc_setTimeout(SMBCCTX *c, int timeout)
667 {
668         c->config.timeout = timeout;
669 }
670
671 /** Get whether to log to standard error instead of standard output */
672 smbc_bool
673 smbc_getOptionDebugToStderr(SMBCCTX *c)
674 {
675         return c->internal->debug_stderr;
676 }
677
678 /** Set whether to log to standard error instead of standard output */
679 void
680 smbc_setOptionDebugToStderr(SMBCCTX *c, smbc_bool b)
681 {
682         c->internal->debug_stderr = b;
683 }
684
685 /**
686  * Get whether to use new-style time attribute names, e.g. WRITE_TIME rather
687  * than the old-style names such as M_TIME.  This allows also setting/getting
688  * CREATE_TIME which was previously unimplemented.  (Note that the old C_TIME
689  * was supposed to be CHANGE_TIME but was confused and sometimes referred to
690  * CREATE_TIME.)
691  */
692 smbc_bool
693 smbc_getOptionFullTimeNames(SMBCCTX *c)
694 {
695         return c->internal->full_time_names;
696 }
697
698 /**
699  * Set whether to use new-style time attribute names, e.g. WRITE_TIME rather
700  * than the old-style names such as M_TIME.  This allows also setting/getting
701  * CREATE_TIME which was previously unimplemented.  (Note that the old C_TIME
702  * was supposed to be CHANGE_TIME but was confused and sometimes referred to
703  * CREATE_TIME.)
704  */
705 void
706 smbc_setOptionFullTimeNames(SMBCCTX *c, smbc_bool b)
707 {
708         c->internal->full_time_names = b;
709 }
710
711 /**
712  * Get the share mode to use for files opened with SMBC_open_ctx().  The
713  * default is SMBC_SHAREMODE_DENY_NONE.
714  */
715 smbc_share_mode
716 smbc_getOptionOpenShareMode(SMBCCTX *c)
717 {
718         return c->internal->share_mode;
719 }
720
721 /**
722  * Set the share mode to use for files opened with SMBC_open_ctx().  The
723  * default is SMBC_SHAREMODE_DENY_NONE.
724  */
725 void
726 smbc_setOptionOpenShareMode(SMBCCTX *c, smbc_share_mode share_mode)
727 {
728         c->internal->share_mode = share_mode;
729 }
730
731 /** Retrieve a previously set user data handle */
732 void *
733 smbc_getOptionUserData(SMBCCTX *c)
734 {
735         return c->internal->user_data;
736 }
737
738 /** Save a user data handle */
739 void
740 smbc_setOptionUserData(SMBCCTX *c, void *user_data)
741 {
742         c->internal->user_data = user_data;
743 }
744
745 /** Get the encoded value for encryption level. */
746 smbc_smb_encrypt_level
747 smbc_getOptionSmbEncryptionLevel(SMBCCTX *c)
748 {
749         return c->internal->smb_encryption_level;
750 }
751
752 /** Set the encoded value for encryption level. */
753 void
754 smbc_setOptionSmbEncryptionLevel(SMBCCTX *c, smbc_smb_encrypt_level level)
755 {
756         c->internal->smb_encryption_level = level;
757 }
758
759 /**
760  * Get from how many local master browsers should the list of workgroups be
761  * retrieved.  It can take up to 12 minutes or longer after a server becomes a
762  * local master browser, for it to have the entire browse list (the list of
763  * workgroups/domains) from an entire network.  Since a client never knows
764  * which local master browser will be found first, the one which is found
765  * first and used to retrieve a browse list may have an incomplete or empty
766  * browse list.  By requesting the browse list from multiple local master
767  * browsers, a more complete list can be generated.  For small networks (few
768  * workgroups), it is recommended that this value be set to 0, causing the
769  * browse lists from all found local master browsers to be retrieved and
770  * merged.  For networks with many workgroups, a suitable value for this
771  * variable is probably somewhere around 3. (Default: 3).
772  */
773 int
774 smbc_getOptionBrowseMaxLmbCount(SMBCCTX *c)
775 {
776         return c->options.browse_max_lmb_count;
777 }
778
779 /**
780  * Set from how many local master browsers should the list of workgroups be
781  * retrieved.  It can take up to 12 minutes or longer after a server becomes a
782  * local master browser, for it to have the entire browse list (the list of
783  * workgroups/domains) from an entire network.  Since a client never knows
784  * which local master browser will be found first, the one which is found
785  * first and used to retrieve a browse list may have an incomplete or empty
786  * browse list.  By requesting the browse list from multiple local master
787  * browsers, a more complete list can be generated.  For small networks (few
788  * workgroups), it is recommended that this value be set to 0, causing the
789  * browse lists from all found local master browsers to be retrieved and
790  * merged.  For networks with many workgroups, a suitable value for this
791  * variable is probably somewhere around 3. (Default: 3).
792  */
793 void
794 smbc_setOptionBrowseMaxLmbCount(SMBCCTX *c, int count)
795 {
796         c->options.browse_max_lmb_count = count;
797 }
798
799 /**
800  * Get whether to url-encode readdir entries.
801  *
802  * There is a difference in the desired return strings from
803  * smbc_readdir() depending upon whether the filenames are to
804  * be displayed to the user, or whether they are to be
805  * appended to the path name passed to smbc_opendir() to call
806  * a further smbc_ function (e.g. open the file with
807  * smbc_open()).  In the former case, the filename should be
808  * in "human readable" form.  In the latter case, the smbc_
809  * functions expect a URL which must be url-encoded.  Those
810  * functions decode the URL.  If, for example, smbc_readdir()
811  * returned a file name of "abc%20def.txt", passing a path
812  * with this file name attached to smbc_open() would cause
813  * smbc_open to attempt to open the file "abc def.txt" since
814  * the %20 is decoded into a space.
815  *
816  * Set this option to True if the names returned by
817  * smbc_readdir() should be url-encoded such that they can be
818  * passed back to another smbc_ call.  Set it to False if the
819  * names returned by smbc_readdir() are to be presented to the
820  * user.
821  *
822  * For backwards compatibility, this option defaults to False.
823  */
824 smbc_bool
825 smbc_getOptionUrlEncodeReaddirEntries(SMBCCTX *c)
826 {
827         return c->options.urlencode_readdir_entries;
828 }
829
830 /**
831  * Set whether to url-encode readdir entries.
832  *
833  * There is a difference in the desired return strings from
834  * smbc_readdir() depending upon whether the filenames are to
835  * be displayed to the user, or whether they are to be
836  * appended to the path name passed to smbc_opendir() to call
837  * a further smbc_ function (e.g. open the file with
838  * smbc_open()).  In the former case, the filename should be
839  * in "human readable" form.  In the latter case, the smbc_
840  * functions expect a URL which must be url-encoded.  Those
841  * functions decode the URL.  If, for example, smbc_readdir()
842  * returned a file name of "abc%20def.txt", passing a path
843  * with this file name attached to smbc_open() would cause
844  * smbc_open to attempt to open the file "abc def.txt" since
845  * the %20 is decoded into a space.
846  *
847  * Set this option to True if the names returned by
848  * smbc_readdir() should be url-encoded such that they can be
849  * passed back to another smbc_ call.  Set it to False if the
850  * names returned by smbc_readdir() are to be presented to the
851  * user.
852  *
853  * For backwards compatibility, this option defaults to False.
854  */
855 void
856 smbc_setOptionUrlEncodeReaddirEntries(SMBCCTX *c, smbc_bool b)
857 {
858         c->options.urlencode_readdir_entries = b;
859 }
860
861 /**
862  * Get whether to use the same connection for all shares on a server.
863  *
864  * Some Windows versions appear to have a limit to the number
865  * of concurrent SESSIONs and/or TREE CONNECTions.  In
866  * one-shot programs (i.e. the program runs and then quickly
867  * ends, thereby shutting down all connections), it is
868  * probably reasonable to establish a new connection for each
869  * share.  In long-running applications, the limitation can be
870  * avoided by using only a single connection to each server,
871  * and issuing a new TREE CONNECT when the share is accessed.
872  */
873 smbc_bool
874 smbc_getOptionOneSharePerServer(SMBCCTX *c)
875 {
876         return c->options.one_share_per_server;
877 }
878
879 /**
880  * Set whether to use the same connection for all shares on a server.
881  *
882  * Some Windows versions appear to have a limit to the number
883  * of concurrent SESSIONs and/or TREE CONNECTions.  In
884  * one-shot programs (i.e. the program runs and then quickly
885  * ends, thereby shutting down all connections), it is
886  * probably reasonable to establish a new connection for each
887  * share.  In long-running applications, the limitation can be
888  * avoided by using only a single connection to each server,
889  * and issuing a new TREE CONNECT when the share is accessed.
890  */
891 void
892 smbc_setOptionOneSharePerServer(SMBCCTX *c, smbc_bool b)
893 {
894         c->options.one_share_per_server = b;
895 }
896
897 /** Get whether to enable use of kerberos */
898 smbc_bool
899 smbc_getOptionUseKerberos(SMBCCTX *c)
900 {
901         return c->flags.bits & SMB_CTX_FLAG_USE_KERBEROS ? True : False;
902 }
903
904 /** Set whether to enable use of kerberos */
905 void
906 smbc_setOptionUseKerberos(SMBCCTX *c, smbc_bool b)
907 {
908         if (b) {
909                 c->flags.bits |= SMB_CTX_FLAG_USE_KERBEROS;
910         } else {
911                 c->flags.bits &= ~SMB_CTX_FLAG_USE_KERBEROS;
912         }
913 }
914
915 /** Get whether to fallback after kerberos */
916 smbc_bool
917 smbc_getOptionFallbackAfterKerberos(SMBCCTX *c)
918 {
919         return c->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS ? True : False;
920 }
921
922 /** Set whether to fallback after kerberos */
923 void
924 smbc_setOptionFallbackAfterKerberos(SMBCCTX *c, smbc_bool b)
925 {
926         if (b) {
927                 c->flags.bits |= SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS;
928         } else {
929                 c->flags.bits &= ~SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS;
930         }
931 }
932
933 /** Get whether to automatically select anonymous login */
934 smbc_bool
935 smbc_getOptionNoAutoAnonymousLogin(SMBCCTX *c)
936 {
937         return c->flags.bits & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON ? True : False;
938 }
939
940 /** Set whether to automatically select anonymous login */
941 void
942 smbc_setOptionNoAutoAnonymousLogin(SMBCCTX *c, smbc_bool b)
943 {
944         if (b) {
945                 c->flags.bits |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON;
946         } else {
947                 c->flags.bits &= ~SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON;
948         }
949 }
950
951 /** Get the function for obtaining authentication data */
952 smbc_get_auth_data_fn
953 smbc_getFunctionAuthData(SMBCCTX *c)
954 {
955         return c->server.get_auth_data_fn;
956 }
957
958 /** Set the function for obtaining authentication data */
959 void
960 smbc_setFunctionAuthData(SMBCCTX *c, smbc_get_auth_data_fn fn)
961 {
962         c->internal->auth_fn_with_context = NULL;
963         c->server.get_auth_data_fn = fn;
964 }
965
966 /** Get the new-style authentication function which includes the context. */
967 smbc_get_auth_data_with_context_fn
968 smbc_getFunctionAuthDataWithContext(SMBCCTX *c)
969 {
970         return c->internal->auth_fn_with_context;
971 }
972
973 /** Set the new-style authentication function which includes the context. */
974 void
975 smbc_setFunctionAuthDataWithContext(SMBCCTX *c,
976                                     smbc_get_auth_data_with_context_fn fn)
977 {
978         c->server.get_auth_data_fn = NULL;
979         c->internal->auth_fn_with_context = fn;
980 }
981
982 /** Get the function for checking if a server is still good */
983 smbc_check_server_fn
984 smbc_getFunctionCheckServer(SMBCCTX *c)
985 {
986         return c->server.check_server_fn;
987 }
988
989 /** Set the function for checking if a server is still good */
990 void
991 smbc_setFunctionCheckServer(SMBCCTX *c, smbc_check_server_fn fn)
992 {
993         c->server.check_server_fn = fn;
994 }
995
996 /** Get the function for removing a server if unused */
997 smbc_remove_unused_server_fn
998 smbc_getFunctionRemoveUnusedServer(SMBCCTX *c)
999 {
1000         return c->server.remove_unused_server_fn;
1001 }
1002
1003 /** Set the function for removing a server if unused */
1004 void
1005 smbc_setFunctionRemoveUnusedServer(SMBCCTX *c,
1006                                    smbc_remove_unused_server_fn fn)
1007 {
1008         c->server.remove_unused_server_fn = fn;
1009 }
1010
1011 /** Get the function to store private data of the server cache */
1012 struct
1013 smbc_server_cache * smbc_getServerCacheData(SMBCCTX *c)
1014 {
1015         return c->cache.server_cache_data;
1016 }
1017
1018 /** Set the function to store private data of the server cache */
1019 void
1020 smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache)
1021 {
1022         c->cache.server_cache_data = cache;
1023 }
1024
1025
1026 /** Get the function for adding a cached server */
1027 smbc_add_cached_srv_fn
1028 smbc_getFunctionAddCachedServer(SMBCCTX *c)
1029 {
1030         return c->cache.add_cached_server_fn;
1031 }
1032
1033 /** Set the function for adding a cached server */
1034 void
1035 smbc_setFunctionAddCachedServer(SMBCCTX *c, smbc_add_cached_srv_fn fn)
1036 {
1037         c->cache.add_cached_server_fn = fn;
1038 }
1039
1040 /** Get the function for server cache lookup */
1041 smbc_get_cached_srv_fn
1042 smbc_getFunctionGetCachedServer(SMBCCTX *c)
1043 {
1044         return c->cache.get_cached_server_fn;
1045 }
1046
1047 /** Set the function for server cache lookup */
1048 void
1049 smbc_setFunctionGetCachedServer(SMBCCTX *c, smbc_get_cached_srv_fn fn)
1050 {
1051         c->cache.get_cached_server_fn = fn;
1052 }
1053
1054 /** Get the function for server cache removal */
1055 smbc_remove_cached_srv_fn
1056 smbc_getFunctionRemoveCachedServer(SMBCCTX *c)
1057 {
1058         return c->cache.remove_cached_server_fn;
1059 }
1060
1061 /** Set the function for server cache removal */
1062 void
1063 smbc_setFunctionRemoveCachedServer(SMBCCTX *c,
1064                                    smbc_remove_cached_srv_fn fn)
1065 {
1066         c->cache.remove_cached_server_fn = fn;
1067 }
1068
1069 /**
1070  * Get the function for server cache purging.  This function tries to
1071  * remove all cached servers (e.g. on disconnect)
1072  */
1073 smbc_purge_cached_srv_fn
1074 smbc_getFunctionPurgeCachedServers(SMBCCTX *c)
1075 {
1076         return c->cache.purge_cached_servers_fn;
1077 }
1078
1079 /**
1080  * Set the function for server cache purging.  This function tries to
1081  * remove all cached servers (e.g. on disconnect)
1082  */
1083 void
1084 smbc_setFunctionPurgeCachedServers(SMBCCTX *c, smbc_purge_cached_srv_fn fn)
1085 {
1086         c->cache.purge_cached_servers_fn = fn;
1087 }
1088
1089 /**
1090  * Callable functions for files.
1091  */
1092
1093 smbc_open_fn
1094 smbc_getFunctionOpen(SMBCCTX *c)
1095 {
1096         return c->posix_emu.open_fn;
1097 }
1098
1099 void
1100 smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn)
1101 {
1102         c->posix_emu.open_fn = fn;
1103 }
1104
1105 smbc_creat_fn
1106 smbc_getFunctionCreat(SMBCCTX *c)
1107 {
1108         return c->posix_emu.creat_fn;
1109 }
1110
1111 void
1112 smbc_setFunctionCreat(SMBCCTX *c, smbc_creat_fn fn)
1113 {
1114         c->posix_emu.creat_fn = fn;
1115 }
1116
1117 smbc_read_fn
1118 smbc_getFunctionRead(SMBCCTX *c)
1119 {
1120         return c->posix_emu.read_fn;
1121 }
1122
1123 void
1124 smbc_setFunctionRead(SMBCCTX *c, smbc_read_fn fn)
1125 {
1126         c->posix_emu.read_fn = fn;
1127 }
1128
1129 smbc_write_fn
1130 smbc_getFunctionWrite(SMBCCTX *c)
1131 {
1132         return c->posix_emu.write_fn;
1133 }
1134
1135 void
1136 smbc_setFunctionWrite(SMBCCTX *c, smbc_write_fn fn)
1137 {
1138         c->posix_emu.write_fn = fn;
1139 }
1140
1141 smbc_unlink_fn
1142 smbc_getFunctionUnlink(SMBCCTX *c)
1143 {
1144         return c->posix_emu.unlink_fn;
1145 }
1146
1147 void
1148 smbc_setFunctionUnlink(SMBCCTX *c, smbc_unlink_fn fn)
1149 {
1150         c->posix_emu.unlink_fn = fn;
1151 }
1152
1153 smbc_rename_fn
1154 smbc_getFunctionRename(SMBCCTX *c)
1155 {
1156         return c->posix_emu.rename_fn;
1157 }
1158
1159 void
1160 smbc_setFunctionRename(SMBCCTX *c, smbc_rename_fn fn)
1161 {
1162         c->posix_emu.rename_fn = fn;
1163 }
1164
1165 smbc_lseek_fn
1166 smbc_getFunctionLseek(SMBCCTX *c)
1167 {
1168         return c->posix_emu.lseek_fn;
1169 }
1170
1171 void
1172 smbc_setFunctionLseek(SMBCCTX *c, smbc_lseek_fn fn)
1173 {
1174         c->posix_emu.lseek_fn = fn;
1175 }
1176
1177 smbc_stat_fn
1178 smbc_getFunctionStat(SMBCCTX *c)
1179 {
1180         return c->posix_emu.stat_fn;
1181 }
1182
1183 void
1184 smbc_setFunctionStat(SMBCCTX *c, smbc_stat_fn fn)
1185 {
1186         c->posix_emu.stat_fn = fn;
1187 }
1188
1189 smbc_fstat_fn
1190 smbc_getFunctionFstat(SMBCCTX *c)
1191 {
1192         return c->posix_emu.fstat_fn;
1193 }
1194
1195 void
1196 smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn)
1197 {
1198         c->posix_emu.fstat_fn = fn;
1199 }
1200
1201 smbc_ftruncate_fn
1202 smbc_getFunctionFtruncate(SMBCCTX *c)
1203 {
1204         return c->internal->posix_emu.ftruncate_fn;
1205 }
1206
1207 void
1208 smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn fn)
1209 {
1210         c->internal->posix_emu.ftruncate_fn = fn;
1211 }
1212
1213 smbc_close_fn
1214 smbc_getFunctionClose(SMBCCTX *c)
1215 {
1216         return c->posix_emu.close_fn;
1217 }
1218
1219 void
1220 smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn fn)
1221 {
1222         c->posix_emu.close_fn = fn;
1223 }
1224
1225
1226 /**
1227  * Callable functions for directories.
1228  */
1229
1230 smbc_opendir_fn
1231 smbc_getFunctionOpendir(SMBCCTX *c)
1232 {
1233         return c->posix_emu.opendir_fn;
1234 }
1235
1236 void
1237 smbc_setFunctionOpendir(SMBCCTX *c, smbc_opendir_fn fn)
1238 {
1239         c->posix_emu.opendir_fn = fn;
1240 }
1241
1242 smbc_closedir_fn
1243 smbc_getFunctionClosedir(SMBCCTX *c)
1244 {
1245         return c->posix_emu.closedir_fn;
1246 }
1247
1248 void
1249 smbc_setFunctionClosedir(SMBCCTX *c, smbc_closedir_fn fn)
1250 {
1251         c->posix_emu.closedir_fn = fn;
1252 }
1253
1254 smbc_readdir_fn
1255 smbc_getFunctionReaddir(SMBCCTX *c)
1256 {
1257         return c->posix_emu.readdir_fn;
1258 }
1259
1260 void
1261 smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn)
1262 {
1263         c->posix_emu.readdir_fn = fn;
1264 }
1265
1266 smbc_getdents_fn
1267 smbc_getFunctionGetdents(SMBCCTX *c)
1268 {
1269         return c->posix_emu.getdents_fn;
1270 }
1271
1272 void
1273 smbc_setFunctionGetdents(SMBCCTX *c, smbc_getdents_fn fn)
1274 {
1275         c->posix_emu.getdents_fn = fn;
1276 }
1277
1278 smbc_mkdir_fn
1279 smbc_getFunctionMkdir(SMBCCTX *c)
1280 {
1281         return c->posix_emu.mkdir_fn;
1282 }
1283
1284 void
1285 smbc_setFunctionMkdir(SMBCCTX *c, smbc_mkdir_fn fn)
1286 {
1287         c->posix_emu.mkdir_fn = fn;
1288 }
1289
1290 smbc_rmdir_fn
1291 smbc_getFunctionRmdir(SMBCCTX *c)
1292 {
1293         return c->posix_emu.rmdir_fn;
1294 }
1295
1296 void
1297 smbc_setFunctionRmdir(SMBCCTX *c, smbc_rmdir_fn fn)
1298 {
1299         c->posix_emu.rmdir_fn = fn;
1300 }
1301
1302 smbc_telldir_fn
1303 smbc_getFunctionTelldir(SMBCCTX *c)
1304 {
1305         return c->posix_emu.telldir_fn;
1306 }
1307
1308 void
1309 smbc_setFunctionTelldir(SMBCCTX *c, smbc_telldir_fn fn)
1310 {
1311         c->posix_emu.telldir_fn = fn;
1312 }
1313
1314 smbc_lseekdir_fn
1315 smbc_getFunctionLseekdir(SMBCCTX *c)
1316 {
1317         return c->posix_emu.lseekdir_fn;
1318 }
1319
1320 void
1321 smbc_setFunctionLseekdir(SMBCCTX *c, smbc_lseekdir_fn fn)
1322 {
1323         c->posix_emu.lseekdir_fn = fn;
1324 }
1325
1326 smbc_fstatdir_fn
1327 smbc_getFunctionFstatdir(SMBCCTX *c)
1328 {
1329         return c->posix_emu.fstatdir_fn;
1330 }
1331
1332 void
1333 smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn)
1334 {
1335         c->posix_emu.fstatdir_fn = fn;
1336 }
1337
1338
1339 /**
1340  * Callable functions applicable to both files and directories.
1341  */
1342
1343 smbc_chmod_fn
1344 smbc_getFunctionChmod(SMBCCTX *c)
1345 {
1346         return c->posix_emu.chmod_fn;
1347 }
1348
1349 void
1350 smbc_setFunctionChmod(SMBCCTX *c, smbc_chmod_fn fn)
1351 {
1352         c->posix_emu.chmod_fn = fn;
1353 }
1354
1355 smbc_utimes_fn
1356 smbc_getFunctionUtimes(SMBCCTX *c)
1357 {
1358         return c->posix_emu.utimes_fn;
1359 }
1360
1361 void
1362 smbc_setFunctionUtimes(SMBCCTX *c, smbc_utimes_fn fn)
1363 {
1364         c->posix_emu.utimes_fn = fn;
1365 }
1366
1367 smbc_setxattr_fn
1368 smbc_getFunctionSetxattr(SMBCCTX *c)
1369 {
1370         return c->posix_emu.setxattr_fn;
1371 }
1372
1373 void
1374 smbc_setFunctionSetxattr(SMBCCTX *c, smbc_setxattr_fn fn)
1375 {
1376         c->posix_emu.setxattr_fn = fn;
1377 }
1378
1379 smbc_getxattr_fn
1380 smbc_getFunctionGetxattr(SMBCCTX *c)
1381 {
1382         return c->posix_emu.getxattr_fn;
1383 }
1384
1385 void
1386 smbc_setFunctionGetxattr(SMBCCTX *c, smbc_getxattr_fn fn)
1387 {
1388         c->posix_emu.getxattr_fn = fn;
1389 }
1390
1391 smbc_removexattr_fn
1392 smbc_getFunctionRemovexattr(SMBCCTX *c)
1393 {
1394         return c->posix_emu.removexattr_fn;
1395 }
1396
1397 void
1398 smbc_setFunctionRemovexattr(SMBCCTX *c, smbc_removexattr_fn fn)
1399 {
1400         c->posix_emu.removexattr_fn = fn;
1401 }
1402
1403 smbc_listxattr_fn
1404 smbc_getFunctionListxattr(SMBCCTX *c)
1405 {
1406         return c->posix_emu.listxattr_fn;
1407 }
1408
1409 void
1410 smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn fn)
1411 {
1412         c->posix_emu.listxattr_fn = fn;
1413 }
1414
1415
1416 /**
1417  * Callable functions related to printing
1418  */
1419
1420 smbc_print_file_fn
1421 smbc_getFunctionPrintFile(SMBCCTX *c)
1422 {
1423         return c->printing.print_file_fn;
1424 }
1425
1426 void
1427 smbc_setFunctionPrintFile(SMBCCTX *c, smbc_print_file_fn fn)
1428 {
1429         c->printing.print_file_fn = fn;
1430 }
1431
1432 smbc_open_print_job_fn
1433 smbc_getFunctionOpenPrintJob(SMBCCTX *c)
1434 {
1435         return c->printing.open_print_job_fn;
1436 }
1437
1438 void
1439 smbc_setFunctionOpenPrintJob(SMBCCTX *c,
1440                              smbc_open_print_job_fn fn)
1441 {
1442         c->printing.open_print_job_fn = fn;
1443 }
1444
1445 smbc_list_print_jobs_fn
1446 smbc_getFunctionListPrintJobs(SMBCCTX *c)
1447 {
1448         return c->printing.list_print_jobs_fn;
1449 }
1450
1451 void
1452 smbc_setFunctionListPrintJobs(SMBCCTX *c,
1453                               smbc_list_print_jobs_fn fn)
1454 {
1455         c->printing.list_print_jobs_fn = fn;
1456 }
1457
1458 smbc_unlink_print_job_fn
1459 smbc_getFunctionUnlinkPrintJob(SMBCCTX *c)
1460 {
1461         return c->printing.unlink_print_job_fn;
1462 }
1463
1464 void
1465 smbc_setFunctionUnlinkPrintJob(SMBCCTX *c,
1466                                smbc_unlink_print_job_fn fn)
1467 {
1468         c->printing.unlink_print_job_fn = fn;
1469 }
1470