Пример #1
0
static void
parse_indexdef(IndexDef *stmt, Oid index, Oid table)
{
    char *sql = pg_get_indexdef_string(index);
    const char *idxname = get_quoted_relname(index);
    const char *tblname = get_relation_name(table);

    /* CREATE [UNIQUE] INDEX */
    stmt->create = sql;
    sql = skip_const(index, sql, "CREATE INDEX", "CREATE UNIQUE INDEX");
    /* index */
    stmt->index = sql;
    sql = skip_const(index, sql, idxname, NULL);
    /* ON */
    sql = skip_const(index, sql, "ON", NULL);
    /* table */
    stmt->table = sql;
    sql = skip_const(index, sql, tblname, NULL);
    /* USING */
    sql = skip_const(index, sql, "USING", NULL);
    /* type */
    stmt->type = sql;
    sql = skip_ident(index, sql);
    /* (columns) */
    if ((sql = strchr(sql, '(')) == NULL)
        parse_error(index);
    sql++;
    stmt->columns = sql;
    if ((sql = skip_until(index, sql, ')')) == NULL)
        parse_error(index);
    /* options */
    stmt->options = sql;
}
Пример #2
0
static void socks4_client(int sock)
{
	struct socks4_header h;
	struct sockaddr_in addr;
	int relay=INVALID_SOCKET;
	unsigned char c;

	if (recv(sock, &c, 1, MSG_PEEK) != 1) goto ex;
	if (c == SOCKS4_EXECBYTE) {
		socks4_exec(sock);
		closesocket(sock);
		return;
	}
	if (c != 0x04) goto reject;

	if (recv_bytes(sock, (char *)&h, sizeof(h), 0) != sizeof(h)) goto ex;
	if (skip_until(sock, '\0')) goto reject;
	if (h.vn != 0x04) goto reject;
	if (h.cd != 0x01) goto reject;		/* BIND method is not supported */

	if ((h.dstip != 0) && ((htonl(h.dstip) & 0xFFFFFF00) == 0))	/* 0.0.0.xxx, xxx!=0 */
		/* SOCKS4A extension... */
		if (parse_socks4a(sock, &h.dstip)) goto reject;
	addr.sin_family = AF_INET;
	addr.sin_port = h.dstport;
	addr.sin_addr.s_addr = h.dstip;

	relay = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (relay == INVALID_SOCKET) goto reject;
	if (connect(relay, (struct sockaddr *)&addr, sizeof(addr))) goto reject;

	h.vn = 0x04;
	h.cd = SOCKS4_SUCCEEDED;	/* success */

	send(sock, (char *)&h, sizeof(h), 0);

	relay_socks(sock, relay);

ex:	if (relay != INVALID_SOCKET) closesocket(relay);
	closesocket(sock);
	return;

reject:	h.vn = 0x04;
	h.cd = SOCKS4_REJECTED;	/* rejected/failed */
	send(sock, (char *)&h, sizeof(h), 0);
	goto ex;
}
Пример #3
0
void declare_locals ( bool ignoring)
{
    num_ilocals = 0;
    num_ulocals = 0;
    localno = 0;
    
    l_d_lineno = lineno;
    bool sav_rep_mul_lin = report_multiline;
    report_multiline = TRUE;

    if ( ignoring || error_check_locals() )
    {
       if ( skip_until ( '}' ) )
       {
	   warn_unterm(TKERROR,
	       "misplaced Local-Values Declaration", l_d_lineno);
       }else{
	   pc++ ;  /*  Get past the close-curly-brace  */
       }
    }else{
       if (gather_locals( TRUE,  &num_ilocals ) )
       {
	   gather_locals( FALSE, &num_ulocals );
       }
    }

    /*  If PC has reached the END,  gather_locals()  will
     *      have already issued an "unterminated" Error;
     *      a "multiline" warning would be redundant
     *      repetitive, unnecessary, excessive, unaesthetic
     *      and -- did I already mention? -- redundant.
     */
    if ( pc < end )
    {
	report_multiline = sav_rep_mul_lin;
	warn_if_multiline( "Local-Values declaration", l_d_lineno);
    }

    /*  Don't do anything if no Locals were declared    */
    /*  This could happen if the  {  }  field is empty  */
    if ( localno != 0 )
    {
	activate_locals();
    }
}
Пример #4
0
void read_series(istream& df, const string &name)
{
  char ch;
  vec_convert vc;
  series t;
  while (df)
  {
    t.init();
    vc.clear();
    df >> ws;
    if (df.peek() == '*')
    {
      t.hide = true;
      df.ignore();
    }
    if (hide_series)
      t.hide = true;
    df >> ws;
    ch = get_token(df, t.ID);
    if (isspace(ch))
      ch = skip_until(df);
    if (ch != ',')
      continue;
    df >> ws;
    string str;
    ch = get_token(df, str);
    try
    {
      t.f = FindResidual(str);
    }
    catch (gError) 
    {
      cout << NOEQ << t.ID << " - " << str << " -  series ignored" << endl;
      while (ch = df.get(), ch != ';' &&
                            ch != EOF);
      continue;
    }
    parser p(df, name);
    SGML el;
    if (isspace(ch))
      while (df >> ws, ch = df.peek(), ch == '<')
      {
        p.GetSGML(el);
        el.compare("var");
        str = el.FindString("name");
        if (!str.empty())
        {
          t.vs.push_back(str);
          t.vx.push_back(el.FindDouble("value"));
        }
      }
    if (ch != ',')
      ch = skip_until(df);
    if (ch == ',')
      df.ignore();
    else
      continue;
    while (df >> ws, ch = df.peek(), ch == '<')
    {
      vc.push_back(convert());
      vc.back().read(p.GetSGML(el));
    }
    if (ch == ',')
      df.ignore();
    t.read(df, 0, t.f.NameOfX(), t.f.ScaleOfX());
    if (!t)
      continue;
    if (vc.empty())
      ser.push_back(t);
    else
    {
      series t1;
      t1.hide = t.hide;
      t1.ID = t.ID;
      t1.f = t.f;
      t1.vs = t.vs;
      t1.vx = t.vx;
      t1.set(t.Ntot(), vc.size());
      for (size_t i = 0; i < vc.size(); ++i)
      {
        if (vc[i].name().empty())
          throw gError("read_series: no name while converting");
        else
          t1.name(i) = vc[i].name();
      }
      t1.scale() = t.scale();
      t1.NOfX() = SearchString(t1.names(), t1.f.NameOfX());
      for (size_t i = 0; i < vc.size(); ++i)
        vc[i].SetID(t.names());
      for (size_t i = 0; i < t.Ntot(); ++i)
      {
        t1.atr(i) = t.atr(i);
        for (size_t j = 0; j < vc.size(); ++j)
          t1(i, j) = vc[j](t(i));
      }
      t1.set_av();
      ser.push_back(t1);
    }
    ser.back().f.SetInput(ser.back().names());
    ser.back().f.SetOnceInput(ser.back().vs);
  }
}
Пример #5
0
int read_config(const char *path, int type)
{
	char line[1024];
	FILE *fp;
	char *s, *key, *val, *end_of_key;
	const char *error;
	char *cp, *cp2;
	int i;
	int lineno = 0;
	int got_transport = 0;
	int min_timeout = 0;
	struct ticket_config defaults = { { 0 } };
	struct ticket_config *current_tk = NULL;


	fp = fopen(path, "r");
	if (!fp) {
		log_error("failed to open %s: %s", path, strerror(errno));
		return -1;
	}

	booth_conf = malloc(sizeof(struct booth_config)
			+ TICKET_ALLOC * sizeof(struct ticket_config));
	if (!booth_conf) {
		fclose(fp);
		log_error("failed to alloc memory for booth config");
		return -ENOMEM;
	}
	memset(booth_conf, 0, sizeof(struct booth_config)
			+ TICKET_ALLOC * sizeof(struct ticket_config));
	ticket_size = TICKET_ALLOC;


	booth_conf->proto = UDP;
	booth_conf->port = BOOTH_DEFAULT_PORT;
	booth_conf->maxtimeskew = BOOTH_DEFAULT_MAX_TIME_SKEW;
	booth_conf->authkey[0] = '\0';


	/* Provide safe defaults. -1 is reserved, though. */
	booth_conf->uid = -2;
	booth_conf->gid = -2;
	strcpy(booth_conf->site_user,  "hacluster");
	strcpy(booth_conf->site_group, "haclient");
	strcpy(booth_conf->arb_user,   "nobody");
	strcpy(booth_conf->arb_group,  "nobody");

	parse_weights("", defaults.weight);
	defaults.clu_test.path  = NULL;
	defaults.clu_test.pid  = 0;
	defaults.clu_test.status  = 0;
	defaults.clu_test.progstate  = EXTPROG_IDLE;
	defaults.term_duration        = DEFAULT_TICKET_EXPIRY;
	defaults.timeout       = DEFAULT_TICKET_TIMEOUT;
	defaults.retries       = DEFAULT_RETRIES;
	defaults.acquire_after = 0;
	defaults.mode          = TICKET_MODE_AUTO;

	error = "";

	log_debug("reading config file %s", path);
	while (fgets(line, sizeof(line), fp)) {
		lineno++;

		s = skip_while(line, isspace);
		if (is_end_of_line(s) || *s == '#')
			continue;
		key = s;


		/* Key */
		end_of_key = skip_while_in(key, isalnum, "-_");
		if (end_of_key == key) {
			error = "No key";
			goto err;
		}

		if (!*end_of_key)
			goto exp_equal;


		/* whitespace, and something else but nothing more? */
		s = skip_while(end_of_key, isspace);


		if (*s != '=') {
exp_equal:
			error = "Expected '=' after key";
			goto err;
		}
		s++;

		/* It's my buffer, and I terminate if I want to. */
		/* But not earlier than that, because we had to check for = */
		*end_of_key = 0;


		/* Value tokenizing */
		s = skip_while(s, isspace);
		switch (*s) {
			case '"':
			case '\'':
				val = s+1;
				s = skip_until(val, *s);
				/* Terminate value */
				if (!*s) {
					error = "Unterminated quoted string";
					goto err;
				}

				/* Remove and skip quote */
				*s = 0;
				s++;
				if (*(s = skip_while(s, isspace)) && *s != '#') {
					error = "Surplus data after value";
					goto err;
				}

				*s = 0;

				break;

			case 0:
no_value:
				error = "No value";
				goto err;
				break;

			default:
				val = s;
				/* Rest of line. */
				i = strlen(s);
				/* i > 0 because of "case 0" above. */
				while (i > 0 && isspace(s[i-1]))
					i--;
				s += i;
				*s = 0;
		}

		if (val == s)
			goto no_value;


		if (strlen(key) > BOOTH_NAME_LEN
				|| strlen(val) > BOOTH_NAME_LEN) {
			error = "key/value too long";
			goto err;
		}

		if (strcmp(key, "transport") == 0) {
			if (got_transport) {
				error = "config file has multiple transport lines";
				goto err;
			}

			if (strcasecmp(val, "UDP") == 0)
				booth_conf->proto = UDP;
			else if (strcasecmp(val, "SCTP") == 0)
				booth_conf->proto = SCTP;
			else {
				error = "invalid transport protocol";
				goto err;
			}
			got_transport = 1;
			continue;
		}

		if (strcmp(key, "port") == 0) {
			booth_conf->port = atoi(val);
			continue;
		}

		if (strcmp(key, "name") == 0) {
			safe_copy(booth_conf->name, 
					val, BOOTH_NAME_LEN,
					"name");
			continue;
		}

#if HAVE_LIBGCRYPT || HAVE_LIBMHASH
		if (strcmp(key, "authfile") == 0) {
			safe_copy(booth_conf->authfile,
					val, BOOTH_PATH_LEN,
					"authfile");
			continue;
		}

		if (strcmp(key, "maxtimeskew") == 0) {
			booth_conf->maxtimeskew = atoi(val);
			continue;
		}
#endif

		if (strcmp(key, "site") == 0) {
			if (add_site(val, SITE))
				goto err;
			continue;
		}

		if (strcmp(key, "arbitrator") == 0) {
			if (add_site(val, ARBITRATOR))
				goto err;
			continue;
		}

		if (strcmp(key, "site-user") == 0) {
			safe_copy(booth_conf->site_user, optarg, BOOTH_NAME_LEN,
					"site-user");
			continue;
		}
		if (strcmp(key, "site-group") == 0) {
			safe_copy(booth_conf->site_group, optarg, BOOTH_NAME_LEN,
					"site-group");
			continue;
		}
		if (strcmp(key, "arbitrator-user") == 0) {
			safe_copy(booth_conf->arb_user, optarg, BOOTH_NAME_LEN,
					"arbitrator-user");
			continue;
		}
		if (strcmp(key, "arbitrator-group") == 0) {
			safe_copy(booth_conf->arb_group, optarg, BOOTH_NAME_LEN,
					"arbitrator-group");
			continue;
		}

		if (strcmp(key, "debug") == 0) {
			if (type != CLIENT && type != GEOSTORE)
				debug_level = max(debug_level, atoi(val));
			continue;
		}

		if (strcmp(key, "ticket") == 0) {
			if (current_tk && strcmp(current_tk->name, "__defaults__")) {
				if (!postproc_ticket(current_tk)) {
					goto err;
				}
			}
			if (!strcmp(val, "__defaults__")) {
				current_tk = &defaults;
			} else if (add_ticket(val, &current_tk, &defaults)) {
				goto err;
			}
			continue;
		}

		/* current_tk must be allocated at this point, otherwise
		 * we don't know to which ticket the key refers
		 */
		if (!current_tk) {
			error = "Unexpected keyword";
			goto err;
		}

		if (strcmp(key, "expire") == 0) {
			current_tk->term_duration = read_time(val);
			if (current_tk->term_duration <= 0) {
				error = "Expected time >0 for expire";
				goto err;
			}
			continue;
		}

		if (strcmp(key, "timeout") == 0) {
			current_tk->timeout = read_time(val);
			if (current_tk->timeout <= 0) {
				error = "Expected time >0 for timeout";
				goto err;
			}
			if (!min_timeout) {
				min_timeout = current_tk->timeout;
			} else {
				min_timeout = min(min_timeout, current_tk->timeout);
			}
			continue;
		}

		if (strcmp(key, "retries") == 0) {
			current_tk->retries = strtol(val, &s, 0);
			if (*s || s == val ||
					current_tk->retries<3 || current_tk->retries > 100) {
				error = "Expected plain integer value in the range [3, 100] for retries";
				goto err;
			}
			continue;
		}

		if (strcmp(key, "renewal-freq") == 0) {
			current_tk->renewal_freq = read_time(val);
			if (current_tk->renewal_freq <= 0) {
				error = "Expected time >0 for renewal-freq";
				goto err;
			}
			continue;
		}

		if (strcmp(key, "acquire-after") == 0) {
			current_tk->acquire_after = read_time(val);
			if (current_tk->acquire_after < 0) {
				error = "Expected time >=0 for acquire-after";
				goto err;
			}
			continue;
		}

		if (strcmp(key, "before-acquire-handler") == 0) {
			if (parse_extprog(val, current_tk)) {
				goto err;
			}
			continue;
		}

		if (strcmp(key, "attr-prereq") == 0) {
			if (parse_attr_prereq(val, current_tk)) {
				goto err;
			}
			continue;
		}

		if (strcmp(key, "mode") == 0) {
			current_tk->mode = retrieve_ticket_mode(val);
			continue;
		}

		if (strcmp(key, "weights") == 0) {
			if (parse_weights(val, current_tk->weight) < 0)
				goto err;
			continue;
		}

		error = "Unknown keyword";
		goto err;
	}
	fclose(fp);

	if ((booth_conf->site_count % 2) == 0) {
		log_warn("Odd number of nodes is strongly recommended!");
	}

	/* Default: make config name match config filename. */
	if (!booth_conf->name[0]) {
		cp = strrchr(path, '/');
		cp = cp ? cp+1 : (char *)path;
		cp2 = strrchr(cp, '.');
		if (!cp2)
			cp2 = cp + strlen(cp);
		if (cp2-cp >= BOOTH_NAME_LEN) {
			log_error("booth config file name too long");
			goto out;
		}
		strncpy(booth_conf->name, cp, cp2-cp);
		*(booth_conf->name+(cp2-cp)) = '\0';
	}

	if (!postproc_ticket(current_tk)) {
		goto out;
	}

	poll_timeout = min(POLL_TIMEOUT, min_timeout/10);
	if (!poll_timeout)
		poll_timeout = POLL_TIMEOUT;

	return 0;


err:
	fclose(fp);
out:
	log_error("%s in config file line %d",
			error, lineno);

	free(booth_conf);
	booth_conf = NULL;
	return -1;
}
Пример #6
0
/**
 * @fn      Datum reorg_get_index_keys(PG_FUNCTION_ARGS)
 * @brief   Get key definition of the index.
 *
 * reorg_get_index_keys(index, table)
 *
 * @param	index	Oid of target index.
 * @param	table	Oid of table of the index.
 * @retval			Create index DDL for temp table.
 *
 * FIXME: this function is named get_index_keys, but actually returns
 * an expression for ORDER BY clause. get_order_by() might be a better name.
 */
