Пример #1
0
static int
nmea_reader_update_time( NmeaReader*  r, Token  tok )
{
    int        hour, minute;
    double     seconds;
    struct tm  tm;
    time_t     fix_time;

    if (tok.p + 6 > tok.end)
        return -1;

    if (r->utc_year <= 2000) {
		r->utc_year = 1970;
		r->utc_mon = 1;
		r->utc_day = 1;
    }

    hour    = str2int(tok.p,   tok.p+2);
    minute  = str2int(tok.p+2, tok.p+4);
    seconds = str2float(tok.p+4, tok.end);

    tm.tm_hour = hour;
    tm.tm_min  = minute;
    tm.tm_sec  = (int) seconds;
    tm.tm_year = r->utc_year - 1900;
    tm.tm_mon  = r->utc_mon - 1;
    tm.tm_mday = r->utc_day;

    fix_time = utc_mktime( &tm );
    r->fix.timestamp = (long long)fix_time * 1000;
    return 0;
}
static bool imap_mktime(struct tm *tm, time_t *time_r)
{
	*time_r = utc_mktime(tm);
	if (*time_r != (time_t)-1)
		return TRUE;

	/* the date is outside valid range for time_t. it might still be
	   technically valid though, so try to handle this case.
	   with 64bit time_t the full 0..9999 year range is valid. */
	if (tm->tm_year <= 100) {
		/* too old. time_t can be signed or unsigned, handle
		   both cases. */
		*time_r = (time_t)-1 < (int)0 ? INT_MIN : 0;
	} else {
		/* too high. return the highest allowed value.
		   we shouldn't get here with 64bit time_t,
		   but handle that anyway. */

		/* APPLE */
		if (time_t_max_bits() == 32 || time_t_max_bits() == 64)
			*time_r = (1UL << (time_t_max_bits()-1)) - 1;
		else
			*time_r = (1UL << time_t_max_bits()) - 1;
	}
	return FALSE;
}
Пример #3
0
static timestamp_t parse_date(const char *date)
{
	int hour, min, sec;
	struct tm tm;
	char *p;

	memset(&tm, 0, sizeof(tm));
	tm.tm_mday = strtol(date, &p, 10);
	if (tm.tm_mday < 1 || tm.tm_mday > 31)
		return 0;
	for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) {
		if (!memcmp(p, monthname(tm.tm_mon), 3))
			break;
	}
	if (tm.tm_mon > 11)
		return 0;
	date = p + 3;
	tm.tm_year = strtol(date, &p, 10);
	if (date == p)
		return 0;
	if (tm.tm_year < 70)
		tm.tm_year += 2000;
	if (tm.tm_year < 100)
		tm.tm_year += 1900;
	if (sscanf(p, "%d:%d:%d", &hour, &min, &sec) != 3)
		return 0;
	tm.tm_hour = hour;
	tm.tm_min = min;
	tm.tm_sec = sec;
	return utc_mktime(&tm);
}
Пример #4
0
static void divedate(char *buffer, void *_when)
{
	int d,m,y;
	time_t *when = _when;
	int success = 0;

	success = tm.tm_sec | tm.tm_min | tm.tm_hour;
	if (sscanf(buffer, "%d.%d.%d", &d, &m, &y) == 3) {
		tm.tm_year = y;
		tm.tm_mon = m-1;
		tm.tm_mday = d;
	} else if (sscanf(buffer, "%d-%d-%d", &y, &m, &d) == 3) {
		tm.tm_year = y;
		tm.tm_mon = m-1;
		tm.tm_mday = d;
	} else {
		fprintf(stderr, "Unable to parse date '%s'\n", buffer);
		success = 0;
	}

	if (success)
		*when = utc_mktime(&tm);

	free(buffer);
}
Пример #5
0
static void divetime(char *buffer, void *_when)
{
	int h,m,s = 0;
	timestamp_t *when = _when;

	if (sscanf(buffer, "%d:%d:%d", &h, &m, &s) >= 2) {
		cur_tm.tm_hour = h;
		cur_tm.tm_min = m;
		cur_tm.tm_sec = s;
		*when = utc_mktime(&cur_tm);
	}
}
Пример #6
0
static void update_time(timestamp_t *when, const char *line)
{
	unsigned h, m, s = 0;
	struct tm tm;

	if (sscanf(line, "%02u:%02u:%02u", &h, &m, &s) < 2)
		return;
	utc_mkdate(*when, &tm);
	tm.tm_hour = h;
	tm.tm_min = m;
	tm.tm_sec = s;
	*when = utc_mktime(&tm);
}
Пример #7
0
static dive_trip_t *create_new_trip(int yyyy, int mm, int dd)
{
	dive_trip_t *trip = calloc(1, sizeof(dive_trip_t));
	struct tm tm = { 0 };

	/* We'll fill in the real data from the trip descriptor file */
	tm.tm_year = yyyy;
	tm.tm_mon = mm-1;
	tm.tm_mday = dd;
	trip->when = utc_mktime(&tm);

	return trip;
}
Пример #8
0
static void update_date(timestamp_t *when, const char *line)
{
	unsigned yyyy, mm, dd;
	struct tm tm;

	if (sscanf(line, "%04u-%02u-%02u", &yyyy, &mm, &dd) != 3)
		return;
	utc_mkdate(*when, &tm);
	tm.tm_year = yyyy - 1900;
	tm.tm_mon = mm - 1;
	tm.tm_mday = dd;
	*when = utc_mktime(&tm);
}
Пример #9
0
/* helper function to parse the Uemis data structures */
static void uemis_ts(char *buffer, void *_when)
{
	struct tm tm;
	timestamp_t *when = _when;

	memset(&tm, 0, sizeof(tm));
	sscanf(buffer, "%d-%d-%dT%d:%d:%d",
	       &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
	       &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
	tm.tm_mon -= 1;
	tm.tm_year -= 1900;
	*when = utc_mktime(&tm);
}
Пример #10
0
static void divetime(char *buffer, void *_when)
{
	int h,m,s = 0;
	time_t *when = _when;

	if (sscanf(buffer, "%d:%d:%d", &h, &m, &s) >= 2) {
		tm.tm_hour = h;
		tm.tm_min = m;
		tm.tm_sec = s;
		if (tm.tm_year)
			*when = utc_mktime(&tm);
	}
	free(buffer);
}
Пример #11
0
time64_t time64_from(const char* format, const char* src)
{
	time64_t v;
	struct tm64 tm64;

#if defined(OS_WINDOWS)
	FILETIME ft;
	SYSTEMTIME st;

	memset(&tm64, 0, sizeof(tm64));
	time64_scanf(&tm64, format, src);
	if(!TIME64_VALID_SYSTEM_TIME(tm64))
		return 0;

	st.wYear = (WORD)(tm64.year + 1900);
	st.wMonth = (WORD)(tm64.month + 1);
	st.wDay = (WORD)tm64.day;
	st.wDayOfWeek = (WORD)tm64.wday;
	st.wHour = (WORD)tm64.hour;
	st.wMinute = (WORD)tm64.minute;
	st.wSecond = (WORD)tm64.second;
	st.wMilliseconds = (WORD)tm64.millisecond;
	SystemTimeToFileTime(&st, &ft);

	v = (((unsigned __int64)ft.dwHighDateTime << 32) | (unsigned __int64)ft.dwLowDateTime) / 10000; // to ms
	v -= 0xA9730B66800; /* 11644473600000LL */ // January 1, 1601 (UTC) -> January 1, 1970 (UTC).
#else
	struct tm t;

	memset(&tm64, 0, sizeof(tm64));
	tm64.day = 1;
	time64_scanf(&tm64, format, src);
	if(!TIME64_VALID_SYSTEM_TIME(tm64))
		return 0;

	t.tm_year = tm64.year;
	t.tm_mon = tm64.month;
	t.tm_mday = tm64.day;
	t.tm_wday = tm64.wday;
	t.tm_hour = tm64.hour;
	t.tm_min = tm64.minute;
	t.tm_sec = tm64.second;
//	v = mktime(&t);
    v = utc_mktime(&t);
    v *= 1000;
	v += tm64.millisecond;
#endif
	return v;
}
Пример #12
0
/* Libdivecomputer: "2011-03-20 10:22:38" */
static void divedatetime(char *buffer, void *_when)
{
	int y,m,d;
	int hr,min,sec;
	timestamp_t *when = _when;

	if (sscanf(buffer, "%d-%d-%d %d:%d:%d",
		&y, &m, &d, &hr, &min, &sec) == 6) {
		cur_tm.tm_year = y;
		cur_tm.tm_mon = m-1;
		cur_tm.tm_mday = d;
		cur_tm.tm_hour = hr;
		cur_tm.tm_min = min;
		cur_tm.tm_sec = sec;
		*when = utc_mktime(&cur_tm);
	}
}
Пример #13
0
//TODO: This should be moved to C-Code.
time_t ShiftImageTimesDialog::epochFromExiv(EXIFInfo *exif)
{
	struct tm tm;
	int year, month, day, hour, min, sec;

	if (strlen(exif->DateTimeOriginal.c_str()))
		sscanf(exif->DateTimeOriginal.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
	else
		sscanf(exif->DateTime.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
	tm.tm_year = year;
	tm.tm_mon = month - 1;
	tm.tm_mday = day;
	tm.tm_hour = hour;
	tm.tm_min = min;
	tm.tm_sec = sec;
	return (utc_mktime(&tm));
}
Пример #14
0
void SG_time__parseRFC850(SG_context* pCtx,const char* pszInputString, SG_int64 * pTime, SG_int64 * pReturnedLocalTime)
{
	int		scanOK = 0;
	char	trash[4];
	int		day = 0;
	int		month = 0;
	int		year = 0;
	int		hour = 0;
	int		minute = 0;
	int		second = 0;
	char	monthstr[4];
	char	tz[4];
	struct tm t;

	SG_UNUSED(pCtx);
	SG_UNUSED(pszInputString);

#if defined(WINDOWS)
	scanOK = sscanf_s(pszInputString, "%3s, %d %3s %d %d:%d:%d %3s",
		trash, sizeof(trash), &day, monthstr, sizeof(monthstr), &year, &hour, &minute, &second, tz, sizeof(tz));
#else
	scanOK = sscanf(pszInputString, "%3s, %d %3s %d %d:%d:%d %3s",
		trash, &day, monthstr, &year, &hour, &minute, &second, tz);
#endif

	if ((scanOK != 8) || (strcmp("GMT", tz) != 0))
	{
		SG_ERR_THROW_RETURN(SG_ERR_ARGUMENT_OUT_OF_RANGE);
	}

	SG_ERR_CHECK_RETURN(  _lookupMonth(pCtx, monthstr, &month)  );

	t.tm_min = minute;
	t.tm_hour = hour;
	t.tm_sec = second;
	t.tm_year = year - 1900;
	t.tm_mon = month;
	t.tm_mday = day;

	*pTime = (SG_int64)utc_mktime(&t) * 1000;
	*pReturnedLocalTime = (SG_int64)mktime(&t) * 1000;
}
Пример #15
0
static bool
iso8601_date_do_parse(const unsigned char *data, size_t size, struct tm *tm_r,
		      time_t *timestamp_r, int *timezone_offset_r)
{
	struct iso8601_date_parser parser;
	time_t timestamp;

	memset(&parser, 0, sizeof(parser));
	parser.cur = data;
	parser.end = data + size;

	if (iso8601_date_parse_date_time(&parser) <= 0)
		return FALSE;

	parser.tm.tm_isdst = -1;
	timestamp = utc_mktime(&parser.tm);
	if (timestamp == (time_t)-1)
		return FALSE;

	*timezone_offset_r = parser.timezone_offset;
	*tm_r = parser.tm;
	*timestamp_r = timestamp - parser.timezone_offset * 60;
	return TRUE;
}
Пример #16
0
static void divedate(char *buffer, void *_when)
{
	int d,m,y;
	int hh,mm,ss;
	timestamp_t *when = _when;

	hh = 0; mm = 0; ss = 0;
	if (sscanf(buffer, "%d.%d.%d %d:%d:%d", &d, &m, &y, &hh, &mm, &ss) >= 3) {
		/* This is ok, and we got at least the date */
	} else if (sscanf(buffer, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hh, &mm, &ss) >= 3) {
		/* This is also ok */
	} else {
		fprintf(stderr, "Unable to parse date '%s'\n", buffer);
		return;
	}
	cur_tm.tm_year = y;
	cur_tm.tm_mon = m-1;
	cur_tm.tm_mday = d;
	cur_tm.tm_hour = hh;
	cur_tm.tm_min = mm;
	cur_tm.tm_sec = ss;

	*when = utc_mktime(&cur_tm);
}
Пример #17
0
/*
 * Uddf specifies ISO 8601 time format.
 *
 * There are many variations on that. This handles the useful cases.
 */
static void uddf_datetime(char *buffer, void *_when)
{
	char c;
	int y,m,d,hh,mm,ss;
	timestamp_t *when = _when;
	struct tm tm = { 0 };
	int i;

	i = sscanf(buffer, "%d-%d-%d%c%d:%d:%d", &y, &m, &d, &c, &hh, &mm, &ss);
	if (i == 7)
		goto success;
	ss = 0;
	if (i == 6)
		goto success;

	i = sscanf(buffer, "%04d%02d%02d%c%02d%02d%02d", &y, &m, &d, &c, &hh, &mm, &ss);
	if (i == 7)
		goto success;
	ss = 0;
	if (i == 6)
		goto success;
bad_date:
	printf("Bad date time %s\n", buffer);
	return;

success:
	if (c != 'T' && c != ' ')
		goto bad_date;
	tm.tm_year = y;
	tm.tm_mon = m - 1;
	tm.tm_mday = d;
	tm.tm_hour = hh;
	tm.tm_min = mm;
	tm.tm_sec = ss;
	*when = utc_mktime(&tm);
}
Пример #18
0
bool http_date_parse(const unsigned char *data, size_t size,
			time_t *timestamp_r)
{
	struct http_date_parser parser;
	time_t timestamp;
	
	memset(&parser, 0, sizeof(parser));
	parser.cur = data;
	parser.end = data + size;

	if (http_date_parse_format_any(&parser) <= 0)
		return FALSE;

	if (parser.cur != parser.end)
		return FALSE;

	parser.tm.tm_isdst = -1;
	timestamp = utc_mktime(&parser.tm);
	if (timestamp == (time_t)-1)
		return FALSE;

	*timestamp_r = timestamp;
	return TRUE;
}
Пример #19
0
int parse_txt_file(const char *filename, const char *csv)
{
	struct memblock memtxt, memcsv;

	if (readfile(filename, &memtxt) < 0) {
		return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
	}

	/*
	 * MkVI stores some information in .txt file but the whole profile and events are stored in .csv file. First
	 * make sure the input .txt looks like proper MkVI file, then start parsing the .csv.
	 */
	if (MATCH(memtxt.buffer, "MkVI_Config") == 0) {
		int d, m, y, he;
		int hh = 0, mm = 0, ss = 0;
		int prev_depth = 0, cur_sampletime = 0, prev_setpoint = -1, prev_ndl = -1;
		bool has_depth = false, has_setpoint = false, has_ndl = false;
		char *lineptr, *key, *value;
		int cur_cylinder_index = 0;
		unsigned int prev_time = 0;

		struct dive *dive;
		struct divecomputer *dc;
		struct tm cur_tm;

		value = parse_mkvi_value(memtxt.buffer, "Dive started at");
		if (sscanf(value, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hh, &mm, &ss) != 6) {
			free(value);
			return -1;
		}
		free(value);
		cur_tm.tm_year = y;
		cur_tm.tm_mon = m - 1;
		cur_tm.tm_mday = d;
		cur_tm.tm_hour = hh;
		cur_tm.tm_min = mm;
		cur_tm.tm_sec = ss;

		dive = alloc_dive();
		dive->when = utc_mktime(&cur_tm);;
		dive->dc.model = strdup("Poseidon MkVI Discovery");
		value = parse_mkvi_value(memtxt.buffer, "Rig Serial number");
		dive->dc.deviceid = atoi(value);
		free(value);
		dive->dc.divemode = CCR;
		dive->dc.no_o2sensors = 2;

		dive->cylinder[cur_cylinder_index].cylinder_use = OXYGEN;
		dive->cylinder[cur_cylinder_index].type.size.mliter = 3000;
		dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = 200000;
		dive->cylinder[cur_cylinder_index].type.description = strdup("3l Mk6");
		dive->cylinder[cur_cylinder_index].gasmix.o2.permille = 1000;
		cur_cylinder_index++;

		dive->cylinder[cur_cylinder_index].cylinder_use = DILUENT;
		dive->cylinder[cur_cylinder_index].type.size.mliter = 3000;
		dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = 200000;
		dive->cylinder[cur_cylinder_index].type.description = strdup("3l Mk6");
		value = parse_mkvi_value(memtxt.buffer, "Helium percentage");
		he = atoi(value);
		free(value);
		value = parse_mkvi_value(memtxt.buffer, "Nitrogen percentage");
		dive->cylinder[cur_cylinder_index].gasmix.o2.permille = (100 - atoi(value) - he) * 10;
		free(value);
		dive->cylinder[cur_cylinder_index].gasmix.he.permille = he * 10;
		cur_cylinder_index++;

		lineptr = strstr(memtxt.buffer, "Dive started at");
		while (!empty_string(lineptr) && (lineptr = strchr(lineptr, '\n'))) {
			++lineptr;	// Skip over '\n'
			key = next_mkvi_key(lineptr);
			if (!key)
				break;
			value = parse_mkvi_value(lineptr, key);
			if (!value) {
				free(key);
				break;
			}
			add_extra_data(&dive->dc, key, value);
			free(key);
			free(value);
		}
		dc = &dive->dc;

		/*
		 * Read samples from the CSV file. A sample contains all the lines with same timestamp. The CSV file has
		 * the following format:
		 *
		 * timestamp, type, value
		 *
		 * And following fields are of interest to us:
		 *
		 * 	6	sensor1
		 * 	7	sensor2
		 * 	8	depth
		 *	13	o2 tank pressure
		 *	14	diluent tank pressure
		 *	20	o2 setpoint
		 *	39	water temp
		 */

		if (readfile(csv, &memcsv) < 0) {
			free(dive);
			return report_error(translate("gettextFromC", "Poseidon import failed: unable to read '%s'"), csv);
		}
		lineptr = memcsv.buffer;
		for (;;) {
			struct sample *sample;
			int type;
			int value;
			int sampletime;
			int gaschange = 0;

			/* Collect all the information for one sample */
			sscanf(lineptr, "%d,%d,%d", &cur_sampletime, &type, &value);

			has_depth = false;
			has_setpoint = false;
			has_ndl = false;
			sample = prepare_sample(dc);

			/*
			 * There was a bug in MKVI download tool that resulted in erroneous sample
			 * times. This fix should work similarly as the vendor's own.
			 */

			sample->time.seconds = cur_sampletime < 0xFFFF * 3 / 4 ? cur_sampletime : prev_time;
			prev_time = sample->time.seconds;

			do {
				int i = sscanf(lineptr, "%d,%d,%d", &sampletime, &type, &value);
				switch (i) {
				case 3:
					switch (type) {
					case 0:
						//Mouth piece position event: 0=OC, 1=CC, 2=UN, 3=NC
						switch (value) {
						case 0:
							add_event(dc, cur_sampletime, 0, 0, 0,
									QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position OC"));
							break;
						case 1:
							add_event(dc, cur_sampletime, 0, 0, 0,
									QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position CC"));
							break;
						case 2:
							add_event(dc, cur_sampletime, 0, 0, 0,
									QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position unknown"));
							break;
						case 3:
							add_event(dc, cur_sampletime, 0, 0, 0,
									QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position not connected"));
							break;
						}
						break;
					case 3:
						//Power Off event
						add_event(dc, cur_sampletime, 0, 0, 0,
								QT_TRANSLATE_NOOP("gettextFromC", "Power off"));
						break;
					case 4:
						//Battery State of Charge in %
#ifdef SAMPLE_EVENT_BATTERY
						add_event(dc, cur_sampletime, SAMPLE_EVENT_BATTERY, 0,
								value, QT_TRANSLATE_NOOP("gettextFromC", "battery"));
#endif
						break;
					case 6:
						//PO2 Cell 1 Average
						add_sample_data(sample, POSEIDON_SENSOR1, value);
						break;
					case 7:
						//PO2 Cell 2 Average
						add_sample_data(sample, POSEIDON_SENSOR2, value);
						break;
					case 8:
						//Depth * 2
						has_depth = true;
						prev_depth = value;
						add_sample_data(sample, POSEIDON_DEPTH, value);
						break;
						//9 Max Depth * 2
						//10 Ascent/Descent Rate * 2
					case 11:
						//Ascent Rate Alert >10 m/s
						add_event(dc, cur_sampletime, SAMPLE_EVENT_ASCENT, 0, 0,
								QT_TRANSLATE_NOOP("gettextFromC", "ascent"));
						break;
					case 13:
						//O2 Tank Pressure
						add_sample_pressure(sample, 0, lrint(value * 1000));
						break;
					case 14:
						//Diluent Tank Pressure
						add_sample_pressure(sample, 1, lrint(value * 1000));
						break;
						//16 Remaining dive time #1?
						//17 related to O2 injection
					case 20:
						//PO2 Setpoint
						has_setpoint = true;
						prev_setpoint = value;
						add_sample_data(sample, POSEIDON_SETPOINT, value);
						break;
					case 22:
						//End of O2 calibration Event: 0 = OK, 2 = Failed, rest of dive setpoint 1.0
						if (value == 2)
							add_event(dc, cur_sampletime, 0, SAMPLE_FLAGS_END, 0,
									QT_TRANSLATE_NOOP("gettextFromC", "O₂ calibration failed"));
						add_event(dc, cur_sampletime, 0, SAMPLE_FLAGS_END, 0,
								QT_TRANSLATE_NOOP("gettextFromC", "O₂ calibration"));
						break;
					case 25:
						//25 Max Ascent depth
						add_sample_data(sample, POSEIDON_CEILING, value);
						break;
					case 31:
						//Start of O2 calibration Event
						add_event(dc, cur_sampletime, 0, SAMPLE_FLAGS_BEGIN, 0,
								QT_TRANSLATE_NOOP("gettextFromC", "O₂ calibration"));
						break;
					case 37:
						//Remaining dive time #2?
						has_ndl = true;
						prev_ndl = value;
						add_sample_data(sample, POSEIDON_NDL, value);
						break;
					case 39:
						// Water Temperature in Celcius
						add_sample_data(sample, POSEIDON_TEMP, value);
						break;
					case 85:
						//He diluent part in %
						gaschange += value << 16;
						break;
					case 86:
						//O2 diluent part in %
						gaschange += value;
						break;
						//239 Unknown, maybe PO2 at sensor validation?
						//240 Unknown, maybe PO2 at sensor validation?
						//247 Unknown, maybe PO2 Cell 1 during pressure test
						//248 Unknown, maybe PO2 Cell 2 during pressure test
						//250 PO2 Cell 1
						//251 PO2 Cell 2
					default:
						break;
					} /* sample types */
					break;
				case EOF:
					break;
				default:
					printf("Unable to parse input: %s\n", lineptr);
					break;
				}

				lineptr = strchr(lineptr, '\n');
				if (!lineptr || !*lineptr)
					break;
				lineptr++;

				/* Grabbing next sample time */
				sscanf(lineptr, "%d,%d,%d", &cur_sampletime, &type, &value);
			} while (sampletime == cur_sampletime);

			if (gaschange)
				add_event(dc, cur_sampletime, SAMPLE_EVENT_GASCHANGE2, 0, gaschange,
						QT_TRANSLATE_NOOP("gettextFromC", "gaschange"));
			if (!has_depth)
				add_sample_data(sample, POSEIDON_DEPTH, prev_depth);
			if (!has_setpoint && prev_setpoint >= 0)
				add_sample_data(sample, POSEIDON_SETPOINT, prev_setpoint);
			if (!has_ndl && prev_ndl >= 0)
				add_sample_data(sample, POSEIDON_NDL, prev_ndl);
			finish_sample(dc);

			if (!lineptr || !*lineptr)
				break;
		}
		record_dive(dive);
		return 1;
	} else {
		return 0;
	}

	return 0;
}
Пример #20
0
/*
 * Dive directory, name is [[yyyy-]mm-]nn-ddd-hh:mm:ss[~hex],
 * and 'timeoff' points to what should be the time part of
 * the name (the first digit of the hour).
 *
 * The root path will be of the form yyyy/mm[/tripdir],
 */
static int dive_directory(const char *root, const char *name, int timeoff)
{
	int yyyy = -1, mm = -1, dd = -1;
	int h, m, s;
	int mday_off, month_off, year_off;
	struct tm tm;

	/* Skip the '-' before the time */
	mday_off = timeoff;
	if (!mday_off || name[--mday_off] != '-')
		return GIT_WALK_SKIP;
	/* Skip the day name */
	while (mday_off > 0 && name[--mday_off] != '-')
		/* nothing */;

	mday_off = mday_off - 2;
	month_off = mday_off - 3;
	year_off = month_off - 5;
	if (mday_off < 0)
		return GIT_WALK_SKIP;

	/* Get the time of day */
	if (sscanf(name+timeoff, "%d:%d:%d", &h, &m, &s) != 3)
		return GIT_WALK_SKIP;
	if (!validate_time(h, m, s))
		return GIT_WALK_SKIP;

	/*
	 * Using the "git_tree_walk()" interface is simple, but
	 * it kind of sucks as an interface because there is
	 * no sane way to pass the hierarchy to the callbacks.
	 * The "payload" is a fixed one-time thing: we'd like
	 * the "current trip" to be passed down to the dives
	 * that get parsed under that trip, but we can't.
	 *
	 * So "active_trip" is not the trip that is in the hierarchy
	 * _above_ us, it's just the trip that was _before_ us. But
	 * if a dive is not in a trip at all, we can't tell.
	 *
	 * We could just do a better walker that passes the
	 * return value around, but we hack around this by
	 * instead looking at the one hierarchical piece of
	 * data we have: the pathname to the current entry.
	 *
	 * This is pretty hacky. The magic '8' is the length
	 * of a pathname of the form 'yyyy/mm/'.
	 */
	if (strlen(root) == 8)
		finish_active_trip();

	/*
	 * Get the date. The day of the month is in the dive directory
	 * name, the year and month might be in the path leading up
	 * to it.
	 */
	dd = atoi(name + mday_off);
	if (year_off < 0) {
		if (sscanf(root, "%d/%d", &yyyy, &mm) != 2)
			return GIT_WALK_SKIP;
	} else
		yyyy = atoi(name + year_off);
	if (month_off >= 0)
		mm = atoi(name + month_off);

	if (!validate_date(yyyy, mm, dd))
		return GIT_WALK_SKIP;

	/* Ok, close enough. We've gotten sufficient information */
	memset(&tm, 0, sizeof(tm));
	tm.tm_hour = h;
	tm.tm_min = m;
	tm.tm_sec = s;
	tm.tm_year = yyyy - 1900;
	tm.tm_mon = mm-1;
	tm.tm_mday = dd;

	finish_active_dive();
	active_dive = create_new_dive(utc_mktime(&tm));
	return GIT_WALK_OK;
}
Пример #21
0
static int dive_cb(const unsigned char *data, unsigned int size,
	const unsigned char *fingerprint, unsigned int fsize,
	void *userdata)
{
	int rc;
	parser_t *parser = NULL;
	device_data_t *devdata = userdata;
	dc_datetime_t dt = {0};
	struct tm tm;
	struct dive *dive;

	rc = create_parser(devdata, &parser);
	if (rc != PARSER_STATUS_SUCCESS) {
		fprintf(stderr, "Unable to create parser for %s", devdata->name);
		return rc;
	}

	rc = parser_set_data(parser, data, size);
	if (rc != PARSER_STATUS_SUCCESS) {
		fprintf(stderr, "Error registering the data.");
		parser_destroy(parser);
		return rc;
	}

	dive = alloc_dive();
	rc = parser_get_datetime(parser, &dt);
	if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
		fprintf(stderr, "Error parsing the datetime.");
		parser_destroy (parser);
		return rc;
	}

	tm.tm_year = dt.year;
	tm.tm_mon = dt.month-1;
	tm.tm_mday = dt.day;
	tm.tm_hour = dt.hour;
	tm.tm_min = dt.minute;
	tm.tm_sec = dt.second;
	dive->when = utc_mktime(&tm);

	// Parse the divetime.
	printf("Parsing the divetime.\n");
	unsigned int divetime = 0;
	rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
	if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
		fprintf(stderr, "Error parsing the divetime.");
		parser_destroy(parser);
		return rc;
	}
	dive->duration.seconds = divetime;

	// Parse the maxdepth.
	printf("Parsing the maxdepth.\n");
	double maxdepth = 0.0;
	rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
	if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
		fprintf(stderr, "Error parsing the maxdepth.");
		parser_destroy(parser);
		return rc;
	}
	dive->maxdepth.mm = maxdepth * 1000 + 0.5;

	// Parse the gas mixes.
	printf("Parsing the gas mixes.\n");
	unsigned int ngases = 0;
	rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
	if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
		fprintf(stderr, "Error parsing the gas mix count.");
		parser_destroy(parser);
		return rc;
	}

	rc = parse_gasmixes(dive, parser, ngases);
	if (rc != PARSER_STATUS_SUCCESS) {
		fprintf(stderr, "Error parsing the gas mix.");
		parser_destroy(parser);
		return rc;
	}

	// Initialize the sample data.
	rc = parse_samples(&dive, parser);
	if (rc != PARSER_STATUS_SUCCESS) {
		fprintf(stderr, "Error parsing the samples.");
		parser_destroy(parser);
		return rc;
	}

	parser_destroy(parser);

	/* If we already saw this dive, abort. */
	if (find_dive(dive, devdata))
		return 0;

	record_dive(dive);
	return 1;
}
Пример #22
0
static int dive_cb(const unsigned char *data, unsigned int size,
	const unsigned char *fingerprint, unsigned int fsize,
	void *userdata)
{
	int rc;
	dc_parser_t *parser = NULL;
	device_data_t *devdata = userdata;
	dc_datetime_t dt = {0};
	struct tm tm;
	struct dive *dive;

	rc = create_parser(devdata, &parser);
	if (rc != DC_STATUS_SUCCESS) {
		dev_info(devdata, _("Unable to create parser for %s %s"), devdata->vendor, devdata->product);
		return rc;
	}

	rc = dc_parser_set_data(parser, data, size);
	if (rc != DC_STATUS_SUCCESS) {
		dev_info(devdata, _("Error registering the data"));
		dc_parser_destroy(parser);
		return rc;
	}

	import_dive_number++;
	dive = alloc_dive();
	rc = dc_parser_get_datetime(parser, &dt);
	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
		dev_info(devdata, _("Error parsing the datetime"));
		dc_parser_destroy(parser);
		return rc;
	}

	tm.tm_year = dt.year;
	tm.tm_mon = dt.month-1;
	tm.tm_mday = dt.day;
	tm.tm_hour = dt.hour;
	tm.tm_min = dt.minute;
	tm.tm_sec = dt.second;
	dive->when = utc_mktime(&tm);

	// Parse the divetime.
	dev_info(devdata, _("Dive %d: %s %d %04d"), import_dive_number,
		monthname(tm.tm_mon), tm.tm_mday, year(tm.tm_year));
	unsigned int divetime = 0;
	rc = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime);
	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
		dev_info(devdata, _("Error parsing the divetime"));
		dc_parser_destroy(parser);
		return rc;
	}
	dive->duration.seconds = divetime;

	// Parse the maxdepth.
	double maxdepth = 0.0;
	rc = dc_parser_get_field(parser, DC_FIELD_MAXDEPTH, 0, &maxdepth);
	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
		dev_info(devdata, _("Error parsing the maxdepth"));
		dc_parser_destroy(parser);
		return rc;
	}
	dive->maxdepth.mm = maxdepth * 1000 + 0.5;

	// Parse the gas mixes.
	unsigned int ngases = 0;
	rc = dc_parser_get_field(parser, DC_FIELD_GASMIX_COUNT, 0, &ngases);
	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
		dev_info(devdata, _("Error parsing the gas mix count"));
		dc_parser_destroy(parser);
		return rc;
	}

	// Check if the libdivecomputer version already supports salinity
	double salinity = 1.03;
