NeoMutt  2018-07-16 +952-a2da0a
Teaching an old dog new tricks
DOXYGEN
monitor.c File Reference

Monitor files for changes. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <poll.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/mutt.h"
#include "monitor.h"
#include "context.h"
#include "curs_lib.h"
#include "globals.h"
#include "mailbox.h"
#include "mutt_curses.h"
#include "mx.h"
+ Include dependency graph for monitor.c:

Go to the source code of this file.

Data Structures

struct  Monitor
 A watch on a file. More...
 
struct  MonitorInfo
 Information about a monitored file. More...
 

Macros

#define INOTIFY_MASK_DIR   (IN_MOVED_TO | IN_ATTRIB | IN_CLOSE_WRITE | IN_ISDIR)
 
#define INOTIFY_MASK_FILE   IN_CLOSE_WRITE
 
#define EVENT_BUFLEN   MAX(4096, sizeof(struct inotify_event) + NAME_MAX + 1)
 
#define RESOLVERES_FAIL_NOMAILBOX   -3
 
#define RESOLVERES_FAIL_NOMAGIC   -2
 
#define RESOLVERES_FAIL_STAT   -1
 
#define RESOLVERES_OK_NOTEXISTING   0
 
#define RESOLVERES_OK_EXISTING   1
 

Functions

static void mutt_poll_fd_add (int fd, short events)
 Add a file to the watch list. More...
 
static int mutt_poll_fd_remove (int fd)
 Remove a file from the watch list. More...
 
static int monitor_init (void)
 Set up file monitoring. More...
 
static void monitor_check_free (void)
 Close down file monitoring. More...
 
static struct Monitormonitor_new (struct MonitorInfo *info, int descriptor)
 Create a new file monitor. More...
 
static void monitor_delete (struct Monitor *monitor)
 Free a file monitor. More...
 
static int monitor_handle_ignore (int desc)
 Listen for when a backup file is closed. More...
 
static int monitor_resolve (struct MonitorInfo *info, struct Mailbox *m)
 Get the monitor for a mailbox. More...
 
int mutt_monitor_poll (void)
 Check for filesystem changes. More...
 
int mutt_monitor_add (struct Mailbox *m)
 Add a watch for a mailbox. More...
 
int mutt_monitor_remove (struct Mailbox *m)
 Remove a watch for a mailbox. More...
 

Variables

int MonitorFilesChanged = 0
 true after a monitored file has changed More...
 
int MonitorContextChanged = 0
 true after the current mailbox has changed More...
 
static int INotifyFd = -1
 
static struct MonitorMonitor = NULL
 
static size_t PollFdsCount = 0
 
static size_t PollFdsLen = 0
 
static struct pollfd * PollFds = NULL
 
static int MonitorContextDescriptor = -1
 

Detailed Description

Monitor files for changes.

Authors
  • Gero Treuer

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, see http://www.gnu.org/licenses/.

Definition in file monitor.c.

Macro Definition Documentation

#define INOTIFY_MASK_DIR   (IN_MOVED_TO | IN_ATTRIB | IN_CLOSE_WRITE | IN_ISDIR)

Definition at line 60 of file monitor.c.

#define INOTIFY_MASK_FILE   IN_CLOSE_WRITE

Definition at line 61 of file monitor.c.

#define EVENT_BUFLEN   MAX(4096, sizeof(struct inotify_event) + NAME_MAX + 1)

Definition at line 63 of file monitor.c.

#define RESOLVERES_FAIL_NOMAILBOX   -3

Definition at line 65 of file monitor.c.

#define RESOLVERES_FAIL_NOMAGIC   -2

Definition at line 66 of file monitor.c.

#define RESOLVERES_FAIL_STAT   -1

Definition at line 67 of file monitor.c.

#define RESOLVERES_OK_NOTEXISTING   0

Definition at line 68 of file monitor.c.

#define RESOLVERES_OK_EXISTING   1

Definition at line 69 of file monitor.c.

Function Documentation

