Common/Source/CFGrowlAdditions.c
author Rudy Richter
Wed Jun 24 23:01:22 2009 -0400 (2009-06-24)
changeset 4229 7293e4e2f375
parent 4095 7f5387ba611d
child 4246 4f52d1d98978
permissions -rw-r--r--
fixes bug #385044
boredzo@1478
     1
//
boredzo@1478
     2
//  CFGrowlAdditions.c
boredzo@1478
     3
//  Growl
boredzo@1478
     4
//
boredzo@1478
     5
//  Created by Mac-arena the Bored Zo on Wed Jun 18 2004.
ingmarstein@3040
     6
//  Copyright 2005-2006 The Growl Project.
boredzo@1478
     7
//
ingmarstein@2290
     8
// This file is under the BSD License, refer to License.txt for details
boredzo@1478
     9
boredzo@1478
    10
#include <Carbon/Carbon.h>
boredzo@2020
    11
#include <unistd.h>
ingmarstein@2634
    12
#include <netinet/in.h>
ingmarstein@2634
    13
#include <arpa/inet.h>
ingmarstein@2634
    14
#include <netdb.h>
ingmarstein@2602
    15
#include "CFGrowlAdditions.h"
boredzo@1478
    16
ingmarstein@3184
    17
#ifndef MIN
ingmarstein@3184
    18
# define MIN(a,b) ((a) < (b) ? (a) : (b))
ingmarstein@3184
    19
#endif
ingmarstein@3184
    20
rudy@2946
    21
extern Boolean CFStringGetFileSystemRepresentation() __attribute__((weak_import));
evands@3712
    22
extern CFIndex CFStringGetMaximumSizeOfFileSystemRepresentation(CFStringRef string) __attribute__((weak_import));
rudy@2946
    23
ingmarstein@2602
    24
char *createFileSystemRepresentationOfString(CFStringRef str) {
ingmarstein@2602
    25
	char *buffer;
evands@3721
    26
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
evands@3721
    27
	/* CFStringGetFileSystemRepresentation will cause a link error despite the weak_import attribute above on 10.5 when compiling with 10.2 compatibility using gcc 3.3.
evands@3721
    28
	 * PPC will therefore always use the 10.3 and below method of creating a file system representation.
evands@3721
    29
	 */
ingmarstein@2602
    30
	if (CFStringGetFileSystemRepresentation) {
ingmarstein@2602
    31
		CFIndex size = CFStringGetMaximumSizeOfFileSystemRepresentation(str);
ingmarstein@2602
    32
		buffer = malloc(size);
ingmarstein@2602
    33
		CFStringGetFileSystemRepresentation(str, buffer, size);
evands@3721
    34
	} else 
evands@3721
    35
#endif
evands@3721
    36
	{
ingmarstein@2641
    37
		buffer = malloc(512);
ingmarstein@2641
    38
		CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, str, kCFURLPOSIXPathStyle, false);
ingmarstein@2641
    39
		if (!CFURLGetFileSystemRepresentation(url, false, (UInt8 *)buffer, 512)) {
ingmarstein@2641
    40
			free(buffer);
ingmarstein@2641
    41
			buffer = NULL;
ingmarstein@2641
    42
		}
ingmarstein@2641
    43
		CFRelease(url);
ingmarstein@2602
    44
	}
ingmarstein@2602
    45
	return buffer;
ingmarstein@2602
    46
}
ingmarstein@2602
    47
evands@3429
    48
STRING_TYPE createStringWithDate(CFDateRef date) {
ingmarstein@2602
    49
	CFLocaleRef locale = CFLocaleCopyCurrent();
ingmarstein@2602
    50
	CFDateFormatterRef dateFormatter = CFDateFormatterCreate(kCFAllocatorDefault,
ingmarstein@2602
    51
															 locale,
ingmarstein@2602
    52
															 kCFDateFormatterMediumStyle,
ingmarstein@2602
    53
															 kCFDateFormatterMediumStyle);
ingmarstein@2602
    54
	CFRelease(locale);
ingmarstein@2602
    55
	CFStringRef dateString = CFDateFormatterCreateStringWithDate(kCFAllocatorDefault,
ingmarstein@2602
    56
																 dateFormatter,
ingmarstein@2602
    57
																 date);
ingmarstein@2602
    58
	CFRelease(dateFormatter);
ingmarstein@2602
    59
	return dateString;
ingmarstein@2602
    60
}
boredzo@1478
    61
evands@3429
    62
STRING_TYPE createStringWithContentsOfFile(CFStringRef filename, CFStringEncoding encoding) {
ingmarstein@2652
    63
	CFStringRef str = NULL;
ingmarstein@2652
    64
ingmarstein@2652
    65
	char *path = createFileSystemRepresentationOfString(filename);
ingmarstein@2652
    66
	if (path) {
ingmarstein@2652
    67
		FILE *fp = fopen(path, "rb");
ingmarstein@2652
    68
		if (fp) {
ingmarstein@2652
    69
			fseek(fp, 0, SEEK_END);
ingmarstein@2652
    70
			unsigned long size = ftell(fp);
ingmarstein@2652
    71
			fseek(fp, 0, SEEK_SET);
ingmarstein@2652
    72
			unsigned char *buffer = malloc(size);
ingmarstein@2652
    73
			if (buffer && fread(buffer, 1, size, fp) == size)
ingmarstein@2652
    74
				str = CFStringCreateWithBytes(kCFAllocatorDefault, buffer, size, encoding, true);
ingmarstein@2652
    75
			fclose(fp);
ingmarstein@2652
    76
		}
ingmarstein@2652
    77
		free(path);
ingmarstein@2652
    78
	}
ingmarstein@2652
    79
ingmarstein@2652
    80
	return str;
ingmarstein@2652
    81
}
ingmarstein@2652
    82