#ifdef DC_FIELD_SALINITY
	rc = dc_parser_get_field(parser, DC_FIELD_SALINITY, 0, &salinity);
	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
		dev_info(devdata, _("Error obtaining water salinity"));
		dc_parser_destroy(parser);
		return rc;
	}
#endif
	dive->salinity = salinity * 10000.0 + 0.5;

	rc = parse_gasmixes(devdata, dive, parser, ngases);
	if (rc != DC_STATUS_SUCCESS) {
		dev_info(devdata, _("Error parsing the gas mix"));
		dc_parser_destroy(parser);
		return rc;
	}

	// Initialize the sample data.
	rc = parse_samples(devdata, &dive, parser);
	if (rc != DC_STATUS_SUCCESS) {
		dev_info(devdata, _("Error parsing the samples"));
		dc_parser_destroy(parser);
		return rc;
	}

	dc_parser_destroy(parser);

	/* If we already saw this dive, abort. */
	if (!devdata->force_download && find_dive(dive, devdata))
		return 0;

	dive->downloaded = TRUE;
	record_dive(dive);
	mark_divelist_changed(TRUE);
	return 1;
}
Пример #23
0
static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
			       const unsigned char *in, unsigned size,
			       struct dive_table *table)
{
	unsigned char *buf = malloc(size);
	struct dive *dive;
	struct divecomputer *dc;
	struct tm tm = {0};
	uint32_t csum[5];