static void mutt_poll_fd_add ( int  fd,
short  events 
)
static

Add a file to the watch list.

Parameters
fdFile to watch
eventsEvents to listen for, e.g. POLLIN

Definition at line 103 of file monitor.c.

104 {
105  int i = 0;
106  for (; (i < PollFdsCount) && (PollFds[i].fd != fd); ++i)
107  ;
108 
109  if (i == PollFdsCount)
110  {
111  if (PollFdsCount == PollFdsLen)
112  {
113  PollFdsLen += 2;
114  mutt_mem_realloc(&PollFds, PollFdsLen * sizeof(struct pollfd));
115  }
116  PollFdsCount++;
117  PollFds[i].fd = fd;
118  PollFds[i].events = events;
119  }
120  else
121  PollFds[i].events |= events;
122 }
static size_t PollFdsLen
Definition: monitor.c:55
static struct pollfd * PollFds
Definition: monitor.c:56
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
static size_t PollFdsCount
Definition: monitor.c:54

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int mutt_poll_fd_remove ( int  fd)
static

Remove a file from the watch list.

Parameters
fdFile to remove
Return values
0Success
-1Error

Definition at line 130 of file monitor.c.

131 {
132  int i = 0;
133  for (; (i < PollFdsCount) && (PollFds[i].fd != fd); ++i)
134  ;
135  if (i == PollFdsCount)
136  return -1;
137  int d = PollFdsCount - i - 1;
138  if (d != 0)
139  memmove(&PollFds[i], &PollFds[i + 1], d * sizeof(struct pollfd));
140  PollFdsCount--;
141  return 0;
142 }
static struct pollfd * PollFds
Definition: monitor.c:56
static size_t PollFdsCount
Definition: monitor.c:54

+ Here is the caller graph for this function:

static int monitor_init ( void  )
static

Set up file monitoring.

Return values
0Success
-1Error

Definition at line 149 of file monitor.c.

150 {
151  if (INotifyFd == -1)
152  {
153  INotifyFd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
154  if (INotifyFd == -1)
155  {
156  mutt_debug(2, "inotify_init1 failed, errno=%d %s\n", errno, strerror(errno));
157  return -1;
158  }
159  mutt_poll_fd_add(0, POLLIN);
160  mutt_poll_fd_add(INotifyFd, POLLIN);
161  }
162  return 0;
163 }
static int INotifyFd
Definition: monitor.c:52
static void mutt_poll_fd_add(int fd, short events)
Add a file to the watch list.
Definition: monitor.c:103
#define mutt_debug(LEVEL,...)
Definition: logging.h:85

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void monitor_check_free ( void  )
static

Close down file monitoring.

Definition at line 168 of file monitor.c.

169 {
170  if (!Monitor && (INotifyFd != -1))
171  {
173  close(INotifyFd);
174  INotifyFd = -1;
176  }
177 }
A watch on a file.
Definition: monitor.c:74
static int INotifyFd
Definition: monitor.c:52
int MonitorFilesChanged
true after a monitored file has changed
Definition: monitor.c:49
static int mutt_poll_fd_remove(int fd)
Remove a file from the watch list.
Definition: monitor.c:130

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static struct Monitor* monitor_new ( struct MonitorInfo info,
int  descriptor 
)
static

Create a new file monitor.

Parameters
infoDetails of file to monitor
descriptorWatch descriptor
Return values
ptrNewly allocated Monitor

Definition at line 185 of file monitor.c.