evands@3429
    83
STRING_TYPE createStringWithStringAndCharacterAndString(STRING_TYPE str0, UniChar ch, STRING_TYPE str1) {
ingmarstein@2632
    84
	CFStringRef cfstr0 = (CFStringRef)str0;
ingmarstein@2632
    85
	CFStringRef cfstr1 = (CFStringRef)str1;
ingmarstein@2632
    86
	CFIndex len0 = (cfstr0 ? CFStringGetLength(cfstr0) : 0);
ingmarstein@2632
    87
	CFIndex len1 = (cfstr1 ? CFStringGetLength(cfstr1) : 0);
ingmarstein@2632
    88
	unsigned length = (len0 + (ch != 0xffff) + len1);
ingmarstein@2632
    89
ingmarstein@2632
    90
	UniChar *buf = malloc(sizeof(UniChar) * length);
ingmarstein@2632
    91
	unsigned i = 0U;
ingmarstein@2632
    92
ingmarstein@2632
    93
	if (cfstr0) {
ingmarstein@2632
    94
		CFStringGetCharacters(cfstr0, CFRangeMake(0, len0), buf);
ingmarstein@2632
    95
		i += len0;
ingmarstein@2632
    96
	}
ingmarstein@2632
    97
	if (ch != 0xffff)
ingmarstein@2632
    98
		buf[i++] = ch;
ingmarstein@2632
    99
	if (cfstr1)
ingmarstein@2632
   100
		CFStringGetCharacters(cfstr1, CFRangeMake(0, len1), &buf[i]);
ingmarstein@2632
   101
ingmarstein@2632
   102
	return CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buf, length, /*contentsDeallocator*/ kCFAllocatorMalloc);
ingmarstein@2632
   103
}
ingmarstein@2632
   104
ingmarstein@2598
   105
char *copyCString(STRING_TYPE str, CFStringEncoding encoding) {
ingmarstein@2598
   106
	CFIndex size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), encoding) + 1;
ingmarstein@2601
   107
	char *buffer = calloc(size, 1);
ingmarstein@2598
   108
	CFStringGetCString(str, buffer, size, encoding);
ingmarstein@2598
   109
	return buffer;
ingmarstein@2598
   110
}
ingmarstein@2598
   111
evands@3429
   112
STRING_TYPE copyCurrentProcessName(void) {
boredzo@1478
   113
	ProcessSerialNumber PSN = { 0, kCurrentProcess };
boredzo@1478
   114
	CFStringRef name = NULL;
boredzo@1478
   115
	OSStatus err = CopyProcessName(&PSN, &name);
boredzo@1478
   116
	if (err != noErr) {
boredzo@1773
   117
		NSLog(CFSTR("in copyCurrentProcessName in CFGrowlAdditions: Could not get process name because CopyProcessName returned %li"), (long)err);
boredzo@1478
   118
		name = NULL;
boredzo@1478
   119
	}
boredzo@1478
   120
	return name;
boredzo@1478
   121
}
boredzo@1478
   122
evands@3429
   123
URL_TYPE copyCurrentProcessURL(void) {
boredzo@1478
   124
	ProcessSerialNumber psn = { 0, kCurrentProcess };
boredzo@1478
   125
	FSRef fsref;
boredzo@1478
   126
	CFURLRef URL = NULL;
boredzo@1478
   127
	OSStatus err = GetProcessBundleLocation(&psn, &fsref);
ingmarstein@1518
   128
	if (err != noErr) {
boredzo@1773
   129
		NSLog(CFSTR("in copyCurrentProcessURL in CFGrowlAdditions: Could not get application location, because GetProcessBundleLocation returned %li\n"), (long)err);
ingmarstein@1518
   130
	} else {
boredzo@1478
   131
		URL = CFURLCreateFromFSRef(kCFAllocatorDefault, &fsref);
ingmarstein@1518
   132
	}
boredzo@1478
   133
	return URL;
boredzo@1478
   134
}
evands@3429
   135
STRING_TYPE copyCurrentProcessPath(void) {
boredzo@1773
   136
	CFURLRef URL = copyCurrentProcessURL();
boredzo@1478
   137
	CFStringRef path = CFURLCopyFileSystemPath(URL, kCFURLPOSIXPathStyle);
boredzo@1478
   138
	CFRelease(URL);
boredzo@1478
   139
	return path;
boredzo@1478
   140
}
boredzo@1478
   141
evands@3429
   142
URL_TYPE copyTemporaryFolderURL(void) {
boredzo@2020
   143
	FSRef ref;
boredzo@2020
   144
	CFURLRef url = NULL;
boredzo@2020
   145
boredzo@2020
   146
	OSStatus err = FSFindFolder(kOnAppropriateDisk, kTemporaryFolderType, kCreateFolder, &ref);
boredzo@2020
   147
	if (err != noErr)
boredzo@2020
   148
		NSLog(CFSTR("in copyTemporaryFolderPath in CFGrowlAdditions: Could not locate temporary folder because FSFindFolder returned %li"), (long)err);
boredzo@2020
   149
	else
boredzo@2020
   150
		url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref);
boredzo@2020
   151
boredzo@2020
   152
	return url;
boredzo@2020
   153
}
evands@3429
   154