	double max_depth, avg_depth, min_temp;
	unsigned int duration = 0, corrupt_dive = 0;

	/*
	 * The scrambling has odd boundaries. I think the boundaries
	 * match some data structure size, but I don't know. They were
	 * discovered the same way we dynamically discover the decode
	 * size: automatically looking for least random output.
	 *
	 * The boundaries are also this confused "off-by-one" thing,
	 * the same way the file size is off by one. It's as if the
	 * cochran software forgot to write one byte at the beginning.
	 */
	partial_decode(0, 0x0fff, decode, 1, mod, in, size, buf);
	partial_decode(0x0fff, 0x1fff, decode, 0, mod, in, size, buf);
	partial_decode(0x1fff, 0x2fff, decode, 0, mod, in, size, buf);
	partial_decode(0x2fff, 0x48ff, decode, 0, mod, in, size, buf);

	/*
	 * This is not all the descrambling you need - the above are just
	 * what appears to be the fixed-size blocks. The rest is also
	 * scrambled, but there seems to be size differences in the data,
	 * so this just descrambles part of it:
	 */

	if (size < 0x4914 + config.logbook_size) {
		// Analyst calls this a "Corrupt Beginning Summary"
		free(buf);
		return;
	}

	// Decode log entry (512 bytes + random prefix)
	partial_decode(0x48ff, 0x4914 + config.logbook_size, decode,
		0, mod, in, size, buf);