Datum
reorg_get_index_keys(PG_FUNCTION_ARGS)
{
    Oid				index = PG_GETARG_OID(0);
    Oid				table = PG_GETARG_OID(1);
    IndexDef		stmt;
    char		   *token;
    char		   *next;
    StringInfoData	str;
    Relation		indexRel = NULL;
    int				nattr;

    parse_indexdef(&stmt, index, table);
    elog(DEBUG2, "indexdef.create  = %s", stmt.create);
    elog(DEBUG2, "indexdef.index   = %s", stmt.index);
    elog(DEBUG2, "indexdef.table   = %s", stmt.table);
    elog(DEBUG2, "indexdef.type    = %s", stmt.type);
    elog(DEBUG2, "indexdef.columns = %s", stmt.columns);
    elog(DEBUG2, "indexdef.options = %s", stmt.options);

    /*
     * FIXME: this is very unreliable implementation but I don't want to
     * re-implement customized versions of pg_get_indexdef_string...
     *
     * TODO: Support ASC/DESC and NULL FIRST/LAST.
     */

    initStringInfo(&str);
    for (nattr = 0, next = stmt.columns; next; nattr++)
    {
        char *opcname;

        token = next;
        while (isspace((unsigned char) *token))
            token++;
        next = skip_until(index, next, ',');
        opcname = skip_until(index, token, ' ');
        if (opcname)
        {
            /* lookup default operator name from operator class */

            Oid				opclass;
            Oid				oprid;
            int16			strategy = BTLessStrategyNumber;
            Oid				opcintype;
            Oid				opfamily;
            HeapTuple		tp;
            Form_pg_opclass	opclassTup;

            opclass = OpclassnameGetOpcid(BTREE_AM_OID, opcname);

            /* Retrieve operator information. */
            tp = SearchSysCache(CLAOID, ObjectIdGetDatum(opclass), 0, 0, 0);
            if (!HeapTupleIsValid(tp))
                elog(ERROR, "cache lookup failed for opclass %u", opclass);
            opclassTup = (Form_pg_opclass) GETSTRUCT(tp);
            opfamily = opclassTup->opcfamily;
            opcintype = opclassTup->opcintype;
            ReleaseSysCache(tp);

            if (!OidIsValid(opcintype))
            {
                if (indexRel == NULL)
                    indexRel = index_open(index, NoLock);

                opcintype = RelationGetDescr(indexRel)->attrs[nattr]->atttypid;
            }

            oprid = get_opfamily_member(opfamily, opcintype, opcintype, strategy);
            if (!OidIsValid(oprid))
                elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
                     strategy, opcintype, opcintype, opfamily);


            opcname[-1] = '\0';
            appendStringInfo(&str, "%s USING %s", token, get_opname(oprid));
        }
        else
            appendStringInfoString(&str, token);
        if (next)
            appendStringInfoString(&str, ", ");
    }

    if (indexRel != NULL)
        index_close(indexRel, NoLock);

    PG_RETURN_TEXT_P(cstring_to_text(str.data));
}
Пример #7
0
static void
parse_indexdef(IndexDef *stmt, Oid index, Oid table)
{
	char *sql = pg_get_indexdef_string(index);
	const char *idxname = get_quoted_relname(index);
	const char *tblname = get_relation_name(table);
	const char *limit = strchr(sql, '\0');

	/* CREATE [UNIQUE] INDEX */
	stmt->create = sql;
	sql = skip_const(index, sql, "CREATE INDEX", "CREATE UNIQUE INDEX");
	/* index */
	stmt->index = sql;
	sql = skip_const(index, sql, idxname, NULL);
	/* ON */
	sql = skip_const(index, sql, "ON", NULL);
	/* table */
	stmt->table = sql;
	sql = skip_const(index, sql, tblname, NULL);
	/* USING */
	sql = skip_const(index, sql, "USING", NULL);
	/* type */
	stmt->type = sql;
	sql = skip_ident(index, sql);
	/* (columns) */
	if ((sql = strchr(sql, '(')) == NULL)
		parse_error(index);
	sql++;
	stmt->columns = sql;
	if ((sql = skip_until(index, sql, ')')) == NULL)
		parse_error(index);

	/* options */
	stmt->options = sql;
	stmt->tablespace = NULL;
	stmt->where = NULL;

	/* Is there a tablespace? Note that apparently there is never, but
	 * if there was one it would appear here. */
	if (sql < limit && strstr(sql, "TABLESPACE"))
	{
		sql = skip_until_const(index, sql, "TABLESPACE");
		stmt->tablespace = sql;
		sql = skip_ident(index, sql);
	}

	/* Note: assuming WHERE is the only clause allowed after TABLESPACE */
	if (sql < limit && strstr(sql, "WHERE"))
	{
		sql = skip_until_const(index, sql, "WHERE");
		stmt->where = sql;
	}

	elog(DEBUG2, "indexdef.create  = %s", stmt->create);
	elog(DEBUG2, "indexdef.index   = %s", stmt->index);
	elog(DEBUG2, "indexdef.table   = %s", stmt->table);
	elog(DEBUG2, "indexdef.type    = %s", stmt->type);
	elog(DEBUG2, "indexdef.columns = %s", stmt->columns);
	elog(DEBUG2, "indexdef.options = %s", stmt->options);
	elog(DEBUG2, "indexdef.tspace  = %s", stmt->tablespace);
	elog(DEBUG2, "indexdef.where   = %s", stmt->where);
}
Пример #8
0
int main(void)
{
	int socket_client;
	int socket_serveur = creer_serveur(8080);
	initialiser_signaux();
	
	const char* message_bienvenue = "#############################################################\n#                                                           #\n#                         BONJOUR !                         #\n#             Bienvenue sur le serveur Wichita              #\n#                                                           #\n#                          ------                           #\n#                                                           #\n#      Wichita tient son nom d'une langue amérindienne.     #\n#        Cette langue est en voie de disparition...         #\n#               ... comme beaucoup d'autres.                #\n#                                                           #\n#  Quoi qu'il en soit, amusez-vous bien avec Wichita ! :-)  #\n#                                                           #\n#############################################################\n";
	
	const char *bad_request = "HTTP/1.1 400 Bad Request\nConnection: close\nContent-Length: 17\n\n400 Bad Request\n";
	const char *connected = "HTTP/1.1 200 OK\nConnection: open\nContent-Length: 80\n\n";
	
	while(1)
	{
		socket_client = accept(socket_serveur, NULL ,NULL);
		if (socket_client == -1)
		{
			perror("socket_client accept error");
			continue;
		}
		
		if (fork() == 0)
		{
			char buffer[BUF_SIZE];
			FILE * client_file = fdopen(socket_client, "w+");
			
			if (fgets(buffer, BUF_SIZE, client_file) == NULL)
			{
				perror("fgets en-tete");
				close(socket_client);
				exit(EXIT_FAILURE);
			}
			printf(buffer);
			if (http_get_request(buffer) != 0)
			{
				fprintf(client_file, "%s", bad_request);
				fflush(client_file);
				close(socket_client);
				exit(EXIT_FAILURE);
			}
			else
			{
				fprintf(client_file, "%s", connected);
				fflush(client_file);
			}
			
			skip_until(client_file, "\r\n");
			fprintf(client_file, "%s", message_bienvenue);
			fflush(client_file);
			
			while(strcmp("FIN\n", buffer) != 0)
			{
				memset(buffer, '\0', strlen(buffer));
				
				if (fgets(buffer, BUF_SIZE, client_file) != NULL)
				{
					// writes to the client
					//fprintf(client_file, "<Wichita> %s", buffer);
					
					// writes to the server
					printf("%s", buffer);
				}
			}
			close(socket_client);
			break;
		}
		else
		{
			close(socket_client);
		}
	}
	
	close(socket_serveur);
	return EXIT_SUCCESS;
}
static void
read_attribute_params (EVCardAttribute *attr, char **p, gboolean *quoted_printable)
{
	char *lp;
	GString *str;
	EVCardAttributeParam *param = NULL;
	gboolean in_quote = FALSE;

	str = g_string_new ("");
	for( lp =  skip_newline( *p, *quoted_printable );
	     *lp != '\n' && *lp != '\r' && *lp != '\0';
	     lp = skip_newline( lp, *quoted_printable ) ) {

		if (*lp == '"') {
			in_quote = !in_quote;
			lp = g_utf8_next_char (lp);
		}
		else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
			g_string_append_unichar (str, g_utf8_get_char (lp));
			lp = g_utf8_next_char (lp);
		}
		/* accumulate until we hit the '=' or ';'.  If we hit
		 * a '=' the string contains the parameter name.  if
		 * we hit a ';' the string contains the parameter
		 * value and the name is either ENCODING (if value ==
		 * QUOTED-PRINTABLE) or TYPE (in any other case.)
		 */
		else if (*lp == '=') {
			if (str->len > 0) {
				param = e_vcard_attribute_param_new (str->str);
				g_string_assign (str, "");
				lp = g_utf8_next_char (lp);
			}
			else {
				skip_until (&lp, ":;");
				if (*lp == ';') {
					lp = g_utf8_next_char (lp);

				} else if (*lp == ':') {
					/* do nothing */

				} else {
					skip_to_next_line( &lp );
					break;
				}
			}
		}
		else if (*lp == ';' || *lp == ':' || *lp == ',') {
			gboolean colon = (*lp == ':');
			gboolean comma = (*lp == ',');

			if (param) {
				if (str->len > 0) {
					e_vcard_attribute_param_add_value (param, str->str);
					g_string_assign (str, "");
					if (!colon)
						lp = g_utf8_next_char (lp);
				}
				else {
					/* we've got a parameter of the form:
					 * PARAM=(.*,)?[:;]
					 * so what we do depends on if there are already values
					 * for the parameter.  If there are, we just finish
					 * this parameter and skip past the offending character
					 * (unless it's the ':'). If there aren't values, we free
					 * the parameter then skip past the character.
					 */
					if (!param->values) {
						e_vcard_attribute_param_free (param);
						param = NULL;
						if (!colon)
							lp = g_utf8_next_char (lp);
					}
				}

				if (param
				    && !g_ascii_strcasecmp (param->name, "encoding")
				    && !g_ascii_strcasecmp (param->values->data, "quoted-printable")) {
					*quoted_printable = TRUE;
					e_vcard_attribute_param_free (param);
					param = NULL;
				}
			}
			else {
				if (str->len > 0) {
					char *param_name;
					if (!g_ascii_strcasecmp (str->str,
								 "quoted-printable")) {
						param_name = "ENCODING";
						*quoted_printable = TRUE;
					}
					/* apple's broken addressbook app outputs naked BASE64
					   parameters, which aren't even vcard 3.0 compliant. */
					else if (!g_ascii_strcasecmp (str->str,
								      "base64")) {
						param_name = "ENCODING";
						g_string_assign (str, "b");
					}
					else {
						param_name = "TYPE";
					}

					if (param_name) {
						param = e_vcard_attribute_param_new (param_name);
						e_vcard_attribute_param_add_value (param, str->str);
					}
					g_string_assign (str, "");
					if (!colon)
						lp = g_utf8_next_char (lp);
				}
				else {
					/* we've got an attribute with a truly empty
					   attribute parameter.  So it's of the form:

					   ATTR;[PARAM=value;]*;[PARAM=value;]*:

					   (note the extra ';')

					   the only thing to do here is, well.. nothing.
					   we skip over the character if it's not a colon,
					   and the rest is handled for us: We'll either
					   continue through the loop again if we hit a ';',
					   or we'll break out correct below if it was a ':' */
					if (!colon)
						lp = g_utf8_next_char (lp);
				}
			}
			if (param && !comma) {
				e_vcard_attribute_add_param (attr, param);
				param = NULL;
			}
			if (colon)
				break;
		}
		else {
			g_warning ("invalid character found in parameter spec");
			g_string_assign (str, "");
			/*			skip_until (&lp, ":;"); */

			skip_to_next_line( &lp );
		}
	}

	if (str)
		g_string_free (str, TRUE);

	*p = lp;
}