2
* pilot-memos.c: Translate Palm Memos into e-mail format
4
* Copyright (c) 1996, Kenneth Albanowski
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License as published by the
8
* Free Software Foundation; either version 2 of the License, or (at your
9
* option) any later version.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14
* Public License for more details.
16
* You should have received a copy of the GNU General Public License along
17
* with this program; if not, write to the Free Software Foundation, Inc.,
18
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
#include "pi-header.h"
29
#include "pi-userland.h"
31
/* constants to determine how to produce memos */
32
#define MEMO_MBOX_STDOUT 0
33
#define MEMO_DIRECTORY 1
34
#define MAXDIRNAMELEN 1024
36
void write_memo_mbox(struct Memo m, struct MemoAppInfo mai, int category);
37
void write_memo_in_directory(char *dirname, struct Memo m,
38
struct MemoAppInfo mai, int category,
39
int verbose, const char *progname);
41
/***********************************************************************
43
* Function: write_memo_mbox
45
* Summary: Write a memo entry to MailDB database
51
***********************************************************************/
52
void write_memo_mbox(struct Memo m, struct MemoAppInfo mai, int category)
60
/* FIXME: might be good to get the time stamp of the memo file for
61
the "Received" line */
63
time_str = ctime(&now);
65
printf("From Palm.Handheld %s"
66
"From: pilot-link memos (MemoDB) <Palm.Handheld@your.machine>\n"
70
"Subject: ", time_str, time_str, time_str);
72
/* print category name in brackets in subject field */
73
printf("[%s] ", mai.category.name[category]);
75
/* print (at least part of) first line as part of subject: */
76
for (j = 0; j < 40; j++) {
77
if ((!m.text[j]) || (m.text[j] == '\n'))
79
printf("%c", m.text[j]);
89
/***********************************************************************
91
* Function: write_memo_in_directory
93
* Summary: Writes each memo into /$DIR/$CATEGORY/$FILENAME form
94
* after the user specifies the -d /dir/name argument
100
***********************************************************************/
102
write_memo_in_directory(char *dirname, struct Memo m,
103
struct MemoAppInfo mai, int category, int verbose, const char *progname)
106
char pathbuffer[MAXDIRNAMELEN] = "",
110
/* Should check if dirname exists and is a directory */
111
mkdir(dirname, 0700);
113
/* Create a directory for the category */
114
strncat(pathbuffer, dirname, MAXDIRNAMELEN);
115
strncat(pathbuffer, "/", 1);
117
/* Should make sure category doesn't have slashes in it */
118
strncat(pathbuffer, mai.category.name[category], 60);
120
/* Should check if pathbuffer exists and is a directory */
121
mkdir(pathbuffer, 0700);
123
/* Should check if there were problems creating directory */
124
/* open the actual file to write */
125
strncat(pathbuffer, "/", 1);
126
for (j = 0; j < 40; j++) {
127
if ((!m.text[j]) || (m.text[j] == '\n'))
129
if (m.text[j] == '/') {
130
strncat(pathbuffer, "=2F", 3);
133
if (m.text[j] == '=') {
134
strncat(pathbuffer, "=3D", 3);
138
if (m.text[j] == ':') {
139
strncat(pathbuffer, "=3A", 3);
143
/* escape if it's an ISO8859 control chcter (note: some
144
are printable on the Palm) */
145
if ((m.text[j] | 0x7f) < ' ') {
147
sprintf(tmp, "=%2X", (unsigned char) m.text[j]);
152
strcat(pathbuffer, tmp);
156
printf("Writing %s\n", pathbuffer);
159
if (!(fd = fopen(pathbuffer, "w"))) {
160
printf("%s: can't open file \"%s\" for writing\n",
161
progname, pathbuffer);
169
int main(int argc, const char *argv[])
180
mode = MEMO_MBOX_STDOUT,
195
*category_name = NULL,
200
struct MemoAppInfo mai;
201
struct pi_file *pif = NULL;
204
regex_t title_pattern;
209
struct poptOption options[] = {
210
USERLAND_RESERVED_OPTIONS
211
{"verbose", 'v', POPT_ARG_VAL, &verbose, 1, "Verbose, with -s, print each filename when written", NULL},
212
{"delete", 'd', POPT_ARG_VAL, &delete, 1, "Delete memo named by number <num>", "<num>"},
213
{"file", 'f', POPT_ARG_STRING, &filename, 0, "Use <file> as input file (instead of MemoDB.pdb)", "<file>"},
214
{"save", 's', POPT_ARG_STRING, &dirname, 0, "Save memos in <dir> instead of writing to STDOUT", "<dir>"},
215
{"category", 'c', POPT_ARG_STRING, &category_name, 0, "Only upload memos in this category", "<category>"},
216
{"regex", 'r', POPT_ARG_STRING, ®ex, 0, "Select memos saved by regular expression on title", "<regex>"},
221
po = poptGetContext("memos", argc, argv, options, 0);
223
poptSetOtherOptionHelp(po,"\n\n"
224
" Manipulate Memo entries from a file or your Palm device\n\n"
225
" By default, the contents of your Palm's memo database will be written to\n"
226
" standard output as a standard UNIX mailbox (mbox-format) file, with each\n"
227
" memo as a separate message. The subject of each message will be the\n"
230
" If '-s' is specified, than instead of being written to standard output,\n"
231
" will be saved in subdirectories of <dir>. Each subdirectory will be the\n"
232
" name of a category on the Palm, and will contain the memos in that\n"
233
" category. Each memo's filename will be the first line (up to the first 40\n"
234
" characters) of the memo. Control chcters, slashes, and equal signs that\n"
235
" would otherwise appear in filenames are converted after the fashion of\n"
236
" MIME's quoted-printable encoding. Note that if you have two memos in the\n"
237
" same category whose first lines are identical, one of them will be\n"
240
" If '-f' is specified, the specified file will be treated as a memo\n"
241
" database from which to read memos, rather than HotSyncing from the Palm.\n");
244
poptPrintUsage(po,stderr,0);
248
while ((c = poptGetNextOpt(po)) >= 0) {
249
fprintf(stderr," ERROR: Unhandled option %d.\n",c);
254
mode = MEMO_DIRECTORY;
257
plu_badoption(po, c);
260
ret = regcomp(&title_pattern, regex, REG_NOSUB);
261
buf = (char *) malloc(bufsize);
263
regerror(ret, &title_pattern, buf, bufsize);
264
fprintf(stderr," ERROR: Regexp - %s\n", buf);
270
/* FIXME - Need to add tests here for port/filename, clean this. -DD */
271
appblock = pi_buffer_new(0xffff);
279
if (dlp_OpenConduit(sd) < 0)
282
/* Open the Memo Pad's database, store access handle in db */
283
if (dlp_OpenDB(sd, 0, 0x80 | 0x40, "MemoDB", &db) < 0) {
284
fprintf(stderr," ERROR: Unable to open MemoDB on Palm.\n");
285
dlp_AddSyncLogEntry(sd,
286
"Unable to open MemoDB.\n");
290
dlp_ReadAppBlock(sd, db, 0, 0xffff, appblock);
292
pif = pi_file_open(filename);
294
fprintf(stderr," ERROR: pi_file_open: %s\n",strerror(errno));
298
pi_file_get_app_info(pif, (void **) &ptr, &len);
299
pi_buffer_append(appblock, ptr, len);
302
unpack_MemoAppInfo(&mai, appblock->data, appblock->used);
303
pi_buffer_free(appblock);
305
if (category_name && category_name[0] != '\0') {
306
match_category = plu_findcategory(&mai.category,category_name, PLU_CAT_WARN_UNKNOWN);
307
if (match_category < 0) {
312
buffer = pi_buffer_new (0xffff);
314
for (idx = 0;; idx++) {
317
if (match_category >= 0) {
318
ret = dlp_ReadNextRecInCategory(sd, db,
322
category = match_category;
324
ret = dlp_ReadRecordByIndex(sd, db, idx,
334
if (pi_file_read_record
335
(pif, idx, (void **) &ptr, &len, &attr, &category,
338
memcpy(buffer->data, ptr, len);
342
/* Skip deleted records */
343
if ((attr & dlpRecAttrDeleted)
344
|| (attr & dlpRecAttrArchived))
347
/* Skip memos whose category doesn't match */
348
if( match_category >= 0 ) {
349
if( match_category != category )
353
unpack_Memo(&m, buffer, memo_v1);
355
/* Skip memos whose title does not match with the query */
356
if (title_matching) {
357
for (len = 0; m.text[len] && m.text[len] != '\n';
359
if (bufsize < len + 1)
360
buf = (char *) realloc(buf, len + 1);
361
strncpy(buf, m.text, len);
363
if (regexec(&title_pattern, buf, 0, NULL, 0) ==
369
case MEMO_MBOX_STDOUT:
370
write_memo_mbox(m, mai, category);
373
write_memo_in_directory(dirname, m, mai,
374
category, verbose, progname);
379
pi_buffer_free (buffer);
381
if (delete && !filename) {
383
printf("Deleting record %d.\n", (int) id);
384
dlp_DeleteRecord(sd, db, 0, id);
387
if (title_matching) {
388
regfree(&title_pattern);
393
/* Close the database */
395
dlp_AddSyncLogEntry(sd, "Successfully read memos from Palm.\n"
396
"Thank you for using pilot-link.\n");