	unsigned int sample_size = size - 0x4914 - config.logbook_size;
	int g;
	unsigned int sample_pre_offset = 0, sample_end_offset = 0;

	// Decode sample data
	partial_decode(0x4914 + config.logbook_size, size, decode,
		0, mod, in, size, buf);

#ifdef COCHRAN_DEBUG
	// Display pre-logbook data
	puts("\nPre Logbook Data\n");
	cochran_debug_write(buf, 0x4914);

	// Display log book
	puts("\nLogbook Data\n");
	cochran_debug_write(buf + 0x4914,  config.logbook_size + 0x400);

	// Display sample data
	puts("\nSample Data\n");
#endif

	dive = alloc_dive();
	dc = &dive->dc;

	unsigned char *log = (buf + 0x4914);

	switch (config.type) {
	case TYPE_GEMINI:
	case TYPE_COMMANDER:
		if (config.type == TYPE_GEMINI) {
			dc->model = "Gemini";
			dc->deviceid = buf[0x18c] * 256 + buf[0x18d];	// serial no
			fill_default_cylinder(&dive->cylinder[0]);
			dive->cylinder[0].gasmix.o2.permille = (log[CMD_O2_PERCENT] / 256
				+ log[CMD_O2_PERCENT + 1]) * 10;
			dive->cylinder[0].gasmix.he.permille = 0;
		} else {
			dc->model = "Commander";
			dc->deviceid = array_uint32_le(buf + 0x31e);	// serial no
			for (g = 0; g < 2; g++) {
				fill_default_cylinder(&dive->cylinder[g]);
				dive->cylinder[g].gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256
					+ log[CMD_O2_PERCENT + g * 2 + 1]) * 10;
				dive->cylinder[g].gasmix.he.permille = 0;
			}
		}