STRING_TYPE copyTemporaryFolderPath(void) {
boredzo@2020
   155
	CFStringRef path = NULL;
boredzo@2020
   156
boredzo@2020
   157
	CFURLRef url = copyTemporaryFolderURL();
ingmarstein@2041
   158
	if (url) {
boredzo@2020
   159
		path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
boredzo@1478
   160
		CFRelease(url);
boredzo@1478
   161
	}
boredzo@2020
   162
boredzo@2020
   163
	return path;
boredzo@1478
   164
}
boredzo@1478
   165
evands@3429
   166
DATA_TYPE readFile(const char *filename)
ingmarstein@3141
   167
{
ingmarstein@3141
   168
	CFDataRef data;
ingmarstein@3141
   169
	// read the file into a CFDataRef
ingmarstein@3141
   170
	FILE *fp = fopen(filename, "r");
ingmarstein@3141
   171
	if (fp) {
ingmarstein@3141
   172
		fseek(fp, 0, SEEK_END);
ingmarstein@3141
   173
		long dataLength = ftell(fp);
ingmarstein@3141
   174
		fseek(fp, 0, SEEK_SET);
ingmarstein@3141
   175
		unsigned char *fileData = malloc(dataLength);
ingmarstein@3141
   176
		fread(fileData, 1, dataLength, fp);
ingmarstein@3141
   177
		fclose(fp);
ingmarstein@3141
   178
		data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, fileData, dataLength, kCFAllocatorMalloc);
ingmarstein@3141
   179
	} else
ingmarstein@3141
   180
		data = NULL;
ingmarstein@3141
   181
ingmarstein@3141
   182
	return data;
ingmarstein@3141
   183
}
ingmarstein@3141
   184
boredzo@4095
   185
URL_TYPE copyURLForApplication(STRING_TYPE appName)
boredzo@4095
   186
{
boredzo@4095
   187
	CFURLRef appURL = NULL;
boredzo@4095
   188
	OSStatus err = LSFindApplicationForInfo(/*inCreator*/  kLSUnknownCreator,
boredzo@4095
   189
											/*inBundleID*/ NULL,
boredzo@4095
   190
											/*inName*/     appName,
boredzo@4095
   191
											/*outAppRef*/  NULL,
boredzo@4095
   192
											/*outAppURL*/  &appURL);
boredzo@4095
   193
	return (err == noErr) ? appURL : NULL;
boredzo@4095
   194
}
boredzo@4095
   195
evands@3429
   196
STRING_TYPE createStringWithAddressData(DATA_TYPE aAddressData) {
ingmarstein@2634
   197
	struct sockaddr *socketAddress = (struct sockaddr *)CFDataGetBytePtr(aAddressData);
ingmarstein@2634
   198
	// IPv6 Addresses are "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
ingmarstein@2634
   199
	//      at max, which is 40 bytes (0-terminated)
ingmarstein@2634
   200
	// IPv4 Addresses are "255.255.255.255" at max which is smaller
ingmarstein@2634
   201
	char stringBuffer[40];
ingmarstein@2634
   202
	CFStringRef addressAsString = NULL;
ingmarstein@2634
   203
	if (socketAddress->sa_family == AF_INET) {
ingmarstein@2634
   204
		struct sockaddr_in *ipv4 = (struct sockaddr_in *)socketAddress;
ingmarstein@2634
   205
		if (inet_ntop(AF_INET, &(ipv4->sin_addr), stringBuffer, 40))
ingmarstein@2634
   206
			addressAsString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s:%d"), stringBuffer, ipv4->sin_port);
ingmarstein@2634
   207
		else
ingmarstein@2634
   208
			addressAsString = CFSTR("IPv4 un-ntopable");
ingmarstein@2634
   209
	} else if (socketAddress->sa_family == AF_INET6) {
ingmarstein@2634
   210
		struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)socketAddress;
ingmarstein@2634
   211
		if (inet_ntop(AF_INET6, &(ipv6->sin6_addr), stringBuffer, 40))
ingmarstein@2634
   212
			// Suggested IPv6 format (see http://www.faqs.org/rfcs/rfc2732.html)
ingmarstein@2634
   213
			addressAsString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("[%s]:%d"), stringBuffer, ipv6->sin6_port);
ingmarstein@2634
   214
		else
ingmarstein@2634
   215
			addressAsString = CFSTR("IPv6 un-ntopable");
ingmarstein@2634
   216
	} else
ingmarstein@2634
   217
		addressAsString = CFSTR("neither IPv6 nor IPv4");
ingmarstein@2634
   218
ingmarstein@2634
   219
	return addressAsString;
ingmarstein@2634
   220
}
ingmarstein@2634
   221
evands@3429
   222
STRING_TYPE createHostNameForAddressData(DATA_TYPE aAddressData) {
ingmarstein@2634
   223
	char hostname[NI_MAXHOST];
ingmarstein@2634
   224
	struct sockaddr *socketAddress = (struct sockaddr *)CFDataGetBytePtr(aAddressData);
ingmarstein@2634
   225
	if (getnameinfo(socketAddress, CFDataGetLength(aAddressData),
ingmarstein@2634
   226
					hostname, sizeof(hostname),
ingmarstein@2634
   227
					/*serv*/ NULL, /*servlen*/ 0,
ingmarstein@2634
   228
					NI_NAMEREQD))
ingmarstein@2634
   229
		return NULL;
ingmarstein@2634
   230
	else
ingmarstein@2634
   231
		return CFStringCreateWithCString(kCFAllocatorDefault, hostname, kCFStringEncodingASCII);
ingmarstein@2634
   232
}
ingmarstein@2634
   233
evands@3429
   234
