GnuCash  5.6-150-g038405b370+
gncAddress.c
1 /********************************************************************\
2  * gncAddress.c -- an Address object *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact: *
16  * *
17  * Free Software Foundation Voice: +1-617-542-5942 *
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19  * Boston, MA 02110-1301, USA gnu@gnu.org *
20  * *
21 \********************************************************************/
22 
23 /*
24  * Copyright (C) 2001 Derek Atkins
25  * Author: Derek Atkins <warlord@MIT.EDU>
26  */
27 
28 #include <config.h>
29 
30 #include <glib.h>
31 #include <qofinstance-p.h>
32 
33 #include "gncAddress.h"
34 #include "gncAddressP.h"
35 #include "gncCustomerP.h"
36 #include "gnc-features.h"
37 
39 {
40  QofInstance inst;
41 
42  QofBook * book;
43  QofInstance * parent;
44  gboolean dirty;
45  const char * name;
46  const char * addr1;
47  const char * addr2;
48  const char * addr3;
49  const char * addr4;
50  const char * phone;
51  const char * fax;
52  const char * email;
53 };
54 
56 {
57  QofInstanceClass parent_class;
58 };
59 
60 static QofLogModule log_module = GNC_MOD_BUSINESS;
61 
62 #define _GNC_MOD_NAME GNC_ADDRESS_MODULE_NAME
63 
64 static inline void mark_address (GncAddress *address);
65 void mark_address (GncAddress *address)
66 {
67  address->dirty = TRUE;
68 
69  if (address->parent)
70  qof_instance_set_dirty(address->parent);
71  qof_event_gen (QOF_INSTANCE(address), QOF_EVENT_MODIFY, address->parent);
72  qof_event_gen (address->parent, QOF_EVENT_MODIFY, NULL);
73 }
74 
75 enum
76 {
77  PROP_0,
78  PROP_NAME,
79  PROP_ADDR1,
80  PROP_ADDR2,
81  PROP_ADDR3,
82  PROP_ADDR4,
83  PROP_PHONE,
84  PROP_FAX,
85  PROP_EMAIL
86 };
87 
88 /* GObject Initialization */
89 G_DEFINE_TYPE(GncAddress, gnc_address, QOF_TYPE_INSTANCE)
90 
91 static void
92 gnc_address_init(GncAddress* addr)
93 {
94 }
95 
96 static void
97 gnc_address_dispose(GObject *addrp)
98 {
99  G_OBJECT_CLASS(gnc_address_parent_class)->dispose(addrp);
100 }
101 
102 static void
103 gnc_address_finalize(GObject* addrp)
104 {
105  G_OBJECT_CLASS(gnc_address_parent_class)->finalize(addrp);
106 }
107 
108 static void
109 gnc_address_get_property (GObject *object,
110  guint prop_id,
111  GValue *value,
112  GParamSpec *pspec)
113 {
114  GncAddress *address;
115 
116  g_return_if_fail(GNC_IS_ADDRESS(object));
117 
118  address = GNC_ADDRESS(object);
119  switch (prop_id)
120  {
121  case PROP_NAME:
122  g_value_set_string(value, address->name);
123  break;
124  case PROP_ADDR1:
125  g_value_set_string(value, address->addr1);
126  break;
127  case PROP_ADDR2:
128  g_value_set_string(value, address->addr2);
129  break;
130  case PROP_ADDR3:
131  g_value_set_string(value, address->addr3);
132  break;
133  case PROP_ADDR4:
134  g_value_set_string(value, address->addr4);
135  break;
136  case PROP_PHONE:
137  g_value_set_string(value, address->phone);
138  break;
139  case PROP_FAX:
140  g_value_set_string(value, address->fax);
141  break;
142  case PROP_EMAIL:
143  g_value_set_string(value, address->email);
144  break;
145  default:
146  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
147  break;
148  }
149 }
150 
151 static void
152 gnc_address_set_property (GObject *object,
153  guint prop_id,
154  const GValue *value,
155  GParamSpec *pspec)
156 {
157  GncAddress *address;
158 
159  g_return_if_fail(GNC_IS_ADDRESS(object));
160 
161  address = GNC_ADDRESS(object);
162  switch (prop_id)
163  {
164  case PROP_NAME:
165  gncAddressSetName(address, g_value_get_string(value));
166  break;
167  case PROP_ADDR1:
168  gncAddressSetAddr1(address, g_value_get_string(value));
169  break;
170  case PROP_ADDR2:
171  gncAddressSetAddr2(address, g_value_get_string(value));
172  break;
173  case PROP_ADDR3:
174  gncAddressSetAddr3(address, g_value_get_string(value));
175  break;
176  case PROP_ADDR4:
177  gncAddressSetAddr4(address, g_value_get_string(value));
178  break;
179  case PROP_PHONE:
180  gncAddressSetPhone(address, g_value_get_string(value));
181  break;
182  case PROP_FAX:
183  gncAddressSetFax(address, g_value_get_string(value));
184  break;
185  case PROP_EMAIL:
186  gncAddressSetEmail(address, g_value_get_string(value));
187  break;
188  default:
189  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
190  break;
191  }
192 }
193 
200 static GList*
201 impl_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
202 {
203  /* Refers to nothing. The parent field doesn't really count since the parent knows which address
204  belongs to it. */
205  return NULL;
206 }
207 
208 static void
209 gnc_address_class_init (GncAddressClass *klass)
210 {
211  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
212  QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
213 
214  gobject_class->dispose = gnc_address_dispose;
215  gobject_class->finalize = gnc_address_finalize;
216  gobject_class->set_property = gnc_address_set_property;
217  gobject_class->get_property = gnc_address_get_property;
218 
219  qof_class->get_display_name = NULL;
220  qof_class->refers_to_object = NULL;
221  qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
222 
223  g_object_class_install_property
224  (gobject_class,
225  PROP_NAME,
226  g_param_spec_string ("name",
227  "Address Name",
228  "The address name is an arbitrary string "
229  "assigned by the user. It is intended to "
230  "a short string to identify the address.",
231  NULL,
232  G_PARAM_READWRITE));
233 
234  g_object_class_install_property
235  (gobject_class,
236  PROP_ADDR1,
237  g_param_spec_string ("addr1",
238  "Address Line 1",
239  "The address line 1 is an arbitrary string "
240  "assigned by the user. It is the first "
241  "line of the address.",
242  NULL,
243  G_PARAM_READWRITE));
244 
245  g_object_class_install_property
246  (gobject_class,
247  PROP_ADDR2,
248  g_param_spec_string ("addr2",
249  "Address Line 2",
250  "The address line 2 is an arbitrary string "
251  "assigned by the user. It is the second "
252  "line of the address.",
253  NULL,
254  G_PARAM_READWRITE));
255 
256  g_object_class_install_property
257  (gobject_class,
258  PROP_ADDR3,
259  g_param_spec_string ("addr3",
260  "Address Line 3",
261  "The address line 3 is an arbitrary string "
262  "assigned by the user. It is the third "
263  "line of the address.",
264  NULL,
265  G_PARAM_READWRITE));
266 
267  g_object_class_install_property
268  (gobject_class,
269  PROP_ADDR4,
270  g_param_spec_string ("addr4",
271  "Address Line 4",
272  "The address line 4 is an arbitrary string "
273  "assigned by the user. It is the fourth "
274  "line of the address.",
275  NULL,
276  G_PARAM_READWRITE));
277 
278  g_object_class_install_property
279  (gobject_class,
280  PROP_PHONE,
281  g_param_spec_string ("phone",
282  "Phone",
283  "The phone number is the number at this address.",
284  NULL,
285  G_PARAM_READWRITE));
286 
287  g_object_class_install_property
288  (gobject_class,
289  PROP_FAX,
290  g_param_spec_string ("fax",
291  "Fax",
292  "The fax number at this address.",
293  NULL,
294  G_PARAM_READWRITE));
295 
296  g_object_class_install_property
297  (gobject_class,
298  PROP_EMAIL,
299  g_param_spec_string ("email",
300  "E-mail address",
301  "The e-mail address at this address.",
302  NULL,
303  G_PARAM_READWRITE));
304 }
305 
306 /* Create/Destroy functions */
307 
308 GncAddress *
309 gncAddressCreate (QofBook *book, QofInstance *prnt)
310 {
311  GncAddress *addr;
312 
313  if (!book) return NULL;
314 
315  addr = g_object_new (GNC_TYPE_ADDRESS, NULL);
316  qof_instance_init_data(&addr->inst, GNC_ID_ADDRESS, book);
317  addr->book = book;
318  addr->dirty = FALSE;
319  addr->parent = prnt;
320 
321  addr->name = CACHE_INSERT ("");
322  addr->addr1 = CACHE_INSERT ("");
323  addr->addr2 = CACHE_INSERT ("");
324  addr->addr3 = CACHE_INSERT ("");
325  addr->addr4 = CACHE_INSERT ("");
326  addr->phone = CACHE_INSERT ("");
327  addr->fax = CACHE_INSERT ("");
328  addr->email = CACHE_INSERT ("");
329 
330  return addr;
331 }
332 
333 static GncAddress *
334 qofAddressCreate (QofBook *book)
335 {
336  /* The address will get set later by another function */
337  return gncAddressCreate(book, NULL);
338 }
339 
340 static void
341 qofAddressSetOwner(GncAddress *addr, QofInstance *ent)
342 {
343  if (!addr || !ent)
344  {
345  return;
346  }
347  if (addr->parent == NULL)
348  {
349  addr->parent = ent;
350  }
351 }
352 
353 static QofInstance*
354 qofAddressGetOwner(const GncAddress *addr)
355 {
356 
357  if (!addr)
358  {
359  return NULL;
360  }
361  return addr->parent;
362 }
363 
364 void
365 gncAddressDestroy (GncAddress *addr)
366 {
367  if (!addr) return;
368  qof_instance_set_destroying(addr, TRUE);
369  gncAddressCommitEdit (addr);
370 }
371 
372 static void
373 gncAddressFree (GncAddress *addr)
374 {
375  if (!addr) return;
376 
377  qof_event_gen (&addr->inst, QOF_EVENT_DESTROY, NULL);
378 
379  CACHE_REMOVE (addr->name);
380  CACHE_REMOVE (addr->addr1);
381  CACHE_REMOVE (addr->addr2);
382  CACHE_REMOVE (addr->addr3);
383  CACHE_REMOVE (addr->addr4);
384  CACHE_REMOVE (addr->phone);
385  CACHE_REMOVE (addr->fax);
386  CACHE_REMOVE (addr->email);
387 
388  /* qof_instance_release (&addr->inst); */
389  g_object_unref (addr);
390 }
391 
392 
393 /* Set functions */
394 
395 #define SET_STR(obj, member, str) { \
396  if (member == str) return; \
397  if (!g_strcmp0 (member, str)) return; \
398  gncAddressBeginEdit (obj); \
399  CACHE_REPLACE(member, str); \
400  }
401 
402 void gncAddressSetName (GncAddress *addr, const char *name)
403 {
404  if (!addr) return;
405  if (!name) return;
406  SET_STR(addr, addr->name, name);
407  mark_address (addr);
408  gncAddressCommitEdit (addr);
409 }
410 
411 void gncAddressSetAddr1 (GncAddress *addr, const char *addr1)
412 {
413  if (!addr) return;
414  if (!addr1) return;
415  SET_STR(addr, addr->addr1, addr1);
416  mark_address (addr);
417  gncAddressCommitEdit (addr);
418 }
419 
420 void gncAddressSetAddr2 (GncAddress *addr, const char *addr2)
421 {
422  if (!addr) return;
423  if (!addr2) return;
424  SET_STR(addr, addr->addr2, addr2);
425  mark_address (addr);
426  gncAddressCommitEdit (addr);
427 }
428 
429 void gncAddressSetAddr3 (GncAddress *addr, const char *addr3)
430 {
431  if (!addr) return;
432  if (!addr3) return;
433  SET_STR(addr, addr->addr3, addr3);
434  mark_address (addr);
435  gncAddressCommitEdit (addr);
436 }
437 
438 void gncAddressSetAddr4 (GncAddress *addr, const char *addr4)
439 {
440  if (!addr) return;
441  if (!addr4) return;
442  SET_STR(addr, addr->addr4, addr4);
443  mark_address (addr);
444  gncAddressCommitEdit (addr);
445 }
446 
447 void gncAddressSetPhone (GncAddress *addr, const char *phone)
448 {
449  if (!addr) return;
450  if (!phone) return;
451  SET_STR(addr, addr->phone, phone);
452  mark_address (addr);
453  gncAddressCommitEdit (addr);
454 }
455 
456 void gncAddressSetFax (GncAddress *addr, const char *fax)
457 {
458  if (!addr) return;
459  if (!fax) return;
460  SET_STR(addr, addr->fax, fax);
461  mark_address (addr);
462  gncAddressCommitEdit (addr);
463 }
464 
465 void gncAddressSetEmail (GncAddress *addr, const char *email)
466 {
467  if (!addr) return;
468  if (!email) return;
469  SET_STR(addr, addr->email, email);
470  mark_address (addr);
471  gncAddressCommitEdit (addr);
472 }
473 
474 void gncAddressBeginEdit (GncAddress *addr)
475 {
476  qof_begin_edit (&addr->inst);
477 }
478 
479 static void gncAddressOnError (QofInstance *inst, QofBackendError errcode)
480 {
481  PERR("Address QofBackend Failure: %d", errcode);
482  gnc_engine_signal_commit_error( errcode );
483 }
484 
485 static void gncAddressOnDone (QofInstance *addr) { }
486 
487 static void address_free (QofInstance *inst)
488 {
489  GncAddress *addr = (GncAddress *) inst;
490  gncAddressFree (addr);
491 }
492 
493 void gncAddressCommitEdit (GncAddress *addr)
494 {
495  /* GnuCash 2.6.3 and earlier didn't handle address kvp's... */
496  if (qof_instance_has_kvp(QOF_INSTANCE(addr)))
497  gnc_features_set_used (qof_instance_get_book (QOF_INSTANCE (addr)), GNC_FEATURE_KVP_EXTRA_DATA);
498 
499  if (!qof_commit_edit (QOF_INSTANCE(addr))) return;
500  qof_commit_edit_part2 (&addr->inst, gncAddressOnError,
501  gncAddressOnDone, address_free);
502 }
503 
504 
505 /* Get Functions */
506 
507 const char * gncAddressGetName (const GncAddress *addr)
508 {
509  if (!addr) return NULL;
510  return addr->name;
511 }
512 
513 const char * gncAddressGetAddr1 (const GncAddress *addr)
514 {
515  if (!addr) return NULL;
516  return addr->addr1;
517 }
518 
519 const char * gncAddressGetAddr2 (const GncAddress *addr)
520 {
521  if (!addr) return NULL;
522  return addr->addr2;
523 }
524 
525 const char * gncAddressGetAddr3 (const GncAddress *addr)
526 {
527  if (!addr) return NULL;
528  return addr->addr3;
529 }
530 
531 const char * gncAddressGetAddr4 (const GncAddress *addr)
532 {
533  if (!addr) return NULL;
534  return addr->addr4;
535 }
536 
537 const char * gncAddressGetPhone (const GncAddress *addr)
538 {
539  if (!addr) return NULL;
540  return addr->phone;
541 }
542 
543 const char * gncAddressGetFax (const GncAddress *addr)
544 {
545  if (!addr) return NULL;
546  return addr->fax;
547 }
548 
549 const char * gncAddressGetEmail (const GncAddress *addr)
550 {
551  if (!addr) return NULL;
552  return addr->email;
553 }
554 
555 gboolean gncAddressIsDirty (const GncAddress *addr)
556 {
557  if (!addr) return FALSE;
558  return addr->dirty;
559 }
560 
561 void gncAddressClearDirty (GncAddress *addr)
562 {
563  if (!addr) return;
564  addr->dirty = FALSE;
565 }
566 
567 int gncAddressCompare (const GncAddress *a, const GncAddress *b)
568 {
569  if (!a && !b) return 0;
570  if (!a && b) return 1;
571  if (a && !b) return -1;
572 
573  return g_strcmp0 (a->name, b->name);
574 }
575 
576 gboolean
578 {
579  if (a == NULL && b == NULL) return TRUE;
580  if (a == NULL || b == NULL) return FALSE;
581 
582  g_return_val_if_fail(GNC_IS_ADDRESS(a), FALSE);
583  g_return_val_if_fail(GNC_IS_ADDRESS(b), FALSE);
584 
585  if (g_strcmp0(a->name, b->name) != 0)
586  {
587  PWARN("names differ: %s vs %s", a->name, b->name);
588  return FALSE;
589  }
590  if (g_strcmp0(a->addr1, b->addr1) != 0)
591  {
592  PWARN("address lines 1 differ: %s vs %s", a->addr1, b->addr1);
593  return FALSE;
594  }
595  if (g_strcmp0(a->addr2, b->addr2) != 0)
596  {
597  PWARN("address lines 2 differ: %s vs %s", a->addr2, b->addr1);
598  return FALSE;
599  }
600  if (g_strcmp0(a->addr3, b->addr3) != 0)
601  {
602  PWARN("address lines 3 differ: %s vs %s", a->addr3, b->addr3);
603  return FALSE;
604  }
605  if (g_strcmp0(a->addr4, b->addr4) != 0)
606  {
607  PWARN("address lines 4 differ: %s vs %s", a->addr4, b->addr4);
608  return FALSE;
609  }
610  if (g_strcmp0(a->phone, b->phone) != 0)
611  {
612  PWARN("phone numbers differ: %s vs %s", a->phone, b->phone);
613  return FALSE;
614  }
615  if (g_strcmp0(a->fax, b->fax) != 0)
616  {
617  PWARN("fax numbers differ: %s vs %s", a->fax, b->fax);
618  return FALSE;
619  }
620  if (g_strcmp0(a->email, b->email) != 0)
621  {
622  PWARN("email addresses differ: %s vs %s", a->email, b->email);
623  return FALSE;
624  }
625 
626  return TRUE;
627 }
628 
629 static QofObject GncAddressDesc =
630 {
631  DI(.interface_version = ) QOF_OBJECT_VERSION,
632  DI(.e_type = ) GNC_ID_ADDRESS,
633  DI(.type_label = ) "Address",
634  DI(.create = ) (gpointer)qofAddressCreate,
635  DI(.book_begin = ) NULL,
636  DI(.book_end = ) NULL,
637  DI(.is_dirty = ) qof_collection_is_dirty,
638  DI(.mark_clean = ) qof_collection_mark_clean,
639  DI(.foreach = ) qof_collection_foreach,
640  DI(.printable = ) NULL,
641  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
642 };
643 
644 gboolean gncAddressRegister (void)
645 {
646  static QofParam params[] =
647  {
648 
649  { ADDRESS_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncAddressGetName, (QofSetterFunc)gncAddressSetName },
650  { ADDRESS_ONE, QOF_TYPE_STRING, (QofAccessFunc)gncAddressGetAddr1, (QofSetterFunc)gncAddressSetAddr1 },
651  { ADDRESS_TWO, QOF_TYPE_STRING, (QofAccessFunc)gncAddressGetAddr2, (QofSetterFunc)gncAddressSetAddr2 },
652  { ADDRESS_THREE, QOF_TYPE_STRING, (QofAccessFunc)gncAddressGetAddr3, (QofSetterFunc)gncAddressSetAddr3 },
653  { ADDRESS_FOUR, QOF_TYPE_STRING, (QofAccessFunc)gncAddressGetAddr4, (QofSetterFunc)gncAddressSetAddr4 },
654  { ADDRESS_PHONE, QOF_TYPE_STRING, (QofAccessFunc)gncAddressGetPhone, (QofSetterFunc)gncAddressSetPhone },
655  { ADDRESS_FAX, QOF_TYPE_STRING, (QofAccessFunc)gncAddressGetFax, (QofSetterFunc)gncAddressSetFax },
656  { ADDRESS_EMAIL, QOF_TYPE_STRING, (QofAccessFunc)gncAddressGetEmail, (QofSetterFunc)gncAddressSetEmail },
657  { ADDRESS_OWNER, QOF_TYPE_CHOICE, (QofAccessFunc)qofAddressGetOwner, (QofSetterFunc)qofAddressSetOwner },
658  { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
659  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
660  { NULL },
661  };
662 
663  qof_class_register (GNC_ID_ADDRESS, (QofSortFunc)gncAddressCompare, params);
664 
665  return qof_object_register(&GncAddressDesc);
666 }
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:255
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
Definition: qofclass.cpp:86
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:223
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:63
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:108
int gncAddressCompare(const GncAddress *a, const GncAddress *b)
compare two addresses
Definition: gncAddress.c:567
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:185
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:178
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:261
gboolean gncAddressEqual(const GncAddress *a, const GncAddress *b)
Deeply compare two addresses.
Definition: gncAddress.c:577
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:299
gboolean qof_instance_has_kvp(QofInstance *inst)
Report whether a QofInstance has anything stored in KVP.
an Address object
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
Utility functions for file access.