		tm.tm_year = log[CMD_YEAR];
		tm.tm_mon = log[CMD_MON] - 1;
		tm.tm_mday = log[CMD_DAY];
		tm.tm_hour = log[CMD_HOUR];
		tm.tm_min = log[CMD_MIN];
		tm.tm_sec = log[CMD_SEC];
		tm.tm_isdst = -1;

		dive->when = dc->when = utc_mktime(&tm);
		dive->number = log[CMD_NUMBER] + log[CMD_NUMBER + 1] * 256 + 1;
		dc->duration.seconds = (log[CMD_BT] + log[CMD_BT + 1] * 256) * 60;
		dc->surfacetime.seconds = (log[CMD_SIT] + log[CMD_SIT + 1] * 256) * 60;
		dc->maxdepth.mm = lrint((log[CMD_MAX_DEPTH] +
			log[CMD_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000);
		dc->meandepth.mm = lrint((log[CMD_AVG_DEPTH] +
			log[CMD_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000);
		dc->watertemp.mkelvin = C_to_mkelvin((log[CMD_MIN_TEMP] / 32) - 1.8);
		dc->surface_pressure.mbar = lrint(ATM / BAR * pow(1 - 0.0000225577
			* (double) log[CMD_ALTITUDE] * 250 * FEET, 5.25588) * 1000);
		dc->salinity = 10000 + 150 * log[CMD_WATER_CONDUCTIVITY];

		SHA1(log + CMD_NUMBER, 2, (unsigned char *)csum);
		dc->diveid = csum[0];

		if (log[CMD_MAX_DEPTH] == 0xff && log[CMD_MAX_DEPTH + 1] == 0xff)
			corrupt_dive = 1;

		sample_pre_offset = array_uint32_le(log + CMD_PREDIVE_OFFSET);
		sample_end_offset = array_uint32_le(log + CMD_END_OFFSET);

		break;
	case TYPE_EMC:
		dc->model = "EMC";
		dc->deviceid = array_uint32_le(buf + 0x31e);	// serial no
		for (g = 0; g < 4; g++) {
			fill_default_cylinder(&dive->cylinder[g]);
			dive->cylinder[g].gasmix.o2.permille =
				(log[EMC_O2_PERCENT + g * 2] / 256
				+ log[EMC_O2_PERCENT + g * 2 + 1]) * 10;
			dive->cylinder[g].gasmix.he.permille =
				(log[EMC_HE_PERCENT + g * 2] / 256
				+ log[EMC_HE_PERCENT + g * 2 + 1]) * 10;
		}

		tm.tm_year = log[EMC_YEAR];
		tm.tm_mon = log[EMC_MON] - 1;
		tm.tm_mday = log[EMC_DAY];
		tm.tm_hour = log[EMC_HOUR];
		tm.tm_min = log[EMC_MIN];
		tm.tm_sec = log[EMC_SEC];
		tm.tm_isdst = -1;

		dive->when = dc->when = utc_mktime(&tm);
		dive->number = log[EMC_NUMBER] + log[EMC_NUMBER + 1] * 256 + 1;
		dc->duration.seconds = (log[EMC_BT] + log[EMC_BT + 1] * 256) * 60;
		dc->surfacetime.seconds = (log[EMC_SIT] + log[EMC_SIT + 1] * 256) * 60;
		dc->maxdepth.mm = lrint((log[EMC_MAX_DEPTH] +
			log[EMC_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000);
		dc->meandepth.mm = lrint((log[EMC_AVG_DEPTH] +
			log[EMC_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000);
		dc->watertemp.mkelvin = C_to_mkelvin((log[EMC_MIN_TEMP] - 32) / 1.8);
		dc->surface_pressure.mbar = lrint(ATM / BAR * pow(1 - 0.0000225577
			* (double) log[EMC_ALTITUDE] * 250 * FEET, 5.25588) * 1000);
		dc->salinity = 10000 + 150 * (log[EMC_WATER_CONDUCTIVITY] & 0x3);

		SHA1(log + EMC_NUMBER, 2, (unsigned char *)csum);
		dc->diveid = csum[0];

		if (log[EMC_MAX_DEPTH] == 0xff && log[EMC_MAX_DEPTH + 1] == 0xff)
			corrupt_dive = 1;

		sample_pre_offset = array_uint32_le(log + EMC_PREDIVE_OFFSET);
		sample_end_offset = array_uint32_le(log + EMC_END_OFFSET);

		break;
	}

	// Use the log information to determine actual profile sample size
	// Otherwise we will get surface time at end of dive.
	if (sample_pre_offset < sample_end_offset && sample_end_offset != 0xffffffff)
		sample_size = sample_end_offset - sample_pre_offset;

	cochran_parse_samples(dive, buf + 0x4914, buf + 0x4914
		+ config.logbook_size, sample_size,
		&duration, &max_depth, &avg_depth, &min_temp);

	// Check for corrupt dive
	if (corrupt_dive) {
		dc->maxdepth.mm = lrint(max_depth * FEET * 1000);
		dc->meandepth.mm = lrint(avg_depth * FEET * 1000);
		dc->watertemp.mkelvin = C_to_mkelvin((min_temp - 32) / 1.8);
		dc->duration.seconds = duration;
	}

	record_dive_to_table(dive, table);
	mark_divelist_changed(true);

	free(buf);
}
Пример #24
0
int mbox_from_parse(const unsigned char *msg, size_t size,
		    time_t *time_r, int *tz_offset_r, char **sender_r)
{
	const unsigned char *msg_start, *sender_end, *msg_end;
	struct tm tm;
	int esc, alt_stamp, timezone_secs = 0, seen_timezone = FALSE;
	time_t t;

	*time_r = (time_t)-1;
	*sender_r = NULL;

	/* <sender> <date> <moreinfo> */
	msg_start = msg;
	msg_end = msg + size;

	/* get sender */
	if (msg < msg_end && *msg == '"') {
		/* "x y z"@domain - skip the quoted part */
		esc = FALSE;
		msg++;
		while (msg < msg_end && (*msg != '"' || esc)) {
			if (*msg == '\r' || *msg == '\n')
				return -1;
			esc = *msg == '\\';
			msg++;
		}
		msg++;
	} 

	while (msg < msg_end && *msg != ' ') {
		if (*msg == '\r' || *msg == '\n')
			return -1;
		msg++;
	}
	sender_end = msg;
	while (msg < msg_end && *msg == ' ') msg++;

	/* next 29 chars should be in the date in asctime() format, eg.
	   "Thu Nov  9 22:33:52 2001 +0300"

	   - Some put the timezone before the year
	   - Some use a named timezone before or after year, which we ignore
	   - Some don't include seconds (-3)
	   - Some don't include timezone (-5)
	*/
	if (msg+29-3-5 > msg_end)
		return -1;

	memset(&tm, 0, sizeof(tm));

	/* skip weekday */
	msg += 4;

	/* month */
	if (mbox_parse_month(msg, &tm) < 0) {
		/* Try alternate timestamp: "Thu, 9 Nov 2002 22:33:52" */
		alt_stamp = TRUE;
		msg++;

		if (!i_isdigit(msg[0]))
			return -1;
		tm.tm_mday = msg[0]-'0';
		msg++;

		if (i_isdigit(msg[0])) {
			tm.tm_mday = tm.tm_mday*10 + msg[0]-'0';
			msg++;
		}
		if (msg[0] != ' ')
			return -1;
		msg++;

		if (mbox_parse_month(msg, &tm) < 0)
			return -1;
		msg += 4;

		if (mbox_parse_year(msg, &tm) < 0)
			return -1;
		msg += 5;
	} else {
		alt_stamp = FALSE;
		msg += 4;

		/* day. single digit is usually preceded by extra space */
		if (msg[0] == ' ')
			msg++;
		if (msg[1] == ' ') {
			if (!i_isdigit(msg[0]))
				return -1;
			tm.tm_mday = msg[0]-'0';
			msg += 2;
		} else {
			if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ')
				return -1;
			tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0');
			msg += 3;
		}
	}
	if (tm.tm_mday == 0)
		tm.tm_mday = 1;

	/* hour */
	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':')
		return -1;
	tm.tm_hour = (msg[0]-'0') * 10 + (msg[1]-'0');
	msg += 3;

	/* minute */
	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]))
		return -1;
	tm.tm_min = (msg[0]-'0') * 10 + (msg[1]-'0');
	msg += 2;

	/* optional second */
	if (msg[0] == ':') {
		msg++;
		if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]))
			return -1;
		tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0');
		msg += 2;

		if (!alt_stamp) {
			if (msg[0] == ' ')
				msg++;
			else
				return -1;
		}
	} else if (!alt_stamp) {
		if (msg[0] != ' ')
			return -1;
		msg++;
	}