DATA_TYPE copyIconDataForPath(STRING_TYPE path) {
boredzo@1773
   235
	CFDataRef data = NULL;
boredzo@1773
   236
boredzo@1773
   237
	//false is probably safest, and is harmless when the object really is a directory.
boredzo@1773
   238
	CFURLRef URL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, /*isDirectory*/ false);
ingmarstein@1777
   239
	if (URL) {
boredzo@1773
   240
		data = copyIconDataForURL(URL);
boredzo@1773
   241
		CFRelease(URL);
boredzo@1773
   242
	}
boredzo@1773
   243
boredzo@1773
   244
	return data;
boredzo@1773
   245
}
evands@3429
   246
evands@3429
   247
DATA_TYPE copyIconDataForURL(URL_TYPE URL)
evands@3429
   248
{
boredzo@1773
   249
	CFDataRef data = NULL;
boredzo@1773
   250
ingmarstein@1777
   251
	if (URL) {
boredzo@1773
   252
		FSRef ref;
ingmarstein@1777
   253
		if (CFURLGetFSRef(URL, &ref)) {
boredzo@1773
   254
			IconRef icon = NULL;
boredzo@1773
   255
			SInt16 label_noOneCares;
boredzo@1773
   256
			OSStatus err = GetIconRefFromFileInfo(&ref,
boredzo@1773
   257
												  /*inFileNameLength*/ 0U, /*inFileName*/ NULL,
boredzo@1773
   258
												  kFSCatInfoNone, /*inCatalogInfo*/ NULL,
boredzo@1773
   259
												  kIconServicesNoBadgeFlag | kIconServicesUpdateIfNeededFlag,
boredzo@1773
   260
												  &icon,
boredzo@1773
   261
												  &label_noOneCares);
ingmarstein@1777
   262
			if (err != noErr) {
boredzo@1773
   263
				NSLog(CFSTR("in copyIconDataForURL in CFGrowlAdditions: could not get icon for %@: GetIconRefFromFileInfo returned %li\n"), URL, (long)err);
boredzo@1773
   264
			} else {
boredzo@1773
   265
				IconFamilyHandle fam = NULL;
boredzo@1773
   266
				err = IconRefToIconFamily(icon, kSelectorAllAvailableData, &fam);
ingmarstein@1777
   267
				if (err != noErr) {
boredzo@1773
   268
					NSLog(CFSTR("in copyIconDataForURL in CFGrowlAdditions: could not get icon for %@: IconRefToIconFamily returned %li\n"), URL, (long)err);
boredzo@1773
   269
				} else {
boredzo@1773
   270
					HLock((Handle)fam);
ingmarstein@1777
   271
					data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)*(Handle)fam, GetHandleSize((Handle)fam));
boredzo@1773
   272
					HUnlock((Handle)fam);
boredzo@1773
   273
					DisposeHandle((Handle)fam);
boredzo@1773
   274
				}
boredzo@1773
   275
				ReleaseIconRef(icon);
boredzo@1773
   276
			}
boredzo@1773
   277
		}
boredzo@1773
   278
	}
boredzo@1773
   279
boredzo@1773
   280
	return data;
boredzo@1773
   281
}
boredzo@2020
   282
evands@3429
   283