186 {
187  struct Monitor *monitor = mutt_mem_calloc(1, sizeof(struct Monitor));
188  monitor->magic = info->magic;
189  monitor->st_dev = info->st_dev;
190  monitor->st_ino = info->st_ino;
191  monitor->desc = descriptor;
192  monitor->next = Monitor;
193  if (info->magic == MUTT_MH)
194  monitor->mh_backup_path = mutt_str_strdup(info->path);
195 
196  Monitor = monitor;
197 
198  return monitor;
199 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
enum MailboxType magic
Definition: monitor.c:89
ino_t st_ino
Definition: monitor.c:79
int desc
Definition: monitor.c:81
A watch on a file.
Definition: monitor.c:74
struct Monitor * next
Definition: monitor.c:76
char * mh_backup_path
Definition: monitor.c:77
enum MailboxType magic
Definition: monitor.c:80
static struct Monitor * Monitor
Definition: monitor.c:53
dev_t st_dev
Definition: monitor.c:78
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:384
const char * path
Definition: monitor.c:91
&#39;MH&#39; Mailbox type
Definition: magic.h:39
dev_t st_dev
Definition: monitor.c:92
ino_t st_ino
Definition: monitor.c:93

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void monitor_delete ( struct Monitor monitor)
static

Free a file monitor.

Parameters
monitorMonitor to free

Definition at line 205 of file monitor.c.

206 {
207  struct Monitor **ptr = &Monitor;
208 
209  if (!monitor)
210  return;
211 
212  while (true)
213  {
214  if (!*ptr)
215  return;
216  if (*ptr == monitor)
217  break;
218  ptr = &(*ptr)->next;
219  }
220 
221  FREE(&monitor->mh_backup_path);
222  monitor = monitor->next;
223  FREE(ptr);
224  *ptr = monitor;
225 }
A watch on a file.
Definition: monitor.c:74
struct Monitor * next
Definition: monitor.c:76
char * mh_backup_path
Definition: monitor.c:77
static struct Monitor * Monitor
Definition: monitor.c:53
#define FREE(x)
Definition: memory.h:46

+ Here is the caller graph for this function:

static int monitor_handle_ignore ( int  desc)
static

Listen for when a backup file is closed.

Parameters
descWatch descriptor
Return values
>=0New descriptor
-1Error

Definition at line 233 of file monitor.c.

234 {
235  int new_desc = -1;
236  struct Monitor *iter = Monitor;
237  struct stat sb;
238 
239  while (iter && (iter->desc != desc))
240  iter = iter->next;
241 
242  if (iter)
243  {
244  if ((iter->magic == MUTT_MH) && (stat(iter->mh_backup_path, &sb) == 0))
245  {
246  new_desc = inotify_add_watch(INotifyFd, iter->mh_backup_path, INOTIFY_MASK_FILE);
247  if (new_desc == -1)
248  {
249  mutt_debug(2, "inotify_add_watch failed for '%s', errno=%d %s\n",
250  iter->mh_backup_path, errno, strerror(errno));
251  }
252  else
253  {
254  mutt_debug(3, "inotify_add_watch descriptor=%d for '%s'\n", desc, iter->mh_backup_path);
255  iter->st_dev = sb.st_dev;
256  iter->st_ino = sb.st_ino;
257  iter->desc = new_desc;
258  }
259  }
260  else
261  {
262  mutt_debug(3, "cleanup watch (implicitly removed) - descriptor=%d\n", desc);
263  }
264 
265  if (MonitorContextDescriptor == desc)
266  MonitorContextDescriptor = new_desc;
267 
268  if (new_desc == -1)
269  {
270  monitor_delete(iter);
272  }
273  }
274 
275  return new_desc;
276 }
#define INOTIFY_MASK_FILE
Definition: monitor.c:61
ino_t st_ino
Definition: monitor.c:79
int desc
Definition: monitor.c:81
static void monitor_delete(struct Monitor *monitor)
Free a file monitor.
Definition: monitor.c:205
A watch on a file.
Definition: monitor.c:74
struct Monitor * next
Definition: monitor.c:76
static int INotifyFd
Definition: monitor.c:52
char * mh_backup_path
Definition: monitor.c:77
enum MailboxType magic
Definition: monitor.c:80
static struct Monitor * Monitor
Definition: monitor.c:53
dev_t st_dev
Definition: monitor.c:78
&#39;MH&#39; Mailbox type
Definition: magic.h:39
static void monitor_check_free(void)
Close down file monitoring.
Definition: monitor.c:168
static int MonitorContextDescriptor
Definition: monitor.c:58
#define mutt_debug(LEVEL,...)
Definition: logging.h:85

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int monitor_resolve ( struct MonitorInfo info,
struct Mailbox m 
)
static

Get the monitor for a mailbox.

Parameters
[out]infoDetails of the mailbox's monitor
[in]mMailbox
Return values
>=0mailbox is valid and locally accessible: 0: no monitor / 1: preexisting monitor
-3no mailbox (MonitorInfo: no fields set)
-2magic not set
-1stat() failed (see errno; MonitorInfo fields: magic, isdir, path)

If m is NULL, the current mailbox (Context) is used.

Definition at line 290 of file monitor.c.

291 {
292  struct Monitor *iter;
293  char *fmt = NULL;
294  struct stat sb;
295 
296  if (m)
297  {
298  info->magic = m->magic;
299  info->path = m->realpath;
300  }
301  else if (Context)
302  {
303  info->magic = Context->mailbox->magic;
304  info->path = Context->mailbox->realpath;
305  }
306  else
307  {
309  }
310 
311  if (!info->magic)
312  {
314  }
315  else if (info->magic == MUTT_MAILDIR)
316  {
317  info->isdir = 1;
318  fmt = "%s/new";
319  }
320  else
321  {
322  info->isdir = 0;
323  if (info->magic == MUTT_MH)
324  fmt = "%s/.mh_sequences";
325  }
326 
327  if (fmt)
328  {
329  snprintf(info->path_buf, sizeof(info->path_buf), fmt, info->path);
330  info->path = info->path_buf;
331  }
332  if (stat(info->path, &sb) != 0)
333  return RESOLVERES_FAIL_STAT;
334 
335  iter = Monitor;
336  while (iter && ((iter->st_ino != sb.st_ino) || (iter->st_dev != sb.st_dev)))
337  iter = iter->next;
338 
339  info->st_dev = sb.st_dev;
340  info->st_ino = sb.st_ino;
341  info->monitor = iter;
342 
344 }
The "current" mailbox.
Definition: context.h:36
enum MailboxType magic
Definition: monitor.c:89
ino_t st_ino
Definition: monitor.c:79
#define RESOLVERES_OK_EXISTING
Definition: monitor.c:69
&#39;Maildir&#39; Mailbox type
Definition: magic.h:40
short isdir
Definition: monitor.c:90
A watch on a file.
Definition: monitor.c:74
struct Monitor * next
Definition: monitor.c:76
struct Mailbox * mailbox
Definition: context.h:50
enum MailboxType magic
mailbox type
Definition: mailbox.h:99
struct Monitor * monitor
Definition: monitor.c:94
#define RESOLVERES_FAIL_NOMAGIC
Definition: monitor.c:66
char path_buf[PATH_MAX]
Definition: monitor.c:95
static struct Monitor * Monitor
Definition: monitor.c:53
dev_t st_dev
Definition: monitor.c:78
const char * path
Definition: monitor.c:91
&#39;MH&#39; Mailbox type
Definition: magic.h:39
dev_t st_dev
Definition: monitor.c:92
char realpath[PATH_MAX]
used for duplicate detection, context comparison, and the sidebar
Definition: mailbox.h:79
#define RESOLVERES_FAIL_NOMAILBOX
Definition: monitor.c:65
#define RESOLVERES_FAIL_STAT
Definition: monitor.c:67
ino_t st_ino
Definition: monitor.c:93
#define RESOLVERES_OK_NOTEXISTING
Definition: monitor.c:68

+ Here is the caller graph for this function:

int mutt_monitor_poll ( void  )

Check for filesystem changes.

Return values
-3unknown/unexpected events: poll timeout / fds not handled by us
-2monitor detected changes, no STDIN input
-1error (see errno)
0(1) input ready from STDIN, or (2) monitoring inactive -> no poll()

Wait for I/O ready file descriptors or signals.

MonitorFilesChanged also reflects changes to monitored files.

Only STDIN and INotify file handles currently expected/supported. More would ask for common infrastructure (sockets?).

Definition at line 360 of file monitor.c.

361 {
362  int rc = 0;
363  char buf[EVENT_BUFLEN] __attribute__((aligned(__alignof__(struct inotify_event))));
364 
366 
367  if (INotifyFd != -1)
368  {
369  int fds = poll(PollFds, PollFdsLen, MuttGetchTimeout);
370 
371  if (fds == -1)
372  {
373  rc = -1;
374  if (errno != EINTR)
375  {
376  mutt_debug(2, "poll() failed, errno=%d %s\n", errno, strerror(errno));
377  }
378  }
379  else
380  {
381  bool inputReady = false;
382  for (int i = 0; fds && (i < PollFdsCount); ++i)
383  {
384  if (PollFds[i].revents)
385  {
386  fds--;
387  if (PollFds[i].fd == 0)
388  {
389  inputReady = true;
390  }
391  else if (PollFds[i].fd == INotifyFd)
392  {
394  mutt_debug(3, "file change(s) detected\n");
395  char *ptr = buf;
396  const struct inotify_event *event;
397 
398  while (true)
399  {
400  int len = read(INotifyFd, buf, sizeof(buf));
401  if (len == -1)
402  {
403  if (errno != EAGAIN)
404  mutt_debug(2, "read inotify events failed, errno=%d %s\n",
405  errno, strerror(errno));
406  break;
407  }
408 
409  while (ptr < (buf + len))
410  {
411  event = (const struct inotify_event *) ptr;
412  mutt_debug(5, "+ detail: descriptor=%d mask=0x%x\n", event->wd,
413  event->mask);
414  if (event->mask & IN_IGNORED)
415  monitor_handle_ignore(event->wd);
416  else if (event->wd == MonitorContextDescriptor)
418  ptr += sizeof(struct inotify_event) + event->len;
419  }
420  }
421  }
422  }
423  }
424  if (!inputReady)
425  rc = MonitorFilesChanged ? -2 : -3;
426  }
427  }
428 
429  return rc;
430 }
#define EVENT_BUFLEN
Definition: monitor.c:63
static size_t PollFdsLen
Definition: monitor.c:55
static struct pollfd * PollFds
Definition: monitor.c:56
static int INotifyFd
Definition: monitor.c:52
int MonitorFilesChanged
true after a monitored file has changed
Definition: monitor.c:49
int MonitorContextChanged
true after the current mailbox has changed
Definition: monitor.c:50
static int MonitorContextDescriptor
Definition: monitor.c:58
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
static size_t PollFdsCount
Definition: monitor.c:54
int MuttGetchTimeout
Timeout in ms for mutt_getch()
Definition: curs_lib.c:94
static int monitor_handle_ignore(int desc)
Listen for when a backup file is closed.
Definition: monitor.c:233

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_monitor_add ( struct Mailbox m)

Add a watch for a mailbox.

Parameters
mMailbox to watch
Return values
0success: new or already existing monitor
-1failed: no mailbox, inaccessible file, create monitor/watcher failed

If mailbox is NULL, the current mailbox (Context) is used.

Definition at line 440 of file monitor.c.

441 {
442  struct MonitorInfo info;
443 
444  int desc = monitor_resolve(&info, m);
445  if (desc != RESOLVERES_OK_NOTEXISTING)
446  {
447  if (!m && (desc == RESOLVERES_OK_EXISTING))
448  MonitorContextDescriptor = info.monitor->desc;
449  return (desc == RESOLVERES_OK_EXISTING) ? 0 : -1;
450  }
451 
452  uint32_t mask = info.isdir ? INOTIFY_MASK_DIR : INOTIFY_MASK_FILE;
453  if (((INotifyFd == -1) && (monitor_init() == -1)) ||
454  (desc = inotify_add_watch(INotifyFd, info.path, mask)) == -1)
455  {
456  mutt_debug(2, "inotify_add_watch failed for '%s', errno=%d %s\n", info.path,
457  errno, strerror(errno));
458  return -1;
459  }
460 
461  mutt_debug(3, "inotify_add_watch descriptor=%d for '%s'\n", desc, info.path);
462  if (!m)
464 
465  monitor_new(&info, desc);
466  return 0;
467 }
#define INOTIFY_MASK_FILE
Definition: monitor.c:61
Information about a monitored file.
Definition: monitor.c:87
#define RESOLVERES_OK_EXISTING
Definition: monitor.c:69
static int monitor_init(void)
Set up file monitoring.
Definition: monitor.c:149
static int INotifyFd
Definition: monitor.c:52
#define INOTIFY_MASK_DIR
Definition: monitor.c:60
static int monitor_resolve(struct MonitorInfo *info, struct Mailbox *m)
Get the monitor for a mailbox.
Definition: monitor.c:290
static int MonitorContextDescriptor
Definition: monitor.c:58
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
static struct Monitor * monitor_new(struct MonitorInfo *info, int descriptor)
Create a new file monitor.
Definition: monitor.c:185
#define RESOLVERES_OK_NOTEXISTING
Definition: monitor.c:68

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_monitor_remove ( struct Mailbox m)

Remove a watch for a mailbox.

Parameters
mMailbox
Return values
0monitor removed (not shared)
1monitor not removed (shared)
2no monitor

If mailbox is NULL, the current mailbox (Context) is used.

Definition at line 478 of file monitor.c.

479 {
480  struct MonitorInfo info, info2;
481 
482  if (!m)
483  {
486  }
487 
488  if (monitor_resolve(&info, m) != RESOLVERES_OK_EXISTING)
489  return 2;
490 
491  if (Context)
492  {
493  if (m)
494  {
495  if ((monitor_resolve(&info2, NULL) == RESOLVERES_OK_EXISTING) &&
496  (info.st_ino == info2.st_ino) && (info.st_dev == info2.st_dev))
497  {
498  return 1;
499  }
500  }
501  else
502  {
504  return 1;
505  }
506  }
507 
508  inotify_rm_watch(info.monitor->desc, INotifyFd);
509  mutt_debug(3, "inotify_rm_watch for '%s' descriptor=%d\n", info.path,
510  info.monitor->desc);
511 
512  monitor_delete(info.monitor);
514  return 0;
515 }
The "current" mailbox.
Definition: context.h:36
struct Mailbox * mutt_find_mailbox(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:268
Information about a monitored file.
Definition: monitor.c:87
#define RESOLVERES_OK_EXISTING
Definition: monitor.c:69
static void monitor_delete(struct Monitor *monitor)
Free a file monitor.
Definition: monitor.c:205
static int INotifyFd
Definition: monitor.c:52
struct Mailbox * mailbox
Definition: context.h:50
int MonitorContextChanged
true after the current mailbox has changed
Definition: monitor.c:50
static void monitor_check_free(void)
Close down file monitoring.
Definition: monitor.c:168
static int monitor_resolve(struct MonitorInfo *info, struct Mailbox *m)
Get the monitor for a mailbox.
Definition: monitor.c:290
static int MonitorContextDescriptor
Definition: monitor.c:58
char realpath[PATH_MAX]
used for duplicate detection, context comparison, and the sidebar
Definition: mailbox.h:79
#define mutt_debug(LEVEL,...)
Definition: logging.h:85

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

int MonitorFilesChanged = 0

true after a monitored file has changed

Definition at line 49 of file monitor.c.

int MonitorContextChanged = 0

true after the current mailbox has changed

Definition at line 50 of file monitor.c.

int INotifyFd = -1
static

Definition at line 52 of file monitor.c.

struct Monitor* Monitor = NULL
static

Definition at line 53 of file monitor.c.

size_t PollFdsCount = 0
static

Definition at line 54 of file monitor.c.

size_t PollFdsLen = 0
static

Definition at line 55 of file monitor.c.

struct pollfd* PollFds = NULL
static

Definition at line 56 of file monitor.c.

int MonitorContextDescriptor = -1
static

Definition at line 58 of file monitor.c.