	/* optional named timezone */
	if (alt_stamp)
		;
	else if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) ||
		 !i_isdigit(msg[2]) || !i_isdigit(msg[3])) {
		/* skip to next space */
		while (msg < msg_end && *msg != ' ') {
			if (*msg == '\r' || *msg == '\n')
				return -1;
			msg++;
		}
		if (msg+5 > msg_end)
			return -1;
		msg++;
	} else if ((msg[0] == '-' || msg[0] == '+') &&
		   i_isdigit(msg[1]) && i_isdigit(msg[2]) &&
		   i_isdigit(msg[3]) && i_isdigit(msg[4]) && msg[5] == ' ') {
		/* numeric timezone, use it */
                seen_timezone = TRUE;
		timezone_secs = (msg[1]-'0') * 10*60*60 + (msg[2]-'0') * 60*60 +
			(msg[3]-'0') * 10 + (msg[4]-'0');
		if (msg[0] == '-') timezone_secs = -timezone_secs;
		msg += 6;
	}

	if (!alt_stamp) {
		/* year */
		if (mbox_parse_year(msg, &tm) < 0)
			return -1;
		msg += 4;
	}

	tm.tm_isdst = -1;
	if (!seen_timezone && msg != msg_end &&
	    msg[0] == ' ' && (msg[1] == '-' || msg[1] == '+') &&
	    i_isdigit(msg[2]) && i_isdigit(msg[3]) &&
	    i_isdigit(msg[4]) && i_isdigit(msg[5])) {
		seen_timezone = TRUE;
		timezone_secs = (msg[2]-'0') * 10*60*60 + (msg[3]-'0') * 60*60 +
			(msg[4]-'0') * 10 + (msg[5]-'0');
		if (msg[1] == '-') timezone_secs = -timezone_secs;
	}

	if (seen_timezone) {
		t = utc_mktime(&tm);
		if (t == (time_t)-1)
			return -1;

		t -= timezone_secs;
		*time_r = t;
		*tz_offset_r = timezone_secs/60;
	} else {
		/* assume local timezone */
		*time_r = mktime(&tm);
		*tz_offset_r = utc_offset(localtime(time_r), *time_r);
	}

	*sender_r = i_strdup_until(msg_start, sender_end);
	return 0;
}
Пример #25
0
static bool
message_date_parser_tokens(struct message_date_parser_context *ctx,
			   time_t *timestamp_r, int *timezone_offset_r)
{
	struct tm tm;
	const unsigned char *value;
	size_t i, len;
	int ret;

	/* [weekday_name "," ] dd month_name [yy]yy hh:mi[:ss] timezone */
	memset(&tm, 0, sizeof(tm));

        rfc822_skip_lwsp(&ctx->parser);

	/* skip the optional weekday */
	if (next_token(ctx, &value, &len) <= 0)
		return FALSE;
	if (len == 3) {
		if (*ctx->parser.data != ',')
			return FALSE;
		ctx->parser.data++;
		rfc822_skip_lwsp(&ctx->parser);

		if (next_token(ctx, &value, &len) <= 0)
			return FALSE;
	}

	/* dd */
	if (len < 1 || len > 2 || !i_isdigit(value[0]))
		return FALSE;

	tm.tm_mday = value[0]-'0';
	if (len == 2) {
		if (!i_isdigit(value[1]))
			return FALSE;
		tm.tm_mday = (tm.tm_mday * 10) + (value[1]-'0');
	}

	/* month name */
	if (next_token(ctx, &value, &len) <= 0 || len < 3)
		return FALSE;

	for (i = 0; i < 12; i++) {
		if (i_memcasecmp(month_names[i], value, 3) == 0) {
			tm.tm_mon = i;
			break;
		}
	}
	if (i == 12)
		return FALSE;

	/* [yy]yy */
	if (next_token(ctx, &value, &len) <= 0 || (len != 2 && len != 4))
		return FALSE;

	for (i = 0; i < len; i++) {
		if (!i_isdigit(value[i]))
			return FALSE;
		tm.tm_year = tm.tm_year * 10 + (value[i]-'0');
	}

	if (len == 2) {
		/* two digit year, assume 1970+ */
		if (tm.tm_year < 70)
			tm.tm_year += 100;
	} else {
		if (tm.tm_year < 1900)
			return FALSE;
		tm.tm_year -= 1900;
	}

	/* hh, allow also single digit */
	if (next_token(ctx, &value, &len) <= 0 ||
	    len < 1 || len > 2 || !i_isdigit(value[0]))
		return FALSE;
	tm.tm_hour = value[0]-'0';
	if (len == 2) {
		if (!i_isdigit(value[1]))
			return FALSE;
		tm.tm_hour = tm.tm_hour * 10 + (value[1]-'0');
	}

	/* :mm (may be the last token) */
	if (!IS_TIME_SEP(*ctx->parser.data))
		return FALSE;
	ctx->parser.data++;
	rfc822_skip_lwsp(&ctx->parser);

	if (next_token(ctx, &value, &len) < 0 || len != 2 ||
	    !i_isdigit(value[0]) || !i_isdigit(value[1]))
		return FALSE;
	tm.tm_min = (value[0]-'0') * 10 + (value[1]-'0');

	/* [:ss] */
	if (ctx->parser.data != ctx->parser.end &&
	    IS_TIME_SEP(*ctx->parser.data)) {
		ctx->parser.data++;
		rfc822_skip_lwsp(&ctx->parser);

		if (next_token(ctx, &value, &len) <= 0 || len != 2 ||
		    !i_isdigit(value[0]) || !i_isdigit(value[1]))
			return FALSE;
		tm.tm_sec = (value[0]-'0') * 10 + (value[1]-'0');
	}

	if ((ret = next_token(ctx, &value, &len)) < 0)
		return FALSE;
	if (ret == 0) {
		/* missing timezone */
		*timezone_offset_r = 0;
	} else {
		/* timezone */
		*timezone_offset_r = parse_timezone(value, len);
	}

	tm.tm_isdst = -1;
	*timestamp_r = utc_mktime(&tm);
	if (*timestamp_r == (time_t)-1)
		return FALSE;

	*timestamp_r -= *timezone_offset_r * 60;

	return TRUE;
}