URL_TYPE createURLByMakingDirectoryAtURLWithName(URL_TYPE parent, STRING_TYPE name)
evands@3429
   284
{
boredzo@2020
   285
	CFURLRef newDirectory = NULL;
boredzo@2020
   286
boredzo@2020
   287
	CFAllocatorRef allocator = parent ? CFGetAllocator(parent) : name ? CFGetAllocator(name) : kCFAllocatorDefault;
boredzo@2020
   288
ingmarstein@2041
   289
	if (parent) parent = CFRetain(parent);
boredzo@2020
   290
	else {
boredzo@2020
   291
		char *cwdBytes = alloca(PATH_MAX);
boredzo@2020
   292
		getcwd(cwdBytes, PATH_MAX);
boredzo@2020
   293
		parent = CFURLCreateFromFileSystemRepresentation(allocator, (const unsigned char *)cwdBytes, strlen(cwdBytes), /*isDirectory*/ true);
ingmarstein@2041
   294
		if (!name) {
boredzo@2020
   295
			newDirectory = parent;
boredzo@2020
   296
			goto end;
boredzo@2020
   297
		}
boredzo@2020
   298
	}
ingmarstein@2041
   299
	if (!parent)
boredzo@2031
   300
		NSLog(CFSTR("in createURLByMakingDirectoryAtURLWithName in CFGrowlAdditions: parent directory URL is NULL (please tell the Growl developers)\n"), parent);
boredzo@2031
   301
	else {
ingmarstein@2041
   302
		if (name)
boredzo@2020
   303
			name = CFRetain(name);
boredzo@2020
   304
		else {
boredzo@2020
   305
			name = CFURLCopyLastPathComponent(parent);
boredzo@2020
   306
			CFURLRef newParent = CFURLCreateCopyDeletingLastPathComponent(allocator, parent);
boredzo@2020
   307
			CFRelease(parent);
boredzo@2020
   308
			parent = newParent;
boredzo@2020
   309
		}
boredzo@2020
   310
ingmarstein@2041
   311
		if (!name)
boredzo@2031
   312
			NSLog(CFSTR("in createURLByMakingDirectoryAtURLWithName in CFGrowlAdditions: name of directory to create is NULL (please tell the Growl developers)\n"), parent);
boredzo@2031
   313
		else {
boredzo@2020
   314
			FSRef parentRef;
ingmarstein@2041
   315
			if (!CFURLGetFSRef(parent, &parentRef))
boredzo@2031
   316
				NSLog(CFSTR("in createURLByMakingDirectoryAtURLWithName in CFGrowlAdditions: could not create FSRef for parent directory at %@ (please tell the Growl developers)\n"), parent);
boredzo@2031
   317
			else {
boredzo@2020
   318
				FSRef newDirectoryRef;
boredzo@2020
   319
boredzo@2020
   320
				struct HFSUniStr255 nameUnicode;
boredzo@2020
   321
				CFRange range = { 0, MIN(CFStringGetLength(name), USHRT_MAX) };
boredzo@2020
   322
				CFStringGetCharacters(name, range, nameUnicode.unicode);
boredzo@2020
   323
				nameUnicode.length = range.length;
boredzo@2020
   324
boredzo@2020
   325
				struct FSRefParam refPB = {
boredzo@2020
   326
					.ref              = &parentRef,
boredzo@2020
   327
					.nameLength       = nameUnicode.length,
boredzo@2020
   328
					.name             = nameUnicode.unicode,
boredzo@2020
   329
					.whichInfo        = kFSCatInfoNone,
boredzo@2020
   330
					.catInfo          = NULL,
boredzo@2020
   331
					.textEncodingHint = kTextEncodingUnknown,
boredzo@2020
   332
					.newRef           = &newDirectoryRef,
boredzo@2020
   333
				};
ingmarstein@2269
   334
boredzo@2020
   335
				OSStatus err = PBCreateDirectoryUnicodeSync(&refPB);
ingmarstein@2041
   336
				if (err == dupFNErr) {
boredzo@2020
   337
					//dupFNErr == file (or folder) exists already. this is fine.
boredzo@2020
   338
					err = PBMakeFSRefUnicodeSync(&refPB);
boredzo@2020
   339
				}
ingmarstein@2041
   340
				if (err == noErr) {
boredzo@2031
   341
					NSLog(CFSTR("PBCreateDirectoryUnicodeSync or PBMakeFSRefUnicodeSync returned %li; calling CFURLCreateFromFSRef"), (long)err); //XXX
boredzo@2020
   342
					newDirectory = CFURLCreateFromFSRef(allocator, &newDirectoryRef);
boredzo@2031
   343
					NSLog(CFSTR("CFURLCreateFromFSRef returned %@"), newDirectory); //XXX
boredzo@2020
   344
				} else
boredzo@2031
   345
					NSLog(CFSTR("in createURLByMakingDirectoryAtURLWithName in CFGrowlAdditions: could not create directory '%@' in parent directory at %@: FSCreateDirectoryUnicode returned %li (please tell the Growl developers)"), name, parent, (long)err);
boredzo@2020
   346
			}
boredzo@2020
   347
Rudy@4229
   348
		} //if (name)
Rudy@4229
   349
		if(parent)
boredzo@2020
   350
			CFRelease(parent);
Rudy@4229
   351
		if(name)
Rudy@4229
   352
			CFRelease(name);
ingmarstein@2041
   353
	} //if (parent)
boredzo@2020
   354
boredzo@2020
   355
end:
boredzo@2020
   356
	return newDirectory;
boredzo@2020
   357
}
boredzo@2020
   358
boredzo@2020
   359
#ifndef COPYFORK_BUFSIZE
boredzo@2020
   360
#	define COPYFORK_BUFSIZE 5242880U /*5 MiB*/
boredzo@2020
   361
#endif
boredzo@2020
   362
ingmarstein@2041
   363
static OSStatus copyFork(const struct HFSUniStr255 *forkName, const FSRef *srcFile, const FSRef *destDir, const struct HFSUniStr255 *destName, FSRef *outDestFile) {
boredzo@2020
   364
	OSStatus err, closeErr;
boredzo@2020
   365
	struct FSForkIOParam srcPB = {
boredzo@2020
   366
		.ref = srcFile,
boredzo@2020
   367
		.forkNameLength = forkName->length,
boredzo@2020
   368
		.forkName = forkName->unicode,
boredzo@2020
   369
		.permissions = fsRdPerm,
boredzo@2020
   370
	};
boredzo@2031
   371
	unsigned char debuggingPathBuf[PATH_MAX] = "";
boredzo@2031
   372
	OSStatus debuggingPathErr;
boredzo@2020
   373
boredzo@2020
   374
	err = PBOpenForkSync(&srcPB);
ingmarstein@2041
   375
	if (err != noErr) {
boredzo@2031
   376
		debuggingPathErr = FSRefMakePath(srcFile, debuggingPathBuf, PATH_MAX);
ingmarstein@2041
   377
		if (debuggingPathErr != noErr)
boredzo@2031
   378
			snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for source file: FSRefMakePath returned %li)", (long)debuggingPathErr);
boredzo@2031
   379
		NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBOpenForkSync (source: %s) returned %li"), debuggingPathBuf, (long)err);
boredzo@2031
   380
	} else {
boredzo@2020
   381
		FSRef destFile;
boredzo@2020
   382
boredzo@2020
   383
		/*the first thing to do is get the name of the destination file, if one
boredzo@2020
   384
		 *	wasn't provided.
boredzo@2020
   385
		 *and while we're at it, we get the catalogue info as well.
boredzo@2020
   386
		 */
boredzo@2020
   387
		struct FSCatalogInfo catInfo;
boredzo@2020
   388
		struct FSRefParam refPB = {
boredzo@2020
   389
			.ref       = srcFile,
boredzo@2020
   390
			.whichInfo = kFSCatInfoGettableInfo & kFSCatInfoSettableInfo,
boredzo@2020
   391
			.catInfo   = &catInfo,
boredzo@2020
   392
			.spec      = NULL,
boredzo@2020
   393
			.parentRef = NULL,
boredzo@2020
   394
			.outName   = destName ? NULL : (struct HFSUniStr255 *)(destName = alloca(sizeof(struct HFSUniStr255))),
boredzo@2020
   395
		};
boredzo@2020
   396
boredzo@2020
   397
		err = PBGetCatalogInfoSync(&refPB);
ingmarstein@2041
   398
		if (err != noErr) {
boredzo@2031
   399
			debuggingPathErr = FSRefMakePath(srcFile, debuggingPathBuf, PATH_MAX);
ingmarstein@2041
   400
			if (debuggingPathErr != noErr)
boredzo@2031
   401
				snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for source file: FSRefMakePath returned %li)", (long)debuggingPathErr);
boredzo@2031
   402
			NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBGetCatalogInfoSync (source: %s) returned %li"), debuggingPathBuf, (long)err);
boredzo@2031
   403
		} else {
boredzo@2020
   404
			refPB.ref              = destDir;
boredzo@2020
   405
			refPB.nameLength       = destName->length;
boredzo@2020
   406
			refPB.name             = destName->unicode;
boredzo@2020
   407
			refPB.textEncodingHint = kTextEncodingUnknown;
boredzo@2020
   408
			refPB.newRef           = &destFile;
boredzo@2020
   409
boredzo@2031
   410
			const char *functionName = "PBMakeFSRefUnicodeSync"; //for error-reporting message
boredzo@2031
   411
boredzo@2020
   412
			err = PBMakeFSRefUnicodeSync(&refPB);
ingmarstein@2041
   413
			if ((err != noErr) && (err != fnfErr)) {
boredzo@2031
   414
			handleMakeFSRefError:
boredzo@2031
   415
				debuggingPathErr = FSRefMakePath(destDir, debuggingPathBuf, PATH_MAX);
ingmarstein@2041
   416
				if (debuggingPathErr != noErr)
boredzo@2031
   417
					snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for destination directory: FSRefMakePath returned %li)", (long)debuggingPathErr);
boredzo@2031
   418
boredzo@2031
   419
				//get filename too
boredzo@2031
   420
				CFStringRef debuggingFilename = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
boredzo@2031
   421
																				   destName->unicode,
boredzo@2031
   422
																				   destName->length,
boredzo@2264
   423
																				   /*contentsDeallocator*/ kCFAllocatorNull);
ingmarstein@2041
   424
				if (!debuggingFilename)
boredzo@2264
   425
					debuggingFilename = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, "(could not get filename for destination file: CFStringCreateWithCharactersNoCopy returned NULL)", kCFStringEncodingASCII, /*contentsDeallocator*/ kCFAllocatorNull);
boredzo@2031
   426
boredzo@2031
   427
				NSLog(CFSTR("in copyFork in CFGrowlAdditions: %s (destination: %s/%@) returned %li"), functionName, debuggingPathBuf, debuggingFilename, (long)err);
boredzo@2031
   428
ingmarstein@2041
   429
				if (debuggingFilename) CFRelease(debuggingFilename);
boredzo@2031
   430
			} else {
boredzo@2020
   431
				//that file doesn't exist in that folder; create it.
boredzo@2020
   432
				err = PBCreateFileUnicodeSync(&refPB);
boredzo@2264
   433
				if (err == noErr) {
boredzo@2020
   434
					/*make sure the Finder knows about the new file.
boredzo@2020
   435
					 *FNNotify returns a status code too, but this isn't an
boredzo@2020
   436
					 *	essential step, so we just ignore it.
boredzo@2020
   437
					 */
boredzo@2020
   438
					FNNotify(destDir, kFNDirectoryModifiedMessage, kNilOptions);
boredzo@2264
   439
				} else if (err == dupFNErr) {
boredzo@2264
   440
					/*dupFNErr: the file already exists.
boredzo@2264
   441
					 *we can safely ignore this error.
boredzo@2264
   442
					 */
boredzo@2264
   443
					err = noErr;
boredzo@2264
   444
				} else {
boredzo@2264
   445
					functionName = "PBCreateFileUnicodeSync";
boredzo@2264
   446
					goto handleMakeFSRefError;
boredzo@2020
   447
				}
boredzo@2020
   448
			}
boredzo@2020
   449
		}
ingmarstein@2041
   450
		if (err == noErr) {
ingmarstein@2041
   451
			if (outDestFile)
boredzo@2020
   452
				memcpy(outDestFile, &destFile, sizeof(destFile));
boredzo@2020
   453
boredzo@2020
   454
			struct FSForkIOParam destPB = {
boredzo@2020
   455
				.ref            = &destFile,
boredzo@2020
   456
				.forkNameLength = forkName->length,
boredzo@2020
   457
				.forkName       = forkName->unicode,
boredzo@2020
   458
				.permissions    = fsWrPerm,
boredzo@2020
   459
			};
boredzo@2020
   460
			err = PBOpenForkSync(&destPB);
boredzo@2031
   461
			NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBOpenForkSync (dest) returned %li"), (long)err);
ingmarstein@2041
   462
			if (err != noErr) {
boredzo@2031
   463
				debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX);
ingmarstein@2041
   464
				if (debuggingPathErr != noErr)
boredzo@2031
   465
					snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for dest file: FSRefMakePath returned %li)", (long)debuggingPathErr);
boredzo@2031
   466
				NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBOpenForkSync (destination: %s) returned %li"), debuggingPathBuf, (long)err);
boredzo@2031
   467
			} else {
boredzo@2020
   468
				void *buf = malloc(COPYFORK_BUFSIZE);
ingmarstein@2041
   469
				if (buf) {
boredzo@2020
   470
					srcPB.buffer = destPB.buffer = buf;
boredzo@2020
   471
					srcPB.requestCount = COPYFORK_BUFSIZE;
ingmarstein@2041
   472
					while (err == noErr) {
boredzo@2020
   473
						err = PBReadForkSync(&srcPB);
ingmarstein@2041
   474
						if (err == eofErr) {
boredzo@2020
   475
							err = noErr;
ingmarstein@2041
   476
							if (srcPB.actualCount == 0)
boredzo@2020
   477
								break;
boredzo@2020
   478
						}
ingmarstein@2041
   479
						if (err != noErr) {
boredzo@2031
   480
							debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX);
ingmarstein@2041
   481
							if (debuggingPathErr != noErr)
boredzo@2031
   482
								snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for source file: FSRefMakePath returned %li)", (long)debuggingPathErr);
boredzo@2031
   483
							NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBReadForkSync (source: %s) returned %li"), debuggingPathBuf, (long)err);
boredzo@2031
   484
						} else {
boredzo@2020
   485
							destPB.requestCount = srcPB.actualCount;
boredzo@2020
   486
							err = PBWriteForkSync(&destPB);
ingmarstein@2041
   487
							if (err != noErr) {
boredzo@2031
   488
								debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX);
ingmarstein@2041
   489
								if (debuggingPathErr != noErr)
boredzo@2031
   490
									snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for dest file: FSRefMakePath returned %li)", (long)debuggingPathErr);
boredzo@2031
   491
								NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBWriteForkSync (destination: %s) returned %li"), debuggingPathBuf, (long)err);
boredzo@2031
   492
							}
boredzo@2020
   493
						}
boredzo@2020
   494
					}
boredzo@2020
   495
boredzo@2020
   496
					free(buf);
boredzo@2020
   497
				}
boredzo@2020
   498
boredzo@2020
   499
				closeErr = PBCloseForkSync(&destPB);
ingmarstein@2041
   500
				if (closeErr != noErr) {
boredzo@2031
   501
					debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX);
ingmarstein@2041
   502
					if (debuggingPathErr != noErr)
boredzo@2031
   503
						snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for dest file: FSRefMakePath returned %li)", (long)debuggingPathErr);
boredzo@2031
   504
					NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBCloseForkSync (destination: %s) returned %li"), debuggingPathBuf, (long)err);
boredzo@2031
   505
				}
ingmarstein@2041
   506
				if (err == noErr) err = closeErr;
boredzo@2020
   507
			}
boredzo@2020
   508
		}
boredzo@2020
   509
boredzo@2020
   510
		closeErr = PBCloseForkSync(&srcPB);
ingmarstein@2041
   511
		if (closeErr != noErr) {
boredzo@2031
   512
			debuggingPathErr = FSRefMakePath(&destFile, debuggingPathBuf, PATH_MAX);
ingmarstein@2041
   513
			if (debuggingPathErr != noErr)
boredzo@2031
   514
				snprintf((char *)debuggingPathBuf, PATH_MAX, "(could not get path for source file: FSRefMakePath returned %li)", (long)debuggingPathErr);
boredzo@2031
   515
			NSLog(CFSTR("in copyFork in CFGrowlAdditions: PBCloseForkSync (source: %s) returned %li"), debuggingPathBuf, (long)err);
boredzo@2031
   516
		}
ingmarstein@2041
   517
		if (err == noErr) err = closeErr;
ingmarstein@2041
   518
	}
ingmarstein@2041
   519
ingmarstein@2041
   520
	return err;
ingmarstein@2041
   521
}
ingmarstein@2041
   522
ingmarstein@2041
   523
static OSStatus GrowlCopyObjectSync(const FSRef *fileRef, const FSRef *destRef, FSRef *destFileRef) {
ingmarstein@2041
   524
	OSStatus err;
ingmarstein@2041
   525
	struct HFSUniStr255 forkName;
ingmarstein@2041
   526
	struct FSForkIOParam forkPB = {
ingmarstein@2041
   527
		.ref = fileRef,
ingmarstein@2041
   528
		.forkIterator = {
ingmarstein@2041
   529
			.initialize = 0L
ingmarstein@2041
   530
		},
ingmarstein@2041
   531
		.outForkName = &forkName,
ingmarstein@2041
   532
	};
ingmarstein@2269
   533
ingmarstein@2041
   534
	do {
ingmarstein@2041
   535
		err = PBIterateForksSync(&forkPB);
ingmarstein@2041
   536
		NSLog(CFSTR("PBIterateForksSync returned %li"), (long)err);
ingmarstein@2041
   537
		if (err != noErr) {
ingmarstein@2041
   538
			if (err != errFSNoMoreItems)
ingmarstein@2041
   539
				NSLog(CFSTR("in GrowlCopyObjectSync in CFGrowlAdditions: PBIterateForksSync returned %li"), (long)err);
ingmarstein@2041
   540
		} else {
ingmarstein@2041
   541
			err = copyFork(&forkName, fileRef, destRef, /*destName*/ NULL, /*outDestFile*/ destFileRef);
ingmarstein@2041
   542
			//copyFork prints its own error messages
ingmarstein@2041
   543
		}
ingmarstein@2041
   544
	} while (err == noErr);
ingmarstein@2041
   545
	if (err == errFSNoMoreItems) err = noErr;
boredzo@2020
   546
boredzo@2020
   547
	return err;
boredzo@2020
   548
}
boredzo@2020
   549
evands@3429
   550
URL_TYPE createURLByCopyingFileFromURLToDirectoryURL(URL_TYPE file, URL_TYPE dest)
evands@3429
   551
{
boredzo@2020
   552
	CFURLRef destFileURL = NULL;
boredzo@2020
   553
boredzo@2020
   554
	FSRef fileRef, destRef, destFileRef;
ingmarstein@2041
   555
	Boolean gotFileRef = CFURLGetFSRef(file, &fileRef);
ingmarstein@2041
   556
	Boolean gotDestRef = CFURLGetFSRef(dest, &destRef);
ingmarstein@2041
   557
	if (!gotFileRef)
boredzo@2031
   558
		NSLog(CFSTR("in createURLByCopyingFileFromURLToDirectoryURL in CFGrowlAdditions: CFURLGetFSRef failed with source URL %@"), file);
ingmarstein@2041
   559
	else if (!gotDestRef)
boredzo@2031
   560
		NSLog(CFSTR("in createURLByCopyingFileFromURLToDirectoryURL in CFGrowlAdditions: CFURLGetFSRef failed with destination URL %@"), dest);
boredzo@2031
   561
	else {
boredzo@2020
   562
		OSStatus err;
boredzo@2020
   563
ingmarstein@2104
   564
		/*
ingmarstein@2104
   565
		 * 10.2 has a problem with weak symbols in frameworks so we use
ingmarstein@2104
   566
		 * MAC_OS_X_VERSION_MIN_REQUIRED >= 10.3.
ingmarstein@2104
   567
		 */
ingmarstein@2152
   568
#if defined(NSAppKitVersionNumber10_3) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
ingmarstein@2041
   569
		if (FSCopyObjectSync) {
ingmarstein@2041
   570
			err = FSCopyObjectSync(&fileRef, &destRef, /*destName*/ NULL, &destFileRef, kFSFileOperationOverwrite);
ingmarstein@2041
   571
		} else {
ingmarstein@2041
   572
#endif
ingmarstein@2041
   573
			err = GrowlCopyObjectSync(&fileRef, &destRef, &destFileRef);
ingmarstein@2152
   574
#if defined(NSAppKitVersionNumber10_3) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
ingmarstein@2041
   575
		}
ingmarstein@2041
   576
#endif
ingmarstein@2041
   577
ingmarstein@2041
   578
		if (err == noErr)
boredzo@2020
   579
			destFileURL = CFURLCreateFromFSRef(kCFAllocatorDefault, &destFileRef);
ingmarstein@2041
   580
		else
ingmarstein@2041
   581
			NSLog(CFSTR("in createURLByCopyingFileFromURLToDirectoryURL in CFGrowlAdditions: CopyObjectSync returned %li for source URL %@"), (long)err, file);
boredzo@2020
   582
	}
boredzo@2020
   583
boredzo@2020
   584
	return destFileURL;
boredzo@2020
   585
}
boredzo@2068
   586
evands@3429
   587
PLIST_TYPE createPropertyListFromURL(URL_TYPE file, u_int32_t mutability, CFPropertyListFormat *outFormat, STRING_TYPE *outErrorString)
evands@3429
   588
{
boredzo@2068
   589
	CFPropertyListRef plist = NULL;
boredzo@2068
   590
ingmarstein@2069
   591
	if (!file)
boredzo@2068
   592
		NSLog(CFSTR("in createPropertyListFromURL in CFGrowlAdditions: cannot read from a NULL URL"));
boredzo@2068
   593
	else {
boredzo@2068
   594
		CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, file);
ingmarstein@2069
   595
		if (!stream)
boredzo@2068
   596
			NSLog(CFSTR("in createPropertyListFromURL in CFGrowlAdditions: could not create stream for reading from URL %@"), file);
boredzo@2068
   597
		else {
ingmarstein@2069
   598
			if (!CFReadStreamOpen(stream))
boredzo@2068
   599
				NSLog(CFSTR("in createPropertyListFromURL in CFGrowlAdditions: could not open stream for reading from URL %@"), file);
boredzo@2068
   600
			else {
boredzo@2068
   601
				CFPropertyListFormat format;
boredzo@2068
   602
				CFStringRef errorString = NULL;
boredzo@2068
   603
boredzo@2068
   604
				plist = CFPropertyListCreateFromStream(kCFAllocatorDefault,
boredzo@2068
   605
													   stream,
boredzo@2068
   606
													   /*streamLength*/ 0,
boredzo@2068
   607
													   mutability,
boredzo@2068
   608
													   &format,
boredzo@2068
   609
													   &errorString);
ingmarstein@2069
   610
				if (!plist)
boredzo@2068
   611
					NSLog(CFSTR("in createPropertyListFromURL in CFGrowlAdditions: could not read property list from URL %@ (error string: %@)"), file, errorString);
boredzo@2068
   612
ingmarstein@2069
   613
				if (outFormat) *outFormat = format;
ingmarstein@2069
   614
				if (errorString) {
ingmarstein@2069
   615
					if (outErrorString)
boredzo@2068
   616
						*outErrorString = errorString;
boredzo@2068
   617
					else
boredzo@2068
   618
						CFRelease(errorString);
boredzo@2068
   619
				}
boredzo@2068
   620
boredzo@2068
   621
				CFReadStreamClose(stream);
boredzo@2068
   622
			}
boredzo@2068
   623
boredzo@2068
   624
			CFRelease(stream);
boredzo@2068
   625
		}
boredzo@2068
   626
	}
boredzo@2068
   627
boredzo@2068
   628
	return plist;
boredzo@2068
   629
}